Bulk transfer domains from TransIP

From Openprovider API documentation

Revision as of 10:08, 13 May 2019 by WikiSysop (Talk | contribs)
(diff) ← Older revision | Current revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Before using this script, please make sure to read API General Examples

Using this script is at your own risk!

<?php

  $help = "Available parameters:
-f: (required) name of file containing domains to transfer
-d: (optional) how to handle DNS zones; allowed values:
    0: (default) do not create DNS zones in Openprovider; use existing
       nameservers
    1: create DNS zones in Openprovider based on TransIP DNS records;
       put the domain on the Openprovider nameservers after transfer;
       existing zones will not be overwritten
    overwrite: create DNS zones, overwrite any existing zones
-h: (optional) how to handle contacts; allowed values:
    0: (default) the script checks if another TransIP contact with the
       same data was processed before; if so, re-use that contact instead
       of creating a new one
    1: create a new Openprovider handle for every domain contact, even if
       the data is similar to a previously processed contact
-v: (optional) whether or not to show extended information during runtime;
    allowed values:
    0: (default) don't show additional ouput
    1: show additional ouput
-t: (optional) whether to run in test mode or not; allowed values:
    0: run live
    1: (default) run in test mode / read-only; no contacts or zones will
       be created, no domains will be transferred

Examples:
  Run in test mode, full debugging output:
    php transfer-from-transip.php -f domains.txt -v1 -t1

  Run in live mode: transfer domains while create DNS zones (but do not
  overwrite existing ones), show limited output:
    php transfer-from-transip.php -f domains.txt -t0 -d1

