Skip to content

Commit 77553af

Browse files
committed
Quite a few updates
- Added second connection file, useful for OT&E tests. - Added rawXml command for sending obscure extensions that we do not support, or for debug purposes. - TLS defaults now to 1.2 as some registries still have trouble with 1.3 - Fixed login issues with complex passwords in some registries. - Fixed client not working when registry uses XML prefixes.
1 parent 2a2a624 commit 77553af

20 files changed

+678
-70
lines changed

examples/Connection.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,16 @@ function connectEpp(string $registry) {
2323
//For EPP-over-HTTPS , port is usually 443
2424
'port' => 700,
2525
'timeout' => 30,
26-
'tls' => '1.3',
26+
'tls' => '1.2', // Change to 1.3 if required
2727
'bind' => false,
2828
'bindip' => '1.2.3.4:0',
2929
'verify_peer' => false,
3030
'verify_peer_name' => false,
3131
//For EPP-over-HTTPS , change false to 2
3232
'verify_host' => false,
3333
'cafile' => '',
34-
'local_cert' => '/root/epp/cert.pem',
35-
'local_pk' => '/root/epp/key.pem',
34+
'local_cert' => '/root/tembo/cert.pem',
35+
'local_pk' => '/root/tembo/key.pem',
3636
'passphrase' => '',
3737
'allow_self_signed' => true
3838
);

examples/Connection2.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
/**
3+
* Tembo EPP client test file
4+
*
5+
* Written in 2023 by Taras Kondratyuk (https://getpinga.com)
6+
* Based on xpanel/epp-bundle written in 2019 by Lilian Rudenco ([email protected])
7+
*
8+
* @license MIT
9+
*/
10+
11+
// Include the Composer autoloader
12+
require_once '../vendor/autoload.php';
13+
14+
use Pinga\Tembo\EppRegistryFactory;
15+
16+
function connectEpp2(string $registry) {
17+
try
18+
{
19+
$epp = EppRegistryFactory::create($registry);
20+
$info = array(
21+
//For EPP-over-HTTPS, 'host' => 'https://registry.example.com/epp',
22+
'host' => 'epp.example.com',
23+
//For EPP-over-HTTPS , port is usually 443
24+
'port' => 700,
25+
'timeout' => 30,
26+
'tls' => '1.2', // Change to 1.3 if required
27+
'bind' => false,
28+
'bindip' => '1.2.3.4:0',
29+
'verify_peer' => false,
30+
'verify_peer_name' => false,
31+
//For EPP-over-HTTPS , change false to 2
32+
'verify_host' => false,
33+
'cafile' => '',
34+
'local_cert' => '/root/tembo/cert.pem',
35+
'local_pk' => '/root/tembo/key.pem',
36+
'passphrase' => '',
37+
'allow_self_signed' => true
38+
);
39+
$epp->connect($info);
40+
$login = $epp->login(array(
41+
'clID' => 'testregistrar2',
42+
'pw' => 'testpassword2',
43+
//'newpw' => 'testpassword3',
44+
'prefix' => 'tembo'
45+
));
46+
if (array_key_exists('error', $login)) {
47+
echo 'Login Error: ' . $login['error'] . PHP_EOL;
48+
exit();
49+
} else {
50+
echo 'Login Result: ' . $login['code'] . ': ' . $login['msg'][0] . PHP_EOL;
51+
}
52+
return $epp;
53+
} catch(\Pinga\Tembo\Exception\EppException $e) {
54+
echo "Error : ".$e->getMessage() . PHP_EOL;
55+
} catch(Throwable $e) {
56+
echo "Error : ".$e->getMessage() . PHP_EOL;
57+
}
58+
}

examples/DomainInfo.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@
3131
echo 'DomainInfo Result: ' . $domainInfo['code'] . ': ' . $domainInfo['msg'] . PHP_EOL;
3232
echo 'Name: ' . $domainInfo['name'] . PHP_EOL;
3333
echo 'ROID: ' . $domainInfo['roid'] . PHP_EOL;
34-
echo 'Status: ' . $domainInfo['status'][1] . PHP_EOL;
34+
$status = $domainInfo['status'] ?? 'No status available';
35+
if (is_array($status)) {
36+
echo 'Status: ' . implode(', ', $status) . PHP_EOL;
37+
} else {
38+
echo 'Status: ' . $status . PHP_EOL;
39+
}
3540
echo 'Registrant: ' . $domainInfo['registrant'] . PHP_EOL;
3641

3742
$contact_types = array("admin", "billing", "tech");

