quoted_printable_decode

(PHP 4, PHP 5, PHP 7, PHP 8)

quoted_printable_decode将 quoted-printable 字符串转换为 8 位字符串

说明

quoted_printable_decode(string $string): string

该函数返回与解码后的 quoted printable 字符串对应的 8 位二进制字符串(根据 » RFC2045,第 6.7 节,而不是 » RFC2821,第 4.5.2 节,因此不会从行首剥离额外的句点)。

此函数类似于 imap_qprint(),只是此函数不需要 IMAP 模块才能工作。

参数

string

输入字符串。

返回值

返回 8 位二进制字符串。

范例

范例 #1 quoted_printable_decode() 范例

<?php

$encoded
= quoted_printable_encode('Möchten Sie ein paar Äpfel?');

var_dump($encoded);
var_dump(quoted_printable_decode($encoded));
?>

以上范例将输出

string(37) "M=C3=B6chten Sie ein paar =C3=84pfel?"
string(29) "Möchten Sie ein paar Äpfel?"

参见

添加说明

用户贡献说明 21 条说明

jab_creations at yahoo dot com
3 年前
如果你得到黑钻石或奇怪的字符,这些字符看似阻止了回声,但仍然遇到 strlen($string) > 0,那么你可能遇到了编码问题。与在 DECODE 页面上编写 ENCODE 函数的人不同,我将实际讨论 DECODE 页面上的 DECODE。

我遇到的具体问题是,一封电子邮件使用俄语编码(KOI8-R)进行编码,尽管我将所有内容输出为 UTF-8,因为:兼容性。

如果你尝试使用俄语编码进行此操作

<?php
echo quoted_printable_decode('=81');
?>

你将获得损坏的数据。

我进行了一些测试,发现以下是如何嵌套 mb_convert_encoding 函数

<?php
echo '<p>Test: "'.mb_convert_encoding(quoted_printable_decode('=81'), 'UTF-8', 'KOI8-R').'".</p>';
?>

不幸的是,我在 RFC 2045 第 6.7 节中没有找到字符映射表或任何内容。但是,我遇到了网站 https://dencode.com/en/string/quoted-printable,它允许你手动选择编码(这是一个开源网站,他们有一个供好奇的人使用的 GIT 存储库)。

事实证明,范围的开始相对于编码。因此,拉丁语(ISO-8859-1)和俄语(KOI8-R)很可能会(未经测试)编码为不同的字符,**相对于字符串编码**。
Karora
15 年前
将之前的一些评论放在一起,你可以综合出一个简洁、高效的 quoted_printable_encode 函数,如下所示

请注意,我将此放在我的标准库文件中,因此我将其包装在一个 !function_exists 中,以便如果存在预先存在的 PHP 函数,它将正常工作,而此函数将被评估为无操作。

<?php
if ( !function_exists("quoted_printable_encode") ) {
/**
* 处理字符串以符合 RFC2045 第 6.7 节的要求。请注意,
* 这可以正常工作,但替换的字符比最小集更多。为了可读性,
* 空格不会被编码为 =20。
*/
function quoted_printable_encode($string) {
return
preg_replace('/[^\r\n]{73}[^=\r\n]{2}/', "$0=\r\n", str_replace("%","=",str_replace("%20"," ",rawurlencode($string))));
}
}
?>

此致,
Andrew McMillan.
madmax at express dot ru
24 年前
一些浏览器(例如 Netscape)
发送 8 位 quoted printable 文本,如下所示
=C5=DD=A3=D2=C1= =DA

"= =" 表示连续的单词。
PHP 函数无法检测到这种情况,并将其转换为类似于
abcde=f
legolas558
17 年前
请注意,在下面的编码函数中存在错误!

<?php
if (($c==0x3d) || ($c>=0x80) || ($c<0x20))
?>

$c 应该与小于或等于编码空格的字符进行比较!

所以正确的代码是

<?php
if (($c==0x3d) || ($c>=0x80) || ($c<=0x20))
?>

请修复代码或发布此说明
soletan at toxa dot de
17 年前
请注意!下面的编码文本方法不符合 RFC1521 的要求!

假设一行包含 75 个 'A' 和一个单一的 é(或类似的非 ASCII 字符)... 下面的方法将编码并返回 78 个字节的一行,违反了 RFC 1521,5.1 规则 #5:“Quoted-Printable 编码要求编码的行长度不超过 76 个字符。”

好的 QP 编码需要比这更多一些。
zg
15 年前
<?php

