Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
25 - 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
 */
24
namespace Facebook;
25
 
26
use Facebook\Authentication\AccessToken;
27
use Facebook\Authentication\OAuth2Client;
28
use Facebook\FileUpload\FacebookFile;
29
use Facebook\FileUpload\FacebookResumableUploader;
30
use Facebook\FileUpload\FacebookTransferChunk;
31
use Facebook\FileUpload\FacebookVideo;
32
use Facebook\GraphNodes\GraphEdge;
33
use Facebook\Url\UrlDetectionInterface;
34
use Facebook\Url\FacebookUrlDetectionHandler;
35
use Facebook\PseudoRandomString\PseudoRandomStringGeneratorFactory;
36
use Facebook\PseudoRandomString\PseudoRandomStringGeneratorInterface;
37
use Facebook\HttpClients\HttpClientsFactory;
38
use Facebook\PersistentData\PersistentDataFactory;
39
use Facebook\PersistentData\PersistentDataInterface;
40
use Facebook\Helpers\FacebookCanvasHelper;
41
use Facebook\Helpers\FacebookJavaScriptHelper;
42
use Facebook\Helpers\FacebookPageTabHelper;
43
use Facebook\Helpers\FacebookRedirectLoginHelper;
44
use Facebook\Exceptions\FacebookSDKException;
45
 
46
/**
47
 * Class Facebook
48
 *
49
 * @package Facebook
50
 */
