FacebookCallback::send_message()   F
last analyzed

Complexity

Conditions 20
Paths 12974

Size

Total Lines 114
Code Lines 75

Duplication

Lines 21
Ratio 18.42 %

Importance

Changes 0
Metric Value
dl 21
loc 114
rs 2
c 0
b 0
f 0
cc 20
eloc 75
nc 12974
nop 4

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
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 11 and the first side effect is on line 13.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * A controller that connects with Facebook, using the Facebook PHP SDK
4
 *
5
 * USEFUL LINKS:
6
 * https://developers.facebook.com/docs/reference/login/extended-permissions/
7
 *
8
 */
9
10
if (!defined("SS_FACEBOOK_API_PATH")) {
11
    define("SS_FACEBOOK_API_PATH", str_replace("/code/control", "", dirname(__FILE__))."/thirdparty/facebook/src/");
12
}
13
require_once SS_FACEBOOK_API_PATH . 'facebook.php';
14
15
class FacebookCallback extends SocialIntegrationControllerBaseClass implements SocialIntegrationAPIInterface
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
16
{
17
18
19
    /**
20
     * Maximum number of friends that can be retrieved
21
     * @var Int
22
     */
23
    private static $number_of_friends_that_can_be_retrieved = 1200;
24
    public static function set_number_of_friends_that_can_be_retrieved($n)
25
    {
26
        self::$number_of_friends_that_can_be_retrieved = $s;
0 ignored issues
show
Bug introduced by
The variable $s does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
27
    }
28
    public static function get_number_of_friends_that_can_be_retrieved()
29
    {
30
        return self::$number_of_friends_that_can_be_retrieved;
31
    }
32
33
//======================================= AVAILABLE METHODS ===============================================
34
35
    /**
36
     * Standard SS variable
37
     * @var Array
38
     */
39
    public static $allowed_actions = array(
40
        'FacebookConnect',
41
        'Connect',
42
        'Login',
43
        'FinishFacebook',
44
        'remove',
45
        'test'
46
    );
47
48
49
//======================================= CONFIGURATION STATIC ===============================================
50
51
    /**
52
     * get it from developer.facebook.com
53
     * @var String
54
     */
55
    protected static $facebook_id = null;
56
    public static function set_facebook_id($i)
57
    {
58
        self::$facebook_id = $i;
59
    }
60
    public static function get_facebook_id()
61
    {
62
        return self::$facebook_id;
63
    }
64
65
    /**
66
     * get it from developer.facebook.com
67
     * @var String
68
     */
69
    protected static $facebook_secret = null;
70
    public static function set_facebook_secret($s)
71
    {
72
        self::$facebook_secret = $s;
73
    }
74
    public static function get_facebook_secret()
75
    {
76
        return self::$facebook_secret;
77
    }
78
79
    /**
80
     * use email as a back-up
81
     * for checking if the user already exists.
82
     * @var Boolean
83
     */
84
    protected static $email_fallback = true;
85
    public static function get_email_fallback()
86
    {
87
        return self::$email_fallback;
88
    }
89
    public static function set_email_fallback($val)
90
    {
91
        self::$email_fallback = (bool)$val;
92
    }
93
94
95
    /**
96
     * @see: https://developers.facebook.com/docs/authentication/permissions/
97
     * @var Array
98
     */
99
    protected static $permissions = false;
100
    public static function add_permission($s)
101
    {
102
        if (!self::$permissions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression self::$permissions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
103
            self::$permissions = array();
104
        } if (!in_array($s, self::$permissions)) {
105
            self::$permissions[] = $s;
106
        }
107
    }
108
    public static function set_permissions($a)
109
    {
110
        self::$permissions = $a;
111
    }
112
    public static function get_permissions()
113
    {
114
        return self::$permissions;
115
    }
116
117
118
//======================================= CONFIGURATION NON-STATIC ===============================================
119
120
121
122
123
//======================================= THIRD-PARTY CONNECTION ===============================================
124
125
    /**
126
     *
127
     *
128
     * @var facebook Class
129
     */
130
    protected static $facebook_sdk_class = null;
131
132
    /**
133
     * holds an instance of the FB class
134
     * @param Boolean $getEvenWithoutCurrentMember
135
     * @return Facebook
136
     */
137
    protected static function get_facebook_sdk_class($getEvenWithoutCurrentMember = false)
138
    {
139
        if (!self::$facebook_id || !self::$facebook_secret) {
140
            user_error("You must set the following variables: Facebook::facebook_id AND Facebook::facebook_secret");
141
        }
142
        if (!self::$facebook_sdk_class) {
143
            $member = Member::currentUser();
144
            if (($member && $member->FacebookID) || $getEvenWithoutCurrentMember) {
145
                self::$facebook_sdk_class = new Facebook(
146
                    array(
147
                        'appId' => self::$facebook_id,
148
                        'secret' => self::$facebook_secret,
149
                        'cookie' => true
150
                    )
151
                );
152
            }
153
        }
154
        return self::$facebook_sdk_class;
155
    }
156
157
158
//======================================= STATIC METHODS ===============================================
159
160
    /**
161
     * returns the currently logged in FB user
162
     * @return Object | Null
163
     */
164
    public static function get_current_user()
165
    {
166
        $user = null;
167
        $data = null;
168
        $facebook = self::get_facebook_sdk_class();
169
        if ($facebook) {
170
            $user = $facebook->getUser();
171
            if ($user) {
172
                try {
173
                    $data = $facebook->api('/me');
174
                    if (isset($data->error)) {
175
                        $data = null;
176
                        SS_Log::log($data->error->message, SS_Log::NOTICE);
177
                    }
178
                } catch (FacebookApiException $e) {
0 ignored issues
show
Bug introduced by
The class FacebookApiException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
179
                    $data = null;
180
                    SS_Log::log($e, SS_Log::NOTICE);
181
                }
182
                try {
183
                    $picture = $facebook->api('/me/?fields=picture');
184
                    if (isset($picture["picture"]["data"]["url"])) {
185
                        $data["picture"] = $picture["picture"]["data"]["url"];
186
                    }
187
                    if (isset($data->error)) {
188
                        SS_Log::log(print_r($data->error, 1).$data->error->message, SS_Log::NOTICE);
189
                    }
190
                } catch (FacebookApiException $e) {
0 ignored issues
show
Bug introduced by
The class FacebookApiException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
191
                    SS_Log::log($e, SS_Log::NOTICE);
192
                }
193
            }
194
        }
195
        return $user ? $data : null;
196
    }
197
198
    /*
199
    /**
200
     * returns true if the message is sent successfully
201
     * @param Int | Member | String $to
202
     * @param String $message
203
     * @param String $link - link to send with message
204
     * @param Array $otherVariables - other variables used in message.
205
             - $redirect_uri = "",
206
             - $RedirectURL = "",
207
             - $name = "",
208
             - $caption = "",
209
             - $description = "",
210
             - $pictureURL = "",
211
             - $Subject = "",
212
             - $actions = array()
213
     * @param String $senderEmail - link to send with message
0 ignored issues
show
Bug introduced by
There is no parameter named $senderEmail. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
214
215
     * @see:  https://developers.facebook.com/docs/reference/php/facebook-api/
216
     * @see   http://facebook.stackoverflow.com/questions/2943297/how-send-message-facebook-friend-through-graph-api-using-accessstoken
217
     *
218
     * @return EmailLink (Dialogue Feed)
0 ignored issues
show
Documentation introduced by
Should the return type not be string|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
219
     */
220
    public static function send_message(
221
        $to = "me",
222
        $message,
0 ignored issues
show
Coding Style introduced by
Parameters which have default values should be placed at the end.

If you place a parameter with a default value before a parameter with a default value, the default value of the first parameter will never be used as it will always need to be passed anyway:

// $a must always be passed; it's default value is never used.
function someFunction($a = 5, $b) { }
Loading history...
223
        $link = "",
224
        $otherVariables = array()
225
    ) {
226
        //FACEBOOK
227
        if ($to instanceof Member) {
228
            $to = $to->FacebookUsername;
229
        }
230
        $facebook = self::get_facebook_sdk_class();
231
        if ($facebook) {
232
            $user = $facebook->getUser();
233
            //get email data that does not go to GRAPH:
234
            if (isset($otherVariables["senderEmail"])) {
235
                $senderEmail = $otherVariables["senderEmail"];
236
                unset($otherVariables["senderEmail"]);
237
            } elseif ($sender = Member::currentUser()) {
238
                $senderEmail = $sender->Email;
239
            }
240
241
            //start hack
242
            $message = trim(strip_tags(stripslashes($message)));
243
            //end hack
244
            $postArray = array(
245
                'message' => $message,
246
                'link' => $link,
247
            );
248
            if (count($otherVariables)) {
249
                foreach ($otherVariables as $key => $value) {
250
                    $postArray[$key] = $value;
251
                }
252
            }
253
            if ($user) {
254 View Code Duplication
                if (empty($otherVariables["Subject"])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
255
                    $subject = substr($message, 0, 30);
256
                } else {
257
                    $subject = $otherVariables["Subject"];
258
                }
259
                //------------- SEND EMAIL TO START DIALOGUE ---
260
                //BUILD LINK
261
                $emailLink = "https://www.facebook.com/dialog/feed?"
262
                        ."to=".$to."&amp;"
263
                        ."app_id=".self::get_facebook_id()."&amp;"
264
                        ."link=".urlencode($link)."&amp;"
265
                        ."message=".urlencode($message)."&amp;";
266
                //FROM
267
                if (isset($otherVariables["redirect_uri"])) {
268
                    $emailLink .= "redirect_uri=".urlencode(Director::absoluteURL("/").$otherVariables["redirect_uri"])."&amp;";
269 View Code Duplication
                } elseif (isset($otherVariables["RedirectURL"])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
270
                    $emailLink .= "redirect_uri=".urlencode(Director::absoluteURL("/").$otherVariables["RedirectURL"])."&amp;";
271
                } else {
272
                    $emailLink .= "redirect_uri=".urlencode(Director::absoluteURL("/"))."&amp;";
273
                }
274 View Code Duplication
                if (isset($otherVariables["pictureURL"])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
275
                    $emailLink .= "picture=".urlencode(Director::absoluteURL("/").$otherVariables["pictureURL"])."&amp;";
276
                }
277 View Code Duplication
                if (isset($otherVariables["description"])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
278
                    $emailLink .= "description=".urlencode($otherVariables["description"])."&amp;";
279
                } elseif ($message) {
280
                    $emailLink .= "description=".urlencode($message)."&amp;";
281
                }
282
                if (isset($otherVariables["name"])) {
283
                    $emailLink .= "name=".urlencode($otherVariables["name"])."&amp;";
284
                }
285 View Code Duplication
                if (isset($otherVariables["caption"])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
286
                    $emailLink .= "caption=".urlencode($otherVariables["caption"])."&amp;";
287
                } elseif (isset($otherVariables["Subject"])) {
288
                    $emailLink .= "caption=".urlencode($otherVariables["Subject"])."&amp;";
289
                }
290
                $from = Email::getAdminEmail();
291
                //TO
292
                //SUBJECT
293
                $subject = _t("FacebookCallback.ACTION_REQUIRED", "Action required for").": ".$subject;
294
                //BODY
295
                $body =
296
                    _t("FacebookCallback.PLEASE_CLICK_ON_THE_LINK", " Please click on the link ")
297
                    ." <a href=\"".$emailLink."\" target=\"_blank\">"._t("FacebookCallback.OPEN_FACEBOOK", "open facebook")."</a> ".
298
                    _t("FacebookCallback.TO_SEND_A_MESSAGE_TO_FRIEND", "to send a message to your friend. ").
299
                    _t("FacebookCallback.DIRECT_LINK", " You can also send the link directly to your friend: ").$link;
300
                //BCC
301
                $bcc = Email::getAdminEmail();
0 ignored issues
show
Unused Code introduced by
$bcc is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
302
                //SEND
303
                $email = new Email(
304
                    $from,
305
                    $senderEmail,
0 ignored issues
show
Bug introduced by
The variable $senderEmail does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
306
                    $subject,
307
                    $body
308
                );
309
                $email->send();
310
                // We have a user ID, so probably a logged in user.
311
                // If not, we'll get an exception, which we handle below.
312
                if (1 == 2) {
313
                    if ($to instanceof Member) {
314
                        $to = $to->FacebookUsername;
315
                    }
316
                    try {
317
                        $ret_obj = $facebook->api('/'.$to.'/feed', 'POST', $postArray);
0 ignored issues
show
Unused Code introduced by
$ret_obj is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
318
                        //SS_Log::log($ret_obj, SS_Log::NOTICE);
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
319
                        return $body;
320
                    } catch (FacebookApiException $e) {
0 ignored issues
show
Bug introduced by
The class FacebookApiException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
321
                        // If the user is logged out, you can have a
322
                        // user ID even though the access token is invalid.
323
                        // In this case, we'll get an exception, so we'll
324
                        // just ask the user to login again here.
325
                        SS_Log::log($user."---".$e->getType()."---".$e->getMessage()."---".$to."---".$message."---".$link."---".$otherVariables."---".print_r($user, 1).print_r(Member::currentUser(), 1), SS_Log::NOTICE);
326
                    }
327
                }
328
            } else {
329
                SS_Log::log("tried to send a message from facebook without being logging in...", SS_Log::NOTICE);
330
            }
331
        }
332
        return false;
333
    }
334
335
336
    /**
337
     * gets a list of friends
338
     * @param Int - $Limit, set to -1 to to maximum
339
     * @param String - $searchString, filter for search string
340
     * @return Array (array("id" => ..., "name" => ...., "picture" => ...))
341
     */
342
    public static function get_list_of_friends($limit = 12, $searchString = "")
343
    {
344
        if ($limit == -1) {
345
            $limit = self::get_number_of_friends_that_can_be_retrieved();
346
        }
347
        $returnObject = array();
348
        $facebook = self::get_facebook_sdk_class();
349
        if ($facebook) {
350
            if ($user = $facebook->getUser()) {
0 ignored issues
show
Unused Code introduced by
$user is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
351
                $fullList = $facebook->api('/me/friends?fields=id,name,picture');
352
                $count = 0;
353
                if (Director::isDev()) {
354
                    $me = self::get_current_user();
355
                    $returnObject[$count]["id"] = $me["id"];
356
                    $returnObject[$count]["name"] = $me["name"];
357
                    $returnObject[$count]["picture"] = $me["picture"];
358
                    $count++;
359
                }
360
                if (isset($fullList["data"])) {
361
                    $limitCount = 0;
0 ignored issues
show
Unused Code introduced by
$limitCount is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
362
                    foreach ($fullList["data"] as $friend) {
363
                        if (!$searchString || stripos("-".$friend["name"], $searchString)) {
364
                            $returnObject[$count]["id"] = $friend["id"];
365
                            $returnObject[$count]["name"] = $friend["name"];
366
                            if (isset($friend["picture"]["data"]["url"])) {
367
                                $returnObject[$count]["picture"] = $friend["picture"]["data"]["url"];
368
                            } elseif (isset($friend["picture"])) {
369
                                $returnObject[$count]["picture"] = $friend["picture"];
370
                            }
371
                            $count++;
372
                        }
373
                        if ($count >= $limit) {
374
                            break;
375
                        }
376
                    }
377
                }
378
            }
379
        }
380
        return $returnObject;
381
    }
382
383
    public static function is_valid_user($id)
384
    {
385
        return true;
386
    }
387
388
    public static function get_updates($lastNumber = 12)
389
    {
390
        $returnObject = array();
0 ignored issues
show
Unused Code introduced by
$returnObject is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
391
        $facebook = self::get_facebook_sdk_class();
392
        if ($facebook) {
393
            if ($user = $facebook->getUser()) {
0 ignored issues
show
Unused Code introduced by
$user is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
394
                return $facebook->api(
395
                    $path = "/me/statuses",
396
                    $method = "GET",
397
                    $params = array(
398
                        "limit" => 100,
399
                        "since" => 2005,
400
                    )
401
                );
402
            }
403
        }
404
    }
405
//======================================= STANDARD SS METHODS ===============================================
406
407
    /**
408
     * magical PHP method
409
     */
410
    public function __construct()
411
    {
412
        if (self::$facebook_secret == null || self::$facebook_id == null) {
413
            user_error('Cannot instigate a FacebookCallback object without an application secret and id', E_USER_ERROR);
414
        }
415
        parent::__construct();
416
    }
417
418
419
420
//==================================== CONNECT ==============================================
421
422
    /**
423
     * easy access to the connection
424
     *
425
     */
426 View Code Duplication
    public function FacebookConnect()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
427
    {
428
        if ($this->isAjax()) {
429
            return $this->connectUser($this->Link('FinishFacebook'));
430
        } else {
431
            Session::set("BackURL", $this->returnURL());
432
            return $this->connectUser($this->returnURL());
433
        }
434
    }
435
436
    /**
437
     * STEP 1 of the connecting process
438
     * @param String $returnTo - the URL to return to
439
     * @param Array $extra - additional paramaters
440
     */
441
    public function connectUser($returnTo = '', array $extra = array())
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
442
    {
443
        $facebook = self::get_facebook_sdk_class($getEvenWithoutCurrentMember = true);
444
        $user = $facebook->getUser();
445
        $data = self::get_current_user();
0 ignored issues
show
Unused Code introduced by
$data is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
446
        $token = SecurityToken::inst();
447
        $returnTo = urlencode($returnTo);
448
        $returnTo = $token->addToUrl($returnTo);
449
        $callback = $this->AbsoluteLink('Connect?BackURL=' . $returnTo);
450
        $callback = $token->addToUrl($callback);
451
        if (self::$permissions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression self::$permissions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
452
            $extra += array(
453
                'scope' => implode(', ', self::$permissions)
454
            );
455
        }
456 View Code Duplication
        if ($user && empty($extra)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
457
            return self::curr()->redirect($callback);
458
        } else {
459
            return self::curr()->redirect(
460
                $facebook->getLoginUrl(
461
                    array(
462
                        'redirect_uri' => $callback
463
                    )
464
                    + $extra
465
                )
466
            );
467
        }
468
    }
469
470
    /**
471
     * Connects the current user.
472
     * completes connecting process
473
     * @param SS_HTTPRequest $reg
0 ignored issues
show
Bug introduced by
There is no parameter named $reg. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
474
     */
475
    public function Connect(SS_HTTPRequest $req)
476
    {
477
        //security
478
        $token = SecurityToken::inst();
479
        if (!$token->checkRequest($req)) {
480
            return $this->httpError(400);
481
        }
482
483
        $data = null;
484
485
        if ($req->getVars() && !$req->getVar('error')) {
486
            $facebook = self::get_facebook_sdk_class($getEvenWithoutCurrentMember = true);
487
            $user = $facebook->getUser();
488
            $data = self::get_current_user();
489
        }
490
        if ($data && $user && is_numeric($user)) {
491
            $this->updateUserFromFacebookData($user, $data, false);
0 ignored issues
show
Bug introduced by
The variable $user does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
492
        }
493
        $returnURL = $this->returnURL();
494
        return $this->redirect($returnURL);
495
    }
496
497
    /**
498
     * finish the login from facebook
499
     * @param HTTPRequest $request
500
     * @return String Javascript
501
     */
502
    public function FinishFacebook($request)
503
    {
504
        $token = SecurityToken::inst();
505
        if (!$token->checkRequest($request)) {
0 ignored issues
show
Documentation introduced by
$request is of type object<HttpRequest>, but the function expects a object<SS_HTTPRequest>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
506
            return $this->httpError(400);
507
        }
508
509
        $member = Member::currentUser();
510
        if ($member && $member->FacebookID) {
511
            return '<script type="text/javascript">//<![CDATA[
512
			opener.FacebookResponse(' . \Convert::raw2json(array(
513
                'name' => $member->FacebookName,
514
                'pages' => $member->getFacebookPages(),
515
                'removeLink' => $token->addToUrl($this->Link('RemoveFacebook')),
516
            )) . ');
517
			window.close();
518
			//]]></script>';
519
        } else {
520
            return '<script type="text/javascript">window.close();</script>';
521
        }
522
    }