function quoted_printable_encode( $str, $chunkLen = 72 )
{
$offset = 0;

$str = strtr(rawurlencode($str), array('%' => '='));
$len = strlen($str);
$enc = '';

while (
$offset < $len )
{
if (
$str{ $offset + $chunkLen - 1 } === '=' )
{
$line = substr($str, $offset, $chunkLen - 1);
$offset += $chunkLen - 1;
}
elseif (
$str{ $offset + $chunkLen - 2 } === '=' )
{
$line = substr($str, $offset, $chunkLen - 2);
$offset += $chunkLen - 2;
}
else
{
$line = substr($str, $offset, $chunkLen);
$offset += $chunkLen;
}

if (
$offset + $chunkLen < $len )
$enc .= $line ."=\n";
else
$enc .= $line;
}

return
$enc;
}

?>
pob at medienrecht dot NOSPAM dot org
23 年前
如果您无法访问 imap_* 并且不想使用
?$message = chunk_split( base64_encode($message) );?
因为您希望能够阅读邮件的 ?源代码?, 您可能想尝试以下方法
(欢迎任何建议!)


function qp_enc($input = "quoted-printable 编码测试字符串", $line_max = 76) {

$hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
$lines = preg_split("/(?:\r\n|\r|\n)/", $input);
$eol = "\r\n";
$escape = "=";
$output = "";

while( list(, $line) = each($lines) ) {
//$line = rtrim($line); // 删除尾部空格 -> 不需要 =20\r\n
$linlen = strlen($line);
$newline = "";
for($i = 0; $i < $linlen; $i++) {
$c = substr($line, $i, 1);
$dec = ord($c);
if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // 仅转换 eol 处的空格
$c = "=20";
} elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // 始终对 "\t" 进行编码, 这是 *不* 必要的
$h2 = floor($dec/16); $h1 = floor($dec%16);
$c = $escape.$hex["$h2"].$hex["$h1"];
}
if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF 不计入
$output .= $newline.$escape.$eol; // 软换行; " =\r\n" 是可以的
$newline = "";
}
$newline .= $c;
} // for 循环结束
$output .= $newline.$eol;
}
return trim($output);

}

$eight_bit = "\xA7 \xC4 \xD6 \xDC \xE4 \xF6 \xFC \xDF = xxx yyy zzz \r\n"
." \xA7 \r \xC4 \n \xD6 \x09 ";
print $eight_bit."\r\n---------------\r\n";
$encoded = qp_enc($eight_bit);
print $encoded;
andre at luyer dot nl
15 年前
下面是对 Andrew 代码的少量更新。此版本保留原始的 CRLF 对 (并允许 preg_replace 按预期工作)

<?php
if (!function_exists("quoted_printable_encode")) {
/**
* 处理字符串以符合 RFC2045 第 6.7 节的要求。请注意
* 这有效, 但替换的字符比最小集合多。为了可读性
* 虽然空格和 CRLF 对没有编码。
*/
function quoted_printable_encode($string) {
return
preg_replace('/[^\r\n]{73}[^=\r\n]{2}/', "$0=\r\n",
str_replace("%", "=", str_replace("%0D%0A", "\r\n",
str_replace("%20"," ",rawurlencode($string)))));
}
}
?>

此致, André
sven at e7o dot de
4 年前
如果您真的很懒, 并且最终生成的是 HTML, 那么只需将其转换为 HTML 实体, 然后将 Unicode/ISO 问题转移到文档的编码

<?php
function qpd($e)
{
return
preg_replace_callback(
'/=([a-z0-9]{2})/i',
function (
$m) {
return
'&#x00' . $m[1] . ';';
},
$e
);
}
?>
yual at inbox dot ru
10 年前
我用一个 hack 来解决这个 bug

$str = str_replace("=\r\n", '', quoted_printable_encode($str));
if (strlen($str) > 73) {$str = substr($str,0,74)."=\n".substr($str,74);}
feedr
15 年前
另一个 (改进的) 版本的 quoted_printable_encode()。请注意 str_replace() 中数组元素的顺序。
我刚刚重写了前面的函数, 以提高可读性。

<?php
if (!function_exists("quoted_printable_encode")) {
/**
* 处理字符串以符合 RFC2045 第 6.7 节的要求。请注意
* 这有效, 但替换的字符比最小集合多。为了可读性
* 虽然空格和 CRLF 对没有编码。
*/
function quoted_printable_encode($string) {
$string = str_replace(array('%20', '%0D%0A', '%'), array(' ', "\r\n", '='), rawurlencode($string));
$string = preg_replace('/[^\r\n]{73}[^=\r\n]{2}/', "$0=\r\n", $string);

return
$string;
}
}
?>
Christian Albrecht
15 年前
除了 david lionhead 的函数之外

