PHP的mail()函数附件是否在Windows上有点破碎?

Kev*_*Kev 6 php email performance attachment

我今天有一张客户登记的机票报告说,mail()当我尝试发送附件时,PHP的功能在我的一个Windows 2003 Server机箱上超时.

经过调查,我能够重现他的问题.包含30-60Kb大小的小附件的消息需要15-20秒才能被该mail()功能处理.较大的附件大约360-500Kb所花费的时间超过允许的最大脚本执行时间(90秒).

我能够在两个不同的Windows 2003服务器和Windows 2008R2服务器上重现该问题.我还尝试了三个不同版本的PHP(5.2.14,5.2.17和5.3.6 - 所有32位和所有非线程安全版本,根据Microsoft的建议在Windows上运行PHP).

在所有情况下,邮件都是通过SMTP发送的(即不使用sendmail实现).我尝试了三种不同的SMTP方案:

  • 直接发送到我们的SMTP智能主机群集(运行exim)
  • 通过本地IIS SMTP服务传递,它传递给我们的智能主机
  • 通过本地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
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

send()功能是一个winsock2功能.

我想知道缓冲区大小(根据下面的知识库文章,默认为8K)或缺乏调优是否会对更大量的数据产生一些影响.没有调用setsockopt()指定缓冲区大小或任何其他选项来优化调用send().

也许mail()使用SMTP传递的Windows上的功能不是用于发送大型电子邮件?

我有兴趣知道是否有其他人看过这段代码或经历过同样的事情.

设计问题 - 使用Winsock通过TCP发送小数据段

为了清楚起见,我们现在已经为客户(SwiftMailer)提供了替代解决方案,因此这不是为了获得替代方案的建议.

Dav*_*itz 1

我的想法是在 Windows 上使用http://glob.com.au/sendmail/和 PEAR Mail 类: http: //pear.php.net/package/Mail。这可能是解决您遇到的延迟的方法。我认为这无法绕过缓冲区,但我认为值得一试。

另外,我从未使用过它,但我听说过有关 SwiftMailer 的好消息: http: //swiftmailer.org/