51
class Facebook
52
{
53
    /**
54
     * @const string Version number of the Facebook PHP SDK.
55
     */
56
    const VERSION = '5.6.2';
57
 
58
    /**
59
     * @const string Default Graph API version for requests.
60
     */
61
    const DEFAULT_GRAPH_VERSION = 'v2.10';
62
 
63
    /**
64
     * @const string The name of the environment variable that contains the app ID.
65
     */
66
    const APP_ID_ENV_NAME = 'FACEBOOK_APP_ID';
67
 
68
    /**
69
     * @const string The name of the environment variable that contains the app secret.
70
     */
71
    const APP_SECRET_ENV_NAME = 'FACEBOOK_APP_SECRET';
72
 
73
    /**
74
     * @var FacebookApp The FacebookApp entity.
75
     */
76
    protected $app;
77
 
78
    /**
79
     * @var FacebookClient The Facebook client service.
80
     */
81
    protected $client;
82
 
83
    /**
84
     * @var OAuth2Client The OAuth 2.0 client service.
85
     */
86
    protected $oAuth2Client;
87
 
88
    /**
89
     * @var UrlDetectionInterface|null The URL detection handler.
90
     */
91
    protected $urlDetectionHandler;
92
 
93
    /**
94
     * @var PseudoRandomStringGeneratorInterface|null The cryptographically secure pseudo-random string generator.
95
     */
96
    protected $pseudoRandomStringGenerator;
97
 
98
    /**
99
     * @var AccessToken|null The default access token to use with requests.
100
     */
101
    protected $defaultAccessToken;
102
 
103
    /**
104
     * @var string|null The default Graph version we want to use.
105
     */
106
    protected $defaultGraphVersion;
107
 
108
    /**
109
     * @var PersistentDataInterface|null The persistent data handler.
110
     */
111
    protected $persistentDataHandler;
112
 
113
    /**
114
     * @var FacebookResponse|FacebookBatchResponse|null Stores the last request made to Graph.
115
     */
116
    protected $lastResponse;
117
 
118
    /**
119
     * Instantiates a new Facebook super-class object.
120
     *
121
     * @param array $config
122
     *
123
     * @throws FacebookSDKException
124
     */
125
    public function __construct(array $config = [])
126
    {
127
        $config = array_merge([
128
            'app_id' => getenv(static::APP_ID_ENV_NAME),
129
            'app_secret' => getenv(static::APP_SECRET_ENV_NAME),
130
            'default_graph_version' => static::DEFAULT_GRAPH_VERSION,
131
            'enable_beta_mode' => false,
132
            'http_client_handler' => null,
133
            'persistent_data_handler' => null,
134
            'pseudo_random_string_generator' => null,
135
            'url_detection_handler' => null,
136
        ], $config);
137
 
138
        if (!$config['app_id']) {
139
            throw new FacebookSDKException('Required "app_id" key not supplied in config and could not find fallback environment variable "' . static::APP_ID_ENV_NAME . '"');
140
        }
141
        if (!$config['app_secret']) {
142
            throw new FacebookSDKException('Required "app_secret" key not supplied in config and could not find fallback environment variable "' . static::APP_SECRET_ENV_NAME . '"');
143
        }
144
 
145
        $this->app = new FacebookApp($config['app_id'], $config['app_secret']);
146
        $this->client = new FacebookClient(
147
            HttpClientsFactory::createHttpClient($config['http_client_handler']),
148
            $config['enable_beta_mode']
149
        );
150
        $this->pseudoRandomStringGenerator = PseudoRandomStringGeneratorFactory::createPseudoRandomStringGenerator(
151
            $config['pseudo_random_string_generator']
152
        );
153
        $this->setUrlDetectionHandler($config['url_detection_handler'] ?: new FacebookUrlDetectionHandler());
154
        $this->persistentDataHandler = PersistentDataFactory::createPersistentDataHandler(
155
            $config['persistent_data_handler']
156
        );
157
 
158
        if (isset($config['default_access_token'])) {
159
            $this->setDefaultAccessToken($config['default_access_token']);
160
        }
161
 
162
        // @todo v6: Throw an InvalidArgumentException if "default_graph_version" is not set
163
        $this->defaultGraphVersion = $config['default_graph_version'];
164
    }
165
 
166
    /**
167
     * Returns the FacebookApp entity.
168
     *
169
     * @return FacebookApp
170
     */
171
    public function getApp()
172
    {
173
        return $this->app;
174
    }
175
 
176
    /**
177
     * Returns the FacebookClient service.
178
     *
179
     * @return FacebookClient
180
     */
181
    public function getClient()
182
    {
183
        return $this->client;
184
    }
185
 
186
    /**
187
     * Returns the OAuth 2.0 client service.
188
     *
189
     * @return OAuth2Client
190
     */
191
    public function getOAuth2Client()
192
    {
193
        if (!$this->oAuth2Client instanceof OAuth2Client) {
194
            $app = $this->getApp();
195
            $client = $this->getClient();
196
            $this->oAuth2Client = new OAuth2Client($app, $client, $this->defaultGraphVersion);
197
        }
198
 
199
        return $this->oAuth2Client;
200
    }
201
 
202
    /**
203
     * Returns the last response returned from Graph.
204
     *
205
     * @return FacebookResponse|FacebookBatchResponse|null
206
     */
207
    public function getLastResponse()
208
    {
209
        return $this->lastResponse;
210
    }
211
 
212
    /**
213
     * Returns the URL detection handler.
214
     *
215
     * @return UrlDetectionInterface
216
     */
217
    public function getUrlDetectionHandler()
218
    {
219
        return $this->urlDetectionHandler;
220
    }
221
 
222
    /**
223
     * Changes the URL detection handler.
224
     *
225
     * @param UrlDetectionInterface $urlDetectionHandler
226
     */
227
    private function setUrlDetectionHandler(UrlDetectionInterface $urlDetectionHandler)
228
    {
229
        $this->urlDetectionHandler = $urlDetectionHandler;
230
    }
231
 
232
    /**
233
     * Returns the default AccessToken entity.
234
     *
235
     * @return AccessToken|null
236
     */
237
    public function getDefaultAccessToken()
238
    {
239
        return $this->defaultAccessToken;
240
    }
241
 
242
    /**
243
     * Sets the default access token to use with requests.
244
     *
245
     * @param AccessToken|string $accessToken The access token to save.
246
     *
247
     * @throws \InvalidArgumentException
248
     */
249
    public function setDefaultAccessToken($accessToken)
250
    {
251
        if (is_string($accessToken)) {
252
            $this->defaultAccessToken = new AccessToken($accessToken);
253
 
254
            return;
255
        }
256
 
257
        if ($accessToken instanceof AccessToken) {
258
            $this->defaultAccessToken = $accessToken;
259
 
260
            return;
261
        }
262
 
263
        throw new \InvalidArgumentException('The default access token must be of type "string" or Facebook\AccessToken');
264
    }
265
 
266
    /**
267
     * Returns the default Graph version.
268
     *
269
     * @return string
270
     */
271
    public function getDefaultGraphVersion()
272
    {
273
        return $this->defaultGraphVersion;
274
    }
275
 
276
    /**
277
     * Returns the redirect login helper.
278
     *
279
     * @return FacebookRedirectLoginHelper
280
     */
281
    public function getRedirectLoginHelper()
282
    {
283
        return new FacebookRedirectLoginHelper(
284
            $this->getOAuth2Client(),
285
            $this->persistentDataHandler,
286
            $this->urlDetectionHandler,
287
            $this->pseudoRandomStringGenerator
288
        );
289
    }
290
 
291
    /**
292
     * Returns the JavaScript helper.
293
     *
294
     * @return FacebookJavaScriptHelper
295
     */
296
    public function getJavaScriptHelper()
297
    {
298
        return new FacebookJavaScriptHelper($this->app, $this->client, $this->defaultGraphVersion);
299
    }
300
 
301
    /**
302
     * Returns the canvas helper.
303
     *
304
     * @return FacebookCanvasHelper
305
     */
306
    public function getCanvasHelper()
307
    {
308
        return new FacebookCanvasHelper($this->app, $this->client, $this->defaultGraphVersion);
309
    }
310
 
311
    /**
312
     * Returns the page tab helper.
313
     *
314
     * @return FacebookPageTabHelper
315
     */
316
    public function getPageTabHelper()
317
    {
318
        return new FacebookPageTabHelper($this->app, $this->client, $this->defaultGraphVersion);
319
    }
320
 
321
    /**
322
     * Sends a GET request to Graph and returns the result.
323
     *
324
     * @param string                  $endpoint
325
     * @param AccessToken|string|null $accessToken
326
     * @param string|null             $eTag
327
     * @param string|null             $graphVersion
328
     *
329
     * @return FacebookResponse
330
     *
331
     * @throws FacebookSDKException
332
     */
333
    public function get($endpoint, $accessToken = null, $eTag = null, $graphVersion = null)
334
    {
335
        return $this->sendRequest(
336
            'GET',
337
            $endpoint,
338
            $params = [],
339
            $accessToken,
340
            $eTag,
341
            $graphVersion
342
        );
343
    }
344
 
345
    /**
346
     * Sends a POST request to Graph and returns the result.
347
     *
348
     * @param string                  $endpoint
349
     * @param array                   $params
350
     * @param AccessToken|string|null $accessToken
351
     * @param string|null             $eTag
352
     * @param string|null             $graphVersion
353
     *
354
     * @return FacebookResponse
355
     *
356
     * @throws FacebookSDKException
357
     */
358
    public function post($endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
359
    {
360
        return $this->sendRequest(
361
            'POST',
362
            $endpoint,
363
            $params,
364
            $accessToken,
365
            $eTag,
366
            $graphVersion
367
        );
368
    }
369
 
370
    /**
371
     * Sends a DELETE request to Graph and returns the result.
372
     *
373
     * @param string                  $endpoint
374
     * @param array                   $params
375
     * @param AccessToken|string|null $accessToken
376
     * @param string|null             $eTag
377
     * @param string|null             $graphVersion
378
     *
379
     * @return FacebookResponse
380
     *
381
     * @throws FacebookSDKException
382
     */
383
    public function delete($endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
384
    {
385
        return $this->sendRequest(
386
            'DELETE',
387
            $endpoint,
388
            $params,
389
            $accessToken,
390
            $eTag,
391
            $graphVersion
392
        );
393
    }
394
 
395
    /**
396
     * Sends a request to Graph for the next page of results.
397
     *
398
     * @param GraphEdge $graphEdge The GraphEdge to paginate over.
399
     *
400
     * @return GraphEdge|null
401
     *
402
     * @throws FacebookSDKException
403
     */
404
    public function next(GraphEdge $graphEdge)
405
    {
406
        return $this->getPaginationResults($graphEdge, 'next');
407
    }
408
 
409
    /**
410
     * Sends a request to Graph for the previous page of results.
411
     *
412
     * @param GraphEdge $graphEdge The GraphEdge to paginate over.
413
     *
414
     * @return GraphEdge|null
415
     *
416
     * @throws FacebookSDKException
417
     */
418
    public function previous(GraphEdge $graphEdge)
419
    {
420
        return $this->getPaginationResults($graphEdge, 'previous');
421
    }
422
 
423
    /**
424
     * Sends a request to Graph for the next page of results.
425
     *
426
     * @param GraphEdge $graphEdge The GraphEdge to paginate over.
427
     * @param string    $direction The direction of the pagination: next|previous.
428
     *
429
     * @return GraphEdge|null
430
     *
431
     * @throws FacebookSDKException
432
     */
433
    public function getPaginationResults(GraphEdge $graphEdge, $direction)
434
    {
435
        $paginationRequest = $graphEdge->getPaginationRequest($direction);
436
        if (!$paginationRequest) {
437
            return null;
438
        }
439
 
440
        $this->lastResponse = $this->client->sendRequest($paginationRequest);
441
 
442
        // Keep the same GraphNode subclass
443
        $subClassName = $graphEdge->getSubClassName();
444
        $graphEdge = $this->lastResponse->getGraphEdge($subClassName, false);
445
 
446
        return count($graphEdge) > 0 ? $graphEdge : null;
447
    }
448
 
449
    /**
450
     * Sends a request to Graph and returns the result.
451
     *
452
     * @param string                  $method
453
     * @param string                  $endpoint
454
     * @param array                   $params
455
     * @param AccessToken|string|null $accessToken
456
     * @param string|null             $eTag
457
     * @param string|null             $graphVersion
458
     *
459
     * @return FacebookResponse
460
     *
461
     * @throws FacebookSDKException
462
     */
463
    public function sendRequest($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
464
    {
465
        $accessToken = $accessToken ?: $this->defaultAccessToken;
466
        $graphVersion = $graphVersion ?: $this->defaultGraphVersion;
467
        $request = $this->request($method, $endpoint, $params, $accessToken, $eTag, $graphVersion);
468
 
469
        return $this->lastResponse = $this->client->sendRequest($request);
470
    }
471
 
472
    /**
473
     * Sends a batched request to Graph and returns the result.
474
     *
475
     * @param array                   $requests
476
     * @param AccessToken|string|null $accessToken
477
     * @param string|null             $graphVersion
478
     *
479
     * @return FacebookBatchResponse
480
     *
481
     * @throws FacebookSDKException
482
     */
483
    public function sendBatchRequest(array $requests, $accessToken = null, $graphVersion = null)
484
    {
485
        $accessToken = $accessToken ?: $this->defaultAccessToken;
486
        $graphVersion = $graphVersion ?: $this->defaultGraphVersion;
487
        $batchRequest = new FacebookBatchRequest(
488
            $this->app,
489
            $requests,
490
            $accessToken,
491
            $graphVersion
492
        );
493
 
494
        return $this->lastResponse = $this->client->sendBatchRequest($batchRequest);
495
    }
496
 
497
    /**
498
     * Instantiates an empty FacebookBatchRequest entity.
499
     *
500
     * @param  AccessToken|string|null $accessToken  The top-level access token. Requests with no access token
501
     *                                               will fallback to this.
502
     * @param  string|null             $graphVersion The Graph API version to use.
503
     * @return FacebookBatchRequest
504
     */
505
    public function newBatchRequest($accessToken = null, $graphVersion = null)
506
    {
507
        $accessToken = $accessToken ?: $this->defaultAccessToken;
508
        $graphVersion = $graphVersion ?: $this->defaultGraphVersion;
509
 
510
        return new FacebookBatchRequest(
511
            $this->app,
512
            [],
513
            $accessToken,
514
            $graphVersion
515
        );
516
    }
517
 
518
    /**
519
     * Instantiates a new FacebookRequest entity.
520
     *
521
     * @param string                  $method
522
     * @param string                  $endpoint
523
     * @param array                   $params
524
     * @param AccessToken|string|null $accessToken
525
     * @param string|null             $eTag
526
     * @param string|null             $graphVersion
527
     *
528
     * @return FacebookRequest
529
     *
530
     * @throws FacebookSDKException
531
     */
532
    public function request($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
533
    {
534
        $accessToken = $accessToken ?: $this->defaultAccessToken;
535
        $graphVersion = $graphVersion ?: $this->defaultGraphVersion;
536
 
537
        return new FacebookRequest(
538
            $this->app,
539
            $accessToken,
540
            $method,
541
            $endpoint,
542
            $params,
543
            $eTag,
544
            $graphVersion
545
        );
546
    }
547
 
548
    /**
549
     * Factory to create FacebookFile's.
550
     *
551
     * @param string $pathToFile
552
     *
553
     * @return FacebookFile
554
     *
555
     * @throws FacebookSDKException
556
     */
557
    public function fileToUpload($pathToFile)
558
    {
559
        return new FacebookFile($pathToFile);
560
    }
561
 
562
    /**
563
     * Factory to create FacebookVideo's.
564
     *
565
     * @param string $pathToFile
566
     *
567
     * @return FacebookVideo
568
     *
569
     * @throws FacebookSDKException
570
     */
571
    public function videoToUpload($pathToFile)
572
    {
573
        return new FacebookVideo($pathToFile);
574
    }
575
 
576
    /**
577
     * Upload a video in chunks.
578
     *
579
     * @param int $target The id of the target node before the /videos edge.
580
     * @param string $pathToFile The full path to the file.
581
     * @param array $metadata The metadata associated with the video file.
582
     * @param string|null $accessToken The access token.
583
     * @param int $maxTransferTries The max times to retry a failed upload chunk.
584
     * @param string|null $graphVersion The Graph API version to use.
585
     *
586
     * @return array
587
     *
588
     * @throws FacebookSDKException
589
     */
590
    public function uploadVideo($target, $pathToFile, $metadata = [], $accessToken = null, $maxTransferTries = 5, $graphVersion = null)
591
    {
592
        $accessToken = $accessToken ?: $this->defaultAccessToken;
593
        $graphVersion = $graphVersion ?: $this->defaultGraphVersion;
594
 
595
        $uploader = new FacebookResumableUploader($this->app, $this->client, $accessToken, $graphVersion);
596
        $endpoint = '/'.$target.'/videos';
597
        $file = $this->videoToUpload($pathToFile);
598
        $chunk = $uploader->start($endpoint, $file);
599
 
600
        do {
601
            $chunk = $this->maxTriesTransfer($uploader, $endpoint, $chunk, $maxTransferTries);
602
        } while (!$chunk->isLastChunk());
603
 
604
        return [
605
          'video_id' => $chunk->getVideoId(),
606
          'success' => $uploader->finish($endpoint, $chunk->getUploadSessionId(), $metadata),
607
        ];
608
    }
609
 
610
    /**
611
     * Attempts to upload a chunk of a file in $retryCountdown tries.
612
     *
613
     * @param FacebookResumableUploader $uploader
614
     * @param string $endpoint
615
     * @param FacebookTransferChunk $chunk
616
     * @param int $retryCountdown
617
     *
618
     * @return FacebookTransferChunk
619
     *
620
     * @throws FacebookSDKException
621
     */
622
    private function maxTriesTransfer(FacebookResumableUploader $uploader, $endpoint, FacebookTransferChunk $chunk, $retryCountdown)
623
    {
624
        $newChunk = $uploader->transfer($endpoint, $chunk, $retryCountdown < 1);
625
 
626
        if ($newChunk !== $chunk) {
627
            return $newChunk;
628
        }
629
 
630
        $retryCountdown--;
631
 
632
        // If transfer() returned the same chunk entity, the transfer failed but is resumable.
633
        return $this->maxTriesTransfer($uploader, $endpoint, $chunk, $retryCountdown);
634
    }
635
}