2024年PHP开发者大会日本站

getmxrr

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

getmxrr获取给定互联网主机名的MX记录

描述

getmxrr(字符串 $hostname, 数组 &$hosts, 数组 &$weights = null): 布尔值

搜索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条注释

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和通配符... 的可能性。
3
Jay
17年前
如前所述,下面列出的一些代码在处理多个相同权重时会出现问题,例如,如果您查询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);”。

希望这对某些人有所帮助。
11
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 Records\n";
print
"Records returned for ".$mx->dns_repl_domain.":\n<pre>";
print_r($mx->arrMX);

?>

返回

02 MX Records Records returned for php.net

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

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

)
3
zorlac_man at hotmail dot com
20年前
出于某种原因,这个函数和其他DNS查找函数在我的Linux机器上似乎非常慢。我已经检查了几件事情,但没有找到解释。

作为一种变通方法,我屈服了,只使用系统调用来挖掘

<?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
"已找到 $domain 的MX记录\n";
return
TRUE;
}
?>

输出

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

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

<?php

// HM2K <php [spat] hm2k.org> 提供的 Windows getmxrr() 函数支持
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);

?>
0
匿名用户
8年前
一个针对 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 );
}
1
geoffbrisbine A T y a h o o DOT c o m
22年前
我很失望地发现 PHP 的 Win32 版本没有包含 getmxrr 函数,因此,作为一个菜鸟新手,我决定自己编写一个(我强调这是“编写”)。这已在 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 );
?>
0
tomhutter at web dot de
18年前
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
0
php dot net at oitc dot com
18年前
此函数在处理别名时有一些奇怪的副作用……

我的函数

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
0
MagicalTux at ooKoo dot org
18年前
如果要在 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);
?>

这样可以避免很多恶意行为;)
0
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 '未找到邮件服务器';
}

// $strDomain 设置为 'fh-rpl.de';
0
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 - 返回 true 或 false。
*/
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”替换为该地址。

Richard。
-1
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
-1
paul at start dot co dot uk
23 年前
通过在模式匹配和 MX 检查中都追加尾随句点“.”到域名,防止您的 DNS 服务器通过将本地域名附加到不完整的电子邮件来“创建”有效的主机名。

<?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;
}
?>
-2
siclawrence at gmail dot com
19年前
此代码复制了允许您检查电子邮件地址是否有效的在线工具。它首先检查电子邮件格式是否正确,然后查找并打印 MX 记录。所有内容都以漂亮的格式和花哨的文字显示,最终打印电子邮件地址有效或无效。

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

print(
"正在检查: $email<br>");

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

print(
"格式测试: 通过<br>");
print(
"在线主机验证测试...<br><br>");
print(
"MX 记录: $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(
"在线主机验证测试: 通过<br><br>");
print(
"邮件状态: 有效");

} else {

print(
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;未找到记录。<br>");
print(
"在线主机验证测试: 失败<br><br>");
print(
"邮件状态: 无效");

}

} else {

print(
"格式测试: 失败<br><br>");
print(
"提供的电子邮件地址无效。<br><br>");
print(
"邮件状态: 无效");

}
?>
-1
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;
}
}

?>
-1
jeff at pzenix dot com
18年前
我应该指出,下面的例子不适用于某些域名(例如 .co.uk、.org.uk、.net.uk),因为它假设(可能不正确)格式为 [DOMAIN].[EXT]。
-2
TZ at inpetho dot net
16年前
如果MX主机上安装了灰名单机制,则会发送“451 4.7.1 请稍后再试”的错误信息。

我的代码片段

<?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;
}
//...
?>
-2
rolf at rowi dot net
19年前
请注意,不仅[email protected]是有效的地址,[email protected]也是有效的(尽管可能不太常见)。我刚在这个检查中遇到了这个问题……

Rolf
To Top