523
524
525
526
527
528
529
//==================================== LOGIN ==============================================
530
531
    public function loginUser(array $extra = array(), $return = false)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
532
    {
533
        $facebook = self::get_facebook_sdk_class($getEvenWithoutCurrentMember = true);
534
        $user = $facebook->getUser();
535
        $data = self::get_current_user();
0 ignored issues
show
Unused Code introduced by
$data is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
536
        $token = SecurityToken::inst();
537
        if ($return) {
538
            $return = $token->addToUrl($return);
0 ignored issues
show
Documentation introduced by
$return is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
539
            $return = urlencode($return);
540
        }
541
        $callback = $this->AbsoluteLink('Login' . ($return ? '?ret=' . $return : ''));
542
        $callback = $token->addToUrl($callback);
543
        if (self::$permissions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression self::$permissions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
544
            $perms = self::$permissions;
545
        } else {
546
            $perms = array();
547
        }
548
        if ($perms) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $perms of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
549
            $extra += array(
550
                'scope' => implode(', ', $perms)
551
            );
552
        }
553
554 View Code Duplication
        if ($user && empty($extra)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
555
            return self::curr()->redirect($callback);
556
        } else {
557
            return self::curr()->redirect($facebook->getLoginUrl(array(
558
                'redirect_uri' => $callback,
559
            ) + $extra));
560
        }
