Passed
Push — master ( 120832...1dab8b )
by Dmitry
02:12
created

General   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 249
Duplicated Lines 0 %

Importance

Changes 9
Bugs 0 Features 4
Metric Value
c 9
b 0
f 4
dl 0
loc 249
rs 10
wmc 28

13 Methods

Rating   Name   Duplication   Size   Complexity  
A verify_sign() 0 9 3
A __construct() 0 5 1
A validate_element() 0 5 2
A check_verify_sign_result() 0 9 3
A get_pub_key() 0 8 2
A parse_request_node() 0 9 2
A Operation() 0 3 1
A Sign() 0 3 1
A DateTime() 0 3 1
C parse_request_data() 0 39 7
A check_and_parse_request_node() 0 5 2
A validate_request() 0 10 2
A ServiceId() 0 3 1
1
<?php
2
3
/**
4
 *      General class for all request types
5
 *
6
 *      @package php_EasyPay
7
 *      @version 1.1
8
 *      @author Dmitry Shovchko <[email protected]>
9
 *
10
 */
11
12
namespace EasyPay\Provider31\Request;
13
14
use EasyPay\Log as Log;
15
use EasyPay\Exception;
16
use EasyPay\Provider31\Request\RAW as RAW;
17
use EasyPay\Key as Key;
18
use EasyPay\OpenSSL as OpenSSL;
19
20
class General
21
{
22
    /**
23
     *      @var EasyPay\Provider31\Request\RAW raw request
0 ignored issues
show
Bug introduced by
The type EasyPay\Provider31\Reque...\Provider31\Request\RAW was not found. Did you mean EasyPay\Provider31\Request\RAW? If so, make sure to prefix the type with \.
Loading history...
24
     */
25
    protected $raw_request;
26
27
    /**
28
     *      @var string 'DateTime' node
29
     */
30
    protected $DateTime;
31
32
    /**
33
     *      @var string 'Sign' node
34
     */
35
    protected $Sign;
36
37
    /**
38
     *      @var string 'Operation' type
39
     */
40
    protected $Operation;
41
42
    /**
43
     *      @var string 'ServiceId' node
44
     */
45
    protected $ServiceId;
46
47
    /**
48
     *      @var array list of possible operations
49
     */
50
    protected $operations = array('Check','Payment','Confirm','Cancel');
51
52
    /**
53
     *      General constructor
54
     *
55
     *      @param EasyPay\Provider31\Request\RAW $raw Raw request data
56
     */
57
    public function __construct($raw)
58
    {
59
        $this->raw_request = $raw;
60
61
        $this->parse_request_data();
62
    }
63
64
    /**
65
     *      Get DateTime
66
     *
67
     *      @return string
68
     */
69
    public function DateTime()
70
    {
71
        return $this->DateTime;
72
    }
73
74
    /**
75
     *      Get Sign
76
     *
77
     *      @return string
78
     */
79
    public function Sign()
80
    {
81
        return $this->Sign;
82
    }
83
84
    /**
85
     *      Get Operation type
86
     *
87
     *      @return string
88
     */
89
    public function Operation()
90
    {
91
        return $this->Operation;
92
    }
93
94
    /**
95
     *      Get ServiceId
96
     *
97
     *      @return string
98
     */
99
    public function ServiceId()
100
    {
101
        return $this->ServiceId;
102
    }
103
104
    /**
105
     *      Parse xml-request, which was previously "extracted" from the body of the http request
106
     *
107
     *      @throws Exception\Structure
108
     */
109
    protected function parse_request_data()
110
    {
111
        // process <Request> group
112
        $r = $this->raw_request->get_nodes_from_request('Request');
113
114
        if (count($r) < 1)
115
        {
116
            throw new Exception\Structure('The xml-query does not contain any element Request!', -52);
117
        }
118
119
        foreach ($r[0]->childNodes as $child)
120
        {
121
            $this->check_and_parse_request_node($child, 'DateTime');
122
            $this->check_and_parse_request_node($child, 'Sign');
123
124
            if (in_array($child->nodeName, $this->operations))
125
            {
126
                if ( ! isset($this->Operation))
127
                {
128
                    $this->Operation = $child->nodeName;
129
                }
130
                else
131
                {
132
                    throw new Exception\Structure('There is more than one Operation type element in the xml-query!', -53);
133
                }
134
            }
135
        }
136
137
        if ( ! isset($this->Operation))
138
        {
139
            throw new Exception\Structure('There is no Operation type element in the xml request!', -55);
140
        }
141
142
        // process <Operation> group
143
        $r = $this->raw_request->get_nodes_from_request($this->Operation);
144
145
        foreach ($r[0]->childNodes as $child)
146
        {
147
            $this->check_and_parse_request_node($child, 'ServiceId');
148
        }
149
    }
150
151
    /**
152
     *      Check if present node of request and then parse it
153
     *
154
     *      @param \DOMNode $n
155
     *      @param string $name
156
     */
157
    protected function check_and_parse_request_node($n, $name)
158
    {
159
        if ($n->nodeName == $name)
160
        {
161
            $this->parse_request_node($n, $name);
162
        }
163
    }
164
165
    /**
166
     *      Parse node of request
167
     *
168
     *      @param \DOMNode $n
169
     *      @param string $name
170
     *
171
     *      @throws Exception\Structure
172
     */
173
    protected function parse_request_node($n, $name)
174
    {
175
        if ( ! isset($this->$name))
176
        {
177
            $this->$name = $n->nodeValue;
178
        }
179
        else
180
        {
181
            throw new Exception\Structure('There is more than one '.$name.' element in the xml-query!', -56);
182
        }
183
    }
184
185
    /**
186
     *      "Rough" validation of the received xml request
187
     *
188
     *      @param array $options
189
     *      @throws Exception\Data
190
     *      @throws Exception\Structure
191
     */
192
    public function validate_request($options)
193
    {
194
        $this->validate_element('DateTime');
195
        $this->validate_element('Sign');
196
        $this->validate_element('ServiceId');
197
198
        // compare received value ServiceId with option ServiceId
199
        if (intval($options['ServiceId']) != intval($this->ServiceId))
200
        {
201
            throw new Exception\Data('This request is not for our ServiceId!', -58);
202
        }
203
    }
204
205
    /**
206
     *      Validation of xml-element
207
     *
208
     *      @param string $name
209
     */
210
    public function validate_element($name)
211
    {
212
        if ( ! isset($this->$name))
213
        {
214
            throw new Exception\Structure('There is no '.$name.' element in the xml request!', -57);
215
        }
216
    }
217
218
    /**
219
     *      Verify signature of request
220
     *
221
     *      @param array $options
222
     */
223
    public function verify_sign($options)
224
    {
225
        if (isset($options['UseSign']) && ($options['UseSign'] === true))
226
        {
227
            $this->check_verify_sign_result(
228
                $result = (new OpenSSL())->verify(
229
                    str_replace($this->Sign, '', $this->raw_request->str()),
230
                    pack("H*", $this->Sign),
231
                    (new OpenSSL())->get_pub_key($this->get_pub_key($options))
232
                )
233
            );
234
        }
235
    }
236
237
    /**
238
     *      load file with easysoft public key
239
     *
240
     *      @param array $options
241
     *      @throws Exception\Runtime
242
     *      @return string
243
     */
244
    protected function get_pub_key($options)
245
    {
246
        if ( ! isset($options['EasySoftPKey']))
247
        {
248
            throw new Exception\Runtime('The parameter EasySoftPKey is not set!', -94);
249
        }
250
251
        return (new Key())->get($options['EasySoftPKey'], 'public');
252
    }
253
254
    /**
255
     *      check result of openssl verify signature
256
     *
257
     *      @param integer $result
258
     *      @throws Exception\Sign
259
     */
260
    protected function check_verify_sign_result($result)
261
    {
262
        if ($result == -1)
263
        {
264
            throw new Exception\Sign('Error verify signature of request!', -96);
265
        }
266
        elseif ($result == 0)
267
        {
268
            throw new Exception\Sign('Signature of request is incorrect!', -95);
269
        }
270
    }
271
272
}
273