<?php
function quoted_printable_encode($txt) {
/* 确保没有 %20 或类似的 */
$txt = rawurldecode($txt);
$tmp="";
$line="";
for (
$i=0;$i<strlen($txt);$i++) {
if ((
$txt[$i]>='a' && $txt[$i]<='z') || ($txt[$i]>='A' && $txt[$i]<='Z') || ($txt[$i]>='0' && $txt[$i]<='9')) {
$line.=$txt[$i];
if (
strlen($line)>=75) {
$tmp.="$line=\n";
$line="";
}
}
else {
/* 重要的是要区分这个情况和上面的情况 */
if (strlen($line)>=72) {
$tmp.="$line=\n";
$line="";
}
$line.="=".sprintf("%02X",ord($txt[$i]));
}
}
$tmp.="$line\n";
return
$tmp;
}
?>
david at lionhead dot nl
15 年前
这是我写的 quoted_printable 编码函数,因为 convert.quoted-printable-encode 过滤器在 Outlook Express 上会出错。这个函数似乎在 Express/Outlook/Thunderbird/Gmail 上都正常工作。

function quoted_printable_encode($txt) {
$tmp="";
$line="";
for ($i=0;$i<strlen($txt);$i++) {
if (($txt[$i]>='a' && $txt[$i]<='z') || ($txt[$i]>='A' && $txt[$i]<='Z') || ($txt[$i]>='0' && $txt[$i]<='9'))
$line.=$txt[$i];
else
$line.="=".sprintf("%02X",ord($txt[$i]));
if (strlen($line)>=75) {
$tmp.="$line=\n";
$line="";
}
}
$tmp.="$line\n";
return $tmp;
}
vita dot plachy at seznam dot cz
16 年前
<?php
$text
= <<<EOF
这个函数可以将文本转换为 quoted-printable 字符串,也可以创建电子邮件头中使用的 encoded-words(参见 http://www.faqs.org/rfcs/rfc2047.html)。

返回文本的每一行都不超过指定长度。Encoded-words 不包含换行符。特殊字符将被移除。
EOF;

define('QP_LINE_LENGTH', 75);
define('QP_LINE_SEPARATOR', "\r\n");

function
quoted_printable_encode($string, $encodedWord = false)
{
if(!
preg_match('//u', $string)) {
throw new
Exception('输入字符串不是有效的 UTF-8');
}

static
$wordStart = '=?UTF-8?Q?';
static
$wordEnd = '?=';
static
$endl = QP_LINE_SEPARATOR;

$lineLength = $encodedWord
? QP_LINE_LENGTH - strlen($wordStart) - strlen($wordEnd)
:
QP_LINE_LENGTH;

$string = $encodedWord
? preg_replace('~[\r\n]+~', ' ', $string) // 我们需要 encoded word 是一行
: preg_replace('~\r\n?~', "\n", $string); // 规范化行尾
$string = preg_replace('~[\x00-\x08\x0B-\x1F]+~', '', $string); // 移除控制字符

$output = $encodedWord ? $wordStart : '';
$charsLeft = $lineLength;

$chr = isset($string{0}) ? $string{0} : null;
$ord = ord($chr);

for (
$i = 0; isset($chr); $i++) {
$nextChr = isset($string{$i + 1}) ? $string{$i + 1} : null;
$nextOrd = ord($nextChr);

if (
$ord > 127 or // 高字节值
$ord === 95 or // 下划线 "_"
$ord === 63 && $encodedWord or // "?" 在 encoded word 中
$ord === 61 or // 等号 "="
// 空格或制表符在 encoded word 中或行尾
$ord === 32 || $ord === 9 and $encodedWord || !isset($nextOrd) || $nextOrd === 10
) {
$chr = sprintf('=%02X', $ord);
}

if (
$ord === 10) { // 换行符
$output .= $endl;
$charsLeft = $lineLength;
} elseif (
strlen($chr) < $charsLeft or
strlen($chr) === $charsLeft and $nextOrd === 10 || $encodedWord
) { // 添加字符
$output .= $chr;
$charsLeft-=strlen($chr);
} elseif (isset(
$nextOrd)) { // 需要另一行
$output .= $encodedWord
? $wordEnd . $endl . "\t" . $wordStart . $chr
: '=' . $endl . $chr;
$charsLeft = $lineLength - strlen($chr);
}

$chr = $nextChr;
$ord = $nextOrd;
}

return
$output . ($encodedWord ? $wordEnd : '');
}

echo
quoted_printable_encode($text/*, true*/);
ludwig at gramberg-webdesign dot de
16 年前
我使用流转换功能的 quoted-printable 编码方法

<?php
/**
* @param string $str
* @return string
* */
function quoted_printable_encode($str) {
$fp = fopen('php://temp', 'w+');
stream_filter_append($fp, 'convert.quoted-printable-encode');
fwrite($fp, $str);
fseek($fp, 0);
$result = '';
while(!
feof($fp))
$result .= fread($fp, 1024);
fclose($fp);
return
$result;
}
?>
roelof
17 年前
我修改了以下版本的 legolas558 在 users dot sausafe dot net 上并添加了包装选项。

<?php
/**
* 将字符串编码为所谓的“quoted printable”。这种类型的编码用于将 8 位电子邮件消息的内容作为 7 位发送。
*
* @access public
* @param string $str 要编码的字符串
* @param bool $wrap 在 74 个字符后添加换行符?
* @return string
*/

function quoted_printable_encode($str, $wrap=true)
{
$return = '';
$iL = strlen($str);
for(
$i=0; $i<$iL; $i++)
{
$char = $str[$i];
if(
ctype_print($char) && !ctype_punct($char)) $return .= $char;
else
$return .= sprintf('=%02X', ord($char));
}
return (
$wrap === true)
?
wordwrap($return, 74, " =\n")
:
$return;
}

?>
legolas558 at users dot sausafe dot net
17 年前
正如 soletan at toxa dot de 所报告的那样,该函数非常糟糕,不能提供有效的引号可打印字符串。在使用它时,我看到垃圾邮件代理将电子邮件标记为 QP_EXCESS,有时电子邮件客户端根本无法识别标题;我真的浪费了很多时间 :(。这是新版本(我们在 Drake CMS 核心代码中使用它),它可以无缝工作。

<?php

//L: 注意 $encoding 是大写的
//L: 此外,你的 PHP 安装必须有 ctype_alpha,否则自己编写它
function quoted_printable_encode($string, $encoding='UTF-8') {
// 将此函数用于标题,而不是电子邮件正文,因为它缺少换行符
$len = strlen($string);
$result = '';
$enc = false;
for(
$i=0;$i<$len;++$i) {
$c = $string[$i];
if (
ctype_alpha($c))
$result.=$c;
else if (
$c==' ') {
$result.='_';
$enc = true;
} else {
$result.=sprintf("=%02X", ord($c));
$enc = true;
}
}
//L: 这样垃圾邮件代理就不会用 QP_EXCESS 标记你的电子邮件
if (!$enc) return $string;
return
'=?'.$encoding.'?q?'.$result.'?=';
}

我希望它有帮助 ;)

?>
Thomas Pequet / Memotoo.com
17 年前
如果你想要一个函数来做“quoted_printable_decode()”的相反操作,请点击链接,你会找到“quoted_printable_encode()”函数。
http://www.memotoo.com/softs/public/PHP/quoted printable_encode.inc.php

兼容“ENCODING=QUOTED-PRINTABLE”。
示例
quoted_printable_encode(ut8_encode("c'est quand l'été ?"))
-> "c'est quand l'=C3=A9t=C3=A9 ?"
steffen dot weber at computerbase dot de
19 年前
由于两位十六进制表示法应该是大写,因此你应该使用“=%02X”(大写 X)而不是“=%02x”作为 sprintf() 的第一个参数。
dmitry at koterov dot ru
19 年前
前面的评论有一个错误:由于不正确地使用了 preg_match_all(),导致对短测试的编码不起作用。有人读过它吗?:-)

