getmxrr

(PHP 4, PHP 5, PHP 7, PHP 8)

getmxrr获取与给定互联网主机名相对应的 MX 记录

说明

getmxrr(string $hostname, array &$hosts, array &$weights = null): bool

搜索 DNS 以获取与 hostname 相对应的 MX 记录。

参数

hostname

互联网主机名。

hosts

找到的 MX 记录列表将被放置到数组 hosts 中。

weights

如果提供了 weights 数组,它将填充收集的权重信息。

返回值

如果找到任何记录,则返回 true;如果未找到任何记录或发生错误,则返回 false

注释

注意:

此函数不应用于地址验证目的。仅返回 DNS 中找到的邮件交换器,但是,根据 » RFC 2821,当没有列出邮件交换器时,应将 hostname 本身用作唯一邮件交换器,优先级为 0

注意:

为了与 Windows 之前的实现兼容,请尝试使用 » PEAR» Net_DNS

参见

  • checkdnsrr() - 检查与给定互联网主机名或 IP 地址相对应的 DNS 记录
  • dns_get_record() - 获取与主机名关联的 DNS 资源记录
  • gethostbyname() - 获取与给定互联网主机名相对应的 IPv4 地址
  • gethostbynamel() - 获取与给定互联网主机名相对应的 IPv4 地址列表
  • gethostbyaddr() - 获取与给定 IP 地址相对应的互联网主机名
  • named(8) 手册页

添加注释

用户贡献的注释 19 个注释

Robert Imhoff
13 年前
我尝试使用 getmxrr() 来验证查询提交表单中的电子邮件地址的域名部分,在检查不存在的域名时,一些顶级域名出现了一种奇怪的现象。

对于 sdlkfjsdl.com,由于域名不存在,getmxrr() 返回 false,正如预期的那样,返回的 mxhosts 数组为空。

但是对于 sdlkfjsdl.gov,getmxrr() 返回 true,返回的 mxhosts 数组包含一个元素:NULL

对于 sdlkfjsdl.org,getmxrr() 返回 true,返回的 mxhosts 数组包含一个元素:'0.0.0.0'

对于 sdlkfjsdl.co.uk,getmxrr() 返回 true 并提供一个 MX 记录:uk-net-wildcard-null-mx.centralnic.net

因此,为了验证电子邮件域名,似乎必须检查返回的 mxhosts 数组,以排除 mxhosts 被返回为 NULL、0.0.0.0 和通配符的可能性...
Jay
16 年前
如前所述,下面列出的一些代码在处理多个相等权重时会遇到问题,例如,如果您查询 gmail.com。以下代码将通过交换键/值来防止这种情况。

<?php

// 获取记录
getmxrr("gmail.com", $mx_records, $mx_weight);

// 将记录放在一个我们可以排序的数组中
for($i=0;$i<count($mx_records);$i++){
$mxs[$mx_records[$i]] = $mx_weight[$i];
}

// 对它们进行排序
asort ($mxs);

// 由于键实际上保存了我们想要的数据,只需将它们放到一个名为 records 的数组中
$records = array_keys($mxs);

// 只需回显 records 数组中的所有内容
for($i = 0; $i < count($records); $i++){
echo
$records[$i];
echo
'<br>';
}

?>

如果您想获得权重,可以使用 "array_values($mxs);" 而不是 "array_keys($mxs);"。

希望这对一些人有所帮助。
rune dot heggtveit at devzone dot progative dot com
19 年前
在 Windows 平台上执行 MX 查询的另一种方法。
我从之前为 DNS 查询编写的另一个类中改写了这段代码 - 所以可能有点混乱 - 但是希望你能明白我的意思。

非常感谢 RFC 社区。

<?php

