Issues (175)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Facebook/FacebookRequest.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Copyright 2016 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
 */
24
namespace Facebook;
25
26
use Facebook\Authentication\AccessToken;
27
use Facebook\Url\FacebookUrlManipulator;
28
use Facebook\FileUpload\FacebookFile;
29
use Facebook\FileUpload\FacebookVideo;
30
use Facebook\Http\RequestBodyMultipart;
31
use Facebook\Http\RequestBodyUrlEncoded;
32
use Facebook\Exceptions\FacebookSDKException;
33
34
/**
35
 * Class Request
36
 *
37
 * @package Facebook
38
 */
39
class FacebookRequest
40
{
41
    /**
42
     * @var FacebookApp The Facebook app entity.
43
     */
44
    protected $app;
45
46
    /**
47
     * @var string|null The access token to use for this request.
48
     */
49
    protected $accessToken;
50
51
    /**
52
     * @var string The HTTP method for this request.
53
     */
54
    protected $method;
55
56
    /**
57
     * @var string The Graph endpoint for this request.
58
     */
59
    protected $endpoint;
60
61
    /**
62
     * @var array The headers to send with this request.
63
     */
64
    protected $headers = [];
65
66
    /**
67
     * @var array The parameters to send with this request.
68
     */
69
    protected $params = [];
70
71
    /**
72
     * @var array The files to send with this request.
73
     */
74
    protected $files = [];
75
76
    /**
77
     * @var string ETag to send with this request.
78
     */
79
    protected $eTag;
80
81
    /**
82
     * @var string Graph version to use for this request.
83
     */
84
    protected $graphVersion;
85
86
    /**
87
     * Creates a new Request entity.
88
     *
89
     * @param FacebookApp|null        $app
90
     * @param AccessToken|string|null $accessToken
91
     * @param string|null             $method
92
     * @param string|null             $endpoint
93
     * @param array|null              $params
94
     * @param string|null             $eTag
95
     * @param string|null             $graphVersion
96
     */
97
    public function __construct(FacebookApp $app = null, $accessToken = null, $method = null, $endpoint = null, array $params = [], $eTag = null, $graphVersion = null)
98
    {
99
        $this->setApp($app);
100
        $this->setAccessToken($accessToken);
101
        $this->setMethod($method);
102
        $this->setEndpoint($endpoint);
103
        $this->setParams($params);
104
        $this->setETag($eTag);
105
        $this->graphVersion = $graphVersion ?: Facebook::DEFAULT_GRAPH_VERSION;
106
    }
107
108
    /**
109
     * Set the access token for this request.
110
     *
111
     * @param AccessToken|string
112
     *
113
     * @return FacebookRequest
114
     */
115
    public function setAccessToken($accessToken)
116
    {
117
        $this->accessToken = $accessToken;
118
        if ($accessToken instanceof AccessToken) {
119
            $this->accessToken = $accessToken->getValue();
120
        }
121
122
        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
     * @return FacebookRequest
131
     *
132
     * @throws FacebookSDKException
133
     */
134
    public function setAccessTokenFromParams($accessToken)
135
    {
136
        $existingAccessToken = $this->getAccessToken();
137
        if (!$existingAccessToken) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $existingAccessToken of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
138
            $this->setAccessToken($accessToken);
139
        } elseif ($accessToken !== $existingAccessToken) {
140
            throw new FacebookSDKException('Access token mismatch. The access token provided in the FacebookRequest and the one provided in the URL or POST params do not match.');
141
        }
142
143
        return $this;
144
    }
145
146
    /**
147
     * Return the access token for this request.
148
     *
149
     * @return string|null
150
     */
151
    public function getAccessToken()
152
    {
153
        return $this->accessToken;
154
    }
155
156
    /**
157
     * Return the access token for this request as an AccessToken entity.
158
     *
159
     * @return AccessToken|null
160
     */
161
    public function getAccessTokenEntity()
162
    {
163
        return $this->accessToken ? new AccessToken($this->accessToken) : null;
164
    }
165
166
    /**
167
     * Set the FacebookApp entity used for this request.
168
     *
169
     * @param FacebookApp|null $app
170
     */
171
    public function setApp(FacebookApp $app = null)
172
    {
173
        $this->app = $app;
174
    }
175
176
    /**
177
     * Return the FacebookApp entity used for this request.
178
     *
179
     * @return FacebookApp
180
     */
181
    public function getApp()
182
    {
183
        return $this->app;
184
    }
185
186
    /**
187
     * Generate an app secret proof to sign this request.
188
     *
189
     * @return string|null
190
     */
191
    public function getAppSecretProof()
192
    {
193
        if (!$accessTokenEntity = $this->getAccessTokenEntity()) {
194
            return null;
195
        }
196
197
        return $accessTokenEntity->getAppSecretProof($this->app->getSecret());
198
    }
199
200
    /**
201
     * Validate that an access token exists for this request.
202
     *
203
     * @throws FacebookSDKException
204
     */
205
    public function validateAccessToken()
206
    {
207
        $accessToken = $this->getAccessToken();
208
        if (!$accessToken) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $accessToken of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
209
            throw new FacebookSDKException('You must provide an access token.');
210
        }
211
    }
