PHP Classes

PHP RDAP Server: Process RDAP queries about an IP address or domain

Recommend this page to a friend!
  Info   View files Example   Demos   View files View files (19)   DownloadInstall with Composer Download .zip   Reputation   Support forum   Blog (1)    
Last Updated Ratings Unique User Downloads Download Rankings
2023-12-14 (6 months ago) RSS 2.0 feedNot yet rated by the usersTotal: 41 All time: 10,850 This week: 88Up
Version License PHP version Categories
rdap-server 1.0.0MIT/X Consortium ...7Networking, Searching, Web services, H..., P...
Description 

Authors

Hiqdev Team
Daniel Marschall
Till Wehowski


Contributor

This package can process RDAP queries about an IP address or domain.

It implements an RDAP Web server that can process queries about IP addresses and domains.

The server returns responses in JSON format according to the RDAP protocol specification.

This server supports falling back to Whois queries when performing an RDAP query about an IP address or domain is impossible.

Innovation Award
PHP Programming Innovation award nominee
December 2023
Number 2
RDAP is an Internet protocol that allows information about IP addresses and domains to be answered.

It is a successor of the Whois protocol. RDAP allows to perform queries using HTTP requests and get query responses in JSON format.

So, the RDAP server responses are more accessible to parse and process than the WHOIS server responses because, nowadays, it is easy to parse data in JSON format in PHP and many other languages.

This package implements an RDAP server in pure PHP code. It allows any PHP developer to implement the responses to queries about domains and IP addresses they can manage.

Manuel Lemos
Picture of Till Wehowski
  Performance   Level  
Name: Till Wehowski <contact>
Classes: 30 packages by
Country: Germany Germany
Age: 45
All time rank: 107269 in Germany Germany
Week rank: 216 Up11 in Germany Germany Up
Innovation award
Innovation award
Nominee: 12x

Example

<?php
declare(strict_types=1);

namespace
Webfan\Webfat\Module\RdapServer;

use
App\Application\Handlers\HttpErrorHandler;
use
App\Application\Handlers\ShutdownHandler;
use
App\Application\ResponseEmitter\ResponseEmitter;
use
DI\ContainerBuilder;
use
Slim\Factory\AppFactory;
use
Slim\Factory\ServerRequestCreatorFactory;
use
frdl\security\floodprotection\FloodProtection;



/**
* @toDo: use libs
*/
class Helper
{
   
 public static
$protocoll = 'HTTP/1.1';

 public static function
sendCorsHeaders(array $allowedOrigins = null, $fallbackOrigin = 'https://invalid.dns.frdl.de') {
   
// CORS
    // Author: Till Wehowski
 
if(null === $allowedOrigins){
    
$allowedOrigins = [
      
"*",
      
$_SERVER['SERVER_NAME'],
      
$_SERVER['HTTP_ORIGIN'],
      
$_SERVER['HTTP_HOST']
     ];
  }
  
  
 
$originRequested = strip_tags(((isset($_SERVER['HTTP_ORIGIN'])) ? $_SERVER['HTTP_ORIGIN'] : "*"));
 
$origin = (in_array($originRequested, $allowedOrigins)) ? $originRequested : $fallbackOrigin;
  
   
header("Access-Control-Allow-Credentials: true");
   
header("Access-Control-Allow-Origin: ".$origin);

   
header("Access-Control-Allow-Headers: If-None-Match, X-Requested-With, Origin, X-Frdlweb-Bugs, Etag, X-Forgery-Protection-Token, X-CSRF-Token, X-Frdl-Request-Negotiation");

    if (isset(
$_SERVER['HTTP_ORIGIN'])) {
       
header('X-Frame-Options: ALLOW-FROM '.$origin);
    } else {
       
header_remove("X-Frame-Options");
    }
  
   
$expose = array('Etag', 'X-CSRF-Token');
    foreach (
headers_list() as $num => $header) {
       
$h = explode(':', $header);
       
$expose[] = trim($h[0]);
    }
   
header("Access-Control-Expose-Headers: ".implode(',',$expose));

   
header("Vary: Origin");
 }
 
  public static function
header($name, $value)
    {
       return
header($name.': '.$value);
    }



