PHP Conference Japan 2024

quoted_printable_encode

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

quoted_printable_encode將 8 位元字串轉換為 quoted-printable 字串

說明

quoted_printable_encode(字串 $string): 字串

根據 » RFC2045 第 6.7 節建立 quoted-printable 字串並回傳。

此函式與 imap_8bit() 類似,但此函式不需要 IMAP 模組即可運作。

參數

字串

輸入字串。

回傳值

回傳編碼後的字串。

範例

範例 #1 quoted_printable_encode() 範例

<?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?"

另請參閱

新增註解

使用者貢獻的註解 6 則註解

jurgen at edesign dot nl
10 年前
PHP 的原生實作和 ericth at NOSPAM dot pennyworth dot com (下方) 的函式都包含一個特性/錯誤 (SMTP 使用不匹配),這已在我的調整中解決。

這個錯誤會導致包含句點字元的文字,在通過這些函式時,編碼後的行首會以句點字元開頭,該行上的第一個句點字元在透過 SMTP 傳輸時將被捨棄。

解決方案:在編碼後會成為行首的句點字元前,新增 (另一個) 前置句點 `.`。

參考 http://stackoverflow.com/a/13949483: 「這是傳輸層的一個不乾淨的產物... SMTP 最可能是罪魁禍首 (請參閱 mail 函式文件中呼籲注意的部分),但也可能有其他低階機制表現類似。例如,如果您調整了 sendmail_path 設定或使用了有錯誤的 sendmail 程式,您可能會遇到類似的問題。」

<?php
define
('PHP_QPRINT_MAXL', 75);

function
leading_dot_fixed_php_quot_print_encode($str)
{
$lp = 0;
$ret = '';
$hex = "0123456789ABCDEF";
$length = strlen($str);
$str_index = 0;

while (
$length--) {
if (((
$c = $str[$str_index++]) == "\015") && ($str[$str_index] == "\012") && $length > 0) {
$ret .= "\015";
$ret .= $str[$str_index++];
$length--;
$lp = 0;
} else {
if (
ctype_cntrl($c)
|| (
ord($c) == 0x7f)
|| (
ord($c) & 0x80)
|| (
$c == '=')
|| ((
$c == ' ') && ($str[$str_index] == "\015")))
{
if ((
$lp += 3) > PHP_QPRINT_MAXL)
{
$ret .= '=';
$ret .= "\015";
$ret .= "\012";
$lp = 3;
}
$ret .= '=';
$ret .= $hex[ord($c) >> 4];
$ret .= $hex[ord($c) & 0xf];
}
else
{
if ((++
$lp) > PHP_QPRINT_MAXL)
{
$ret .= '=';
$ret .= "\015";
$ret .= "\012";
$lp = 1;
}
$ret .= $c;
if(
$lp == 1 && $c == '.') {
$ret .= '.';
$lp++;
}
}
}
}

return
$ret;
}

?>
arnaudv6
13 年前
我們應該知道並清楚地閱讀 RFC2045 規定一行不得超過 75 個字元。
因此,quoted_printable_encode() 會在此限制下分割行。
Thorsten Glaser
14 年前
兩個錯誤

1) 你的換行錯誤

$linebreak = "\r\n";

2) 沒有空格的行接續會出錯

/*
* 空格後的文字必須
* 重新讀取 ( + 任何額外的字元
* 這些字元是由於
* 空格後的編碼過程產生的)
*
* 此外,如果整行 *沒有*
* 空格,不要從 0 開始
*/
if (($i + $addtl_chars) > $whitesp_diff) {
$output .= substr($cur_conv_line, 0,
(strlen($cur_conv_line) - $whitesp_diff)) .
$linebreak;
$i = $i - $whitesp_diff + $addtl_chars;
} else {
/* 發出接續 --mirabilos */
$output .= $cur_conv_line .
'=' . $linebreak;
}
ericth at NOSPAM dot pennyworth dot com
13 年前
我已將 PHP 5.3.8 的 quoted_printable_encode 函式用 PHP 重寫,以便在 PHP < 5.3 版本中使用。已使用 PHP 5.2.11 測試。

<?php
define
('PHP_QPRINT_MAXL', 75);

