1

I am trying to use CentralNic PHP EPP library to interact with Nominet EPP.

It is clear how to genrate command frames using Net_EPP_Frame_Command class For instance,

$frame = new Net_EPP_Frame_Command("check", "host");
$frame->addObjectProperty("name", "ns1.example.com");
$frame->addObjectProperty("name", "ns2.example.com");
$frame->addObjectProperty("name", "ns3.example.com");
$client->sendFrame($frame->saveXML());

The result is

<?xml version="1.0"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<check>
<host:check xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>ns1.example.com</host:name>
<host:name>ns2.example.com</host:name>
<host:name>ns3.example.com</host:name>
</host:check>
</check>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

Which is exactly what I need. The only problem is that I am unable to generate login frame that has to look similar to

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
     <command>
       <login>
         <clID>ClientX</clID>
         <pw>foo-BAR2</pw>
         <newPW>bar-FOO2</newPW>
         <options>
           <version>1.0</version>
           <lang>en</lang>
         </options>
         <svcs>
           <objURI>urn:ietf:params:xml:ns:obj1</objURI>
           <objURI>urn:ietf:params:xml:ns:obj2</objURI>
           <objURI>urn:ietf:params:xml:ns:obj3</objURI>
           <svcExtension>
             <extURI>http://custom/obj1ext-1.0</extURI>
           </svcExtension>
         </svcs>
       </login>
       <clTRID>ABC-12345</clTRID>
     </command>
</epp>

Could you please guide me in a right direction?

Thank you


I edited https://github.com/centralnic/php-epp/blob/master/Net/EPP/Frame/Command.php By inserting two more functions to the class

       function setParam($param, $value)
        {
            $this->$param->appendChild($this->createTextNode($value));
            //$this->$param->setAttribute($param, $value);
        }

        function addElement($name, $value, $parentNode)
        {
            $element = $this->createElement($name);
            $element->appendChild($this->createTextNode($value));
            $this->$parentNode->appendChild($element);
        }

The way I use it now:

    public function login($clid, $pw)
    {
        $frame = $this->buildLoginFrame($clid, $pw);
        $this->client->sendFrame($frame->saveXML());
        print_r($frame->friendly());
        print_r($this->client->getFrame());
    }

    private function buildLoginFrame($clid, $pw)
    {
        $frame = new Net_EPP_Frame_Command_Login();
        $frame->setParam("clID", $clid);
        $frame->setParam("pw", $pw);
        $frame->setParam("eppVersion", self::VERSION);
        $frame->setParam("eppLang", self::LANG);
        $frame->addElement("objURI", "urn:ietf:params:xml:ns:contact-1.0", "svcs");
        $frame->addElement("objURI", "urn:ietf:params:xml:ns:domain-1.0", "svcs");
        $frame->addElement("objURI", "urn:ietf:params:xml:ns:host-1.0", "svcs");
        $frame->setParam("clTRID", $this->clTRID);
        return $frame;
    }

The final version that seems the best in the current situation

class EPPHelper
    {
        static function setParam($frame, $param, $value)
        {
            $frame->$param->appendChild($frame->createTextNode($value));
        } 

        public function addElement($frame, $name, $value, $parentNode)
        {
            $element = $frame->createElement($name);
            $element->appendChild($frame->createTextNode($value));
            $parentNode->appendChild($element);
        }
    }
}

...

public function login($clid, $pw)
{
    $frame = $this->buildLoginFrame($clid, $pw);
    $this->client->sendFrame($frame->saveXML());
    print_r($frame->friendly());
    print_r($this->client->getFrame());
}

