В Windows не работает поддержка вложенных функций mail () в PHP? - PullRequest
6 голосов
/ 23 сентября 2011

У меня сегодня был зарегистрирован тикет, в котором клиент сообщил, что при попытке отправить вложение функция PHP mail() остановила его на одном из наших серверов Windows 2003 Server.

После расследования я смогвоспроизвести его проблему.Сообщения, содержащие небольшие вложения размером около 30–60 КБ, занимали 15–20 секунд, чтобы обрабатываться функцией mail().Большие вложения размером около 360-500 КБ занимали больше времени, чем максимально допустимое время выполнения сценария (90 секунд).

Мне удалось воспроизвести проблему на двух разных серверах Windows 2003 и сервере Windows 2008R2.Я также попробовал три разные версии PHP (5.2.14, 5.2.17 и 5.3.6 - все 32-битные и все не поточнобезопасные сборки в соответствии с рекомендациями Microsoft по запуску PHP в Windows).

Во всех случаяхпочта отправлялась через SMTP (т.е. не использовала реализацию sendmail).Я пробовал три различных сценария SMTP:

  • Доставка напрямую в наш SMTP-кластер smarthost (работает exim)
  • Доставка через локальную службу IIS SMTP, которая пересылается на наши smarthosts
  • Доставка через локальную службу IIS SMTP, но с поиском MX и прямой доставкой

Независимо от вышесказанного, отправка вложений все еще была неоптимальной, что означает, что проблема не может быть зафиксирована на медленном реле.

Затем я запустил тот же код на наших серверах CentOS, который не обнаружил ни одной из этих проблем, функция mail() вернулась почти сразу.Однако PHP на этих серверах настроен на использование sendmail.

. Затем я решил написать исходный код PHP, чтобы выяснить, как выглядит реализация функции mail(), и обнаружил этот код в ext/standard/mail.c.:

if (!sendmail_path) {
#if (defined PHP_WIN32 || defined NETWARE)
    /* handle old style win smtp sending */
    if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, headers, subject, to, message, NULL, NULL, NULL TSRMLS_CC) == FAILURE) {
        if (tsm_errmsg) {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", tsm_errmsg);
            efree(tsm_errmsg);
        } else {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", GetSMErrorText(tsm_err));
    }
        return 0;
    }
    return 1;
#else
    return 0;
#endif

TSendMail() реализовано в другом исходном файле (win32/sendmail.c).В конечном итоге все данные, отправляемые на SMTP-сервер, по-видимому, передаются синхронно через функцию Post() в sendmail.c, которая выглядит следующим образом:

static int Post(LPCSTR msg)
{
    int len = strlen(msg);
    int slen;
    int index = 0;

    while (len > 0) {
        if ((slen = send(sc, msg + index, len, 0)) < 1)
            return (FAILED_TO_SEND);
        len -= slen;
        index += slen;
    }
    return (SUCCESS);
}

Функция send() является функцией winsock2.

Мне интересно, влияет ли размер буфера (8К по умолчанию в соответствии со статьей КБ ниже) или отсутствие настройки влияет на большие объемы данных.Нет вызовов на setsockopt() для указания размера буфера или любых других опций для оптимизации вызовов на send().

Возможно, функция mail() в Windows, использующая доставку SMTP, не предназначена для отправки больших писем?

Мне было бы интересно узнать, смотрел ли кто-нибудь еще этот код илииспытал то же самое.

Проблемы проектирования - Отправка небольших сегментов данных по TCP с помощью Winsock

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

1 Ответ

1 голос
/ 23 сентября 2011

В моих мыслях будет использоваться http://glob.com.au/sendmail/ в Windows с классом PEAR Mail: http://pear.php.net/package/Mail. Возможно, это временное решение проблемы задержки, с которой вы столкнулись.Я думаю, что это не сможет обойти буфер, но я думаю, что стоило бы попробовать.

Кроме того, я никогда не использовал его, но я слышал хорошие вещи о SwiftMailer:1007 *http://swiftmailer.org/

...