Completed
Push — master ( 7a22fa...06d3cb )
by Raza
01:29
created

PayPalRequest::verifyIPN()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 8
rs 9.4285
1
<?php
2
3
namespace Srmklive\PayPal\Traits;
4
5
use GuzzleHttp\Client as HttpClient;
6
use GuzzleHttp\Exception\BadResponseException as HttpBadResponseException;
7
use GuzzleHttp\Exception\ClientException as HttpClientException;
8
use GuzzleHttp\Exception\ServerException as HttpServerException;
9
use Illuminate\Support\Collection;
10
11
trait PayPalRequest
12
{
13
    /**
14
     * Http Client class object.
15
     *
16
     * @var HttpClient
17
     */
18
    private $client;
19
20
    /**
21
     * PayPal API mode to be used.
22
     *
23
     * @var string
24
     */
25
    public $mode;
26
27
    /**
28
     * Request data to be sent to PayPal.
29
     *
30
     * @var \Illuminate\Support\Collection
31
     */
32
    protected $post;
33
34
    /**
35
     * PayPal API configuration.
36
     *
37
     * @var array
38
     */
39
    private $config;
40
41
    /**
42
     * Default currency for PayPal.
43
     *
44
     * @var string
45
     */
46
    private $currency;
47
48
    /**
49
     * Additional options for PayPal API request.
50
     *
51
     * @var array
52
     */
53
    private $options;
54
55
    /**
56
     * Default payment action for PayPal.
57
     *
58
     * @var string
59
     */
60
    private $paymentAction;
61
62
    /**
63
     * Default locale for PayPal.
64
     *
65
     * @var string
66
     */
67
    private $locale;
68
69
    /**
70
     * PayPal API Endpoint.
71
     *
72
     * @var string
73
     */
74
    private $apiUrl;
75
76
    /**
77
     * IPN notification url for PayPal.
78
     *
79
     * @var string
80
     */
81
    private $notifyUrl;
82
83
    /**
84
     * Http Client request body parameter name.
85
     *
86
     * @var string
87
     */
88
    private $httpBodyParam;
89
90
    /**
91
     * Validate SSL details when creating HTTP client.
92
     *
93
     * @var bool
94
     */
95
    private $validateSSL;
96
97
    /**
98
     * Function To Set PayPal API Configuration.
99
     *
100
     * @param array $config
101
     *
102
     * @return void
103
     */
104
    private function setConfig(array $config = [])
105
    {
106
        // Set Api Credentials
107
        if (function_exists('config')) {
108
            $this->setApiCredentials(
109
                config('paypal')
110
            );
111
        } elseif (!empty($config)) {
112
            $this->setApiCredentials($config);
113
        }
114
115
        $this->setRequestData();
116
    }
117
118
    /**
119
     * Function to initialize Http Client.
120
     *
121
     * @return void
122
     */
123
    protected function setClient()
124
    {
125
        $this->client = new HttpClient([
126
            'curl' => [
127
                CURLOPT_SSLVERSION     => CURL_SSLVERSION_TLSv1_2,
128
                CURLOPT_SSL_VERIFYPEER => $this->validateSSL,
129
            ],
130
        ]);
131
    }
132
133
    /**
134
     * Set PayPal API Credentials.
135
     *
136
     * @param array $credentials
137
     *
138
     * @throws \Exception
139
     *
140
     * @return void
141
     */
142
    public function setApiCredentials($credentials)
143
    {
144
        // Setting Default PayPal Mode If not set
145
        $this->setApiEnvironment($credentials);
146
147
        // Set API configuration for the PayPal provider
148
        $this->setApiProviderConfiguration($credentials);
149
150
        // Set default currency.
151
        $this->setCurrency($credentials['currency']);
152
153
        // Setting Http Client
154
        $this->setClient();
155
156
        // Set default payment action.
157
        $this->paymentAction = !empty($this->config['payment_action']) ? $this->config['payment_action'] : 'Sale';
158
159
        // Set default locale.
160
        $this->locale = !empty($this->config['locale']) ? $this->config['locale'] : 'en_US';
161
162
        // Set PayPal API Endpoint.
163
        $this->apiUrl = $this->config['api_url'];
164
165
        // Set PayPal IPN Notification URL
166
        $this->notifyUrl = $this->config['notify_url'];
167
    }
168
169
    /**
170
     * Set API environment to be used by PayPal.
171
     *
172
     * @param array $credentials
173
     *
174
     * @return void
175
     */
176
    private function setApiEnvironment($credentials)
177
    {
178
        if (empty($credentials['mode']) || !in_array($credentials['mode'], ['sandbox', 'live'])) {
179
            $this->mode = 'live';
180
        } else {
181
            $this->mode = $credentials['mode'];
182
        }
183
    }
184
185
    /**
186
     * Set configuration details for the provider.
187
     *
188
     * @param array $credentials
189
     *
190
     * @throws \Exception
191
     *
192
     * @return void
193
     */
194
    private function setApiProviderConfiguration($credentials)
195
    {
196
        // Setting PayPal API Credentials
197
        collect($credentials[$this->mode])->map(function ($value, $key) {
198
            $this->config[$key] = $value;
199
        });
200
201
        // Setup PayPal API Signature value to use.
202
        $this->config['signature'] = empty($this->config['certificate']) ?
203
            $this->config['secret'] : file_get_contents($this->config['certificate']);
204
205
        $this->validateSSL = !empty($credentials['validate_ssl']) ? $credentials['validate_ssl'] : false;
206
207
        if ($this instanceof \Srmklive\PayPal\Services\AdaptivePayments) {
208
            $this->setAdaptivePaymentsOptions();
209
        } elseif ($this instanceof \Srmklive\PayPal\Services\ExpressCheckout) {
210
            $this->setExpressCheckoutOptions($credentials);
211
        } else {
212
            throw new \Exception('Invalid api credentials provided for PayPal!. Please provide the right api credentials.');
213
        }
214
    }
215
216
    /**
217
     * Setup request data to be sent to PayPal.
218
     *
219
     * @param array $data
220
     *
221
     * @return \Illuminate\Support\Collection
222
     */
223
    protected function setRequestData(array $data = [])
224
    {
225
        if (($this->post instanceof Collection) && (!$this->post->isEmpty())) {
226
            unset($this->post);
227
        }
228
229
        $this->post = new Collection($data);
230
231
        return $this->post;
232
    }
233
234
    /**
235
     * Set other/override PayPal API parameters.
236
     *
237
     * @param array $options
238
     *
239
     * @return $this
240
     */
241
    public function addOptions(array $options)
242
    {
243
        $this->options = $options;
244
245
        return $this;
246
    }
247
248
    /**
249
     * Function to set currency.
250
     *
251
     * @param string $currency
252
     *
253
     * @throws \Exception
254
     *
255
     * @return $this
256
     */
257
    public function setCurrency($currency = 'USD')
258
    {
259
        $allowedCurrencies = ['AUD', 'BRL', 'CAD', 'CZK', 'DKK', 'EUR', 'HKD', 'HUF', 'ILS', 'JPY', 'MYR', 'MXN', 'NOK', 'NZD', 'PHP', 'PLN', 'GBP', 'SGD', 'SEK', 'CHF', 'TWD', 'THB', 'USD', 'RUB'];
260
261
        // Check if provided currency is valid.
262
        if (!in_array($currency, $allowedCurrencies)) {
263
            throw new \Exception('Currency is not supported by PayPal.');
264
        }
265
266
        $this->currency = $currency;
267
268
        return $this;
269
    }
270
271
    /**
272
     * Retrieve PayPal IPN Response.
273
     *
274
     * @param array $post
275
     *
276
     * @return array
277
     */
278
    public function verifyIPN($post)
279
    {
280
        $this->setRequestData($post);
281
282
        $this->apiUrl = $this->config['gateway_url'].'/cgi-bin/webscr';
283
284
        return $this->doPayPalRequest('verifyipn');
285
    }
286
287
    /**
288
     * Create request payload to be sent to PayPal.
289
     *
290
     * @param string $method
291
     */
292
    private function createRequestPayload($method)
293
    {
294
        $config = array_merge([
295
            'USER'      => $this->config['username'],
296
            'PWD'       => $this->config['password'],
297
            'SIGNATURE' => $this->config['signature'],
298
            'VERSION'   => 123,
299
            'METHOD'    => $method,
300
        ], $this->options);
301
302
        $this->post = $this->post->merge($config);
303
        if ($method === 'verifyipn') {
304
            $this->post->forget('METHOD');
305
        }
306
    }
307
308
    /**
309
     * Perform PayPal API request & return response.
310
     *
311
     * @throws \Exception
312
     *
313
     * @return \Psr\Http\Message\StreamInterface
314
     */
315
    private function makeHttpRequest()
316
    {
317
        try {
318
            return $this->client->post($this->apiUrl, [
319
                $this->httpBodyParam => $this->post->toArray(),
320
            ])->getBody();
321
        } catch (HttpClientException $e) {
322
            throw new \Exception($e->getRequest().' '.$e->getResponse());
323
        } catch (HttpServerException $e) {
324
            throw new \Exception($e->getRequest().' '.$e->getResponse());
325
        } catch (HttpBadResponseException $e) {
326
            throw new \Exception($e->getRequest().' '.$e->getResponse());
327
        }
328
    }
329
330
    /**
331
     * Function To Perform PayPal API Request.
332
     *
333
     * @param string $method
334
     *
335
     * @throws \Exception
336
     *
337
     * @return array|\Psr\Http\Message\StreamInterface
338
     */
339
    private function doPayPalRequest($method)
340
    {
341
        // Setup PayPal API Request Payload
342
        $this->createRequestPayload($method);
343
344
        try {
345
            // Perform PayPal HTTP API request.
346
            $response = $this->makeHttpRequest();
347
348
            return $this->retrieveData($method, $response);
349
        } catch (\Exception $e) {
350
            $message = collect($e->getTrace())->implode('\n');
351
        }
352
353
        return [
354
            'type'    => 'error',
355
            'message' => $message,
356
        ];
357
    }
358
359
    /**
360
     * Parse PayPal NVP Response.
361
     *
362
     * @param string                                  $method
363
     * @param array|\Psr\Http\Message\StreamInterface $response
364
     *
365
     * @return array
366
     */
367
    private function retrieveData($method, $response)
368
    {
369
        if ($method === 'verifyipn') {
370
            return $response;
371
        }
372
373
        parse_str($response, $output);
374
375
        return $output;
376
    }
377
}
378