function
php_quot_print_encode($str)
{
$lp = 0;
$ret = '';
$hex = "0123456789ABCDEF";
$length = strlen($str);
$str_index = 0;

while (
$length--) {
if (((
$c = $str[$str_index++]) == "\015") && ($str[$str_index] == "\012") && $length > 0) {
$ret .= "\015";
$ret .= $str[$str_index++];
$length--;
$lp = 0;
} else {
if (
ctype_cntrl($c)
|| (
ord($c) == 0x7f)
|| (
ord($c) & 0x80)
|| (
$c == '=')
|| ((
$c == ' ') && ($str[$str_index] == "\015")))
{
if ((
$lp += 3) > PHP_QPRINT_MAXL)
{
$ret .= '=';
$ret .= "\015";
$ret .= "\012";
$lp = 3;
}
$ret .= '=';
$ret .= $hex[ord($c) >> 4];
$ret .= $hex[ord($c) & 0xf];
}
else
{
if ((++
$lp) > PHP_QPRINT_MAXL)
{
$ret .= '=';
$ret .= "\015";
$ret .= "\012";
$lp = 1;
}
$ret .= $c;
}
}
}

return
$ret;
}

?>
marcus at synchromedia dot co dot uk
7 年前
請注意,此函式會以 Windows / RFC822 CRLF 斷行格式返回 quoted-printable 字串。如果您將此函式的輸出傳遞給 mail(),您可能需要先將其斷行格式轉換為 Unix LF 格式。
tzangerl [dot] pdc {dot} kth dot se
14 年前
一個用於 QP 編碼輸入字串(為 PHP < 5.3 撰寫)並同時
進行斷行處理的函式,以避免根據 SpamAssassin 的 MIME QP 長行規則被歸類為垃圾郵件。感謝 Matt Jeffers 指出下方 quoted_printable 腳本中的錯誤!

<?php
function quoted_printable_encode($input, $line_max = 75) {
$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);
$linebreak = "=0D=0A=\r\n";
/* the linebreak also counts as characters in the mime_qp_long_line
* rule of spam-assassin */
$line_max = $line_max - strlen($linebreak);
$escape = "=";
$output = "";
$cur_conv_line = "";
$length = 0;
$whitespace_pos = 0;
$addtl_chars = 0;

// iterate lines
for ($j=0; $j<count($lines); $j++) {
$line = $lines[$j];
$linlen = strlen($line);

// iterate chars
for ($i = 0; $i < $linlen; $i++) {
$c = substr($line, $i, 1);
$dec = ord($c);

$length++;

if (
$dec == 32) {
// space occurring at end of line, need to encode
if (($i == ($linlen - 1))) {
$c = "=20";
$length += 2;
}

$addtl_chars = 0;
$whitespace_pos = $i;
} elseif ( (
$dec == 61) || ($dec < 32 ) || ($dec > 126) ) {
$h2 = floor($dec/16); $h1 = floor($dec%16);
$c = $escape . $hex["$h2"] . $hex["$h1"];
$length += 2;
$addtl_chars += 2;
}

// length for wordwrap exceeded, get a newline into the text
if ($length >= $line_max) {
$cur_conv_line .= $c;

// read only up to the whitespace for the current line
$whitesp_diff = $i - $whitespace_pos + $addtl_chars;

/* the text after the whitespace will have to be read
* again ( + any additional characters that came into
* existence as a result of the encoding process after the whitespace)
*
* Also, do not start at 0, if there was *no* whitespace in
* the whole line */
if (($i + $addtl_chars) > $whitesp_diff) {
$output .= substr($cur_conv_line, 0, (strlen($cur_conv_line) -
$whitesp_diff)) . $linebreak;
$i = $i - $whitesp_diff + $addtl_chars;
} else {
$output .= $cur_conv_line . $linebreak;
}

$cur_conv_line = "";
$length = 0;
$whitespace_pos = 0;
} else {
// length for wordwrap not reached, continue reading
$cur_conv_line .= $c;
}
}
// end of for

$length = 0;
$whitespace_pos = 0;
$output .= $cur_conv_line;
$cur_conv_line = "";

if (
$j<=count($lines)-1) {
$output .= $linebreak;
}
}
// end for

return trim($output);
}
// end quoted_printable_encode
?>
To Top