imap_8bit 似乎有一个错误,因为它不会对“?”进行编码。
在用
带有尾部“?”的德语变音符号编码邮件主题时遇到了很多麻烦...
尝试这个
$subject = "=?iso-8859-1?Q?" . str_replace("?","=3F",imap_8bit($tsubject_to_encode)) . "?=";
(PHP 4,PHP 5,PHP 7,PHP 8)
imap_8bit — 将 8 位字符串转换为 quoted-printable 字符串
字符串
要转换的 8 位字符串
返回已引用的可打印字符串,或在失败时返回 **false
**。
imap_8bit 似乎有一个错误,因为它不会对“?”进行编码。
在用
带有尾部“?”的德语变音符号编码邮件主题时遇到了很多麻烦...
尝试这个
$subject = "=?iso-8859-1?Q?" . str_replace("?","=3F",imap_8bit($tsubject_to_encode)) . "?=";
...deed.ztinmehc-ut.zrh@[email protected]...
我在没有 IMAP 模块的情况下使用 PHP 时
会使用以下函数代替 imap_8bit,
它基于
https://php.net/quoted_printable_decode 中找到的代码
并且(据称)会产生与 imap_8bit 完全相同的结果,
(在数千个随机字符串中进行了测试,其中包含大量
空格、制表符、crlf、lfcr、lf、cr 等内容,
到目前为止还没有发现反例 :))
而且可以强制编码尾随空格,
这与 imap_8bit 所做的相反,
我认为这违反了 RFC2045,
(参见 http://bugs.php.net/bug.php?id=35290)
通过注释掉一个中心行。
<?php
function quoted_printable_encode($sText,$bEmulate_imap_8bit=true) {
// split text into lines
$aLines=explode(chr(13).chr(10),$sText);
for ($i=0;$i<count($aLines);$i++) {
$sLine =& $aLines[$i];
if (strlen($sLine)===0) continue; // do nothing, if empty
$sRegExp = '/[^\x09\x20\x21-\x3C\x3E-\x7E]/e';
// imap_8bit encodes x09 everywhere, not only at lineends,
// for EBCDIC safeness encode !"#$@[\]^`{|}~,
// for complete safeness encode every character :)
if ($bEmulate_imap_8bit)
$sRegExp = '/[^\x20\x21-\x3C\x3E-\x7E]/e';
$sReplmt = 'sprintf( "=%02X", ord ( "$0" ) ) ;';
$sLine = preg_replace( $sRegExp, $sReplmt, $sLine );
// encode x09,x20 at lineends
{
$iLength = strlen($sLine);
$iLastChar = ord($sLine{$iLength-1});
// !!!!!!!!
// imap_8_bit does not encode x20 at the very end of a text,
// here is, where I don't agree with imap_8_bit,
// please correct me, if I'm wrong,
// or comment next line for RFC2045 conformance, if you like
if (!($bEmulate_imap_8bit && ($i==count($aLines)-1)))
if (($iLastChar==0x09)||($iLastChar==0x20)) {
$sLine{$iLength-1}='=';
$sLine .= ($iLastChar==0x09)?'09':'20';
}
} // imap_8bit encodes x20 before chr(13), too
// although IMHO not requested by RFC2045, why not do it safer :)
// and why not encode any x20 around chr(10) or chr(13)
if ($bEmulate_imap_8bit) {
$sLine=str_replace(' =0D','=20=0D',$sLine);
//$sLine=str_replace(' =0A','=20=0A',$sLine);
//$sLine=str_replace('=0D ','=0D=20',$sLine);
//$sLine=str_replace('=0A ','=0A=20',$sLine);
}
// finally split into softlines no longer than 76 chars,
// for even more safeness one could encode x09,x20
// at the very first character of the line
// and after soft linebreaks, as well,
// but this wouldn't be caught by such an easy RegExp
preg_match_all( '/.{1,73}([^=]{0,2})?/', $sLine, $aMatch );
$sLine = implode( '=' . chr(13).chr(10), $aMatch[0] ); // add soft crlf's
}
// join lines into text
return implode(chr(13).chr(10),$aLines);
}
?>
MS Exchange 服务器中存在一个错误,它错误地处理 CRLF。似乎它同时将 CR 和 LF 转换为 LF,所以,您不仅会得到一个新行,还会得到两行。
然后电子邮件客户端会错误地分析标题信息,并通常在消息正文中查看。
这会使自定义创建的标题无法使用。
我发现解决此问题的唯一方法是违反标题格式设置的 RFC 规则,并且仅将 \n 用于新行。
不幸的是,我还没能得知发生此问题的 Exchange 服务器版本,但我觉得这并不只是我偶然遇到的问题。
希望这能帮到某些人。
我对使用波兰文字符编码大型主题遇到问题。问题在于 imap_8bit() 分割主题(在第 75 个字符处),但当我添加“=?ISO-8859-2?Q?”时,标题太长。
这是一个解决方案
<?php
$subject = str_replace(" ", "_", trim($subject)) ;
// 我们需要删除 imap_8bit() 生成的“=\r\n”并替换 '?'
$subject = str_replace("?", "=3F", str_replace("=\r\n", "", imap_8bit($subject))) ;
// 现在,我们按 \r\n 分割,但对“=?ISO ...”的文本进行编码
$subject = str_replace("\r\n", "?=\r\n =?ISO-8859-2?Q?", chunk_split($subject, 55)) ;
// 我们还必须删除最后不必要的编码文本:
$subject = "=?ISO-8859-2?Q?" .substr($subject, 0, strlen($subject)-20) . "?=" ;
?>
umu 的代码似乎运行得很好。但是,如果你在 Unix 系统上,你应该将所有 chr(13).chr(10) 替换为仅为 chr(10)
无论如何,它都在 php5.mail() -> [email protected] -> outlook express 中为我运行
按照 RFC2047 将一封邮件主题字符串编码成一个有关注符字符和 75 个字符总行长的编码单词。
示例:“Subject Testä” -> “=?ISO-8859-1?Q?Subject_Test=E4?="
<?php
function getSubjectEncoded($_str,$_charset='ISO-8859-1'){
// 27.08.2015 david jufer
// Convert an 8bit string to a encoded-word string (according to RFC2047) www.ietf.org/rfc/rfc2047.txt
// encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
// An 'encoded-word' may not be more than 75 characters long, including 'charset', 'encoding', 'encoded-text', and delimiters.
// The "Q" encoding is similar to the "Quoted-Printable" content-transfer-encoding defined in RFC 2045
$ret = '';
$str = imap_8bit($_str);
$len = 7+strlen($_charset);
// remove linebreaks from imap_8bit, string chunks are too long
$str = str_replace("=\r\n",'',$str);
// insert linebreaks at right position, be aware of special chars ("ä" "=E4") do not split them
$s = 0;
$l = 75-$len;
while(strlen($str)>$s){
$ts = $s;
if(substr($str,($s+$l)-2,1)=='='){
$s += $l-2;
}else if(substr($str,($s+$l)-1,1)=='='){
$s += $l-1;
}else{
$s += $l;
}
$ret .= "\r\n".substr($str,$ts,$s-$ts);
}
// remove first linebreak, replace SPACES with "_"
$ret = str_replace(' ','_',trim($ret));
// put together encoded-word
$ret = '=?'.$_charset.'?Q?'.str_replace("\r\n","?=\r\n =?".$_charset."?Q?",$ret)."?=";
// rückgabe
return $ret;
}
?>
阅读 Bully 的笔记
你可以使用以下代码生成更大的主题
<?
$encoded = str_replace("=\r\n","",imap_8bit($string_to_encode));
?>
有误。该头不得超过每行 75 个字符。
正确的解决方案
<?
$encoded = rtrim( str_replace( "\n","\n\t", imap_8bit ($string_to_encode)))."\r\n";
?>
它将在编码的新行开头添加 \t。
邮件系统将主题后面的行看成该头的扩展。
创建可引用打印电子邮件时的正确方法是
$subject="Subject: =?iso-8859-1?Q?". imap_8bit("áéíóú"). "?=";
而以下方法是错误的,因为在 "=ED" 处 qprint 将生成 8bit 数据 ( í )
$subject="Subject: =?iso-8859-1?Q?". imap_qprint("=ED"). "?=";
代码基于 k dot kozlowski at enter dot pl,但针对 UTF-8
(我在垃圾邮件测试中使用非常长的主题时唯一遇到的问题是 SUBJECT_ENCODED_TWICE,但其他 MUA 也生成同样的问题)
<?
function header_quoted_printable_encode($string, $encoding='UTF-8') {
$string = str_replace(" ", "_", trim($string)) ;
// 我们需要删除 imap_8bit() 生成的 "=\r\n" 和替换 ?
$string = str_replace("?", "=3F", str_replace("=\r\n", "", imap_8bit($string))) ;
// 现在我们按 \r\n 分割 - 我不清楚具体是多少字符(头名称是否计算在内?)
$string = chunk_split($string, 73);
// 我们还必须删除最后一个不需要的 \r\n
$string = substr($string, 0, strlen($string)-2);
// 用编码文本 "=?UTF ..." 替换换行符
$string = str_replace("\r\n", "?=".HEAD_CRLF." =?".$encoding."?Q?", $string) ;
return '=?'.$encoding.'?Q?'.$string.'?=';
}
?>
我修改了 nick at plumdigitalmedia dot com 的注释,以便它可以支持 ISO-8859-1 编码头
<?php
public function encodeSubject($string,$prefix="=?ISO-8859-1?Q?",$postfix="?=") {
$crlf = "\n\t";
$string = preg_replace('!(\r\n|\r|\n)!', $crlf, $string) . $crlf ;
$f[] = '/([\000-\010\013\014\016-\037\075\177-\377])/e' ;
$r[] = "'=' . sprintf('%02X', ord('\\1'))" ;
$f[] = '/([\011\040])' . $crlf . '/e' ;
$r[] = "'=' . sprintf('%02X', ord('\\1')) . '" . $crlf . "'" ;
$string = preg_replace($f, $r, $string);
return $prefix.trim(wordwrap($string, 70 - strlen($prefix) - strlen($postfix), ' ' . $postfix . $crlf . $prefix, true)).$postfix;
}
?>
此致,汉斯,电子邮件地址:http://lintoo.dk/
您可以使用以下内容来生成较大的主题。
使用 imap_qprint() 函数来转换您的主题。
示例
<?php
$subject .= "=?iso-8859-1?Q?" . imap_qprint($subject) . "?=";
?>
此函数似乎会将行包装在单词中间,而不只是空白处,在用来设置电子邮件正文文本时,这样会影响某些版本的 Outlook Express。相对于此函数,我们更有幸使用到了
<?
函数 quoted_printable($string)
{
$crlf = "\n" ;
$string = preg_replace('!(\r\n|\r|\n)!', $crlf, $string) . $crlf ;
$f[] = '/([\000-\010\013\014\016-\037\075\177-\377])/e' ;
$r[] = "'=' . sprintf('%02X', ord('\\1'))" ;
$f[] = '/([\011\040])' . $crlf . '/e' ;
$r[] = "'=' . sprintf('%02X', ord('\\1')) . '" . $crlf . "'" ;
$string = preg_replace($f, $r, $string) ;
return trim(wordwrap($string, 70, ' =' . $crlf)) ;
}
?>
对“75 个字符后拆分”现象的评论
通过在 75 个字符后拆分行,这个函数的行为符合 RFC2047(http://www.ietf.org/rfc/rfc2047.txt)(指定用于消息头中的非 ASCII 文本),“2. 编码单词的语法”。
所谓的“编码单词”具有以下格式
编码单词 = "=?" 字符集 "?" 编码 "?" 编码文本 "?="
'编码单词' 的长度不得超过 75 个字符,包括 'charset'、'encoding'、'encoded-text' 和定界符。如果要编码的文本大于可容纳在 75 个字符的 'encoded-word' 中,可以使用多个 'encoded-word'(以 CRLF SPACE 分隔)。
hth
WOT
你可以使用以下代码生成更大的主题
$encoded = str_replace("=\r\n","",imap_8bit($string_to_encode));
此注释下方的代码会给 SpamAssassin 带来看很多麻烦,要解决此问题,你需要使用诸如以下内容来编码你的主题
<?php
/**
* 必要时编码标头
* 根据 RFC2047
*/
私有函数 encodeHeader($input, $charset = 'ISO-8859-1')
{
preg_match_all('/(\s?\w*[\x80-\xFF]+\w*\s?)/', $input, $matches);
foreach ($matches[1] as $value) {
$replacement = preg_replace('/([\x20\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value);
$input = str_replace($value, '=?' . $charset . '?Q?' . $replacement . '?=', $input);
}
返回 wordwrap($input,75,"\n\t",true);
}
?>