Статья размещена автором Бетке Сергей Сергеевич

mailto, кириллица, IE, Outlook и PHP: как же их помирить?

Решил сегодня провести русификацию темы своего блога. При этом наткнулся и на нерабочую “фичу” – ссылку в правом верхнем углу статьи “Отправить ссылку почтой”. Мягко говоря, ссылка оказалась нерабочей. Кириллические заголовки статьи передавались в Outlook совершенно нечитабельными. Приступил к исправлению, что, как оказалось, требует определённого изучения. Поэтому решил описать.

Подсмотрим, каким кодом сгенерирована ссылка:

<a
    rel="nofollow"
    href="mailto:?subject=<?php
        the_title();
    ?>&amp;body=<?php
        _e('I thought you might like this','inanis');
        the_permalink();
    ?>"
>
    <?php _e('Email','inanis');?>
</a>

Естественно, такой код будет работать только для заголовкой латиницей, да и то — без пробелов. А про кирилицу и говорить нечего. Будем исправлять.

Обратим внимание на функцию PHP urlencode. Естественно, придётся поправить вызовы функций wordpress the_title (чтобы возвращала результат для дальнейшей обработки, а не сразу в поток выбрасывала). По этой же причине заменяем вызов _e() на __(). И, в идеале (как и указано в большинстве статей в сети), приведённый ниже код должен работать:

<a
    rel="nofollow"
    href="mailto:?subject=<?php
        echo urlencode(the_title('','',false));
    ?>&amp;body=<?php
        echo urlencode(__('I thought you might like this','inanis'));
        the_permalink();
    ?>"
>
    <?php _e('Email','inanis');?>
</a>

Однако — сгенерированный вроде бы корректно URL передаёт в Outlook вместо кирилицы полную жуть. Суть в том, что мы кодируем с помощью urlencode строку UTF-8. А Outlook ожидает Windows-1251. На самом деле, при использовании любых не ASCII символов мы должны кодировку указывать (об этом — далее). Пока сделаем ему то, что он хочет, используем iconv. Кроме того, чтобы решить проблему с неправильным кодированием пробелов, заменим фукнцию urlencode на rawurlencode.

Итого, условно рабочий вариант кода:

<a
    rel="nofollow"
    href="mailto:?subject=<?php
        echo rawurlencode(iconv("UTF-8","WINDOWS-1251",the_title('','',false)));
    ?>&amp;body=<?php
        echo rawurlencode(iconv("UTF-8","WINDOWS-1251",__('I thought you might like this','inanis')));
        the_permalink();
    ?>"
>
    <?php _e('Email','inanis');?>
</a>

Приведённый выше код замечательно работает. Хотя не должен. Осталось понять, как правильно указать кодировку в URL, чтобы не догадываться, какую кодировку будет пытаться использовать клиент, а указать ему на кодировку. С указанной целью изучим RFC2368. Данный стандарт показал, что с помощью параметров url mailto мы можем задать не только тему и адресата, но и значения любых других полей заголовка письма, в том числе — и собственных! Указанный выше стандарт ссылается на следующий стандарт: RFC2047, раздел 2. Итак, кодированная строка должна выглядеть следующим образом:

=?charset?encoding?encoded-text?=

Итак, для UTF-8 выглядеть строка должна приблизительно так: =?UTF-8?Q?encoded-text?=. Кодирование при этом должно выглядеть следующим образом (воспользуемся для корректной подготовки url также фукнцией php htmlentities):

<a
    rel="nofollow"
    href="mailto:?"<?php
        echo htmlentities(
            'subject=' .
            '=?UTF-8?B?' . base64_encode(the_title('','',false)) . '?=' .
            '&body=' .
            '=?UTF-8?B?' . base64_encode(__('I thought you might like this','inanis')) . '?='
        );
        the_permalink();?>"
>
    <?php _e('Email','inanis');?>
</a>

По идее, такой вариант должен работать изумительно. С другой стороны, RFC2368, конец второго раздела:

8-битные символы в URL-адресе mailto запрещены. MIME кодированные фразы (RFC2047) разрешены в значениях полей заголовка письма, но не для элемента body.

При этом должен сказать, кодированный текст успешно передаётся и в body (в случае с outlook это так).

Итак, делаем всё правильно с точки зрения RFC, но почтовый клиент не декодирует значения в соответствии с RFC2047. Посему пока я вынужден останавиться на варианте с предварительным кодированием в windows-1251.

В одном из черновиков RTF в разделе 7.3 приведены примеры кодированных значений в mailto, в том числе UTF-8 (советую познакомиться). Также должен дать ссылку на статью, описывающую поведение IE на ссылках mailto. Кстати, там и прочитал:

This is a problem for the mail client handling the mailto URIs, since it has no guarantee of how non US-ASCII characters have been encoded. In versions of Outlook prior to the 2007 version, Outlook would assume the system codepage had been used to encode the URI. This means that this scenario would only work with older versions of Outlook, if the document you’re viewing has the same character encoding as your current system codepage.

Теперь поведение Outlook 2003 вполне понятно.

И на последок нашёл статью на эту же тему. Приведу функцию из этой статьи:

function mime_header_encode($data_charset, $send_charset, $str) {
    if($data_charset != $send_charset) {
        $str = iconv($data_charset, $send_charset, $str);
    }
//    return '=?' . $send_charset . '?B?' . base64_encode($str) . '?=';
    return '=?' . $send_charset . '?Q?' . rawurlencode($str) . '?=';
}

echo '<a rel="nofollow" href="';
        echo
            htmlentities('mailto:?') .
            htmlentities('subject=') .
                mime_header_encode('UTF-8', 'CP1251',
                    html_entity_decode(the_title('','',false), ENT_COMPAT, 'UTF-8')
                ) .
            htmlentities('&body=') .
                rawurlencode(iconv('UTF-8', 'CP1251', __('I thought you might like this','inanis')))
        ;
        the_permalink();
echo '">';
    _e('Email','inanis');
echo '</a>';

Хорошо видно, что результат далёк от совершенства… Буду благодарен, если расскажете, как эта ссылка ведёт себя в Outlook 2007, 2010. Также пока не очень ясно, что делать с телом — там кодировку прямо не задать…

Задача решена, однако буду благодарен за любые рекомендации и ссылки, которые помогут правильным образом оформить ссылку mailto для передачи кириллических и не только символов почтовому клиенту, обеспечивая при этом хотя сответствие RFC.

Опубликовать комментарий

XHTML: Вы можете использовать следующие HTML теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Tags Связь с комментариями статьи:
RSS комментарии
Обратная ссылка