Completed
Push — master ( 703ea3...18d4bf )
by
unknown
01:23
created

AbstractClient::__construct()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.6
c 0
b 0
f 0
cc 4
nc 4
nop 2
1
<?php
2
3
namespace AfriCC\EPP;
4
5
use AfriCC\EPP\Frame\Command\Login as LoginCommand;
6
use AfriCC\EPP\Frame\Response as ResponseFrame;
7
use AfriCC\EPP\Frame\ResponseFactory;
8
use Exception;
9
10
/**
11
 * An abstract client client for the Extensible Provisioning Protocol (EPP)
12
 *
13
 * Extend this class in your custom EPP Client
14
 *
15
 * @see http://tools.ietf.org/html/rfc5734
16
 * @see ClientInterface
17
 *
18
 * As this class is abstract and relies on subclass implementation details it's untestable
19
 * @codeCoverageIgnore
20
 */
21
abstract class AbstractClient implements ClientInterface
22
{
23
    protected $host;
24
    protected $port;
25
    protected $username;
26
    protected $password;
27
    protected $lang;
28
    protected $version;
29
    protected $services;
30
    protected $serviceExtensions;
31
    protected $ssl;
32
    protected $local_cert;
33
    protected $ca_cert;
34
    protected $pk_cert;
35
    protected $passphrase;
36
    protected $debug;
37
    protected $connect_timeout;
38
    protected $timeout;
39
    protected $objectSpec;
40
41
    /**
42
     * {@inheritdoc}
43
     *
44
     * @see \AfriCC\EPP\ClientInterface::connect()
45
     */
46
    abstract public function connect($newPassword = false);
47
48
    abstract public function close();
49
50
    abstract protected function log($message);
51
52
    /**
53
     * Send frame to EPP server
54
     *
55
     * @param FrameInterface $frame Frame to send
56
     *
57
     * @throws Exception on send error
58
     */
59
    abstract public function sendFrame(FrameInterface $frame);
60
61
    /**
62
     * Get response frame from EPP server (use after sendFrame)
63
     *
64
     * @throws Exception on frame receive error
65
     *
66
     * @return string raw XML of EPP Frame
67
     */
68
    abstract public function getFrame();
69
70
    public function request(FrameInterface $frame)
71
    {
72
        if ($frame instanceof TransactionAwareInterface) {
73
            $frame->setClientTransactionId(
74
                $this->generateClientTransactionId()
75
                );
76
        }
77
78
        $this->sendFrame($frame);
79
80
        $return = $this->getFrame();
81
82
        return ResponseFactory::build($return, $this->objectSpec);
83
    }
84
85
    public function __construct(array $config, ObjectSpec $objectSpec = null)
86
    {
87
        if (!empty($config['debug']) && is_bool($config['debug'])) {
88
            $this->debug = $config['debug'];
89
        } else {
90
            $this->debug = false;
91
        }
92
93
        if (is_null($objectSpec)) {
94
            $objectSpec = new ObjectSpec();
95
        }
96
97
        $this->objectSpec = $objectSpec;
98
99
        $this->prepareConnectionOptions($config);
100
        $this->prepareCredentials($config);
101
        $this->prepareSSLOptions($config);
102
        $this->prepareEPPServices($config);
103
        $this->prepareEPPVersionLang($config);
104
    }
105
106
    /**
107
     * Get client's ObjectSpec
108
     *
109
     * @return ObjectSpec
110
     */
111
    public function getObjectSpec()
112
    {
113
        return $this->objectSpec;
114
    }
115
116
    /**
117
     * Set client's ObjectSpec
118
     *
119
     * @param ObjectSpec $newObjectSpec
120
     */
121
    public function setObjectSpec(ObjectSpec $newObjectSpec)
122
    {
123
        $this->objectSpec = $newObjectSpec;
124
    }
125
126
    /**
127
     * Get config value from config array if set (default otherwise)
128
     *
129
     * Basically, a simple null coallesce operator (since we need to support PHP 5.5)
130
     *
131
     * @param array $config
132
     * @param string $key
133
     * @param mixed $default
134
     *
135
     * @return mixed
136
     */
137
    protected function getConfigDefault(array $config, string $key, $default = null)
138
    {
139
        if (!empty($config[$key])) {
140
            return $config[$key];
141
        }
142
143
        return $default;
144
    }
145
146
    /**
147
     * Get config value from config array if set (default otherwise)
148
     *
149
     * special version for bool values
150
     *
151
     * @param array $config
152
     * @param string $key
153
     * @param mixed $default
154
     *
155
     * @return mixed
156
     *
157
     * @see AbstractClient::getConfigDefault
158
     */
159
    protected function getConfigDefaultBool(array $config, string $key, $default = null)
160
    {
161
        if (!empty($config[$key]) && is_bool($config[$key])) {
162
            return $config[$key];
163
        }
164
165
        return $default;
166
    }
167
168
    /**
169
     * Get config value from config array if set (default otherwise)
170
     *
171
     * special version for aray values
172
     *
173
     * @param array $config
174
     * @param string $key
175
     * @param mixed $default
176
     *
177
     * @return mixed
178
     *
179
     * @see AbstractClient::getConfigDefault
180
     */
181
    protected function getConfigDefaultArray(array $config, string $key, $default = null)
182
    {
183
        if (!empty($config[$key]) && is_array($config[$key])) {
184
            return $config[$key];
185
        }
186
187
        return $default;
188
    }
189
190
    /**
191
     * Get config value from config array if set (default otherwise)
192
     *
193
     * special version for files
194
     *
195
     * @param array $config
196
     * @param string $key
197
     * @param mixed $default
198
     *
199
     * @throws Exception in case file is specified but not readable
200
     *
201
     * @return mixed
202
     *
203
     * @see AbstractClient::getConfigDefault
204
     */
205
    protected function getConfigDefaultReadableFile(array $config, string $key, $default = null)
206
    {
207
        if (!empty($config[$key])) {
208
            $return = (string) $config[$key];
209
210
            if (!is_readable($return)) {
211
                throw new \Exception(sprintf('unable to read %s: %s', $key, $return));
212
            }
213
214
            return $return;
215
        }
216
217
        return $default;
218
    }
219
220
    protected function prepareConnectionOptions(array $config)
221
    {
222
        $this->host = $this->getConfigDefault($config, 'host');
223
        $this->port = $this->getConfigDefault($config, 'port', false);
224
        $this->connect_timeout = (int) $this->getConfigDefault($config, 'connect_timeout', 16);
225
        $this->timeout = (int) $this->getConfigDefault($config, 'timeout', 32);
226
    }
227
228
    protected function prepareCredentials(array $config)
229
    {
230
        $this->username = $this->getConfigDefault($config, 'username');
231
        $this->password = $this->getConfigDefault($config, 'password');
232
    }
233
234
    protected function prepareSSLOptions(array $config)
235
    {
236
        $this->ssl = $this->getConfigDefaultBool($config, 'ssl', false);
237
238
        $this->local_cert = $this->getConfigDefaultReadableFile($config, 'local_cert');
239
        $this->ca_cert = $this->getConfigDefaultReadableFile($config, 'ca_cert');
240
        $this->pk_cert = $this->getConfigDefaultReadableFile($config, 'pk_cert');
241
242
        $this->passphrase = $this->getConfigDefault($config, 'passphrase');
243
    }
244
245
    protected function prepareEPPServices(array $config)
246
    {
247
        $this->services = $this->getConfigDefaultArray($config, 'services');
248
        $this->serviceExtensions = $this->getConfigDefaultArray($config, 'serviceExtensions');
249
    }
250
251
    protected function prepareEPPVersionLang(array $config)
252
    {
253
        $this->lang = $this->getConfigDefault($config, 'lang', 'en');
254
        $this->version = $this->getConfigDefault($config, 'version', '1.0');
255
    }
256
257
    protected function generateClientTransactionId()
258
    {
259
        return Random::id(64, $this->username);
260
    }
261
262
    /**
263
     * Generate and send login frame
264
     *
265
     * @param bool|string $newPassword New password to set on login, false if not changing password
266
     *
267
     * @throws \Exception On unsuccessful login
268
     *
269
     * @return \AfriCC\EPP\Frame\Response Login response
270
     */
271
    protected function login($newPassword = false)
272
    {
273
        // send login command
274
        $login = new LoginCommand($this->objectSpec);
275
        $login->setClientId($this->username);
276
        $login->setPassword($this->password);
277
        if ($newPassword) {
278
            $login->setNewPassword($newPassword);
279
        }
280
        $login->setVersion($this->version);
281
        $login->setLanguage($this->lang);
282
283
        if (!empty($this->services) && is_array($this->services)) {
284
            foreach ($this->services as $urn) {
285
                $login->addService($urn);
286
            }
287
288
            if (!empty($this->serviceExtensions) && is_array($this->serviceExtensions)) {
289
                foreach ($this->serviceExtensions as $extension) {
290
                    $login->addServiceExtension($extension);
291
                }
292
            }
293
        }
294
295
        $response = $this->request($login);
296
        unset($login);
297
298
        // check if login was successful
299
        if (!($response instanceof ResponseFrame)) {
300
            throw new \Exception('there was a problem logging onto the EPP server');
301
        } elseif ($response->code() !== 1000) {
302
            throw new \Exception($response->message(), $response->code());
303
        }
304
305
        return $response;
306
    }
307
}
308