561
    }
562
563
    public function Login(SS_HTTPRequest $req)
564
    {
565
        //security
566
        $token = SecurityToken::inst();
567
        if (!$token->checkRequest($req)) {
568
            return $this->httpError(400);
569
        }
570
571
        //denied!
572
        if ($req->getVar('denied') || $req->getVar('error_reason') == 'user_denied') {
573
            Session::set('FormInfo.FacebookLoginForm_LoginForm.formError.message', 'Login cancelled.');
574
            Session::set('FormInfo.FacebookLoginForm_LoginForm.formError.type', 'error');
575
            return $this->redirect('Security/login#FacebookLoginForm_LoginForm_tab');
576
        }
577
        $facebook = self::get_facebook_sdk_class($getEvenWithoutCurrentMember = true);
578
        $user = $facebook->getUser();
579
        $data = self::get_current_user();
580
        $error = "";
581
        if (!$user) {
582
            $error = 'Login cancelled.';
0 ignored issues
show
Unused Code introduced by
$error is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
583
            return $this->redirect('Security/login#FacebookLoginForm_LoginForm_tab');
584
        }
585
        if ($error) {
586
            Session::set('FormInfo.FacebookLoginForm_LoginForm.formError.message', 'Login error: ' . $data->error->message);
587
            Session::set('FormInfo.FacebookLoginForm_LoginForm.formError.type', 'error');
588
            return $this->redirect('Security/login#FacebookLoginForm_LoginForm_tab');
589
        }
590
        $this->updateUserFromFacebookData($user, $data, $keepLoggedIn = Session::get('SessionForms.FacebookLoginForm.Remember'));
591
        Session::clear('SessionForms.FacebookLoginForm.Remember');
592
        return $this->redirect($this->returnURL());
593
    }