  public static function
status($code = 200)
    {
       if((int)
$code == 200)return header(self::$protocoll.' 200 Ok');
       if((int)
$code == 201)return header(self::$protocoll.' 201 Created');

       if((int)
$code == 400)return header(self::$protocoll.' 400 Bad Request');
       if((int)
$code == 401)return header(self::$protocoll.' 401 Unauthorized');
       if((int)
$code == 403)return header(self::$protocoll.' 403 Forbidden');
       if((int)
$code == 404)return header(self::$protocoll.' 404 Not Found');
       if((int)
$code == 409)return header(self::$protocoll.' 409 Conflict');
      
       if((int)
$code == 422)return header(self::$protocoll.' 422 Validation Failure');
      
       if((int)
$code == 429)return header(self::$protocoll.' 429 Too Many Requests');
      
       if((int)
$code == 455)return header(self::$protocoll.' 455 Blocked Due To Misbehavior');

      
       if((int)
$code == 500)return header(self::$protocoll.' 500 Internal Server Error');
       if((int)
$code == 501)return header(self::$protocoll.' 501 Not Implemented');
       if((int)
$code == 503)return header(self::$protocoll.' 503 Service Unavailable');
       if((int)
$code == 511)return header(self::$protocoll.' 511 Network Authentication Required');
     
     
       if(
0===intval($code)){
      return
header(self::$protocoll.' 501 Not Implemented');
       }
     
      \
trigger_error('status code '.intval($code).' not implemented in \'' . get_class($this) . '\' ' . __METHOD__. ' '.__LINE__, E_USER_ERROR);
    }
   
   
}

ini_set('display_errors', '0');
require_once
__DIR__ . '/../vendor/autoload.php';
//require_once __DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'dns.frdl.de'.\DIRECTORY_SEPARATOR.'vendor'.\DIRECTORY_SEPARATOR.'autoload.php';

//\Webfan\Psr4Loader\RemoteFromWebfan::getInstance('frdl.webfan.de', true, 'latest', false);

if(!is_dir(__DIR__ . '/../cache/flood-protection/')){
 
mkdir(__DIR__ . '/../cache/flood-protection/', 0777, true);
}

if(!
is_dir(__DIR__ . '/../cache/container/')){
 
mkdir(__DIR__ . '/../cache/container/', 0777, true);
}


// Instantiate PHP-DI ContainerBuilder
$containerBuilder = new ContainerBuilder();

//if (false) { // Should be set to true in production
   
$containerBuilder->enableCompilation(__DIR__ . '/../cache/container');
//}

// Set up settings
$settings = require __DIR__ . '/../app/settings.php';
$settings($containerBuilder);

// Set up dependencies
$dependencies = require __DIR__ . '/../app/dependencies.php';
$dependencies($containerBuilder);

// Build PHP-DI Container instance
$container = $containerBuilder->build();





 
$FloodProtection = new FloodProtection('rdap', 30, 60, __DIR__ . '/../cache/flood-protection/');
 if(
$_SERVER['REMOTE_ADDR'] !== $_SERVER['SERVER_ADDR']
     && !
in_array($_SERVER['REMOTE_ADDR'], ['212.53.140.43', '212.72.182.211'])
    &&
$FloodProtection->check($_SERVER['REMOTE_ADDR'])
   ){
   
header("HTTP/1.1 429 Too Many Requests");
    exit(
"Too Many Requests, try again later!");
 }

       
$ShutdownTasks = \frdlweb\Thread\ShutdownTasks::mutex();
       
$ShutdownTasks(function($container, $FloodProtection, $tempRdapDir, $CacheDir, $maxCacheTime){
            @\
ignore_user_abort(true);
           
$container->get('rdap.cache')->prune();
            if(
is_dir($tempRdapDir)){
           
// \webfan\hps\patch\Fs::pruneDir($tempRdapDir, $maxCacheTime * 4, true, false);
           
}
           
           
           
$FloodProtection->prune();
            if(
is_dir($CacheDir)){
              \
webfan\hps\patch\Fs::pruneDir($CacheDir, $maxCacheTime, true, false);
            }
        },
$container, $FloodProtection, __DIR__.'/../cache/rdap/', __DIR__ . '/../cache/flood-protection/', 31 * 24 * 60 * 60);




// Instantiate the app
AppFactory::setContainer($container);
$app = AppFactory::create();
$callableResolver = $app->getCallableResolver();

// Register routes
$routes = require __DIR__ . '/../app/routes.php';
$routes($app);

/** @var bool $displayErrorDetails */
$displayErrorDetails = $container->get('settings')['displayErrorDetails'];

// Create Request object from globals
$serverRequestCreator = ServerRequestCreatorFactory::create();



$request = $serverRequestCreator->createServerRequestFromGlobals();




// Create Error Handler
$responseFactory = $app->getResponseFactory();
$errorHandler = new HttpErrorHandler($callableResolver, $responseFactory);
$errorHandler->setDisplayErrorDetailsFlag($displayErrorDetails);

// Create Shutdown Handler
$shutdownHandler = new ShutdownHandler($request, $errorHandler, $displayErrorDetails);
register_shutdown_function($shutdownHandler);