212
213
    /**
214
     * Set the HTTP method for this request.
215
     *
216
     * @param string
217
     */
218
    public function setMethod($method)
219
    {
220
        $this->method = strtoupper($method);
221
    }
222
223
    /**
224
     * Return the HTTP method for this request.
225
     *
226
     * @return string
227
     */
228
    public function getMethod()
229
    {
230
        return $this->method;
231
    }
232
233
    /**
234
     * Validate that the HTTP method is set.
235
     *
236
     * @throws FacebookSDKException
237
     */
238
    public function validateMethod()
239
    {
240
        if (!$this->method) {
241
            throw new FacebookSDKException('HTTP method not specified.');
242
        }
243
244
        if (!in_array($this->method, ['GET', 'POST', 'DELETE'])) {
245
            throw new FacebookSDKException('Invalid HTTP method specified.');
246
        }
247
    }
248
249
    /**
250
     * Set the endpoint for this request.
251
     *
252
     * @param string
253
     *
254
     * @return FacebookRequest
255
     *
256
     * @throws FacebookSDKException
257
     */
258
    public function setEndpoint($endpoint)
259
    {
260
        // Harvest the access token from the endpoint to keep things in sync
261
        $params = FacebookUrlManipulator::getParamsAsArray($endpoint);
262
        if (isset($params['access_token'])) {
263
            $this->setAccessTokenFromParams($params['access_token']);
264
        }
265
266
        // Clean the token & app secret proof from the endpoint.
267
        $filterParams = ['access_token', 'appsecret_proof'];
268
        $this->endpoint = FacebookUrlManipulator::removeParamsFromUrl($endpoint, $filterParams);
269
270
        return $this;
271
    }
272
273
    /**
274
     * Return the endpoint for this request.
275
     *
276
     * @return string
277
     */
278
    public function getEndpoint()
279
    {
280
        // For batch requests, this will be empty
281
        return $this->endpoint;
282
    }
283
284
    /**
285
     * Generate and return the headers for this request.
286
     *
287
     * @return array
288
     */
289
    public function getHeaders()
290
    {
291
        $headers = static::getDefaultHeaders();
292
293
        if ($this->eTag) {
294
            $headers['If-None-Match'] = $this->eTag;
295
        }
296
297
        return array_merge($this->headers, $headers);
298
    }
299
300
    /**
301
     * Set the headers for this request.
302
     *
303
     * @param array $headers
304
     */
305
    public function setHeaders(array $headers)
306
    {
307
        $this->headers = array_merge($this->headers, $headers);
308
    }
309
310
    /**
311
     * Sets the eTag value.
312
     *
313
     * @param string $eTag
314
     */
315
    public function setETag($eTag)
316
    {
317
        $this->eTag = $eTag;
318
    }
319
320
    /**
321
     * Set the params for this request.
322
     *
323
     * @param array $params
324
     *
325
     * @return FacebookRequest
326
     *
327
     * @throws FacebookSDKException
328
     */
329
    public function setParams(array $params = [])
330
    {
331
        if (isset($params['access_token'])) {
332
            $this->setAccessTokenFromParams($params['access_token']);
333
        }
334
335
        // Don't let these buggers slip in.
336
        unset($params['access_token'], $params['appsecret_proof']);
337
338
        // @TODO Refactor code above with this
339
        //$params = $this->sanitizeAuthenticationParams($params);
340
        $params = $this->sanitizeFileParams($params);
341
        $this->dangerouslySetParams($params);
342
343
        return $this;
344
    }
345
346
    /**
347
     * Set the params for this request without filtering them first.
348
     *
349
     * @param array $params
350
     *
351
     * @return FacebookRequest
352
     */