594
595
596
597
//========================================== REMOVE  =====================================
598
599
    /**
600
     * alias for RemoveFaceBook
601
     */
602 View Code Duplication
    public function remove($request = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
603
    {
604
        $token = SecurityToken::inst();
605
        if (!$token->checkRequest($request)) {
606
            return $this->httpError(400);
607
        }
608
        return $this->RemoveFacebook($request);
609
    }
610
611
    /**
612
     * remove connection to facebook
613
     * TO DO: remove links
614
     * TO DO: FB session
615
     * @param HTTPRequest
616
     */
617
    public function RemoveFacebook($request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

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

Loading history...
618
    {
619
        //security check
620
        //
621
        $m = $this->CurrentMember();
622
        if ($m) {
623
            $m->FacebookID = 0;
624
            $m->FacebookURL = "";
625
            $m->FacebookPicture = "";
626
            $m->FacebookName = "";
627
            $m->FacebookEmail = "";
628
            $m->FacebookFirstName = "";
629
            $m->FacebookMiddleName = "";
630
            $m->FacebookLastName = "";
631
            $m->FacebookUsername = "";
632
            $m->write();
633
        }
634
        $facebook = new Facebook(array(
635
            'appId' => self::$facebook_id,
636
            'secret' => self::$facebook_secret
637
        ));
638
        //do we need to encode URL ????
639
        $url = $facebook->getLogoutUrl(array("next" => $this->returnURL(true)));
640
        $this->redirect($url);
641
    }
642
643
//========================================== HELPER METHODS =====================================
644
645
646
647
648
    /**
649
     * Saves the FB data to the member and logs in the member if that has not been done yet.
650
     * @param Int $user - the ID of the current twitter user
651
     * @param Object $facebookData - the data returned from FB
652
     * @param Boolean $keepLoggedIn - does the user stay logged in
653
     * @return Member
654
     */
655
    protected function updateUserFromFacebookData($user, $facebookData, $keepLoggedIn = false)
656
    {
657
        //clean up data
658
        if (is_array($facebookData)) {
659
            $obj = new DataObject();
660
            foreach ($facebookData as $key => $value) {
661
                $obj->$key = $value;
662
            }
663
            $facebookData = $obj;
664
        }
665
666
        //find member
667
        $member = null;
668
        if ($user) {
669
            $member = DataObject::get_one('Member', '"FacebookID" = \'' . Convert::raw2sql($user) . '\'');
670
        }
671
        if (!$member) {
672
            $member = Member::currentUser();
673
            if (!$member) {
674
                $member = new Member();
675
            }
676
        }
677
        //check if anyone else uses the email:
678 View Code Duplication
        if ($facebookEmail = Convert::raw2sql($facebookData->email)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
679
            $memberID = intval($member->ID)-0;
680
            $existingMember = DataObject::get_one(
681
                'Member',
682
                '("Email" = \'' . $facebookEmail . '\' OR "FacebookEmail" = \''.$facebookEmail.'\') AND "Member"."ID" <> '.$memberID
683
            );
684
            if ($existingMember) {
685
                $member = $existingMember;
686
            }
687
        }
688
        $member->FacebookID = empty($user) ? 0 : $user;
689
        $member->FacebookURL = empty($facebookData->link) ? "" : $facebookData->link;
690
        $member->FacebookPicture = empty($facebookData->picture) ? "" : $facebookData->picture;
691
        $member->FacebookName = empty($facebookData->name) ? "" : $facebookData->name;
692
        ;
693
        $member->FacebookEmail = empty($facebookData->email) ? "" : $facebookData->email;
694
        $member->FacebookFirstName = empty($facebookData->first_name) ? "" : $facebookData->first_name;
695
        $member->FacebookMiddleName = empty($facebookData->middle_name) ? "" : $facebookData->middle_name;
696
        $member->FacebookLastName = empty($facebookData->last_name) ? "" : $facebookData->last_name;
697
        $member->FacebookUsername = empty($facebookData->username) ? "" : $facebookData->username;
698
        if (!$member->FirstName) {
699
            $member->FirstName = $member->FacebookFirstName;
700
        }
701
        if (!$member->Surname) {
702
            $member->Surname = $member->FacebookLastName;
703
        }
704
        if (!empty($facebookData->email)) {
705
            if (!$member->Email) {
706
                $memberID = intval($member->ID)-0;
707
                $anotherMemberWithThisEmail = DataObject::get_one(
708
                    'Member',
709
                    '("Email" = \'' . $facebookData->email . '\' OR "FacebookEmail" = \''.$facebookData->email.'\') AND "Member"."ID" <> '.$memberID
710
                );
711
                if (!$anotherMemberWithThisEmail) {
712
                    $member->Email = $facebookData->email;
713
                }
714
            }
715
        }
716
        $member->write();
717
        $oldMember = Member::currentUser();
718 View Code Duplication
        if ($oldMember) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
719
            if ($oldMember->ID != $member->ID) {
720
                $oldMember->logout();
721
                $member->login($keepLoggedIn);
722
            } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
723
                //already logged in - nothing to do.
724
            }
725
        } else {
726
            $member->login($keepLoggedIn);
727
        }
728
        return $member;
729
    }
