在 CPanel 中编辑 DNS 记录的 PHP 脚本

Posted

技术标签:

【中文标题】在 CPanel 中编辑 DNS 记录的 PHP 脚本【英文标题】:PHP Script to Edit DNS Records in CPanel 【发布时间】:2012-06-02 04:53:17 【问题描述】:

我想自给自足,因此不使用 DNSDynamic 和 DYNDNS 等服务。而且我不喜欢为我可以自己做的服务付费。

这就是场景 - 我的主要网站由托管公司托管。我还有一个家庭服务器,上面有我的音乐等。但问题是我的 ISP (BT) 不向消费者提供静态 IP 地址。

我想让我的主域(指向我的主主机)的子域指向我的家庭 IP。这是通过一个简单的 A 记录完成的 - 我自己完成了。

这归结为我想要制作一个 php 脚本(由我的家庭服务器上的 cron 作业运行)以将 cPanel 中的 A 记录更新为我的家庭服务器的当前 IP。

这是一些示例代码 - 当然,缺少的部分是与 cPanel 通信的 API 代码,我非常感谢任何可以为我填补空白的人。

<?php
    $current_ip = file_get_contents("http://mydomain.com/getip.php");
    $username = "CPANEL_USERNAME";
    $password = "CPANEL_PASSWORD";
    $domain = "CPANEL_DOMAIN";

    $request = file_get_contents("http://someapipage?username=".$username."&pw=".$password."&domain=".$domain."&ip=".$current_ip);

?>

http://mydomain.com/getip.php 中的代码很简单

<?php echo $_SERVER["REMOTE_ADDR"]; ?>

我已经掌握了如何设置 cron 作业,因为我的家庭服务器正在运行 Ubuntu,并且我已经阅读了使用 wget 在我的 localhost 目录中调用我的 cron.php 的教程。

我试过this link,但我无法理解他在做什么。提前致谢。

【问题讨论】:

我们可以在 jordih.net 上看到您尝试实现该方法的代码吗? 请记住,(afaik)每次您的 DNS 地址更改时,您都必须等待 TTL 过期,然后才能在全球范围内反映更改。出于这个原因,我应该认为动态 DNS 服务器的 TTL 会非常低。 @halfer 感谢您的指点 - 问题是 jordih.net 上的代码没有真正解释,并且有大量没有定义的变量;所以我真的不知道从哪里开始。 嗯,应该是$CPANEL_DOMAIN = 'https://mydomain.com:2083/';(用于安全访问)和$core_domain = 'mydomain.com'; 加上第一块代码。试试print_r($response); ?&gt; 看看你得到了什么,并引导你完成剩下的工作。缺少的一件事是对 cPanel 系统的身份验证——您可能需要登录、获取 cookie 并将其提供给未来的调用。这需要向file_get_contents 提供“上下文”,而这又需要进行一些研究! 如果端口 2083 顺便说一句不起作用,请尝试使用简单的 http 使用 2082 - 这会使您的会话不加密,但可能更容易开始工作。 【参考方案1】:

编辑:以下链接现已损坏。以下是整个脚本供参考:

#!/usr/bin/perl
# -------------------------------------------------------------------------------
# neobitti_update_ip.pl
#
# Version 1.0 - 16.01.2012
#
# PERL script to dynamically update the IP of a host via the cPanel-API. This
# script was written to work with the Finnish hoster Neobitti but it might work
# with other hosters which use cPanel too.
#
# Copyright (C) 2012 Stefan Gofferje - http://stefan.gofferje.net/
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
# -------------------------------------------------------------------------------
use strict;
use LWP::UserAgent;
use MIME::Base64;
use XML::Simple;
use Data::Dumper;
# --- Command line parameters ------------------------------------------------
my $param_domain=$ARGV[0];
my $param_host=$ARGV[1];
my $param_ip=$ARGV[2];
# --- cPanel information -----------------------------------------------------
# Storing passwords in clear text is ugly!
my $cpanel_domain = "example.com";
my $user = "username";
my $pass = "password";
my $auth = "Basic " . MIME::Base64::encode( $user . ":" . $pass );
# --- Deactivate SSL certificate validation ----------------------------------
# This is ugly but neccessary because Neobitti uses self-signed SSL
# certificates which will fail validation
my $ua = LWP::UserAgent->new(ssl_opts =>  verify_hostname => 0 );
# --- Find out the linenumber for the A-record we want to change -------------
sub getlinenumber_a 
  my $domain=$_[0];
  my $hostname=$_[1].".";
  my $xml = new XML::Simple;
  my $request = HTTP::Request->new( GET => "https://$cpanel_domain:2083/xml-api/cpanel?cpanel_xmlapi_module=ZoneEdit&cpanel_xmlapi_func=fetchzone&domain=$domain" );
  $request->header( Authorization => $auth );
  my $response = $ua->request($request);
  my $zone = $xml->XMLin($response->content);
  my $linenumber="";
  print $response->content . "\n";
  print $zone . "\n";
  print $zone->'data'->'status' . "\n";
  print $zone->'data'->'record' . "\n";
  if ($zone->'data'->'status' eq "1") 
    my $count = @$zone->'data'->'record';
    my $oldip="";
    for (my $item=0;$item<=$count;$item++) 
        my $name=$zone->'data'->'record'[$item]->'name';
        my $type=$zone->'data'->'record'[$item]->'type';
        print $name;
        if ( ($name eq $hostname) && ($type eq "A") ) 
          $linenumber=$zone->'data'->'record'[$item]->'Line';
          $oldip=$zone->'data'->'record'[$item]->'record';
          print "Found $hostname in line $linenumber with IP $oldip.\n"; # DEBUG
        
    
   else 
    $linenumber="0";
    print $zone->'event'->'data'->'statusmsg;'
  
  return($linenumber);