private function buildLoginFrame($clid, $pw)
{
    $frame = new Net_EPP_Frame_Command_Login();
    //$frame->setParam("clID", $clid);
    EPPHelper::setParam($frame, "clID", $clid);
    EPPHelper::setParam($frame, "pw", $pw);

    EPPHelper::setParam($frame, "eppVersion", self::VERSION);
    EPPHelper::setParam($frame, "eppLang", self::LANG);
    EPPHelper::addElement($frame, "objURI", "urn:ietf:params:xml:ns:contact-1.0", $frame->svcs);
    EPPHelper::addElement($frame, "objURI", "urn:ietf:params:xml:ns:domain-1.0", $frame->svcs);
    EPPHelper::addElement($frame, "objURI", "urn:ietf:params:xml:ns:host-1.0", $frame->svcs);
    EPPHelper::setParam($frame, "clTRID", $this->clTRID);

    return $frame;
}
Vladimir Hraban
  • 3,543
  • 4
  • 26
  • 46
  • What does the documentation of that library shares about the login? There seems to be a dedicated class for it: https://github.com/centralnic/php-epp/blob/master/Net/EPP/Frame/Command/Login.php – hakre Jul 05 '13 at 13:06
  • I am afraid there is no documentation in the net whatsoever. I had to modify the Login.php file to suit my needs and also remove debug_log on line #32 in Command.php. Seems the project itself is really raw and needs a lot of fixing. I managed to generate the frame but I am not sure that is the way it was originally intended to be done. If anyone is interested, I can post the workaround – Vladimir Hraban Jul 05 '13 at 13:30
  • You don't need to. It works the same as the class you've outlined above. Because `svcs` is a DOMElement, you can just add child-nodes to your needs even with these more complex looking properties. You might want to add the code where you edited to your question (divide by a line), it should be easy then to give some better suggestions how the intended use is. See as well: http://php.net/book.dom - this is the underlying library CentralNic PHP EPP is built on top of. – hakre Jul 05 '13 at 13:34
  • Instead of editing that file, you can extend from it. Then use your extended file with those new helper methods which seem fair to me. However you could also create an object of it's own adding those routines and then using aggregation. Can you follow what I write? – hakre Jul 05 '13 at 14:24
  • Yep, I do. The inheritance goes all the way to Command.php and even even deeper. So I decided to put them into that file instead. I just find it a bit of strange not to have those functions and that made me think I am missing something. Having a parent classes to extend needed frame classes is not an option because there are a dozens of different ones and I do not want to make the code hard to maintain – Vladimir Hraban Jul 05 '13 at 14:29
  • I also edited the question accrordingly – Vladimir Hraban Jul 05 '13 at 14:36
  • The I suggest you use aggregation in your case. Otherwise you don't benefit from that library much. I must admit it's design is a bit limited, this is probably why you fear to miss something. Hmm. I would at least give aggregation a try in a second branch. Editing the base-class is somewhat a hack you need to take care off in case of updates of that library. What about creating an issue ticket and suggest the project owner your changes? This would be another alternative way to deal with the issue. – hakre Jul 05 '13 at 14:44
  • I decided to use a helper class and insert those two functions into it making them static. The only disadvantage is that I have to pass the frame object as a parameter. Probably I will raise a ticket, thank you for the help. I will see how my project develops further and whether it will be a good idea to make my classes extending the library ones. I updated my question – Vladimir Hraban Jul 05 '13 at 15:38
  • Nah, I would really do aggregation, not those static methods. I'd say this could be also modeled inside a DOMElementNode base type for that library. Anyway, as the design of that lib is that inflexible (favors inheritance over aggregation, the better is the opposite), best would be to make the original aware of the issue and let's see how that turns out. Should be easy to extend. – hakre Jul 05 '13 at 17:10

1 Answers1

1

for exactly this reason I created a new library: https://github.com/AfriCC/php-epp2 - it started as extension/fork of Net_EPP, but ending up sharing maybe only 1% of the code of Net_EPP.

Basically it is a "high-level" EPP Client for PHP. High-level means, you don't have to worry about creating objects/XML but can just use the convenient methods to modify your frames.

<?php
require 'src/AfriCC/autoload.php';

use AfriCC\EPP\Frame\Command\Create\Host as CreateHost;

$frame = new CreateHost;
$frame->setHost('ns1.example.com');
$frame->addAddr('8.8.8.8');
$frame->addAddr('8.8.4.4');
$frame->addAddr('2a00:1450:4009:809::1001');
echo $frame;

Also if you use the Client, it will automatically do the login/logout for your:

<?php
require 'src/AfriCC/autoload.php';

use AfriCC\EPP\Client as EPPClient;

$epp_client = new EPPClient([
    'host' => 'epptest.org',
    'username' => 'foo',
    'password' => 'bar',
    'services' => [
        'urn:ietf:params:xml:ns:domain-1.0',
        'urn:ietf:params:xml:ns:contact-1.0'
    ],
    'debug' => true,
]);

try {
    $greeting = $epp_client->connect();
} catch(Exception $e) {
    echo $e->getMessage() . PHP_EOL;
    unset($epp_client);
    exit(1);
}

$epp_client->close();

It is still fairly new, so there might be some bugs. Its opensource, so don't be a dick about it and just file a bug report or do a merge request :)

lifeofguenter
  • 1,121
  • 1
  • 13
  • 22