PHP 8.4.2 Released!

quoted_printable_encode

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

quoted_printable_encode将 8-bit 字符串转换成 quoted-printable 字符串

说明

quoted_printable_encode(string $string): string

返回 quoted-printable 格式的字符,该格式由 » RFC2045 6.7.章节里制定。

该函数与 imap_8bit() 函数十分相似,不同的是该函数不需要 IMAP 模块就能运行。

参数

string

输入的字符串。

返回值

返回编码之后的字符串。

示例

示例 #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 notes

up
9
jurgen at edesign dot nl
10 years ago
Both PHP's native implementation and the function of ericth at NOSPAM dot pennyworth dot com (below) contain an feature/error (usage for SMTP mismatch) which has been solved in my adjustment below.

The error causes a text containing period character(s), when passed through these functions, end up with encoded lines starting with a period character, the first period character on that line will be discarded when it is transported over SMTP.

Solution: add (another) leading '.' to period characters which would end up as first character on a line when encoded.

See http://stackoverflow.com/a/13949483: "This is a dirty artifact of your transport layer... SMTP is the most probable culprit (see the call for caution in the mail function documentation) but there may be other low level mecanisms that behave similarly. For example if you tweaked the sendmail_path setting or use a buggy sendmail program you may experience similar woes."

<?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;
}

?>
up
6
arnaudv6
13 years ago
One will like to know and clearly read that RFC2045 specifies a line shall not exceed 75 characters.
Accordingly, quoted_printable_encode() splits line at this limit.
up
3
Thorsten Glaser
14 years ago
Two bugs:

1) your linebreak is wrong

$linebreak = "\r\n";

2) continuation of lines with no whitespace is broken

/*
* 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 {
/* emit continuation --mirabilos */
$output .= $cur_conv_line .
'=' . $linebreak;
}
up
3
ericth at NOSPAM dot pennyworth dot com
13 years ago
I have re-written the PHP 5.3.8 function for quoted_printable_encode into PHP for use with PHP < 5.3. Tested with 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;
}

?>
up
2
marcus at synchromedia dot co dot uk
7 years ago
Note that this function returns the quoted-printable string with Windows / RFC822 CRLF line breaks. If you're passing the output of this function into mail(), you may need to convert its line breaks to Unix LF style first.
up
-1
tzangerl [dot] pdc {dot} kth dot se
14 years ago
A function that QP-encodes an input string (written for PHP < 5.3) and
wordwraps it at the same time, in order to avoid classification according to the MIME QP LONG LINE rule of SpamAssassin. Thanks for Matt Jeffers to point out errors in the below quoted_printable script!

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