Issues (2002)

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.

code/model/address/EcommerceRegion.php (16 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
/**
4
 * @description: This class helps you to manage regions within the context of e-commerce.
5
 * The regions can be states (e.g. we only sell within New York and Penn State), suburbs (pizza delivery place),
6
 * or whatever other geographical borders you are using.
7
 * Each region has one country, so a region can not span more than one country.
8
 *
9
 *
10
 * @authors: Nicolaas [at] Sunny Side Up .co.nz
11
 * @package: ecommerce
12
 * @sub-package: address
13
 * @inspiration: Silverstripe Ltd, Jeremy
14
 **/
15
class EcommerceRegion extends DataObject implements EditableEcommerceObject
16
{
17
    /**
18
     * what variables are accessible through  http://mysite.com/api/ecommerce/v1/EcommerceRegion/.
19
     *
20
     * @var array
21
     */
22
    private static $api_access = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
23
        'view' => array(
24
                'Code',
25
                'Name',
26
            ),
27
     );
28
29
    /**
30
     * standard SS variable.
31
     *
32
     * @var array
33
     */
34
    private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
35
        'Code' => 'Varchar(20)',
36
        'Name' => 'Varchar(200)',
37
        'DoNotAllowSales' => 'Boolean',
38
        'IsDefault' => 'Boolean',
39
    );
40
41
    /**
42
     * standard SS variable.
43
     *
44
     * @var array
45
     */
46
    private static $has_one = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
47
        'Country' => 'EcommerceCountry',
48
    );
49
50
    /**
51
     * standard SS variable.
52
     *
53
     * @var string
54
     */
55
    private static $indexes = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
56
        'Name' => true,
57
        'Code' => true,
58
        'DoNotAllowSales' => true
59
    );
60
61
    /**
62
     * standard SS variable.
63
     *
64
     * @var string
65
     */
66
    private static $default_sort = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
67
        'Name' => 'ASC',
68
        'ID' => 'ASC'
69
    ];
70
71
    /**
72
     * standard SS variable.
73
     *
74
     * @var string
75
     */
76
    private static $singular_name = 'Region';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
77
    public function i18n_singular_name()
78
    {
79
        return _t('EcommerceRegion.REGION', 'Region');
80
    }
81
82
    /**
83
     * standard SS variable.
84
     *
85
     * @var string
86
     */
87
    private static $plural_name = 'Regions';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
88
    public function i18n_plural_name()
89
    {
90
        return _t('EcommerceRegion.REGIONS', 'Regions');
91
    }
92
93
    /**
94
     * standard SS variable.
95
     *
96
     * @var array
97
     */
98
    private static $searchable_fields = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
99
        'Name' => 'PartialMatchFilter',
100
        'Code' => 'PartialMatchFilter',
101
    );
102
103
    /**
104
     * standard SS variable.
105
     *
106
     * @var array
107
     */
108
    private static $field_labels = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
109
        'Name' => 'Region',
110
    );
111
112
    /**
113
     * standard SS variable.
114
     *
115
     * @var array
116
     */
117
    private static $summary_fields = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
118
        'Name' => 'Name',
119
        'Country.Title' => 'Country',
120
    );
121
122
    /**
123
     * Standard SS variable.
124
     *
125
     * @var string
126
     */
127
    private static $description = 'A region within a country.  This can be a state or a province or the equivalent.';
128
129
    /**
130
     * do we use regions at all in this ecommerce application?
131
     *
132
     * @return bool
133
     **/
134
    public static function show()
135
    {
136
        if (Config::inst()->get('EcommerceRegion', 'show_freetext_region_field')) {
137
            return true;
138
        }
139
        return EcommerceRegion::get()->count() ? true : false;
140
    }
141
142
    /**
143
     * Standard SS FieldList.
144
     *
145
     * @return FieldList
146
     **/
147
    public function getCMSFields()
148
    {
149
        $fields = parent::getCMSFields();
150
        $title = singleton('EcommerceRegion')->i18n_singular_name();
0 ignored issues
show
$title 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...
151
        $fields->removeByName('CountryID');
152
153
        return $fields;
154
    }
155
156
    /**
157
     * link to edit the record.
158
     *
159
     * @param string | Null $action - e.g. edit
160
     *
161
     * @return string
0 ignored issues
show
Should the return type not be null|string?

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...
162
     */
