Request::getHeaders()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 2
rs 9.9666
c 0
b 0
f 0
1
<?php
2
/**
3
 * Copyright 2017 Facebook, Inc.
4
 *
5
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
6
 * use, copy, modify, and distribute this software in source code or binary
7
 * form for use in connection with the web services and APIs provided by
8
 * Facebook.
9
 *
10
 * As with any software that integrates with the Facebook platform, your use
11
 * of this software is subject to the Facebook Developer Principles and
12
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
13
 * shall be included in all copies or substantial portions of the software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 * DEALINGS IN THE SOFTWARE.
22
 */
23
namespace Facebook;
24
25
use Facebook\Authentication\AccessToken;
26
use Facebook\Url\UrlManipulator;
27
use Facebook\FileUpload\File;
28
use Facebook\FileUpload\Video;
29
use Facebook\Http\RequestBodyMultipart;
30
use Facebook\Http\RequestBodyUrlEncoded;
31
use Facebook\Exception\SDKException;
32
33
/**
34
 * Class Request.
35
 *
36
 * @package Facebook
37
 */
38
class Request
39
{
40
    /**
41
     * @var Application the Facebook app entity
42
     */
43
    protected $app;
44
45
    /**
46
     * @var null|string the access token to use for this request
47
     */
48
    protected $accessToken;
49
50
    /**
51
     * @var string the HTTP method for this request
52
     */
53
    protected $method;
54
55
    /**
56
     * @var string the Graph endpoint for this request
57
     */
58
    protected $endpoint;
59
60
    /**
61
     * @var array the headers to send with this request
62
     */
63
    protected $headers = [];
64
65
    /**
66
     * @var array the parameters to send with this request
67
     */
68
    protected $params = [];
69
70
    /**
71
     * @var array the files to send with this request
72
     */
73
    protected $files = [];
74
75
    /**
76
     * @var string ETag to send with this request
77
     */
78
    protected $eTag;
79
80
    /**
81
     * @var string graph version to use for this request
82
     */
83
    protected $graphVersion;
84
85
    /**
86
     * Creates a new Request entity.
87
     *
88
     * @param null|Application        $app
89
     * @param null|AccessToken|string $accessToken
90
     * @param null|string             $method
91
     * @param null|string             $endpoint
92
     * @param null|array              $params
93
     * @param null|string             $eTag
94
     * @param null|string             $graphVersion
95
     */
96 99
    public function __construct(Application $app = null, $accessToken = null, $method = null, $endpoint = null, array $params = [], $eTag = null, $graphVersion = null)
97
    {
98 99
        $this->setApp($app);
99 99
        $this->setAccessToken($accessToken);
100 99
        $this->setMethod($method);
101 99
        $this->setEndpoint($endpoint);
102 99
        $this->setParams($params);
103 98
        $this->setETag($eTag);
104 98
        $this->graphVersion = $graphVersion;
105 98
    }
106
107
    /**
108
     * Set the access token for this request.
109
     *
110
     * @param null|AccessToken|string
111
     * @param mixed $accessToken
112
     *
113
     * @return Request
114
     */
115 99
    public function setAccessToken($accessToken)
116
    {
117 99
        $this->accessToken = $accessToken;
118 99
        if ($accessToken instanceof AccessToken) {
119 6
            $this->accessToken = $accessToken->getValue();
120
        }
121
122 99
        return $this;
123
    }
124
125
    /**
126
     * Sets the access token with one harvested from a URL or POST params.
127
     *
128
     * @param string $accessToken the access token
129
     *
130
     * @throws SDKException
131
     *
132
     * @return Request
133
     */
134 3
    public function setAccessTokenFromParams($accessToken)
135
    {
136 3
        $existingAccessToken = $this->getAccessToken();
137 3
        if (!$existingAccessToken) {
138 1
            $this->setAccessToken($accessToken);
139 2
        } elseif ($accessToken !== $existingAccessToken) {
140 1
            throw new SDKException('Access token mismatch. The access token provided in the Request and the one provided in the URL or POST params do not match.');
141
        }
142
143 2
        return $this;
144
    }
145
146
    /**
147
     * Return the access token for this request.
148
     *
149
     * @return null|string
150
     */
151 51
    public function getAccessToken()
152
    {
153 51
        return $this->accessToken;
154
    }
155
156
    /**
157
     * Return the access token for this request as an AccessToken entity.
158
     *
159
     * @return null|AccessToken
160
     */
161 31
    public function getAccessTokenEntity()
162
    {
163 31
        return $this->accessToken ? new AccessToken($this->accessToken) : null;
164
    }
165
166
    /**
167
     * Set the Application entity used for this request.
168
     *
169
     * @param null|Application $app
170
     */
171 99
    public function setApp(Application $app = null)
172
    {
173 99
        $this->app = $app;
174 99
    }
175
176
    /**
177
     * Return the Application entity used for this request.
178
     *
179
     * @return Application
180
     */
181 28
    public function getApplication()
182
    {
183 28
        return $this->app;
184
    }
185
186
    /**
187
     * Generate an app secret proof to sign this request.
188
     *
189
     * @return null|string
190
     */
191 31
    public function getAppSecretProof()
192
    {
193 31
        if (!$accessTokenEntity = $this->getAccessTokenEntity()) {
194
            return null;
195
        }
196
197 31
        return $accessTokenEntity->getAppSecretProof($this->app->getSecret());
198
    }
199
200
    /**
201
     * Validate that an access token exists for this request.
202
     *
203
     * @throws SDKException
204
     */
205 11
    public function validateAccessToken()
206
    {
207 11
        $accessToken = $this->getAccessToken();
208 11
        if (!$accessToken) {
209 2
            throw new SDKException('You must provide an access token.');
210
        }
211 9
    }
212
213
    /**
214
     * Set the HTTP method for this request.
215
     *
216
     * @param string
217
     * @param mixed $method
218
     */
219 99
    public function setMethod($method)
220
    {
221 99
        $this->method = strtoupper($method);
222 99
    }
223
224
    /**
225
     * Return the HTTP method for this request.
226
     *
227
     * @return string
228
     */
229 27
    public function getMethod()
230
    {
231 27
        return $this->method;
232
    }
233
234
    /**
235
     * Validate that the HTTP method is set.
236
     *
237
     * @throws SDKException
238
     */
239 24
    public function validateMethod()
240
    {
241 24
        if (!$this->method) {
242 1
            throw new SDKException('HTTP method not specified.');
243
        }
244
245 23
        if (!in_array($this->method, ['GET', 'POST', 'DELETE'])) {
246 1
            throw new SDKException('Invalid HTTP method specified.');
247
        }
248 22
    }
249
250
    /**
251
     * Set the endpoint for this request.
252
     *
253
     * @param string
254
     * @param mixed $endpoint
255
     *
256
     * @throws SDKException
257
     *
258
     * @return Request
259
     */
260 99
    public function setEndpoint($endpoint)
261
    {
262
        // Harvest the access token from the endpoint to keep things in sync
263 99
        $params = UrlManipulator::getParamsAsArray($endpoint);
264 99
        if (isset($params['access_token'])) {
265
            $this->setAccessTokenFromParams($params['access_token']);
266
        }
267
268
        // Clean the token & app secret proof from the endpoint.
269 99
        $filterParams = ['access_token', 'appsecret_proof'];
270 99
        $this->endpoint = UrlManipulator::removeParamsFromUrl($endpoint, $filterParams);
271
272 99
        return $this;
273
    }
274
275
    /**
276
     * Return the endpoint for this request.
277
     *
278
     * @return string
279
     */
280 26
    public function getEndpoint()
281
    {
282
        // For batch requests, this will be empty
283 26
        return $this->endpoint;
284
    }
285
286
    /**
287
     * Generate and return the headers for this request.
288
     *
289
     * @return array
290
     */
291 20
    public function getHeaders()
292
    {
293 20
        $headers = static::getDefaultHeaders();
294
295 20
        if ($this->eTag) {
296 1
            $headers['If-None-Match'] = $this->eTag;
297
        }
298
299 20
        return array_merge($this->headers, $headers);
300
    }
301
302
    /**
303
     * Set the headers for this request.
304
     *
305
     * @param array $headers
306
     */
307 11
    public function setHeaders(array $headers)
308
    {
309 11
        $this->headers = array_merge($this->headers, $headers);
310 11
    }
311
312
    /**
313
     * Sets the eTag value.
314
     *
315
     * @param string $eTag
316
     */
317 98
    public function setETag($eTag)
318
    {
319 98
        $this->eTag = $eTag;
320 98
    }
321
322
    /**
323
     * Set the params for this request.
324
     *
325
     * @param array $params
326
     *
327
     * @throws SDKException
328
     *
329
     * @return Request
330
     */
331 99
    public function setParams(array $params = [])
332
    {
333 99
        if (isset($params['access_token'])) {
334 3
            $this->setAccessTokenFromParams($params['access_token']);
335
        }
336
337
        // Don't let these buggers slip in.
338 98
        unset($params['access_token'], $params['appsecret_proof']);
339
340
        // @TODO Refactor code above with this
341
        //$params = $this->sanitizeAuthenticationParams($params);
342 98
        $params = $this->sanitizeFileParams($params);
343 98
        $this->dangerouslySetParams($params);
344
345 98
        return $this;
346
    }
347
348
    /**
349
     * Set the params for this request without filtering them first.
350
     *
351
     * @param array $params
352
     *
353
     * @return Request
354
     */
355 98
    public function dangerouslySetParams(array $params = [])
356
    {
357 98
        $this->params = array_merge($this->params, $params);
358
359 98
        return $this;
360
    }
361
362
    /**
363
     * Iterate over the params and pull out the file uploads.
364
     *
365
     * @param array $params
366
     *
367
     * @return array
368
     */
369 98
    public function sanitizeFileParams(array $params)
370
    {
371 98
        foreach ($params as $key => $value) {
372 66
            if ($value instanceof File) {
373 10
                $this->addFile($key, $value);
374 66
                unset($params[$key]);
375
            }
376
        }
377
378 98
        return $params;
379
    }
380
381
    /**
382
     * Add a file to be uploaded.
383
     *
384
     * @param string $key
385
     * @param File   $file
386
     */
387 10
    public function addFile($key, File $file)
388
    {
389 10
        $this->files[$key] = $file;
390 10
    }
391
392
    /**
393
     * Removes all the files from the upload queue.
394
     */
395 3
    public function resetFiles()
396
    {
397 3
        $this->files = [];
398 3
    }
399
400
    /**
401
     * Get the list of files to be uploaded.
402
     *
403
     * @return array
404
     */
405 3
    public function getFiles()
406
    {
407 3
        return $this->files;
408
    }
409
410
    /**
411
     * Let's us know if there is a file upload with this request.
412
     *
413
     * @return bool
414
     */
415 31
    public function containsFileUploads()
416
    {
417 31
        return !empty($this->files);
418
    }
419
420
    /**
421
     * Let's us know if there is a video upload with this request.
422
     *
423
     * @return bool
424
     */
425 13
    public function containsVideoUploads()
426
    {
427 13
        foreach ($this->files as $file) {
428 8
            if ($file instanceof Video) {
429 8
                return true;
430
            }
431
        }
432
433 11
        return false;
434
    }
435
436
    /**
437
     * Returns the body of the request as multipart/form-data.
438
     *
439
     * @return RequestBodyMultipart
440
     */
441 6
    public function getMultipartBody()
442
    {
443 6
        $params = $this->getPostParams();
444
445 6
        return new RequestBodyMultipart($params, $this->files);
446
    }
447
448
    /**
449
     * Returns the body of the request as URL-encoded.
450
     *
451
     * @return RequestBodyUrlEncoded
452
     */
453 17
    public function getUrlEncodedBody()
454
    {
455 17
        $params = $this->getPostParams();
456
457 17
        return new RequestBodyUrlEncoded($params);
458
    }
459
460
    /**
461
     * Generate and return the params for this request.
462
     *
463
     * @return array
464
     */
465 30
    public function getParams()
466
    {
467 30
        $params = $this->params;
468
469 30
        $accessToken = $this->getAccessToken();
470 30
        if ($accessToken) {
471 30
            $params['access_token'] = $accessToken;
472 30
            $params['appsecret_proof'] = $this->getAppSecretProof();
473
        }
474
475 30
        return $params;
476
    }
477
478
    /**
479
     * Only return params on POST requests.
480
     *
481
     * @return array
482
     */
483 19
    public function getPostParams()
484
    {
485 19
        if ($this->getMethod() === 'POST') {
486 13
            return $this->getParams();
487
        }
488
489 9
        return [];
490
    }
491
492
    /**
493
     * The graph version used for this request.
494
     *
495
     * @return null|string
496
     */
497 5
    public function getGraphVersion()
498
    {
499 5
        return $this->graphVersion;
500
    }
501
502
    /**
503
     * Generate and return the URL for this request.
504
     *
505
     * @return string
506
     */
507 22
    public function getUrl()
508
    {
509 22
        $this->validateMethod();
510
511 22
        $graphVersion = UrlManipulator::forceSlashPrefix($this->graphVersion);
512 22
        $endpoint = UrlManipulator::forceSlashPrefix($this->getEndpoint());
513
514 22
        $url = $graphVersion . $endpoint;
515
516 22
        if ($this->getMethod() !== 'POST') {
517 12
            $params = $this->getParams();
518 12
            $url = UrlManipulator::appendParamsToUrl($url, $params);
519
        }
520
521 22
        return $url;
522
    }
523
524
    /**
525
     * Return the default headers that every request should use.
526
     *
527
     * @return array
528
     */
529 20
    public static function getDefaultHeaders()
530
    {
531
        return [
532 20
            'User-Agent' => 'fb-php-' . Facebook::VERSION,
533 20
            'Accept-Encoding' => '*',
534
        ];
535
    }
536
}
537