更正版本(似乎如此),还额外添加了 imap_8bit() 函数的模拟。

if (!function_exists('imap_8bit')) {
function imap_8bit($text) {
return quoted_printable_encode($text);
}
}

function quoted_printable_encode_character ( $matches ) {
$character = $matches[0];
return sprintf ( '=%02x', ord ( $character ) );
}

// 基于 http://www.freesoft.org/CIE/RFC/1521/6.htm
function quoted_printable_encode ( $string ) {
// 规则 #2、#3(保留空格和制表符)
$string = preg_replace_callback (
'/[^\x21-\x3C\x3E-\x7E\x09\x20]/',
'quoted_printable_encode_character',
$string
);
$newline = "=\r\n"; // '=' + CRLF(规则 #4)
// 确保拆分行不会干扰转义字符
// (chunk_split 这里失败)
$string = preg_replace ( '/(.{73}[^=]{0,3})/', '$1'.$newline, $string);
return $string;
}
naitsirch at e dot mail dot de
4 年前
如果传递的字符串中存在空字节,quoted_printable_decode 将裁剪空字节本身及其后的所有内容。

<?php
$result
= quoted_printable_decode("This is a\0 test.");
// $result === 'This is a'
?>

这不是一个错误,而是预期行为,由 RFC 2045(参见 https://www.ietf.org/rfc/rfc2045.txt)在第 2.7 和 2.8 段中定义。
To Top