Completed
Push — master ( 6a9768...17524c )
by Barry
06:59
created

PayPalHttpConnection::execute()   C

Complexity

Conditions 15
Paths 120

Size

Total Lines 91
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 56
nc 120
nop 1
dl 0
loc 91
rs 5.75
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Never5\DownloadMonitor\Dependencies\PayPal\Core;
4
5
use Never5\DownloadMonitor\Dependencies\PayPal\Exception\PayPalConfigurationException;
6
use Never5\DownloadMonitor\Dependencies\PayPal\Exception\PayPalConnectionException;
7
8
/**
9
 * A wrapper class based on the curl extension.
10
 * Requires the PHP curl module to be enabled.
11
 * See for full requirements the PHP manual: http://php.net/curl
12
 */
13
class PayPalHttpConnection
14
{
15
16
    /**
17
     * @var PayPalHttpConfig
18
     */
19
    private $httpConfig;
20
21
    /**
22
     * LoggingManager
23
     *
24
     * @var PayPalLoggingManager
25
     */
26
    private $logger;
27
28
    /**
29
     * @var array
30
     */
31
    private $responseHeaders = array();
32
33
    /**
34
     * @var bool
35
     */
36
    private $skippedHttpStatusLine = false;
37
38
    /**
39
     * Default Constructor
40
     *
41
     * @param PayPalHttpConfig $httpConfig
42
     * @param array            $config
43
     * @throws PayPalConfigurationException
44
     */
45
    public function __construct(PayPalHttpConfig $httpConfig, array $config)
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

45
    public function __construct(PayPalHttpConfig $httpConfig, /** @scrutinizer ignore-unused */ array $config)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
46
    {
47
        if (!function_exists("curl_init")) {
48
            throw new PayPalConfigurationException("Curl module is not available on this system");
49
        }
50
        $this->httpConfig = $httpConfig;
51
        $this->logger = PayPalLoggingManager::getInstance(__CLASS__);
52
    }
53
54
    /**
55
     * Gets all Http Headers
56
     *
57
     * @return array
58
     */
59
    private function getHttpHeaders()
60
    {
61
        $ret = array();
62
        foreach ($this->httpConfig->getHeaders() as $k => $v) {
63
            $ret[] = "$k: $v";
64
        }
65
        return $ret;
66
    }
67
68
    /**
69
     * Parses the response headers for debugging.
70
     *
71
     * @param resource $ch
72
     * @param string $data
73
     * @return int
74
     */
75
    protected function parseResponseHeaders($ch, $data) {
76
        if (!$this->skippedHttpStatusLine) {
77
            $this->skippedHttpStatusLine = true;
78
            return strlen($data);
79
        }
80
81
        $trimmedData = trim($data);
82
        if (strlen($trimmedData) == 0) {
83
            return strlen($data);
84
        }
85
86
        // Added condition to ignore extra header which dont have colon ( : )
87
        if (strpos($trimmedData, ":") == false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($trimmedData, ':') of type integer to the boolean false. If you are specifically checking for 0, consider using something more explicit like === 0 instead.
Loading history...
88
            return strlen($data);
89
        }
90
        
91
        list($key, $value) = explode(":", $trimmedData, 2);
92
93
        $key = trim($key);
94
        $value = trim($value);
95
96
        // This will skip over the HTTP Status Line and any other lines
97
        // that don't look like header lines with values
98
        if (strlen($key) > 0 && strlen($value) > 0) {
99
            // This is actually a very basic way of looking at response headers
100
            // and may miss a few repeated headers with different (appended)
101
            // values but this should work for debugging purposes.
102
            $this->responseHeaders[$key] = $value;
103
        }
104
105
        return strlen($data);
106
    }
107
108
109
    /**
110
     * Implodes a key/value array for printing.
111
     *
112
     * @param array $arr
113
     * @return string
114
     */
115
    protected function implodeArray($arr) {
116
        $retStr = '';
117
        foreach($arr as $key => $value) {
118
            $retStr .= $key . ': ' . $value . ', ';
119
        }
120
        rtrim($retStr, ', ');
121
        return $retStr;
122
    }
123
124
    /**
125
     * Executes an HTTP request
126
     *
127
     * @param string $data query string OR POST content as a string
128
     * @return mixed
129
     * @throws PayPalConnectionException
130
     */
131
    public function execute($data)
132
    {
133
        //Initialize the logger
134
        $this->logger->info($this->httpConfig->getMethod() . ' ' . $this->httpConfig->getUrl());
135
136
        //Initialize Curl Options
137
        $ch = curl_init($this->httpConfig->getUrl());
138
        $options = $this->httpConfig->getCurlOptions();
139
        if (empty($options[CURLOPT_HTTPHEADER])) {
140
            unset($options[CURLOPT_HTTPHEADER]);
141
        }
142
        curl_setopt_array($ch, $options);
143
        curl_setopt($ch, CURLOPT_URL, $this->httpConfig->getUrl());
144
        curl_setopt($ch, CURLOPT_HEADER, false);
145
        curl_setopt($ch, CURLINFO_HEADER_OUT, true);
146
        curl_setopt($ch, CURLOPT_HTTPHEADER, $this->getHttpHeaders());
147
148
        //Determine Curl Options based on Method
149
        switch ($this->httpConfig->getMethod()) {
150
            case 'POST':
151
                curl_setopt($ch, CURLOPT_POST, true);
152
                curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
153
                break;
154
            case 'PUT':
155
            case 'PATCH':
156
            case 'DELETE':
157
                curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
158
                break;
159
        }
160
161
        //Default Option if Method not of given types in switch case
162
        if ($this->httpConfig->getMethod() != null) {
163
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->httpConfig->getMethod());
164
        }
165
166
        $this->responseHeaders = array();
167
        $this->skippedHttpStatusLine = false;
168
        curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, 'parseResponseHeaders'));
