I'm Sham
一个在通往码农道路上走走停停的行政文员

使用PHP实现阿里云动态解析DDNS

这里是记录如何使用PHP来实现阿里云动态解析DDNS功能,因为家里ip每次断电或路由器重启后会更换,所以这个功能是个必须的。

首先,是需要到阿里云申请AccessKey,然后给它设置管理DNS的权限,之后获取它的id和secret,这个将用于获取域名的相关记录及更新。

然后就是上代码:

<?php
  date_default_timezone_set("GMT");
  $ipnow = (json_decode(file_get_contents("http://httpbin.org/ip"),true))['origin']; //从网上接口获取到服务器公网ip
  
  if($ipnow == null || $ipnow == ''){
	//如果没有获取到IP
    echo 'IP获取失败,稍后再试';  
  }else{
	//获取到IP的话,判断是否有变化,然后更新
	
	//首次运行时或者服务器上iPfile文件被删除后
    if(!file_exists(("ipfile.txt")) || filesize("ipfile.txt") ==0){  
      $ipfile = fopen("ipfile.txt", "w") or die("Unable to open file!");
      fwrite($ipfile, $ipnow);  //将ip写入文件用于下次判断
      fclose($ipfile);
      
      //绑定 ip 到域名
      Ali::Obj()->UpdateDomainRecord($ipnow);
	  
    }else{
	//如果已经存在ipfile.txt文件
      $ipfile = fopen("ipfile.txt", "r") or die("Unable to open file!");
      $iprecord = fread($ipfile,filesize("ipfile.txt"));
      if($iprecord == $ipnow){  
        //如果判断出当前ip和原来的没变化
        echo '现在服务器IP为:'.$iprecord.',没有改变,无需更新!';
        fclose($ipfile);
      }else{
        //如果ip发生变化
        $ipfile = fopen("ipfile.txt", "w") or die("Unable to open file!");
        //绑定 ip 到域名
        Ali::Obj()->UpdateDomainRecord($ipnow);
        fwrite($ipfile, $ipnow); 
        fclose($ipfile);
      }
    }
  }
  
  $Ali = new Ali();  //阿里云动态解析函数
  Ali::Obj()->UpdateDomainRecord($ip);

  //封装阿里云动态解析DDNS
  class Ali
  {
  
	/**以下4条记得修改**/
    private $accessKeyId  = "accessKeyId";   //阿里云的accesskeyid
    private $accessSecret = "accessSecret";  //阿里云的accesssecrec
    private $domainname = 'xxx.com';  //你需要更新的域名,不要带任何前缀
    private $rrlist = ['@','www'];  //你需要更新的域名前缀数组,前提是这几个在你已经解析的清单中已经生效过了
	/**以上4条记得修改**/
	
	
    private static $obj  = null;
    public static function Obj ()
    {
        if(is_null(self::$obj))
        {
            self::$obj = new self();
        }
        return self::$obj;
    }

    public function DescribeDomainRecords()
    {
        $requestParams = array(
            "Action"    =>  "DescribeDomainRecords",
            "DomainName"    => $this->domainname
        );
		//通过阿里云接口获取域名对应的主机(子域名)清单,并把获取到的数据转换成需要的数组
        $val =  $this->requestAli($requestParams);  
        $recordslist = json_decode($val,true);
        $records = $recordslist['DomainRecords']['Record'];

        for($i=0;$i<count($records);$i++){
          $rr = $records[$i]['RR'];  
          //判断是否在你设置的前缀清单中
          if (in_array($rr, ($this->rrlist))){
            $record[$rr] = $records[$i];  //获取你要更新的对应前缀的域名清单
          }
        }
        return $record;
    }
 
    /**更新 ip**/
    public function UpdateDomainRecord($ip)
    {
		//通过获取到的域名清单,循环更新数据
        $recordslist = $this -> DescribeDomainRecords(); 
        foreach($recordslist as $lists){
          $requestParams = array(
              "Action"        =>  "UpdateDomainRecord",
              "RecordId"      =>  $lists['RecordId'],
              "RR"            =>  $lists['RR'],
              "Type"          =>  $lists['Type'],
              "Value"         =>  $ip,
          );
          $val =  $this->requestAli($requestParams);
          $this->outPut($val."  ".$ip);
        }
    }
 
	//阿里云官方获取dns数据的接口
    private function requestAli($requestParams)
    {
        $publicParams = array(
            "Format"        =>  "JSON",
            "Version"       =>  "2015-01-09",
            "AccessKeyId"   =>  $this->accessKeyId,
            "Timestamp"     =>  date("Y-m-d\TH:i:s\Z"),
            "SignatureMethod"   =>  "HMAC-SHA1",
            "SignatureVersion"  =>  "1.0",
            "SignatureNonce"    =>  substr(md5(rand(1,99999999)),rand(1,9),14),
        );
 
        $params = array_merge($publicParams, $requestParams);
        $params['Signature'] =  $this->sign($params, $this->accessSecrec);
        $uri = http_build_query($params);
        $url = 'http://alidns.aliyuncs.com/?'.$uri;
        return $this->curl($url);
    }
 

    private function sign($params, $accessSecret, $method="GET")
    {
        ksort($params);
        $stringToSign = strtoupper($method).'&'.$this->percentEncode('/').'&';
 
        $tmp = "";
        foreach($params as $key=>$val){
            $tmp .= '&'.$this->percentEncode($key).'='.$this->percentEncode($val);
        }
        $tmp = trim($tmp, '&');
        $stringToSign = $stringToSign.$this->percentEncode($tmp);
 
        $key  = $accessSecret.'&';
        $hmac = hash_hmac("sha1", $stringToSign, $key, true);
 
        return base64_encode($hmac);
    }
 
 
    private function percentEncode($value=null)
    {
        $en = urlencode($value);
        $en = str_replace("+", "%20", $en);
        $en = str_replace("*", "%2A", $en);
        $en = str_replace("%7E", "~", $en);
        return $en;
    }
 
    private function curl($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL,$url );
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 );
        $result=curl_exec ($ch);
        return $result;
    }
 
    private function outPut($msg)
    {
        echo date("Y-m-d H:i:s")."  ".$msg.PHP_EOL;
    }
  }
?>

然后,通过定时器或者比如宝塔面板的计划任务,来个每几秒访问执行这个php文件一次,就能实时更新解析记录啦。

因为加了ip判断,也不用担心过多的访问阿里云接口可能被禁掉或限制啥的,也不会增加多少服务器负担,完美

赞(0) 赏杯咖啡!
未经允许不得转载:Sham@双目瞿 » 使用PHP实现阿里云动态解析DDNS

评论 2

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #50

    public function UpdateDomainRecord($ip)这里会报错

    榮华3年前 (2021-08-14)回复
    • 报的什么错

      sham3年前 (2021-08-14)回复

如果你觉得文章好,请赏1杯速溶咖啡给Sham吧!

微信扫一扫打赏