// Add Routing Middleware
$app->addRoutingMiddleware();

// Add Error Middleware
$errorMiddleware = $app->addErrorMiddleware($displayErrorDetails, false, false);
$errorMiddleware->setDefaultErrorHandler($errorHandler);
 
Helper::status(200);

    
Helper::sendCorsHeaders([(isset($_SERVER['HTTP_ORIGIN']))?$_SERVER['HTTP_ORIGIN']:'*'], '*');

// Run App & Emit Response
$response = $app->handle($request);
Helper::status($response->getStatusCode());
$responseEmitter = new ResponseEmitter();
ob_start(function($c) use($response) {
 
Helper::sendCorsHeaders([(isset($_SERVER['HTTP_ORIGIN']))?$_SERVER['HTTP_ORIGIN']:'*'], '*');
  
Helper::status($response->getStatusCode());
    return
$c;
});
$responseEmitter->emit($response);



Details

RDAP Server in PHP

This RDAP Server is OIDplus aware and provides a WHOIS result in the remarks of a RDAP result.

Installation

  • Install the dependencies:
    composer require frdl/rdap-server
    
    OR move into the directory and
    
    composer install
  • Make the `cache` and `logs` directory and their subdirectories writable.

Customization

  • Edit the file `public/index.html` to change the index page
  • The Infos are requested from OIDplus instance for the `domain` route per default. This produces overhead, see this issue for more info. To change this behavior edit the file `app/routes.php` to switch back to RDAP-only domain route.

DEMO

This demo shows the way and where we get all the OIDplus instances.

ToDo
  • move Env\Dotenv to composer deps
  • const for root instance/OID of the local RDAP instance/bootstrap
  • Instead of requesting all instances in a sequence, can we start asynchronous requests/threads (by e.g. exec, AMP framework, ...) and wait/collect (like Promise.all) for them in the main thread, to speed up the over all request response time for the end user???
  • And can we introduce a more powerful caching/proxy/index system, like and/or a global INDEX??? (global meaning global in the focus of the instance building a web/federation-index)
  • RDAP-Conformance also for OIDplus objectTypes ???
  • test
  • IO4/OIDplus/... - Plugable Adapters (for local instance)

Reference notes


  Frdlweb RDAP ServerExternal page  

Open in a separate window

  Files folder image Files  
File Role Description
Files folder imageapp (3 files)
Files folder imageclasses (3 files)
Files folder imagepublic (3 files)
Files folder imagesrc (1 directory)
Files folder imagetests (1 file)
Accessible without login Plain text file composer.json Data Auxiliary data
Accessible without login Plain text file LICENSE Lic. License text
Accessible without login Plain text file phpunit.xml Data Auxiliary data
Accessible without login Plain text file README.md Doc. Documentation

  Files folder image Files  /  app  
File Role Description
  Plain text file dependencies.php Class Class source
  Plain text file routes.php Class Class source
  Accessible without login Plain text file settings.php Example Example script

  Files folder image Files  /  classes  
File Role Description
  Plain text file Cache2.php Class Class source
  Plain text file Status.php Class Class source
  Plain text file WhoisDomainProvider2.php Class Class source

  Files folder image Files  /  public  
File Role Description
  Accessible without login Plain text file .htaccess Data Auxiliary data
  Accessible without login Plain text file index.html Data Application home page
  Accessible without login Plain text file index.php Example Example script

  Files folder image Files  /  src  
File Role Description
Files folder imageApplication (3 directories)

  Files folder image Files  /  src  /  Application  
File Role Description
Files folder imageActions (2 directories)
Files folder imageHandlers (2 files)
Files folder imageResponseEmitter (1 file)

  Files folder image Files  /  src  /  Application  /  Actions  
File Role Description
Files folder imageDomain (1 file)
Files folder imageOID (1 file)

  Files folder image Files  /  src  /  Application  /  Actions  /  Domain  
File Role Description
  Plain text file GetDomainInfoAction.php Class Class source

  Files folder image Files  /  src  /  Application  /  Actions  /  OID  
File Role Description
  Plain text file GetOIDInfoAction.php Class Class source

  Files folder image Files  /  src  /  Application  /  Handlers  
File Role Description
  Plain text file HttpErrorHandler.php Class Class source
  Plain text file ShutdownHandler.php Class Class source

  Files folder image Files  /  src  /  Application  /  ResponseEmitter  
File Role Description
  Plain text file ResponseEmitter.php Class Class source

  Files folder image Files  /  tests  
File Role Description
  Plain text file bootstrap.php Class Class source

 Version Control Unique User Downloads Download Rankings  
 100%
Total:41
This week:0
All time:10,850
This week:88Up