class mxlookup
{
var
$dns_socket = NULL;
var
$QNAME = "";
var
$dns_packet= NULL;
var
$ANCOUNT = 0;
var
$cIx = 0;
var
$dns_repl_domain;
var
$arrMX = array();

function
mxlookup($domain, $dns="192.168.2.1")
{
$this->QNAME($domain);
$this->pack_dns_packet();
$dns_socket = fsockopen("udp://$dns", 53);

fwrite($dns_socket,$this->dns_packet,strlen($this->dns_packet));
$this->dns_reply = fread($dns_socket,1);
$bytes = stream_get_meta_data($dns_socket);
$this->dns_reply .= fread($dns_socket,$bytes['unread_bytes']);
fclose($dns_socket);
$this->cIx=6;
$this->ANCOUNT = $this->gord(2);
$this->cIx+=4;
$this->parse_data($this->dns_repl_domain);
$this->cIx+=7;

for(
$ic=1;$ic<=$this->ANCOUNT;$ic++)
{
$QTYPE = ord($this->gdi($this->cIx));
if(
$QTYPE!==15){print("[MX Record not returned]"); die();}
$this->cIx+=9;
$mxPref = ord($this->gdi($this->cIx));
$this->parse_data($curmx);
$this->arrMX[] = array("MX_Pref" => $mxPref, "MX" => $curmx);
$this->cIx+=3;
}
}

function
parse_data(&$retval)
{
$arName = array();
$byte = ord($this->gdi($this->cIx));
while(
$byte!==0)
{
if(
$byte==192) //compressed
{
$tmpIx = $this->cIx;
$this->cIx = ord($this->gdi($cIx));
$tmpName = $retval;
$this->parse_data($tmpName);
$retval=$retval.".".$tmpName;
$this->cIx = $tmpIx+1;
return;
}
$retval="";
$bCount = $byte;
for(
$b=0;$b<$bCount;$b++)
{
$retval .= $this->gdi($this->cIx);
}
$arName[]=$retval;
$byte = ord($this->gdi($this->cIx));
}
$retval=join(".",$arName);
}

function
gdi(&$cIx,$bytes=1)
{
$this->cIx++;
return(
substr($this->dns_reply, $this->cIx-1, $bytes));
}

function
QNAME($domain)
{
$dot_pos = 0; $temp = "";
while(
$dot_pos=strpos($domain,"."))
{
$temp = substr($domain,0,$dot_pos);
$domain = substr($domain,$dot_pos+1);
$this->QNAME .= chr(strlen($temp)).$temp;
}
$this->QNAME .= chr(strlen($domain)).$domain.chr(0);
}

function
gord($ln=1)
{
$reply="";
for(
$i=0;$i<$ln;$i++){
$reply.=ord(substr($this->dns_reply,$this->cIx,1));
$this->cIx++;
}

return
$reply;
}

function
pack_dns_packet()
{
$this->dns_packet = chr(0).chr(1).
chr(1).chr(0).
chr(0).chr(1).
chr(0).chr(0).
chr(0).chr(0).
chr(0).chr(0).
$this->QNAME.
chr(0).chr(15).
chr(0).chr(1);
}

}

?>

<?php

/* 使用示例: */
$mx = new mxlookup("php.net");

print
$mx->ANCOUNT." MX 记录\n";
print
"返回的 $mx->dns_repl_domain 的记录:\n<pre>";
print_r($mx->arrMX);

?>

返回

02 MX 记录 返回的 php.net 记录

数组
(
[0] => 数组
(
[MX_Pref] => 15
[MX] => smtp.osuosl.org
)

[1] => 数组
(
[MX_Pref] => 5
[MX] => osu1.php.net
)

)
zorlac_man at hotmail dot com
20 年前
由于某种原因,这个函数和其他 DNS 查询函数在我的 Linux 机器上运行非常慢。我已经检查了几个方面,但没有找到解释。

作为一种解决方法,我最终使用了系统调用来执行 dig

<?php
CheckMX
("fakedomain.org");
CheckMX("hotmail.com");

function
CheckMX($domain) {
exec("dig +short MX " . escapeshellarg($domain),$ips);
if(
$ips[0] == "") {
print
"未找到 fakedomain.org 的 MX 记录!\n";
return
FALSE;
}
print
"找到 hotmail.com 的 MX 记录\n";
return
TRUE;
}
?>

输出

未找到 fakedomain.org 的 MX 记录!
找到 hotmail.com 的 MX 记录