163
    public function CMSEditLink($action = null)
164
    {
165
        return CMSEditLinkAPI::find_edit_link_for_object($this, $action);
166
    }
167
168
    /**
169
     * checks if a code is allowed.
170
     *
171
     * @param string $code - e.g. NZ, NSW, or CO
172
     *
173
     * @return bool
174
     */
175
    public static function code_allowed($code)
176
    {
177
        $region = DataObject::get_one(
178
            'EcommerceRegion',
179
            array('Code' => $code)
180
        );
181
        if ($region) {
182
            return self::regionid_allowed($region->ID);
183
        }
184
185
        return false;
186
    }
187
188
    /**
189
     * checks if a code is allowed.
190
     *
191
     * @param string $code - e.g. NZ, NSW, or CO
0 ignored issues
show
There is no parameter named $code. 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...
192
     *
193
     * @return bool
194
     */
195
    public static function regionid_allowed($regionID)
196
    {
197
        return array_key_exists($regionID, self::list_of_allowed_entries_for_dropdown());
198
    }
199
200
    /**
201
     * converts a code into a proper title.
202
     *
203
     * @param int $regionID (Code)
204
     *
205
     * @return string ( name)
206
     */
207
    public static function find_title($regionID)
208
    {
209
        $options = self::get_default_array();
210
        // check if code was provided, and is found in the country array
211
        if ($options && isset($options[$regionID])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options 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...
212
            return $options[$regionID];
213
        } else {
214
            return '';
215
        }
216
    }
217
218
    /**
219
     * This function returns back the default list of regions, filtered by the currently selected country.
220
     *
221
     * @return array - array of Region.ID => Region.Name
222
     **/
223
    protected static function get_default_array()
224
    {
225
        $defaultArray = array();
226
        $regions = EcommerceRegion::get()
227
            ->Exclude(array('DoNotAllowSales' => 1));
228
        $defaultRegion = EcommerceCountry::get_country_id();
229
        if ($defaultRegion) {
230
            $regions = $regions->Filter(array('CountryID' => EcommerceCountry::get_country_id()));
231
        }
232
        if ($regions && $regions->count()) {
233
            foreach ($regions as $region) {
234
                $defaultArray[$region->ID] = $region->Name;
235
            }
236
        }
237
238
        return $defaultArray;
239
    }
240
241
    // DYNAMIC LIMITS.....
242
243
    /**
244
     * takes the defaultArray and limits it with "only show" and "do not show" value, relevant for the current order.
245
     *
246
     * @return array (Code, Title)
247
     **/
248
    public static function list_of_allowed_entries_for_dropdown()
249
    {
250
        $defaultArray = self::get_default_array();
251
        $onlyShow = self::get_for_current_order_only_show_regions();
252
        $doNotShow = self::get_for_current_order_do_not_show_regions();
253
        if (is_array($onlyShow) && count($onlyShow)) {
254
            foreach ($defaultArray as $id => $value) {
255
                if (!in_array($id, $onlyShow)) {
256
                    unset($defaultArray[$id]);
257
                }
258
            }
259
        }
260
        if (is_array($doNotShow) && count($doNotShow)) {
261
            foreach ($doNotShow as $id) {
262
                if (isset($defaultArray[$id])) {
263
                    unset($defaultArray[$id]);
264
                }
265
            }
266
        }
267
268
        return $defaultArray;
269
    }
270
271
    /**
272
     * these variables and methods allow to to "dynamically limit the regions available, based on, for example: ordermodifiers, item selection, etc....
273
     * for example, if hot delivery of a catering item is only available in a certain region, then the regions can be limited with the methods below.
274
     * NOTE: these methods / variables below are IMPORTANT, because they allow the dropdown for the region to be limited for just that order.
275
     *
276
     * @var array of regions codes, e.g. ("NSW", "WA", "VIC");
277
     **/
278
    protected static $_for_current_order_only_show_regions = array();
279
280
    /**
281
     * @param int $orderID
282
     *
283
     * @return array
284
     */
285
    public static function get_for_current_order_only_show_regions($orderID = 0)
