E-mail de PHP a cassé l'en-tête de l'encodage
Mon script PHP envoie un email aux utilisateurs et lors de la réception d'un email à leurs boîtes aux lettres, la ligne de sujet ($subject
) a des personnages comme a^£
ajouté à la fin de mon texte de l'objet. C'est à l'évidence et l'encodage de problème. L'e-mail le contenu du message lui-même est très bien, juste la ligne d'objet est cassé.
J'ai cherché partout mais impossible de trouver la façon de coder mon sujet correctement.
C'est ma tête. Notez que je suis en utilisant Content-Type
avec charset=utf-8
et Content-Transfer-Encoding: 8bit
.
//set all necessary headers
$headers = "From: $sender_name<$from>\n";
$headers .= "Reply-To: $sender_name<$from>\n";
$headers .= "X-Sender: $sender_name<$from>\n";
$headers .= "X-Mailer: PHP4\n"; //mailer
$headers .= "X-Priority: 3\n"; //1 UrgentMessage, 3 Normal
$headers .= "MIME-Version: 1.0\n";
$headers .= "X-MSMail-Priority: High\n";
$headers .= "Importance: 3\n";
$headers .= "Date: $date\n";
$headers .= "Delivered-to: $to\n";
$headers .= "Return-Path: $sender_name<$from>\n";
$headers .= "Envelope-from: $sender_name<$from>\n";
$headers .= "Content-Transfer-Encoding: 8bit\n";
$headers .= "Content-Type: text/plain; charset=UTF-8\n";
- Avez-vous pensé à l'aide de phpmailer.worxware.com cela vous permettra d'économiser des tas de soucis.
- En plus des réponses apportées, note que, selon la doc, vous êtes censé pour séparer plusieurs en-têtes avec CRLF (
\r\n
), et pas seulement LF (\n
).
Vous devez vous connecter pour publier un commentaire.
Mise à jour Pour plus de pratique et up-to-date de la réponse, avoir un regard sur Palec réponse.
Le caractère spécifique de l'encodage en Content-Type ne fait que décrire le codage de caractères du corps du message mais pas la tête. Vous devez utiliser le des mots codés syntaxe avec le quoted-printable encodage ou la Le codage Base64:
Vous pouvez utiliser
imap_8bit
pour la quoted-printable d'encodage et debase64_encode
pour l'encodage Base64:=xx
.Subject: =?utf-8?B?0LjQstGB0YLRg9C/0LjRgtC10LvRjNC90L7QtSDQsdGA0L7Q?= =?utf-8?B?vdC40YDQvtCy0LDQvdC40LUg0L3QvtC80LXRgNGMIDA0OC0xMzktMTMg?= =?utf-8?B?LSBBbWlnb3MgQXBhcnRtZW50IC0g0L/Qu9Cw0YLQtdC2INC/0LXRgNC1?= =?utf-8?B?0YfQuNGB0LvQtdC90LXQvA==?=
Subject: =?utf-8?B?0LjQstGB0YLRg9C/0LjRgtC10LvRjNC90L7QtQ==?= =?utf-8?B?INCx0YDQvtC90LjRgNC+0LLQsNC90LjQtQ==?= =?utf-8?B?INC90L7QvNC10YDRjA==?= =?utf-8?B?IDA1Mi0xMzktMTM=?= =?utf-8?B?IC0=?= =?utf-8?B?IEFtaWdvcw==?= =?utf-8?B?IEFwYXJ0bWVudA==?= =?utf-8?B?IC0=?= =?utf-8?B?INC/0LvQsNGC0LXQtg==?= =?utf-8?B?INC/0LXRgNC10YfQuNGB0LvQtdC90LXQvA==?=
j'espère que ce sera utile pour quelqu'un - je passer 8h sur le débogage et la fixation de problème.imap_8bit()
, sauf celui-ci ne nécessite pas le module IMAP de travail.=?…?…?…?=
) doit être d'au plus 75 caractères et les lignes contenant des mots codés doit être à plus de 76 caractères (y compris l'espace au début d'une continuation de la ligne). Il est nécessaire de coder le texte en plus de mots et de plier le champ de sorte qu'il s'inscrit dans les limites.TL;DR
ou
Problème et de la solution
La
Content-Type
etContent-Transfer-Encoding
en-têtes s'applique seulement pour le corps de votre message. Pour les en-têtes, il y a un mécanisme qui permet de spécifier leur encodage spécifié dans RFC 2047.Vous devez encoder vos
Subject
viaiconv_mime_encode()
, qui existe depuis PHP 5:Changer
input-charset
pour correspondre à l'encodage de votre chaîne$subject
. Vous devriez laisseroutput-charset
commeUTF-8
. Avant de PHP 5.4, l'utilisationarray()
au lieu de[]
.Maintenant
$encoded_subject
est (sans point de retour à la ligne)pour
$subject
contenant:Comment ça fonctionne?
La
iconv_mime_encode()
fonction divise le texte, code pour chaque pièce séparément dans un<mots codés>
jeton et plis les espaces entre eux. Codé mot est=?<charset>?<encoding>?<encoded-text>?=
où:<encoding>
est soitB
(pour En Base 64 – voirbase64_encode()
) ouQ
(pour Quoted-printable – voirquoted_printable_encode()
),<encoded-text>
est une chaîne codée avec<encoding>
, qui a charset<charset>
après décodage.Vous pouvez décoder
=?CP1250?B?QWhvaiwgc3bsdGU=?=
en chaîne UTF-8Ahoj, světe
(Hello, world
en tchèque) viaiconv("CP1250", "UTF-8", base64_decode("QWhvaiwgc3bsdGU="))
ou directement viaiconv_mime_decode("=?CP1250?B?QWhvaiwgc3bsdGU=?=", 0, "UTF-8")
.L'encodage en mots codés est plus compliqué, parce que la spécification exige que chaque mots codés jeton pour être au plus 75 octets de long et de chaque ligne contenant l'un des mots codés jeton doit être à plus de 76 octets de long (y compris le vide au début d'une continuation de la ligne). Ne pas mettre en œuvre le codage de vous-même. Tous vous avez vraiment besoin de savoir, c'est que
iconv_mime_encode()
respecte les spécifications.Intéressantes liées à la lecture est l'article de Wikipédia Unicode et e-mail.
Alternatives
Rudimentaire option est à utiliser seulement un ensemble limité de caractères. ASCII est garanti pour fonctionner. ISO Latin 1 (ISO-8859-1), comme user2250504 suggéré, sera sans doute trop de travail, car il est souvent utilisé en remplacement lors de l'encodage n'est pas spécifié. Mais ces jeux de caractères sont très petits et vous serez probablement pas en mesure d'encoder tous les caractères que vous voudrez. En outre, les Rfc ne rien dire au sujet de savoir si le Latin 1 devrait fonctionner ou pas.
Vous pouvez également utiliser
mb_encode_mimeheader()
, comme Paul Norman répondu, mais il est facile de l'utiliser de manière incorrecte.Vous devez utiliser
mb_internal_encoding()
pour définir les fonctions mbstring " interne utilisé l'encodage. Lemb_*
fonctions s'attendre à des chaînes d'entrée pour être dans cet encodage. Attention: Le deuxième paramètre demb_encode_mimeheader()
n'a rien à voir avec la chaîne d'entrée (en dépit de ce que le manuel dit). Il correspond à la<charset>
lors de l'encodage du mot (voir Comment ça fonctionne? ci-dessus). La chaîne d'entrée est recodée à partir du codage interne à celui-ci avant d'être passé au B ou Q encodage.Paramètre de codage interne peut ne pas être nécessaire, car de PHP 5.6, parce que le sous-jacent
mbstring.internal_encoding
option de configuration a été dépréciée en faveur de ladefault_charset
option, qui a été mis en UTF-8 par défaut, depuis. Remarque que c'est juste un défaut, et il peut être inapproprié de s'appuyer sur les valeurs par défaut dans votre code.Vous devez inclure le nom d'en-tête et du côlon dans la chaîne d'entrée. Le RFC impose une forte limite sur la longueur de la ligne et il doit tenir pour la première ligne, trop! Une alternative est de jouer avec le cinquième paramètre (
$indent
; dernier en septembre 2015), mais c'est encore moins pratique.La mise en œuvre pourrait avoir des bugs. Même si elle est utilisée correctement, vous risquez d'avoir cassé la sortie. Au moins ce est ce que beaucoup de commentaires sur la page de manuel de dire. Je n'ai pas réussi à trouver en cas de problème, mais je sais que la mise en œuvre de mots codés est délicate. Si vous trouvez réels ou potentiels bugs dans
mb_encode_mimeheader()
ouiconv_mime_encode()
, s'il vous plaît, laissez-moi savoir dans les commentaires.Il y a aussi au moins un à l'envers à l'aide de
mb_encode_mimeheader()
: il n'est pas toujours encoder tous les en-tête de contenu, ce qui économise de l'espace et laisse le texte lisible par l'homme. Le codage est nécessaire uniquement pour les non-ASCII pièces. La sortie analogue à laiconv_mime_encode()
exemple ci-dessus est:Exemple d'utilisation de
mb_encode_mimeheader()
:C'est une alternative à l'extrait de code dans TL;DR en haut de ce post. Au lieu de simplement en réservant l'espace pour
Subject:
, il se met là et puis l'enlève afin d'être en mesure de l'utiliser avec lesmail()
’s stupide interface.Si vous aimez les fonctions mbstring mieux que la fonction iconv, vous pourriez vouloir utiliser
mb_send_mail()
. Il utilisemail()
en interne, mais code objet et le corps du message automatiquement. Encore une fois, à utiliser avec précaution.En-têtes d'autre que de soumettre besoin d'un traitement différent
Notez que vous ne devez pas supposer que l'encodage de l'ensemble du contenu d'un en-tête est OK pour tous les en-têtes qui peuvent contenir des caractères non-ASCII. E. g. De, À, Cc, Cci et De Réponse peut contenir des noms pour les adresses qu'ils contiennent, mais seulement les noms peuvent être encodés, pas les adresses. La raison en est que
<encoded-word>
jeton peut remplacer juste<text>
,<ctext>
et<word>
jetons, et seulement dans certaines circonstances (voir §5 de la RFC 2047).Encodage des textes non-ASCII dans les autres en-têtes est un lien mais une autre question. Si vous souhaitez en savoir plus sur ce sujet, la recherche. Si vous ne trouvez pas de réponse, poser une autre question et de m'indiquer dans les commentaires.
iconv_mime_decode("=?CP1250?B?QWhvaiwgc3bsdGU=?=", 0, "UTF-8")
, +1 juste pour cette ligne.mb_encode_mimeheader() pour des chaînes UTF-8 peut être utile ici, par exemple,
=?UTF-8?B?
préfixe n'a pas été ajouté au début de ma chaîne, mais quelque part au milieu. J'ai donc revenue à la construction de la syntaxe des mots codés manuellement que le Gombo a montré.Enregistrer le fichier php avec le bon charset.
Dans mon cas, dans Sublime Text, j'ai utilisé l'option suivante:
Fichier > Enregistrer avec l'Encodage > Occidentale (ISO-8859-1) [portugais Brésilien]
Faisant cela, vous n'avez pas besoin d'utiliser n'importe quelle commande.