Client::fetch()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 22
rs 9.2
cc 3
eloc 12
nc 4
nop 3
1
<?php
2
/**
3
 * Jaeger - REST Client
4
 *
5
 * @copyright	Copyright (c) 2016, mithra62
6
 * @link		http://jaegerapp.net/
7
 * @version		1.0
8
 * @filesource 	./jaeger-app/Rest/Client.php
9
 */
10
 
11
namespace JaegerApp\Rest;
12
13
use PhilipBrown\Signature\Token;
14
use PhilipBrown\Signature\Request;
15
16
/**
17
 * Rest Client Object
18
 *
19
 * Simple object to interact with a Jaeger installation
20
 *
21
 * @package Rest\Client
22
 * @author Eric Lamb <[email protected]>
23
 */
24
class Client
25
{
26
    /**
27
     * The configuration details for connection
28
     * @var array
29
     */
30
    protected $config = array();
31
    
32
    /**
33
     * The expected format for the config array
34
     * @var array
35
     */
36
    protected $config_prototype = array(
37
        'api_key' => '',
38
        'api_secret' => '',
39
        'site_url' => '',
40
    );
41
    
42
    /**
43
     * The API Key to use
44
     * @var string
45
     */
46
    protected $api_key = null;
47
    
48
    /**
49
     * The API Secret to use
50
     * @var string
51
     */
52
    protected $api_secret = null;
53
    
54
    /**
55
     * The URL to the Backup Pro API endpoint
56
     * @var string
57
     */
58
    protected $site_url = null;
59
    
60
    /**
61
     * The debug information
62
     * @var string
63
     */
64
    protected $debug_info = array();
65
    
66
    /**
67
     * The Curl handle
68
     * @var resource
69
     */
70
    protected $curl_handle = null;
71
    
72
    /**
73
     * The HTTP verb names
74
     * @var string
75
     */
76
    const HTTP_METHOD_GET = 'GET';
77
    const HTTP_METHOD_POST = 'POST';
78
    const HTTP_METHOD_PUT = 'PUT';
79
    const HTTP_METHOD_DELETE = 'DELETE';
80
    
81
    /**
82
     * Sets it up
83
     * @param array $config
84
     */
85
    public function __construct(array $config = array())
86
    {
87
        $this->config = array_merge($this->config_prototype, $config);
88
        $this->api_key = $this->config['api_key'];
89
        $this->api_secret = $this->config['api_secret'];
90
        $this->site_url = $this->config['site_url'];
91
    }
92
    
93
    /**
94
     * Returns the config
95
     * @return array
96
     */
97
    public function getConfig()
98
    {
99
        return $this->config;
100
    }
101
    
102
    /**
103
     * Sets the API key to use for authentication
104
     * @param string $key
105
     * @return \JargerApp\Rest\Client
106
     */
107
    public function setApiKey($key)
108
    {
109
        $this->api_key = $key;
110
        return $this;
111
    }
112
    
113
    /**
114
     * Returns the API key 
115
     * @return string
116
     */
117
    public function getApiKey()
118
    {
119
        return $this->api_key;
120
    }
121
    
122
    /**
123
     * Sets the API secret to use for authentication
124
     * @param string $secret
125
     * @return \JargerApp\Rest\Client
126
     */
127
    public function setApiSecret($secret)
128
    {
129
        $this->api_secret = $secret;
130
        return $this;
131
    }
132
    
133
    /**
134
     * Returns the API secret
135
     * @return string
136
     */
137
    public function getApiSecret()
138
    {
139
        return $this->api_secret;
140
    }
141
    
142
    /**
143
     * Sets the Backup Pro REST API site URL 
144
     * @param string $site_url
145
     * @return \JargerApp\Rest\Client
146
     */
147
    public function setSiteUrl($site_url)
148
    {
149
        $this->site_url = $site_url;
150
        return $this;
151
    }
152
    
153
    /**
154
     * Returns the Backup Pro REST API site URL
155
     * @param string $endpoint
156
     * @return string
157
     */
158
    public function getSiteUrl($endpoint = '', array $query = array())
159
    {
160
        if(count($query) != '0') {
161
            $endpoint .= '&'.http_build_query($query);
162
        }
163
        
164
        return $this->site_url.$endpoint;
165
    }
166
    
167
    /**
168
     * Send a POST request
169
     * @param string $endpoint The API endpoint
170
     * @param array $payload Data to submit
171
     */
172
    public function post($endpoint, array $payload = array())
173
    {
174
        return $this->fetch($endpoint, $payload, self::HTTP_METHOD_POST);
175
    }
176
    
177
    /**
178
     * Sends a GET request
179
     * @param string $endpoint The API endpoint
180
     * @param array $payload
181
     */
182
    public function get($endpoint, array $payload = array())
183
    {
184
        return $this->fetch($endpoint, $payload);
185
    }
186
    
187
    /**
188
     * PUT to an authenciated API endpoint w/ payload
189
     *
190
     * @param string $endpoint
191
     * @param array $payload
192
     * @return array
193
     */
194
    public function put($endpoint, array $payload = array())
195
    {
196
        return $this->fetch($endpoint, $payload, self::HTTP_METHOD_PUT);
197
    }
198
    
199
    /**
200
     * Performs a DELETE request
201
     * @param string $endpoint
202
     * @param array $payload
203
     * @return bool
204
     */
205
    public function delete($endpoint, array $payload = array())
206
    {
207
        return $this->fetch($endpoint, $payload, self::HTTP_METHOD_DELETE);
208
    }
209
    
210
    /**
211
     * Sets up the Hmac authentication headers and dispatches the request
212
     * @param string $endpoint The API endpoing we want
213
     * @param array $payload Any data to send along
214
     * @param string $method The HTTP method 
215
     * @return bool
216
     */
217
    public function fetch($endpoint, array $payload = array(), $method = 'GET')
218
    {
219
        //so we don't want to use the query params for HMAC since we won't know what's 
220
        //being sent versus what's expected to be sent. So we remove them and prepare for 
221
        //query usage
222
        $query = array();
223
        if(strtolower($method)== 'get') {
224
            $query = $payload;
225
            $payload = array();
226
        }
227
        
228
        $token   = new Token($this->getApiKey(), $this->getApiSecret());
229
        $request = new Request($method, $endpoint, $payload);
230
        $headers = $request->sign($token, 'm62_auth_');
231
        
232
        if(strtolower($method)== 'get') {
233
            $payload = array();
234
        }
235
        
236
        $endpoint = $this->getSiteUrl($endpoint, $query);
237
        return $this->request($endpoint, $payload, $method, $headers);
238
    }    
239
    
240
    /**
241
     * Returns the debug data
242
     * @return array
243
     */
244
    public function getDebugInfo()
245
    {
246
        return $this->debug_info;
247
    }
248
    
249
    /**
250
     * Make a CURL request
251
     *
252
     * @param string $url
253
     * @param array $payload
254
     * @param string $method
255
     * @param array $headers
256
     * @param array $curl_options
257
     * @throws \RuntimeException
258
     * @return array
259
     */
260
    protected function request($url, array $payload = array(), $method = 'GET', array $headers = array(), array $curl_options = array())
261
    {
262
        $ch = $this->getCurlHandle();
263
        $parsed_headers = array();
264
        foreach($headers AS $key => $value) {
265
            $parsed_headers[] = $key.': '.$value;
266
        }
267
        
268
        $options = array(
269
            CURLOPT_CUSTOMREQUEST => strtoupper($method),
270
            CURLOPT_RETURNTRANSFER => true,
271
            CURLOPT_URL => $url,
272
            CURLOPT_HTTPHEADER => $parsed_headers,
273
            CURLOPT_SSL_VERIFYPEER => false,
274
            CURLOPT_FOLLOWLOCATION => true
275
        );
276
        if (!empty($payload)) {
277
            if ($options[CURLOPT_CUSTOMREQUEST] == self::HTTP_METHOD_POST || 
278
                $options[CURLOPT_CUSTOMREQUEST] == self::HTTP_METHOD_PUT || 
279
                $options[CURLOPT_CUSTOMREQUEST] == self::HTTP_METHOD_DELETE) {
280
                $json_payload = json_encode($payload);
281
                
282
                $options[CURLOPT_POSTFIELDS] = $json_payload;
283
                $parsed_headers[] = 'Content-Length: ' . strlen($json_payload);
284
                $parsed_headers[] = 'Content-Type: application/json';
285
                $options[CURLOPT_HTTPHEADER] = $parsed_headers;
286
            } 
287
        }
288
        if (!empty($curl_options)) {
289
            $options = array_replace($options, $curl_options);
290
        }
291
        if (isset($this->config['curl_options']) && !empty($this->config['curl_options'])) {
292
            $options = array_replace($options, $this->config['curl_options']);
293
        }
294
        
295
        curl_setopt_array($ch, $options);
296
        $response_raw = curl_exec($ch);
297
        $this->debug_info = curl_getinfo($ch);
298
299
        if ($response_raw === false) {
300
            throw new \RuntimeException('Request Error: ' . curl_error($ch));
301
        }
302
        
303
        curl_getinfo($ch, CURLINFO_HTTP_CODE);
304
        $response = json_decode($response_raw, true);
305
        if (isset($response['status']) && ($response['status'] < 200 || $response['status'] > 300)) {
306
            return Client\ApiProblem::fromJson($response_raw); 
307
        }
308
        
309
        if(!empty($this->debug_info['http_code']) && $this->debug_info['http_code'] == '404') {
310
            $response_raw = array('status' => $this->debug_info['http_code'], 'title' => 'Not Found');
311
            return Client\ApiProblem::fromJson(json_encode($response_raw));
312
        }
313
        
314
        return Client\Hal::fromJson($response_raw, 3);
315
    }
316
    
317
    
318
    protected function getCurlHandle()
319
    {
320
        if (!$this->curl_handle) {
321
            $this->curl_handle = curl_init();
322
        }
323
        return $this->curl_handle;
324
    }
325
    
326
    public function __destruct()
327
    {
328
        if ($this->curl_handle) {
329
            curl_close($this->curl_handle);
330
        }
331
    }
332
}