169
170
        //Execute Curl Request
171
        $result = curl_exec($ch);
172
        //Retrieve Response Status
173
        $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
174
175
        //Retry if Certificate Exception
176
        if (curl_errno($ch) == 60) {
177
            $this->logger->info("Invalid or no certificate authority found - Retrying using bundled CA certs file");
178
            curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
179
            $result = curl_exec($ch);
180
            //Retrieve Response Status
181
            $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
182
        }
183
184
        //Throw Exception if Retries and Certificates doenst work
185
        if (curl_errno($ch)) {
186
            $ex = new PayPalConnectionException(
187
                $this->httpConfig->getUrl(),
188
                curl_error($ch),
189
                curl_errno($ch)
190
            );
191
            curl_close($ch);
192
            throw $ex;
193
        }
194
195
        // Get Request and Response Headers
196
        $requestHeaders = curl_getinfo($ch, CURLINFO_HEADER_OUT);
197
        $this->logger->debug("Request Headers \t: " . str_replace("\r\n", ", ", $requestHeaders));
198
        $this->logger->debug(($data && $data != '' ? "Request Data\t\t: " . $data : "No Request Payload") . "\n" . str_repeat('-', 128) . "\n");
199
        $this->logger->info("Response Status \t: " . $httpStatus);
200
        $this->logger->debug("Response Headers\t: " . $this->implodeArray($this->responseHeaders));
201
202
        //Close the curl request
203
        curl_close($ch);
204
205
        //More Exceptions based on HttpStatus Code
206
        if ($httpStatus < 200 || $httpStatus >= 300) {
207
            $ex = new PayPalConnectionException(
208
                $this->httpConfig->getUrl(),
209
                "Got Http response code $httpStatus when accessing {$this->httpConfig->getUrl()}.",
210
                $httpStatus
211
            );
212
            $ex->setData($result);
213
            $this->logger->error("Got Http response code $httpStatus when accessing {$this->httpConfig->getUrl()}. " . $result);
214
            $this->logger->debug("\n\n" . str_repeat('=', 128) . "\n");
215
            throw $ex;
216
        }
217
218
        $this->logger->debug(($result && $result != '' ? "Response Data \t: " . $result : "No Response Body") . "\n\n" . str_repeat('=', 128) . "\n");
219
220
        //Return result object
221
        return $result;
222
    }
223
}
224