Full documentation is available at https://openprovider.zendesk.com/hc/en-us/articles/360019994414
";

  // Openprovider API credentials
  $auth = array('username' => $op_user, 'hash' => $op_hash);

  // TransIP and Openprovider API
  require_once('Transip/DomainService.php');
  require_once('API.php');
  $api = new OP_API ('https://api.openprovider.eu');

  // Read runtime parameters
  $opts = getopt('f:d:t:h:v:', array('help'));
  $domainFile      = $opts['f']; // filename (required)
  $withDns         = $opts['d']; // 0, 1 or overwrite (default = 0)
  $forceNewHandles = $opts['h']; // 0 or 1 (default = 0)
  $verbose         = $opts['v']; // 0 or 1 (default = 0)
  $testMode        = $opts['t']; // 0 or 1 (default = 1)

  if (isset($opts['help'])) {
    echo $help;
    exit;
  }


  // Get list with domains to transfer
  if (file_exists($domainFile)) {
    $domains = file($domainFile, FILE_IGNORE_NEW_LINES);
  }
  else {
    die("Cannot find domain list; file [$f] does not exist\n");
  }

  // Check other parameters
  if (!in_array($withDns, array(0, 1, 'overwrite'))) {
    $withDns = 0;
  }
  if (!in_array($testMode, array(0, 1))) {
    $testMode = 1;
  }
  if (!in_array($forceNewHandles, array(0, 1))) {
    $forceNewHandles = 0;
  }
  if (!in_array($verbose, array(0, 1))) {
    $verbose = 0;
  }

  // Keep track of handles that were already created
  $handleRelations = array();
  if (!$forceNewHandles) {
    if (file_exists('transip-handle-relations.dat')) {
      if ($f = fopen('transip-handle-relations.dat', 'r')) {
        while (!feof($f)) {
          list($md5, $opHandle) = fgetcsv($f);
          $handleRelations[$md5] = $opHandle;
        }
        fclose($f);
      }
      else {
        die("Cannot open file transip-handle-relations.dat\n");
      }
    }
    $fHandles = fopen('transip-handle-relations.dat', 'a');
  }

  foreach ($domains as $dom) {
    $continue = true;

    if ($verbose) {
      echo "Starting domain $dom\n";
      echo "Retrieve data for domain $dom from TransIP API\n";
    }
    try {
      $domain = Transip_DomainService::getInfo($dom);
      if ($verbose) {
        echo "TransIP returned the following data for domain $dom:\n";
        print_r($domain);
      }
    }
    catch(SoapFault $e) {
      // It is possible that an error occurs when connecting to the TransIP Soap API,
      // those errors will be thrown as a SoapFault exception.
      echo "@@ERROR: An error occurred while querying the TransIP API for domain [$dom]: ".htmlspecialchars($e->getMessage())."\n";
      continue;
    }

    $args = array();
    
    // Nameservers
    if ($verbose) {
      echo "Preparing nameservers for domain [$dom]\n";
    }
    if ($withDns) {
      if (!$domain->dnsEntries) {
        echo "@@ERROR: no DNS entries found for import in Openprovider for $dom; skipping this domain\n";
        continue;
      }
      if (createOpenproviderZone($dom, $domain->dnsEntries)) {
        $args['nsGroup'] = 'dns-openprovider';
      }
      else {
        echo "@@ERROR: while creating DNS zone for $dom; skipping this domain\n";
        continue;
      }
    }
    else {
      if (isset($domain->nameservers)) {
        foreach ($domain->nameservers as $ns) {
          $args['nameServers'][] = array(
            'name' => $ns->hostname,
            'ip'   => (isset($ns->ipv4) ? $ns->ipv4 : NULL),
            'ip6'  => (isset($ns->ipv6) ? $ns->ipv6 : NULL),
          );
        }
      }
    }

    // Contacts (handles)
    if ($verbose) {
      echo "Preparing contact handles for domain [$dom]\n";
    }
    foreach ($domain->contacts as $contact) {
      $type = ;
      switch ($contact->type) {
        case 'registrant'     : $type = 'owner'; break;
        case 'administrative' : $type = 'admin'; break;
        case 'technical'      : $type = 'tech'; break;
        default               : echo "@@WARNING: invalid contact type ".$contact->type." for domain [$dom]; skipping\n"; break;
      }
      unset($contact->type);

      $hash = md5(implode(, get_object_vars($contact)));
      if (!$forceNewHandles && isset($handleRelations[$hash])) {
        $opHandle = $handleRelations[$hash];
      }
      else {
        if ($opHandle = createOpenproviderContact($contact)) {
          if (!$testMode) {
            fwrite($fHandles, $hash.','.$opHandle."\n");
            $handleRelations[$hash] = $opHandle;
          }
        }
        else {
          echo "@@ERROR while creating Openprovider contact for $type of $dom\n";
          $continue = false;
          continue 2;
        }
      }
      $args[$type.'Handle'] = $opHandle;
    }

    // Authcode
    $args['authCode'] = $domain->authCode;

    // Unlock domain, if required
    if ($verbose) {
      echo "Unlocking domain [$dom] (if applicable)\n";
    }
    if ($domain->isLocked) {
      if ($testMode) {
        echo "TEST MODE: skipping unlocking domain\n";
      }
      else {
        try {
          $isLocked = Transip_DomainService::unsetLock($dom);
        }
        catch(SoapFault $e)
        {
          // It is possible that an error occurs when connecting to the TransIP Soap API,
          // those errors will be thrown as a SoapFault exception.
          echo "@@ERROR: An error occurred while unlocking domain [$dom]: " . htmlspecialchars($e->getMessage())."\n";
        }
      }
    }

    list($d, $e) = explode('.', $dom, 2);
    $args['domain'] = array(
      'name' => $d,
      'extension' => $e,
    );
    $args['period'] = 1;

    if ($verbose) {
      echo "Start transfer for domain [$dom] in Openprovider with the following data array:\n";
      print_r($args);
    }
    if ($testMode) {
      echo "TEST MODE: skip domain transfer for [$dom]\n";
    }
    else {
      $request = new OP_Request;
      $request->setCommand('transferDomainRequest')
        ->setAuth($auth)
        ->setArgs($args);
      $reply = $api->process($request);
      if ($reply->getFaultCode() != 0) {
        echo "@@ERROR on domain transfer [$dom]: ".$reply->getFaultCode().' - '.$reply->getFaultString()."\n";
        if ($verbose) {
          echo "Full data array:\n";
          print_r($args);
        }
      }
      else {
        echo "Transfer for $dom successfully requested\n";
      }
    }
  }

  function createOpenproviderZone($domain, $dnsEntries) {
    global $api, $auth;
    global $testMode, $withDns, $verbose;

    list($d, $e) = explode('.', $domain, 2);

    // Check if a zone already exists
    $request = new OP_Request;
    $request->setCommand('retrieveZoneDnsRequest')
      ->setAuth($auth)
      ->setArgs(array(
        'name' => $domain,
        'withRecords' => false,
        'withHistory' => false
      ));
    $reply = $api->process($request);
    $response = $reply->getValue();
    if ($response) {
      if ($withDns == 'overwrite') {
        if ($testMode) {
          echo "@@WARNING: TEST MODE: Zone for [$domain] already exists, skip removing of existing zone\n";
        }
        else {
          echo "@@WARNING: Zone for [$domain] already exists; removing existing zone\n";

          $request = new OP_Request;
          $request->setCommand('deleteZoneDnsRequest')
            ->setAuth($auth)
            ->setArgs(array(
              'domain' => array(
                'name' => $d,
                'extension' => $e
              ),
            ));
          $reply = $api->process($request);
          $response = $reply->getValue();
        }
      }
      else {
        echo "@@WARNING: Zone for [$domain] already exists; skipping import\n";
      }
    }

    $records = array();
    foreach ($dnsEntries as $record) {
      if (in_array($record->type, array('NS', 'SOA'))) {
        continue;
      }

      if (in_array($record->type, array('MX', 'SRV'))) {
        list($prio, $value) = explode(' ', $record->content, 2);
      }
      else {
        $prio = NULL;
        $value = $record->content;
      }

      $records[] = array(
        'type'  => $record->type,
        'name'  => ($record->name == '@' ?  : $record->name),
        'value' => ($value == '@' ? $domain : $value),
        'prio'  => $prio,
        'ttl'   => ($record->expire < 600 ? 600 : $record->expire),
      );
    }

    if ($testMode) {
      echo "TEST MODE - skip DNS zone creation for $domain\n";
      if ($verbose) {
        echo "Zone contents:\n";
        print_r($records);
      }
      return true;
    }
    else {
      $request = new OP_Request;
      $request->setCommand('createZoneDnsRequest')
        ->setAuth($auth)
        ->setArgs(array(
          'domain' => array(
            'name' => $d,
            'extension' => $e,
          ),
          'type' => 'master',
          'records' => $records,
        ));
      $reply = $api->process($request);
      if ($reply->getFaultCode() != 0) {
        echo "@@ERROR on DNS zone creation for [$domain]: ".$reply->getFaultCode().' - '.$reply->getFaultString()."; full data array:\n";
        print_r($records);
        return false;
      }
      else {
        if ($verbose) {
          echo "DNS zone for $domain successfully created with the following records:\n";
          print_r($records);
        }
        return true;
      }
    }
  }
  
  function createOpenproviderContact($contact) {
    global $api, $auth;
    global $testMode, $verbose;

    // Split telephone number
    // Country code separated?
    $matches = array();
    if (preg_match('/^(\+?\d+)[ \-\.](.*)$/', $contact->phoneNumber, $matches)) {
      $tel1 = (substr($matches[1], 0, 1) == '+' ?  : '+').$matches[1];
      $rest = preg_replace('/[^\d]/', , $matches[2]);
    }
    // Else consider first 2 numbers the country code
    else {
      $tel = preg_replace('/[^\d]/', , $contact->phoneNumber);
      $tel1 = '+'.substr($tel, 0, 2);
      $rest = $matches[2];
    }
    $tel2 = substr($rest, 0, 2);
    $tel3 = substr($rest, 2);

    // Split address number
    $matches = array();
    if (preg_match('/^\d+$/', $contact->number)) {
      $number = $contact->number;
      $suffix = NULL;
    }
    else if (preg_match('/^(\d+)([^\d].*)$/', $contact->number, $matches)) {
      $number = $matches[1];
      $suffix = $matches[2];
    }
    else {
      $number = 1;
      $suffix = $contact->number;
    }

    $args = array(
      'companyName' => $contact->companyName,
      'name' => array(
        'firstName' => $contact->firstName,
        'prefix' => $contact->middleName,
        'lastName' => $contact->lastName,
      ),
      'phone' => array(
        'countryCode' => $tel1,
        'areaCode' => $tel2,
        'subscriberNumber' => $tel3,
      ),
      'address' => array(
         'street' => $contact->street,
         'number' => $number,
         'suffix' => $suffix,
         'zipcode' => $contact->postalCode,
         'city' => $contact->city,
         'country' => strtoupper($contact->country),
      ),
      'email' => $contact->email,
      'additionalData' => ($contact->companyKvk ? array('companyRegistrationNumber' => $contact->companyKvk) : NULL),
    );

    if ($testMode) {
      echo "TEST MODE - skip handle creation\n";
      if ($verbose) {
        echo "Handle details are the following:\n";
        print_r($args);
      }
      return true;
    }
    else {
      $request = new OP_Request;
      $request->setCommand('createCustomerRequest')
        ->setAuth($auth)
        ->setArgs($args);
      $reply = $api->process($request);
      if ($reply->getFaultCode() != 0) {
        echo "@@ERROR on contact creation for [$domain]: ".$reply->getFaultCode().' - '.$reply->getFaultString()."; full data array:\n";
        print_r($args);
        return false;
      }
      else {
        $response = $reply->getValue();
        if ($verbose) {
          echo "Successfully created handle ".$response['handle']."\n";
        }
        return $response['handle'];
      }
    }
  }

?>
Views
Personal tools