286
    {
287
        $orderID = ShoppingCart::current_order_id($orderID);
288
289
        return isset(self::$_for_current_order_only_show_regions[$orderID]) ? self::$_for_current_order_only_show_regions[$orderID] : array();
290
    }
291
292
    /**
293
     * merges arrays...
294
     *
295
     * @param array $a
296
     * @param int   $orderID
297
     */
298
    public static function set_for_current_order_only_show_regions(array $a, $orderID = 0)
299
    {
300
        //We MERGE here because several modifiers may limit the countries
301
        $previousArray = self::get_for_current_order_only_show_regions($orderID);
302
        self::$_for_current_order_only_show_regions[$orderID] = array_intersect($a, $previousArray);
303
    }
304
305
    /**
306
     * @var array
307
     */
308
    private static $_for_current_order_do_not_show_regions = array();
309
310
    /**
311
     * @param int $orderID
312
     *
313
     * @return array
314
     */
315
    public static function get_for_current_order_do_not_show_regions($orderID = 0)
316
    {
317
        $orderID = ShoppingCart::current_order_id($orderID);
318
319
        return isset(self::$_for_current_order_do_not_show_regions[$orderID]) ? self::$_for_current_order_do_not_show_regions[$orderID] : array();
320
    }
321
322
    /**
323
     * merges arrays...
324
     *
325
     * @param array $a
326
     * @param int   $orderID
327
     */
328
    public static function set_for_current_order_do_not_show_regions(array $a, $orderID = 0)
329
    {
330
        //We MERGE here because several modifiers may limit the countries
331
        $previousArray = self::get_for_current_order_do_not_show_regions($orderID);
332
        self::$_for_current_order_do_not_show_regions[$orderID] = array_merge($a, $previousArray);
333
    }
334
335
    /**
336
     * This function works out the most likely region for the current order.
337
     *
338
     * @return int
339
     **/
340
    public static function get_region_id()
341
    {
342
        $regionID = 0;
343
        if ($order = ShoppingCart::current_order()) {
344
            if ($region = $order->Region()) {
345
                $regionID = $region->ID;
346
            }
347
        }
348
        //3. check GEOIP information
349
        if (!$regionID) {
350
            $regions = EcommerceRegion::get()->filter(array('IsDefault' => 1));
351
            if ($regions) {
352
                $regionArray = self::list_of_allowed_entries_for_dropdown();
353
                foreach ($regions as $region) {
354
                    if (in_array($region->ID, $regionArray)) {
355
                        return $region->ID;
356
                    }
357
                }
358
            }
359
            if (is_array($regionArray) && count($regionArray)) {
360
                foreach ($regionArray as $regionID => $regionName) {
0 ignored issues
show
The variable $regionArray 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...
361
                    break;
362
                }
363
            }
364
        }
365
366
        return $regionID;
367
    }
368
369
    /**
370
     * returns the country based on the Visitor Country Provider.
371
     * this is some sort of IP recogniser system (e.g. Geoip Class).
372
     *
373
     * @return int
374
     **/
375
    public static function get_region_from_ip()
376
    {
377
        $visitorCountryProviderClassName = EcommerceConfig::get('EcommerceCountry', 'visitor_region_provider');
378
        if (!$visitorCountryProviderClassName) {
379
            $visitorCountryProviderClassName = 'EcommerceRegion_VisitorRegionProvider';
380
        }
381
        $visitorCountryProvider = new $visitorCountryProviderClassName();
382
383
        return $visitorCountryProvider->getRegion();
384
    }
385
386
    /**
387
     * @alias for get_region_id
388
     */
389
    public static function get_region()
390
    {
391
        return self::get_region_id();
392
    }
393
394
    /**
395
     * standard SS method
396
     * cleans up codes.
397
     */
398
    public function onBeforeWrite()
399
    {
400
        parent::onBeforeWrite();
401
        $filter = EcommerceCodeFilter::create();
402
        $filter->checkCode($this);
403
    }
404
}
405
406
class EcommerceRegion_VisitorRegionProvider extends Object
407
{
408
    /**
409
     * @return int - region ID
0 ignored issues
show
Should the return type not be integer|null?

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...
410
     */
411
    public function getRegion()
412
    {
413
        $region = DataObject::get_one('EcommerceRegion');
414
        if ($region) {
415
            return $region->ID;
416
        }
417
    }
418
}
419