# --- Change the IP address record for a certain linenumber ------------------
sub setip 
  my $domain=$_[0];
  my $linenumber=$_[1];
  my $newip=$_[2];
  my $result="";
  my $xml = new XML::Simple;
  my $request = HTTP::Request->new( GET => "https://$cpanel_domain:2083/xml-api/cpanel?cpanel_xmlapi_module=ZoneEdit&cpanel_xmlapi_func=edit_zone_record&domain=$domain&line=$linenumber&address=$newip" );
  $request->header( Authorization => $auth );
  my $response = $ua->request($request);

  my $reply = $xml->XMLin($response->content);
  if ($reply->'data'->'status' eq "1") 
    $result="1";
   else 
    $result=$reply->'data'->'statusmsg';
  
  return($result);

# --- Main procedure ---------------------------------------------------------
print "Trying to find the linenumber for $param_host in $param_domain...\n";
my $line=getlinenumber_a($param_domain,$param_host);
if ( ($line ne "0") && ($line ne "") ) 
  print "Trying to update IP...\n";
  my $result=setip ($param_domain,$line,$param_ip);
  if ($result eq "1") 
    print "Update successful!\n";
   else 
    print "$result\n";
  
 else 
  print "Error - check domain and hostname!\n";

您需要将“用户名”和“密码”替换为您自己的凭据。

运行脚本,传入域名、子域名和子域的新IP:

./neobitti_update_ip.pl <domain> <subdomain> <ip>

例子:

./neobitti_update_ip.pl example.com subdomain.example.com 93.184.216.34

以下是我的原始答案,带有指向源的链接:


这里有一个 Perl 脚本正在执行您所要求的确切操作:

http://stefan.gofferje.net/it-stuff/scripts/50-dynamic-dns-update-via-cpanel-api

如果它必须是 PHP,我想从 Perl 翻译成 PHP(或任何其他语言)应该相当简单。脚本作者发了一些background information here。

【讨论】:

“你没有权限查看这个页面”,太糟糕了,链接坏了 是的,它现在好像坏了。我在帖子中添加了脚本的副本以供参考。【参考方案2】:

我刚刚根据 cPanel 的文档和指向该文档的 jordih.net 链接为 cPanel 的 JSON-API 编写了这个库。它没有很好的记录,但它的要点是:

通过调用创建一个 zone_records 对象

$zones = new zone_records("cpaneluser", "pass", "website_to_login", "domain_of_records")

请注意,登录网站通常是 127.0.0.1,如果您从要更改记录的服务器上运行此网站。

一旦调用,您就可以访问成员$zones-&gt;DNSrecords。这包含一组 DNS A 记录和 CNAME 记录(两者都是 DNSrecord 对象)。其他(TXT 除外)是无关紧要的,因为如果不对类进行额外的添加(功能),您就无法编辑它们。

每个 DNSrecord 都有一些成员(例如目标、ttl、名称、类型),而 private 可以通过 $record-&gt;ttl 访问,因为我添加了“神奇”__get 方法。 “魔术”__set 方法的实现仅用于更改 ttl 和目标(您无法使用此 API 函数更改其他属性,如果您尝试这样做,对象将引发异常)。

你可以使用

$zones->addrecord($type, $target, $name, $ttl)

添加记录,或

$zones->deleterecord($line)

删除区域文件中$line 行的记录 - 您可以通过$record-&gt;line 找到它。

如果您想在 ZoneEdit 模块中进行一些自己的查询,可以调用

$zones->doquery("function_from_API", array("parameters=>"here"), array("headers"=>"here"))

它会返回 cPanel 响应(addrecord 和 deleterecord 方法也是如此)。最后,我建议您使用try ... catch (Exception $e) ...,因为如果/当出现问题时,我的对象会抛出异常(您当然可以编辑它们)。

这段代码在公共领域——你可以在https://github.com/ShadowLNC/cpanel_dns得到它(classdns.php是主文件,dns_update.php是一个例子)。

【讨论】:

【参考方案3】:

有一个用于 linux 的 bash 脚本来解决最初提出的问题,即如何自动更新网址以指向不断变化的 IP。众所周知且运行良好的 ddclient 是许多提供商的标准工具,但不幸的是(尚未)为 cPanel 驱动的提供商工作(我使用 serverprofis.de,但还有很多其他的)。

bash 脚本位于github,我刚刚在代码中编辑了 cPanel 上的凭据等,然后添加了一个 cron 作业以每隔几分钟执行一次。与 ddclient 一样,该脚本检查 IP 是否已更改,如果与提供程序的上次更新相比没有检测到更改,则停止。如果 IP 已更改,它会更改提供商处的记录以指向新 IP。

到目前为止效果很好。

【讨论】:

以上是关于在 CPanel 中编辑 DNS 记录的 PHP 脚本的主要内容,如果未能解决你的问题,请参考以下文章

hostease域名解析教程

使用 DNS 工具的无 cpanel 替代方案 [关闭]

在 cPanel 中添加子域后出现“找不到服务器 DNS 地址”错误

cPanel XSS漏洞分析研究(CVE-2023-29489)

如何增加 cPanel 中的最大上传大小?

Dns 电子邮件记录 godaddy 和 AWS route53