正如其他人指出的那样,如果未找到 MX 记录,那么谨慎起见,应该检查 TLD 是否具有 IP 地址。
php [spat] hm2k.org
15 年前
我决定在做了一些研究之后尝试一下...

<?php

// HM2K 为 Windows 提供 getmxrr() 支持 <php [spat] hm2k.org>
function win_getmxrr($hostname, &$mxhosts, &$mxweight=false) {
if (
strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') return;
if (!
is_array ($mxhosts) ) $mxhosts = array();
if (empty(
$hostname)) return;
$exec='nslookup -type=MX '.escapeshellarg($hostname);
@
exec($exec, $output);
if (empty(
$output)) return;
$i=-1;
foreach (
$output as $line) {
$i++;
if (
preg_match("/^$hostname\tMX preference = ([0-9]+), mail exchanger = (.+)$/i", $line, $parts)) {
$mxweight[$i] = trim($parts[1]);
$mxhosts[$i] = trim($parts[2]);
}
if (
preg_match('/responsible mail addr = (.+)$/i', $line, $parts)) {
$mxweight[$i] = $i;
$mxhosts[$i] = trim($parts[1]);
}
}
return (
$i!=-1);
}

// 定义
if (!function_exists('getmxrr')) {
function
getmxrr($hostname, &$mxhosts, &$mxweight=false) {
return
win_getmxrr($hostname, $mxhosts, $mxweight);
}
}

/* 示例 */

$domain='php.net';
echo
"<pre>";
getmxrr($domain,$mxhosts,$mxweight);
print_r($mxhosts);
print_r($mxweight);

?>
匿名
7 年前
用于 getmxrr 函数的一个小 polyfill(即使它在 Linux 系统中缺失)

function getmxrr($hostname, &$mxhosts, array &$mxweight=null)
{
$mxhosts = array();
exec('nslookup -type=mx '.$hostname, $result_arr);
foreach($result_arr as $line)
{
if (preg_match("/.*mail exchanger = (.*)/", $line, $matches))
{
$s_xo=explode(' ', $matches[1]);
$mxhosts[] = $s_xo[1];
$mxweight[] = $s_xo[0];
}
}
return( count($mxhosts) > 0 );
}
geoffbrisbine A T y a h o o DOT c o m
21 年前
我很失望地发现 PHP 的 Win32 版本没有包含 getmxrr,所以,由于我是一个天真无知的菜鸟,我决定自己 hack 一个(我强调是 hack)。已经在 Win 2000 和 Win XP 上测试过。没有理由这在 Win NT 上不能正常工作,但它在 Win 9x 上不会工作(你需要 nslookup 命令)。它将以数组 $mx 结束,它将是一个多维数组,包含 MX 优先级、主机名和 IP 地址。你可以使用 print_r ( $mx ) 来查看它的样子。

-----------------------------------------------

<?php
$command
= "nslookup -type=mx yahoo.com";
exec ( $command, $result );

$i = 0;
while ( list (
$key, $value ) = each ( $result ) ) {
if (
strstr ( $value, "mail exchanger" ) ) { $nslookup[$i] = $value; $i++; }
}

while ( list (
$key, $value ) = each ( $nslookup ) ) {
$temp = explode ( " ", $value );
$mx[$key][0] = $temp[3];
$mx[$key][1] = $temp[7];
$mx[$key][2] = gethostbyname ( $temp[7] );
}

array_multisort ( $mx );
?>
tomhutter at web dot de
17 年前
Leonardt 的代码在处理具有相同权重的多个 MX 记录时会失败。你可以通过在 mxs 数组中交换键和值来轻松更改它

for($i=0;$i<count($mx_records);$i++){
$mxs[$mx_records[$i]] = $mx_weight[$i];
}

arsort ($mxs );
reset ($mxs);

while (list ($mx_host, $mx_weight) = each ($mxs) ) {

干杯

Tom
php dot net at oitc dot com
17 年前
这个函数在处理别名时有一些奇怪的副作用...

我的函数

if (getmxrr($fqdn, $mx_records, $mx_weight)) {
// 将 mx 记录和权重复制到数组 $mxs 中
// 忽略相同权重的多个 mx
for ($i = 0; $i < count($mx_records); $i++) {
$mxs[$mx_weight[$i]] = $mx_records[$i];
}
// 对数组 mxs 进行排序,以获取优先级最高的服务器
ksort ($mxs, SORT_NUMERIC);
reset ($mxs);
} else {
// 没有 MX,所以使用 A
$mxs[0]= $fqdn;
}

会失败,因为包含别名的 $fqdn 返回 true,但在返回时 $mx_records 和 $mx_weight 都为空!

在修复此问题之前,解决方案是将 if (getmxrr($fqdn, $mx_records, $mx_weight)) 替换为

// 处理别名等
if ($result = getmxrr($fqdn, $mx_records, $mx_weight)) {
if(!isset($mx_records) || (count($mx_records) == 0)) $result = false;
}
// 处理 MX
if ($result) {

希望这能帮助其他人.... Tom
MagicalTux at ooKoo dot org
17 年前
如果你想在 Windows 上使用 getmxrr,要小心,因为 choward AT fast DOT net DOT NO SPAM PLZ 的函数存在安全漏洞。

它将参数传递给外部命令,而没有对其进行转义。如果你不验证输入,有人可能会在你的系统上运行一些恶意程序。

这是一个修复后的版本(只是添加了 escapeshellarg())

<?php
function getmxrr($hostname, &$mxhosts)
{
$mxhosts = array();
exec('%SYSTEMDIRECTORY%\\nslookup.exe -q=mx '.escapeshellarg($hostname), $result_arr);
foreach(
$result_arr as $line)
{
if (
preg_match("/.*mail exchanger = (.*)/", $line, $matches))
$mxhosts[] = $matches[1];
}
return(
count($mxhosts) > 0 );
}
//--工作区的结束

//测试..
getmxrr('yahoo.com', $mxhosts);
print_r($mxhosts);
?>

这样你就可以避免很多讨厌的事情;)
off at NOSPAM dot abwesend dot de
18 年前
关于 'rolf at rowi dot net' 的消息(检查包含子域的地址),我们可以使用

$email = '[email protected]';

$strDot = '.';
$strAfterAt = substr(strstr($email, '@'), 1);
$chunks = explode($strDot, $strAfterAt);
$cntChunks = count($chunks) - 1;

$strDomain = $chunks[($cntChunks-1)] . $strDot . $chunks[$cntChunks];

if (!getmxrr( $strDomain, $mxhosts )) {
echo 'Mailserver not found';
}

// $strDomain 设置为 'fh-rpl.de';
richard dot quadling at bandvulc dot co dot uk
19 年前
Windows 下无需 PEAR 的 getmxrr 替代方案。

<?php
define
('DEFAULT_GATEWAY', 'nnn.nnn.nnn.nnn');
if (!
function_exists('getmxrr'))
{
/*
此函数用于替换 Windows 系统中缺失的 getmxrr 函数。

参数与标准 getmxrr 函数相同。

该函数执行的步骤如下:

1 - 使用 NSLOOKUP.EXE 获取指定主机的 MX 记录。
2 - 使用正则表达式提取邮件服务器和优先级。
3 - 按优先级对结果进行排序。
4 - 设置返回数组。
5 - 返回真或假。
*/
function getmxrr($s_HostName, array &$a_MXHosts = NULL, array &$a_Weights = NULL)
{
// 通过执行 Windows 的 NSLOOKUP 模拟所有必需的网络活动。
$s_NSLookup = shell_exec("nslookup -q=mx {$s_HostName} 2>nul");
preg_match_all("'^.*MX preference = (\d{1,10}), mail exchanger = (.*)$'simU", $s_NSLookup, $a_MXMatches);

// 如果有东西要返回...
if (count($a_MXMatches[2]) > 0)
{
// 如果请求了输出数组,则生成输出数组。
$i_ArgCount = func_num_args();
if (
$i_ArgCount > 1)
{
array_multisort($a_MXMatches[1], $a_MXMatches[2]);
switch (
$i_ArgCount)
{
case
3 :
$a_Weights = $a_MXMatches[1];
case
2 :
$a_MXHosts = $a_MXMatches[2];
}
}
return
True;
}
else
{
return
False;
}
}
}
?>

您需要知道您的默认网关(它的 IP 地址或名称)。

为此,请在命令提示符中运行程序 IPCONFIG /ALL,然后查找默认网关。

然后用该地址替换“nnn.nnn.nnn.nnn”。

理查德。
ng4rrjanbiah at rediffmail dot com
20 年前
以下是在 Windows 平台上更好的解决方法。已在 Windows XP 上测试。对“geoffbrisbine A T y a h o o DOT c o m”的 nslookup 使用方法印象深刻。

<?php
function getmxrr($hostname, &$mxhosts)
{
$mxhosts = array();
exec('nslookup -type=mx '.$hostname, $result_arr);
foreach(
$result_arr as $line)
{
if (
preg_match("/.*mail exchanger = (.*)/", $line, $matches))
$mxhosts[] = $matches[1];
}
return(
count($mxhosts) > 0 );
}
//--End of workaround

//test..
echo getmxrr('yahoo.com', $mxhosts);
print_r($mxhosts);
?>

希望对您有所帮助,
R. Rajesh Jeba Anbiah
paul at start dot co dot uk
23 年前
通过在域名后面添加一个“.”,防止您的 DNS 服务器通过将本地域名追加到不完整的电子邮件来“创建”有效的主机名,这两种情况都出现在模式匹配和 MX 检查中。

<?php
if (eregi("^[0-9a-z_]([-_.]?[0-9a-z])*@[0-9a-z][-.0-9a-z]*\\.[a-z]{2,3}[.]?$", $string, $check)) {
$host = substr(strstr($check[0], '@'), 1).".";
if (
getmxrr($host, $validate_email_temp) )
return
TRUE;
// 这将捕获不是 MX 的 DNS。
if(checkdnsrr($host,"ANY"))
return
TRUE;
}
?>
siclawrence at gmail dot com
19 年前
此代码复制了让您检查电子邮件地址是否有效的在线工具。首先它检查电子邮件格式是否正确,然后查找并打印 MX 记录。所有内容都以漂亮的格式和花哨的词语排列,最终打印电子邮件地址是否有效或无效。

<?php
$email
= "[email protected]";

print(
"Checking: $email<br>");

if (
eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)+$", $email)) {

print(
"Format Test: PASSED<br>");
print(
"Online host verification Test...<br><br>");
print(
"MX Records for: $email<br>");

list(
$alias, $domain) = split("@", $email);

if (
checkdnsrr($domain, "MX")) {

getmxrr($domain, $mxhosts);

foreach(
$mxhosts as $mxKey => $mxValue){
print(
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$mxValue<br>");
}

print(
"Online host verification Test: PASSED<br><br>");
print(
"Email Status: VALID");

} else {

print(
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;No records found.<br>");
print(
"Online host verification Test: FAILED<br><br>");
print(
"Email Status: INVALID");

}

} else {

print(
"Format Test: FAILED<br><br>");
print(
"Invalid email address provided.<br><br>");
print(
"Email Status: INVALID");

}
?>
Lennart Poot(www.twing.nl)
18 年前
此脚本使用 getmxrr 和 fsockopen 验证电子邮件地址。

1. 它验证地址的语法。
2. 通过主机名获取 MX 记录。
3. 连接邮件服务器并验证邮箱(使用 SMTP 命令 RCTP TO:<email>)。

当函数“validate_email([email])”无法连接到 MX 记录中优先级最高的邮件服务器时,它将继续连接第二个邮件服务器,依此类推。

函数“validate_email([email])”在上述 3 个步骤中任何一个步骤失败时返回 0,否则返回 1。

致敬,Lennart Poot

<?
function validate_email($email){
$mailparts=explode("@",$email);
$hostname = $mailparts[1];

// 验证电子邮件地址语法
$exp = "^[a-z\'0-9]+([._-][a-z\'0-9]+)*@([a-z0-9]+([._-][a-z0-9]+))+$";
$b_valid_syntax=eregi($exp, $email);

// 通过 getmxrr 获取 MX 地址
$b_mx_avail=getmxrr( $hostname, $mx_records, $mx_weight );
$b_server_found=0;

if($b_valid_syntax && $b_mx_avail){
// 将 mx 记录和权重复制到数组 $mxs 中
$mxs=array();

for($i=0;$i<count($mx_records);$i++){
$mxs[$mx_weight[$i]]=$mx_records[$i];
}

// 对数组 mxs 进行排序,以获取优先级最高的服务器
ksort ($mxs, SORT_NUMERIC );
reset ($mxs);

while (list ($mx_weight, $mx_host) = each ($mxs) ) {
if($b_server_found == 0){

// 尝试在端口 25 上进行连接
$fp = @fsockopen($mx_host,25, $errno, $errstr, 2);
if($fp){
$ms_resp="";
// 对邮件服务器说 HELO
$ms_resp.=send_command($fp, "HELO microsoft.com");

// 初始化发送邮件
$ms_resp.=send_command($fp, "MAIL FROM:<[email protected]>");

// 尝试接收方地址,如果成功将返回 250..
$rcpt_text=send_command($fp, "RCPT TO:<".$email.">");
$ms_resp.=$rcpt_text;

if(substr( $rcpt_text, 0, 3) == "250")
$b_server_found=1;

// 退出邮件服务器连接
$ms_resp.=send_command($fp, "QUIT");

fclose($fp);

}

}
}
}
return $b_server_found;
}

function send_command($fp, $out){

fwrite($fp, $out . "\r\n");
return get_data($fp);
}

function get_data($fp){
$s="";
stream_set_timeout($fp, 2);

for($i=0;$i<2;$i++)
$s.=fgets($fp, 1024);

return $s;
}

// 支持 Windows 平台
if (!function_exists ('getmxrr') ) {
function getmxrr($hostname, &$mxhosts, &$mxweight) {
if (!is_array ($mxhosts) ) {
$mxhosts = array ();
}

if (!empty ($hostname) ) {
$output = "";
@exec ("nslookup.exe -type=MX $hostname.", $output);
$imx=-1;

foreach ($output as $line) {
$imx++;
$parts = "";
if (preg_match ("/^$hostname\tMX preference = ([0-9]+), mail exchanger = (.*)$/", $line, $parts) ) {
$mxweight[$imx] = $parts[1];
$mxhosts[$imx] = $parts[2];
}
}
return ($imx!=-1);
}
return false;
}
}

?>
jeff at pzenix dot com
18 年前
我应该指出,以下示例不适用于某些域名(例如 .co.uk、.org.uk、.net.uk),因为它假设(可能是错误的)格式为 [DOMAIN].[EXT]。
TZ at inpetho dot net
16 年前
如果 MX 主机上安装了灰名单,那么它会发送一个“451 4.7.1 Please try again later”。

我的代码片段

<?php
//...
foreach ($mx_records as $mx_host) {
$code = CheckMX($mx_host, $eMail);
if (
$code == 0) continue; // 主机未找到
if ($code == 451) $code = CheckMX($mx_host, $eMail); // 灰色列表
if ($code == 250) {
$ok = true;
break;
}
}
//...

function CheckMX($mx_host, $eMail)
{
$code = 0;
$fp = @fsockopen($mx_host, 25, $errno, $errstr, 2);
if (
$fp) {
send_command($fp, 'HELO microsoft.com');
send_command($fp, 'MAIL FROM:<[email protected]>');
$erg = send_command($fp, 'RCPT TO:<'.$eMail.'>');
fclose($fp);
$code = intval(substr($erg, 0, 3));
}
return
$code;
}
//...
?>
rolf at rowi dot net
19 年前
请注意,不仅 [email protected] 是有效的地址,[email protected] 也是有效的(但可能不太常见)。我刚在用这个检查时遇到了麻烦...

Rolf
To Top