353
    public function dangerouslySetParams(array $params = [])
354
    {
355
        $this->params = array_merge($this->params, $params);
356
357
        return $this;
358
    }
359
360
    /**
361
     * Iterate over the params and pull out the file uploads.
362
     *
363
     * @param array $params
364
     *
365
     * @return array
366
     */
367
    public function sanitizeFileParams(array $params)
368
    {
369
        foreach ($params as $key => $value) {
370
            if ($value instanceof FacebookFile) {
371
                $this->addFile($key, $value);
372
                unset($params[$key]);
373
            }
374
        }
375
376
        return $params;
377
    }
378
379
    /**
380
     * Add a file to be uploaded.
381
     *
382
     * @param string       $key
383
     * @param FacebookFile $file
384
     */
385
    public function addFile($key, FacebookFile $file)
386
    {
387
        $this->files[$key] = $file;
388
    }
389
390
    /**
391
     * Removes all the files from the upload queue.
392
     */
393
    public function resetFiles()
394
    {
395
        $this->files = [];
396
    }
397
398
    /**
399
     * Get the list of files to be uploaded.
400
     *
401
     * @return array
402
     */
403
    public function getFiles()
404
    {
405
        return $this->files;
406
    }
407
408
    /**
409
     * Let's us know if there is a file upload with this request.
410
     *
411
     * @return boolean
412
     */
413
    public function containsFileUploads()
414
    {
415
        return !empty($this->files);
416
    }
417
418
    /**
419
     * Let's us know if there is a video upload with this request.
420
     *
421
     * @return boolean
422
     */
423
    public function containsVideoUploads()
424
    {
425
        foreach ($this->files as $file) {
426
            if ($file instanceof FacebookVideo) {
427
                return true;
428
            }
429
        }
430
431
        return false;
432
    }
433
434
    /**
435
     * Returns the body of the request as multipart/form-data.
436
     *
437
     * @return RequestBodyMultipart
438
     */
439
    public function getMultipartBody()
440
    {
441
        $params = $this->getPostParams();
442
443
        return new RequestBodyMultipart($params, $this->files);
444
    }
445
446
    /**
447
     * Returns the body of the request as URL-encoded.
448
     *
449
     * @return RequestBodyUrlEncoded
450
     */
451
    public function getUrlEncodedBody()
452
    {
453
        $params = $this->getPostParams();
454
455
        return new RequestBodyUrlEncoded($params);
456
    }
457
458
    /**
459
     * Generate and return the params for this request.
460
     *
461
     * @return array
462
     */
463
    public function getParams()
464
    {
465
        $params = $this->params;
466
467
        $accessToken = $this->getAccessToken();
468
        if ($accessToken) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $accessToken of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
469
            $params['access_token'] = $accessToken;
470
            $params['appsecret_proof'] = $this->getAppSecretProof();
471
        }
472
473
        return $params;
474
    }
475
476
    /**
477
     * Only return params on POST requests.
478
     *
479
     * @return array
480
     */
481
    public function getPostParams()
482
    {
483
        if ($this->getMethod() === 'POST') {
484
            return $this->getParams();
485
        }
486
487
        return [];
488
    }
489
490
    /**
491
     * The graph version used for this request.
492
     *
493
     * @return string
494
     */
495
    public function getGraphVersion()
496
    {
497
        return $this->graphVersion;
498
    }
499
500
    /**
501
     * Generate and return the URL for this request.
502
     *
503
     * @return string
504
     */
505
    public function getUrl()
506
    {
507
        $this->validateMethod();
508
509
        $graphVersion = FacebookUrlManipulator::forceSlashPrefix($this->graphVersion);
510
        $endpoint = FacebookUrlManipulator::forceSlashPrefix($this->getEndpoint());
511
512
        $url = $graphVersion . $endpoint;
513
514
        if ($this->getMethod() !== 'POST') {
515
            $params = $this->getParams();
516
            $url = FacebookUrlManipulator::appendParamsToUrl($url, $params);
517
        }
518
519
        return $url;
520
    }
521
522
    /**
523
     * Return the default headers that every request should use.
524
     *
525
     * @return array
526
     */
527
    public static function getDefaultHeaders()
528
    {
529
        return [
530
            'User-Agent' => 'fb-php-' . Facebook::VERSION,
531
            'Accept-Encoding' => '*',
532
        ];
533
    }
534
}
535