examples/RawXml.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
/**
3+
* Tembo EPP client test file
4+
*
5+
* Written in 2023 by Taras Kondratyuk (https://getpinga.com)
6+
* Based on xpanel/epp-bundle written in 2019 by Lilian Rudenco ([email protected])
7+
*
8+
* @license MIT
9+
*/
10+
11+
// Include the Composer autoloader
12+
require_once '../vendor/autoload.php';
13+
require_once 'Connection.php';
14+
15+
try
16+
{
17+
$epp = connectEpp('generic');
18+
19+
$params = array(
20+
'xml' => '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
21+
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0"
22+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
23+
xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
24+
<command>
25+
<check>
26+
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
27+
<domain:name>example.com</domain:name>
28+
<domain:name>example.net</domain:name>
29+
</domain:check>
30+
</check>
31+
<clTRID>ABC-12345</clTRID>
32+
</command>
33+
</epp>
34+
');
35+
$rawXml = $epp->rawXml($params);
36+
37+
if (array_key_exists('error', $rawXml))
38+
{
39+
echo 'RawXml Error: ' . $rawXml['error'] . PHP_EOL;
40+
}
41+
else
42+
{
43+
echo 'RawXml Result: ' . $rawXml['code'] . ': ' . $rawXml['msg'] . PHP_EOL;
44+
echo 'Command Result: ' . $rawXml['xml'] . PHP_EOL;
45+
}
46+
47+
$logout = $epp->logout();
48+
49+
echo 'Logout Result: ' . $logout['code'] . ': ' . $logout['msg'][0] . PHP_EOL;
50+
} catch(\Pinga\Tembo\Exception\EppException $e) {
51+
echo "Error : ".$e->getMessage() . PHP_EOL;
52+
} catch(Throwable $e) {
53+
echo "Error : ".$e->getMessage() . PHP_EOL;
54+
}

src/Epp.php

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?php
22
/**
3-
* Tembo EPP client library
3+
* Namingo EPP client library
44
*
5-
* Written in 2023 by Taras Kondratyuk (https://getpinga.com)
5+
* Written in 2023-2024 by Taras Kondratyuk (https://namingo.org)
66
* Based on xpanel/epp-bundle written in 2019 by Lilian Rudenco ([email protected])
77
*
88
* @license MIT
@@ -124,9 +124,18 @@ public function writeRequest($xml)
124124
if (fwrite($this->resource, pack('N', (strlen($xml) + 4)) . $xml) === false) {
125125
throw new EppException('Error writing to the connection.');
126126
}
127-
$r = simplexml_load_string($this->readResponse());
128-
if (isset($r->response) && $r->response->result->attributes()->code >= 2000) {
129-
throw new EppException($r->response->result->msg);
127+
$responseXml = $this->readResponse();
128+
// Try to load the XML without namespace first
129+
$r = simplexml_load_string($responseXml);
130+
if ($r === false || !isset($r->response)) {
131+
// If loading without namespace fails, try loading with the epp namespace
132+
$r = simplexml_load_string($responseXml, null, 0, 'epp', true);
133+
}
134+
if ($r === false) {
135+
throw new EppException('Error parsing the XML response.');
136+
}
137+
if (isset($r->response->result) && (int)$r->response->result->attributes()->code >= 2000) {
138+
throw new EppException((string)$r->response->result->msg);
130139
}
131140
return $r;
132141
}
@@ -188,10 +197,10 @@ public function login($params = array())
188197
$from[] = '/{{ clID }}/';
189198
$to[] = htmlspecialchars($params['clID']);
190199
$from[] = '/{{ pwd }}/';
191-
$to[] = htmlspecialchars($params['pw']);
200+
$to[] = '<![CDATA[' . $params['pw'] . ']]>';
192201
if (isset($params['newpw']) && !empty($params['newpw'])) {
193202
$from[] = '/{{ newpw }}/';
194-
$to[] = PHP_EOL . ' <newPW>' . htmlspecialchars($params['newpw']) . '</newPW>';
203+
$to[] = PHP_EOL . ' <newPW><![CDATA[' . $params['newpw'] . ']]></newPW>';
195204
} else {
196205
$from[] = '/{{ newpw }}/';
197206
$to[] = '';
@@ -2703,6 +2712,38 @@ public function pollAck($params = array())
27032712
return $return;
27042713
}
27052714

2715+
/**
2716+
* rawXml
2717+
*/
2718+
public function rawXml($params = array())
2719+
{
2720+
if (!$this->isLoggedIn) {
2721+
return array(
2722+
'code' => 2002,
2723+
'msg' => 'Command use error'
2724+
);
2725+
}
2726+
2727+
$return = array();
2728+
try {
2729+
$r = $this->writeRequest($params['xml']);
2730+
$code = (int)$r->response->result->attributes()->code;
2731+
$msg = (string)$r->response->result->msg;
2732+
2733+
$return = array(
2734+
'code' => $code,
2735+
'msg' => $msg,
2736+
'xml' => $r->asXML()
2737+
);
2738+
} catch (\Exception $e) {
2739+
$return = array(
2740+
'error' => $e->getMessage()
2741+
);
2742+
}
2743+
2744+
return $return;
2745+
}
2746+
27062747
public function _response_log($content)
27072748
{
27082749
// Add formatted content to the log

src/EppRegistryInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,6 @@ public function domainReport(array $params);
5353

5454
public function pollReq();
5555
public function pollAck(array $params);
56+
57+
public function rawXml(array $params);
5658
}

src/Registries/EuEpp.php

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,10 @@ public function login($params = array())
189189
$from[] = '/{{ clID }}/';
190190
$to[] = htmlspecialchars($params['clID']);
191191
$from[] = '/{{ pwd }}/';
192-
$to[] = htmlspecialchars($params['pw']);
192+
$to[] = '<![CDATA[' . $params['pw'] . ']]>';
193193
if (isset($params['newpw']) && !empty($params['newpw'])) {
194194
$from[] = '/{{ newpw }}/';
195-
$to[] = PHP_EOL . ' <newPW>' . htmlspecialchars($params['newpw']) . '</newPW>';
195+
$to[] = PHP_EOL . ' <newPW><![CDATA[' . $params['newpw'] . ']]></newPW>';
196196
} else {
197197
$from[] = '/{{ newpw }}/';
198198
$to[] = '';
@@ -2092,6 +2092,38 @@ public function pollAck($params = array())
20922092
return $return;
20932093
}
20942094

2095+
/**
2096+
* rawXml
2097+
*/
2098+
public function rawXml($params = array())
2099+
{
2100+
if (!$this->isLoggedIn) {
2101+
return array(
2102+
'code' => 2002,
2103+
'msg' => 'Command use error'
2104+
);
2105+
}
2106+
2107+
$return = array();
2108+
try {
2109+
$r = $this->writeRequest($params['xml']);
2110+
$code = (int)$r->response->result->attributes()->code;
2111+
$msg = (string)$r->response->result->msg;
2112+
2113+
$return = array(
2114+
'code' => $code,
2115+
'msg' => $msg,
2116+
'xml' => $r->asXML()
2117+
);
2118+
} catch (\Exception $e) {
2119+
$return = array(
2120+
'error' => $e->getMessage()
2121+
);
2122+
}
2123+
2124+
return $return;
2125+
}
2126+
20952127
public function _response_log($content)
20962128
{
20972129
// Add formatted content to the log

src/Registries/FrEpp.php

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ public function __construct()
4343

4444
// Create handlers - The second parameter is the max number of files to keep (0 means unlimited)
4545
// The third parameter is the log level
46-
$responseHandler = new RotatingFileHandler(dirname(__FILE__) . '/../log/response-fr.log', 0, Logger::DEBUG);
47-
$requestHandler = new RotatingFileHandler(dirname(__FILE__) . '/../log/request-fr.log', 0, Logger::DEBUG);
48-
$commonHandler = new RotatingFileHandler(dirname(__FILE__) . '/../log/common-fr.log', 0, Logger::DEBUG);
46+
$responseHandler = new RotatingFileHandler(dirname(__FILE__) . '/../../log/response-fr.log', 0, Logger::DEBUG);
47+
$requestHandler = new RotatingFileHandler(dirname(__FILE__) . '/../../log/request-fr.log', 0, Logger::DEBUG);
48+
$commonHandler = new RotatingFileHandler(dirname(__FILE__) . '/../../log/common-fr.log', 0, Logger::DEBUG);
4949

5050
// Set the formatter to the handlers
5151
$responseHandler->setFormatter($formatter);
@@ -189,10 +189,10 @@ public function login($params = array())
189189
$from[] = '/{{ clID }}/';
190190
$to[] = htmlspecialchars($params['clID']);
191191
$from[] = '/{{ pwd }}/';
192-
$to[] = htmlspecialchars($params['pw']);
192+
$to[] = '<![CDATA[' . $params['pw'] . ']]>';
193193
if (isset($params['newpw']) && !empty($params['newpw'])) {
194194
$from[] = '/{{ newpw }}/';
195-
$to[] = PHP_EOL . ' <newPW>' . htmlspecialchars($params['newpw']) . '</newPW>';
195+
$to[] = PHP_EOL . ' <newPW><![CDATA[' . $params['newpw'] . ']]></newPW>';
196196
} else {
197197
$from[] = '/{{ newpw }}/';
198198
$to[] = '';
@@ -2516,6 +2516,38 @@ public function pollAck($params = array())
25162516
return $return;
25172517
}
25182518

2519+
/**
2520+
* rawXml
2521+
*/
2522+
public function rawXml($params = array())
2523+
{
2524+
if (!$this->isLoggedIn) {
2525+
return array(
2526+
'code' => 2002,
2527+
'msg' => 'Command use error'
2528+
);
2529+
}
2530+
2531+
$return = array();
2532+
try {
2533+
$r = $this->writeRequest($params['xml']);
2534+
$code = (int)$r->response->result->attributes()->code;
2535+
$msg = (string)$r->response->result->msg;
2536+
2537+
$return = array(
2538+
'code' => $code,
2539+
'msg' => $msg,
2540+
'xml' => $r->asXML()
2541+
);
2542+
} catch (\Exception $e) {
2543+
$return = array(
2544+
'error' => $e->getMessage()
2545+
);
2546+
}
2547+
2548+
return $return;
2549+
}
2550+
25192551
public function _response_log($content)
25202552
{
25212553
// Add formatted content to the log

0 commit comments

Comments
 (0)