730
731
732
    /**
733
     * retrieve the various identities this user has on Facebook
734
     *
735
     * @return Array
736
     */
737
    public function getFacebookPages()
738
    {
739
        $facebook = self::get_facebook_sdk_class();
740
        $user = $facebook->getUser();
741
        if ($user) {
742
            $pages = array(
743
                'me/feed' => 'Personal Page'
744
            );
745
            try {
746
                $resp = $facebook->api('/me/accounts', 'GET');
747
                if (isset($resp->data)) {
748
                    foreach ($resp->data as $app) {
749
                        if ($app->category != 'Application') {
750
                            $pages[$app->id] = $app->name . ' <small>(' . $app->category . ')</small>';
751
                        }
752
                    }
753
                }
754
            } catch (FacebookApiException $e) {
0 ignored issues
show
Bug introduced by
The class FacebookApiException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
755
                SS_Log::log($e, SS_Log::ERR);
756
            }
757
            return $pages;
758
        }
759
        return array();
760
    }
761
762
763
764
    public function meondatabase()
765
    {
766
        $member = Member::currentUser();
767
        if ($member) {
768
            echo "<ul>";
769
            echo "<li>FacebookID: ".$member->FacebookID."</li>";
770
            echo "<li>FacebookName: ".$member->FacebookName."</li>";
771
            echo "<li>FacebookEmail: ".$member->FacebookEmail."</li>";
772
            echo "<li>FacebookFirstName: ".$member->FacebookFirstName."</li>";
773
            echo "<li>FacebookMiddleName: ".$member->FacebookMiddleName."</li>";
774
            echo "<li>FacebookLastName: ".$member->FacebookLastName."</li>";
775
            echo "<li>FacebookUsername: ".$member->FacebookUsername."</li>";
776
            echo "<li>FacebookPicture: <img src=\"".$member->FacebookPicture."\" alt=\"\" /></li>";
777
            echo "<li>FacebookURL: <a href=\"".$member->FacebookURL."\" />click ".$member->FacebookURL."</a></li>";
778
            echo "</ul>";
779
        } else {
780
            echo "<h2>You are not logged in.</h2>";
781
        }
782
    }
783
}
784