Completed
Pull Request — development (#546)
by Nick
06:51
created

cache::updateCacheStatusFromLatestLog()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 61
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 25
nc 5
nop 3
dl 0
loc 61
rs 8.6806
c 0
b 0
f 0

How to fix   Long Method   

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
2
/***************************************************************************
3
 * for license information see LICENSE.md
4
 *   get/set has to be committed with save
5
 *   add/remove etc. is executed instantly
6
 ***************************************************************************/
7
8
require_once __DIR__ . '/logtypes.inc.php';
9
10
class cache
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...
11
{
12
    public $nCacheId = 0;
13
14
    public $reCache;
15
16
    /**
17
     * @param $wp
18
     * @return int|null
19
     */
20
    public static function cacheIdFromWP($wp)
21
    {
22
        if (mb_strtoupper(mb_substr($wp, 0, 2)) === 'GC') {
23
            $rs = sql("SELECT `cache_id` FROM `caches` WHERE `wp_gc_maintained`='&1'", $wp);
24
            if (sql_num_rows($rs) !== 1) {
25
                sql_free_result($rs);
26
27
                return null;
28
            }
29
            $r = sql_fetch_assoc($rs);
30
            sql_free_result($rs);
31
32
            $cacheId = $r['cache_id'];
33
        } else {
34
            $cacheId = sql_value("SELECT `cache_id` FROM `caches` WHERE `wp_oc`='&1'", 0, $wp);
35
        }
36
37
        return $cacheId;
38
    }
39
40
    /**
41
     * @param $wp
42
     * @return cache|null
43
     */
44
    public static function fromWP($wp)
45
    {
46
        $cacheId = self::cacheIdFromWP($wp);
47
        if ($cacheId === 0) {
48
            return null;
49
        }
50
51
        return new cache($cacheId);
52
    }
53
54
    /**
55
     * @param $uuid
56
     * @return mixed
57
     */
58
    public static function cacheIdFromUUID($uuid)
59
    {
60
        $cacheId = sql_value("SELECT `cache_id` FROM `caches` WHERE `uuid`='&1'", 0, $uuid);
61
62
        return $cacheId;
63
    }
64
65
    /**
66
     * @param $uuid
67
     * @return cache|null
68
     */
69
    public static function fromUUID($uuid)
70
    {
71
        $cacheId = self::cacheIdFromUUID($uuid);
72
        if ($cacheId === 0) {
73
            return null;
74
        }
75
76
        return new cache($cacheId);
77
    }
78
79
    public function __construct($nNewCacheId = ID_NEW)
80
    {
81
        $this->reCache = new rowEditor('caches');
82
        $this->reCache->addPKInt('cache_id', null, false, RE_INSERT_AUTOINCREMENT);
83
        $this->reCache->addString('uuid', '', false, RE_INSERT_AUTOUUID);
84
        $this->reCache->addInt('node', 0, false);
85
        $this->reCache->addDate('date_created', time(), true, RE_INSERT_IGNORE);
86
        $this->reCache->addDate('last_modified', time(), true, RE_INSERT_IGNORE);
87
        $this->reCache->addDate('listing_last_modified', time(), true, RE_INSERT_IGNORE);
88
        $this->reCache->addInt('user_id', 0, false);
89
        $this->reCache->addString('name', '', false);
90
        $this->reCache->addDouble('longitude', 0, false);
91
        $this->reCache->addDouble('latitude', 0, false);
92
        $this->reCache->addInt('type', 1, false);
93
        $this->reCache->addInt('status', 5, false);
94
        $this->reCache->addString('country', '', false);
95
        $this->reCache->addDate('date_hidden', time(), false);
96
        $this->reCache->addInt('size', 1, false);
97
        $this->reCache->addFloat('difficulty', 1, false);
98
        $this->reCache->addFloat('terrain', 1, false);
99
        $this->reCache->addString('logpw', '', false);
100
        $this->reCache->addFloat('search_time', 0, false);
101
        $this->reCache->addFloat('way_length', 0, false);
102
        $this->reCache->addString('wp_oc', null, true);
103
        $this->reCache->addString('wp_gc', '', false);
104
        $this->reCache->addString('wp_gc_maintained', '', false);
105
        $this->reCache->addString('wp_nc', '', false);
106
        $this->reCache->addString('desc_languages', '', false, RE_INSERT_IGNORE);
107
        $this->reCache->addString('default_desclang', '', false);
108
        $this->reCache->addDate('date_activate', null, true);
109
        $this->reCache->addInt('need_npa_recalc', 1, false, RE_INSERT_IGNORE);
110
        $this->reCache->addInt('show_cachelists', 1, false);
111
        $this->reCache->addInt('protect_old_coords', 0, false);
112
        $this->reCache->addInt('needs_maintenance', 0, false);
113
        $this->reCache->addInt('listing_outdated', 0, false);
114
        $this->reCache->addDate('flags_last_modified', '0000-00-00 00:00:00', false);
115
116
        $this->nCacheId = $nNewCacheId + 0;
117
118
        if ($nNewCacheId == ID_NEW) {
119
            $this->reCache->addNew(null);
120
        } else {
121
            $this->reCache->load($this->nCacheId);
122
        }
123
    }
124
125
    /**
126
     * @return bool
127
     */
128
    public function exist()
129
    {
130
        return $this->reCache->exist();
131
    }
132
133
    /**
134
     * @return int
135
     */
136
    public function getCacheId()
137
    {
138
        return $this->nCacheId;
139
    }
140
141
    public function getStatus()
142
    {
143
        return $this->reCache->getValue('status');
144
    }
145
146
    public function getType()
147
    {
148
        return $this->reCache->getValue('type');
149
    }
150
151
    public function getName()
152
    {
153
        return $this->reCache->getValue('name');
154
    }
155
156
    public function getLongitude()
157
    {
158
        return $this->reCache->getValue('longitude');
159
    }
160
161
    public function getLatitude()
162
    {
163
        return $this->reCache->getValue('latitude');
164
    }
165
166
    public function getUserId()
167
    {
168
        return $this->reCache->getValue('user_id');
169
    }
170
171
    public function getUsername()
172
    {
173
        return sql_value("SELECT `username` FROM `user` WHERE `user_id`='&1'", '', $this->getUserId());
174
    }
175
176
    public function getWPOC()
177
    {
178
        return $this->reCache->getValue('wp_oc');
179
    }
180
181
    public function getWPGC()
182
    {
183
        return $this->reCache->getValue('wp_gc');
184
    }
185
186
    public function getWPGC_maintained()
187
    {
188
        return $this->reCache->getValue('wp_gc_maintained');
189
    }
190
191
    public function getUUID()
192
    {
193
        return $this->reCache->getValue('uuid');
194
    }
195
196
    public function getDateCreated()
197
    {
198
        return $this->reCache->getValue('date_created');
199
    }
200
201
    public function getLastModified()
202
    {
203
        return $this->reCache->getValue('last_modified');
204
    }
205
206
    public function getListingLastModified()
207
    {
208
        return $this->reCache->getValue('listing_last_modified');
209
    }
210
211
    public function getNode()
212
    {
213
        return $this->reCache->getValue('node');
214
    }
215
216
    public function setNode($value)
217
    {
218
        return $this->reCache->setValue('node', $value);
219
    }
220
221
    public function setStatus($value)
222
    {
223
        global $login;
224
        if (sql_value("SELECT COUNT(*) FROM `cache_status` WHERE `id`='&1'", 0, $value) == 1) {
225
            sql("SET @STATUS_CHANGE_USER_ID='&1'", $login->userid);
226
227
            return $this->reCache->setValue('status', $value);
228
        } else {
229
            return false;
230
        }
231
    }
232
233
    public function getDescLanguages()
234
    {
235
        return explode($this->reCache->getValue('desc_languages'), ',');
236
    }
237
238
    public function getDefaultDescLanguage()
239
    {
240
        return $this->reCache->getValue('default_desclang');
241
    }
242
243
    public function getProtectOldCoords()
244
    {
245
        return $this->reCache->getValue('protect_old_coords');
246
    }
247
248
    public function setProtectOldCoords($value)
249
    {
250
        return $this->reCache->setValue('protect_old_coords', $value);
251
    }
252
253
    // cache condition flags
254
    public function getNeedsMaintenance()
255
    {
256
        return $this->reCache->getValue('needs_maintenance');
257
    }
258
259
    public function setNeedsMaintenance($value)
260
    {
261
        return $this->reCache->setValue('needs_maintenance', $value);
262
    }
263
264
    public function getListingOutdated()
265
    {
266
        return $this->reCache->getValue('listing_outdated');
267
    }
268
269
    public function getListingOutdatedLogUrl()
270
    {
271
        $url = '';
272
        $rs = sql(
273
            "SELECT `id`, `listing_outdated`
274
             FROM `cache_logs`
275
             WHERE `cache_id`='&1'
276
             AND `listing_outdated`>0
277
             ORDER BY `order_date` DESC, `date_created` DESC, `id` DESC",
278
            // same sorting order as in DB function sp_update_logstat()
279
            $this->getCacheId()
280
        );
281
        if ($r = sql_fetch_assoc($rs)) {
282
            if ($r['listing_outdated'] == 2) {
283
                $url = 'viewlogs.php?cacheid=' . $this->getCacheId() . '#log' . $r['id'];
284
            }
285
        }
286
        sql_free_result($rs);
287
288
        return $url;
289
    }
290
291
    // test if af the time of insertion of an existing log the listing
292
    // was outdated and there is no newer listing-[not]-outdated-log
293
294
    public function getListingOutdatedRelativeToLog($logId)
295
    {
296
        $logDate = sql_value("SELECT `order_date` FROM `cache_logs` WHERE `id`='&1'", '', $logId);
297
298
        return
299
            sql_value(  // Is there a newer log with LO flag?
300
                "SELECT 1
301
                 FROM `cache_logs`
302
                 WHERE `cache_id`='&1'
303
                 AND `order_date`>'&2'
304
                 AND `listing_outdated`>0
305
                 LIMIT 1",
306
                0,
307
                $this->getCacheId(),
308
                $logDate
309
            ) == 0 && sql_value(  // Was the listing outdated before the log was posted?
310
                "SELECT `listing_outdated`
311
                 FROM `cache_logs`
312
                 WHERE `cache_id`='&1'
313
                 AND `listing_outdated`>0
314
                 AND `id`!='&2'
315
                 ORDER BY `order_date` DESC, `date_created` DESC, `id` DESC
316
                 LIMIT 1",
317
                0,
318
                $this->getCacheId(),
319
                $logId
320
            ) == 2;
321
    }
322
323
    public function setListingOutdated($value)
324
    {
325
        return $this->reCache->setValue('listing_outdated', $value);
326
    }
327
328
    public function getConditionHistory()
329
    {
330
        $cache_id = $this->nCacheId;
331
        $rs = sql(
332
            "SELECT `date`, `needs_maintenance`, `listing_outdated`
333
         FROM `cache_logs`
334
         WHERE `cache_id`='&1' AND (`needs_maintenance` IS NOT NULL OR `listing_outdated` IS NOT NULL)
335
         ORDER BY `date`, `id`",
336
            $cache_id
337
        );
338
        $nm = $lo = 0;
339
        $cond = [
340
            [
341
                'needs_maintenance' => $nm,
342
                'listing_outdated' => $lo,
343
                'date' => '0000-00-00 00:00:00'
344
            ]
345
        ];
346
        while ($r = sql_fetch_assoc($rs)) {
347
            if ($r['needs_maintenance'] != $nm || $r['listing_outdated'] != $lo) {
348
                $nm = $r['needs_maintenance'];
349
                $lo = $r['listing_outdated'];
350
                $cond[] = [
351
                    'needs_maintenance' => $nm,
352
                    'listing_outdated' => $lo,
353
                    'date' => $r['date']
354
                ];
355
            }
356
        }
357
        sql_free_result($rs);
358
        $cond[] = [
359
            'needs_maintenance' => $nm,
360
            'listing_outdated' => $lo,
361
            'date' => '9999-12-31 23:59:59'
362
        ];
363
364
        return $cond;
365
    }
366
367
    /**
368
     * @param int $attr_id
369
     * @return bool
370
     */
371
    public function hasAttribute($attr_id)
372
    {
373
        return sql_value(
374
            "SELECT 1
375
             FROM `caches_attributes` `ca`
376
             WHERE `ca`.`cache_id`='&1'
377
             AND `attrib_id`='&2'",
378
            0,
379
            $this->nCacheId,
380
            $attr_id
381
        ) == 1;
382
    }
383
384
    // other
385
    public function getAnyChanged()
386
    {
387
        return $this->reCache->getAnyChanged();
388
    }
389
390
    // return if successful (with insert)
391
    public function save()
392
    {
393
        if ($this->reCache->save()) {
394
            sql_slave_exclude();
395
396
            return true;
397
        } else {
398
            return false;
399
        }
400
    }
401
402
    public function requireLogPW()
403
    {
404
        return $this->reCache->getValue('logpw') != '';
405
    }
406
407
    // TODO: use prepared one way hash
408
    public function validateLogPW($nLogType, $sLogPW)
409
    {
410
        if (!$this->requireLogPW()) {
411
            return true;
412
        }
413
414
        if (sql_value("SELECT `require_password` FROM `log_types` WHERE `id`='&1'", 0, $nLogType) == 0) {
415
            return true;
416
        }
417
418
        return ($sLogPW == $this->reCache->getValue('logpw'));
419
    }
420
421
    /**
422
     * @param $nVisitUserId
423
     * @param $sRemoteAddr
424
     * @param $nCacheId
425
     * @return void
426
     */
427
    public static function visitCounter($nVisitUserId, $sRemoteAddr, $nCacheId)
0 ignored issues
show
Coding Style introduced by
visitCounter uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
428
    {
429
        global $opt, $_SERVER;
430
431
        // delete cache_visits older 1 day 60*60*24 = 86400
432
        sql(
433
            "DELETE FROM `cache_visits`
434
             WHERE `cache_id`='&1'
435
             AND `user_id_ip`!='0'
436
             AND NOW()-`last_modified`>86400",
437
            $nCacheId
438
        );
439
440
        if ($nVisitUserId == 0) {
441
            $se = explode(';', $opt['logic']['search_engines']);
442
            $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "";
443
            foreach ($se as $s) {
444
                if (strpos($ua, $s) !== false) {
445
                    return;
446
                }
447
            }   // do not count search engine views
448
449
            $sIdentifier = $sRemoteAddr;
450
        } else {
451
            $sIdentifier = $nVisitUserId;
452
        }
453
454
        // note the visit of this user
455
        sql(
456
            "INSERT INTO `cache_visits` (`cache_id`, `user_id_ip`, `count`)
457
             VALUES (&1, '&2', 1)
458
             ON DUPLICATE KEY UPDATE `count`=`count`+1",
459
            $nCacheId,
460
            $sIdentifier
461
        );
462
463
        // if the previous statement does an INSERT, it was the first visit for this user today
464
        if (sql_affected_rows() == 1) {
465
            if ($nVisitUserId != sql_value("SELECT `user_id` FROM `caches` WHERE `cache_id`='&1'", 0, $nCacheId)) {
466
                // increment the counter for this cache
467
                sql(
468
                    "INSERT INTO `cache_visits` (`cache_id`, `user_id_ip`, `count`)
469
                     VALUES (&1, '0', 1)
470
                     ON DUPLICATE KEY UPDATE `count`=`count`+1",
471
                    $nCacheId
472
                );
473
            }
474
        }
475
    }
476
477
    /**
478
     * @param $cacheId
479
     * @return array
480
     */
481
    public static function getLogsCount($cacheId)
482
    {
483
        //prepare the logs
484
        $rsLogs = sql("SELECT COUNT(*) FROM `cache_logs` WHERE `cache_id`='&1'", $cacheId);
485
        $rLog = sql_fetch_assoc($rsLogs);
486
        sql_free_result($rsLogs);
487
488
        return $rLog;
489
    }
490
491
    /**
492
     * @param integer $start
493
     * @param integer $count
494
     * @param bool $deleted
495
     * @param bool $protect_old_coords
496
     * @return array
497
     */
498
    public function getLogsArray($start, $count, $deleted = false, $protect_old_coords = false)
499
    {
500
        global $login, $translate;
501
502
        // negative or abornally high numbers like 1.0E+15 can crash the LIMIT statement
503
        if ($count <= 0 || $count > 10000) {
504
            return [];
505
        }
506
507
        $coords = [];
508
        if ($this->getType() != 7 && $this->getType() != 8 &&  // quiz cache
509
            $this->hasAttribute(61) != true &&                 // safari cache
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison !== instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
510
            $this->getStatus() != 5                            // unpublished cache
511
        ) {
512
            $rsCoords = sql(
513
                "SELECT
514
                    `date_created` `date`,
515
                    `date_created` - INTERVAL 4 SECOND AS `adjusted_date_created`,
516
                     /*
517
                        The first cache_coordinates entry is created immediately after
518
                        inserting the cache into caches table. This usually takes
519
                        a few milliseconds. We apply a 4 seconds 'safety margin' for
520
                        detecting the original coords. In the extremly unlikely case that
521
                        it took more than 4 seconds AND the owner did a coordinate change
522
                        before publish AND someone posts a log entry with date inbetween
523
                        the coord change and the publish, the coords before the change
524
                        will be exposed (which would be unpleasant but not critical).
525
526
                        Increasing the 4 seconds lag would increase the chance that
527
                        original coords which were set immediately before publish are
528
                        hidden (which would be unpleasant but not critical).
529
530
                        4 seconds was chosen as estimated shortest interval someone will
531
                        need to change coordinates of an unpublished cache AND publish
532
                        it, minus 1 second.
533
                     */
534
                    `latitude`,
535
                    `longitude`
536
                 FROM `cache_coordinates`
537
                 WHERE `cache_id`='&1'
538
                 ORDER BY `date_created` DESC",
539
                $this->nCacheId
540
            );
541
            $publish_date = $this->getDateCreated();
542
            while ($rCoord = sql_fetch_assoc($rsCoords)) {
543
                $coords[] = $rCoord;
544
                if (strtotime($rCoord['adjusted_date_created']) <= $publish_date) {
545
                    // This are the cache coords at publish time, which we will
546
                    // show as "original coords". Older coordinate changes
547
                    // (before publish) are discarded.
548
                    break;
549
                }
550
            }
551
            sql_free_result($rsCoords);
552
        }
553
554
        if ($deleted && ($login->admin && ADMIN_USER) > 0) {
555
            // admins may view owner-deleted logs
556
            $table = 'cache_logs_archived';
557
            $delfields = 'IFNULL(`u2`.`username`,"") AS `deleted_by_name`, `deletion_date`, "1" AS `deleted`';
558
            $addjoin = 'LEFT JOIN `user` `u2` ON `u2`.`user_id`=`cache_logs`.`deleted_by`';
559
        } else {
560
            $table = 'cache_logs';
561
            $delfields = '"" AS `deleted_by_name`, NULL AS `deletion_date`, "0" AS `deleted`';
562
            $addjoin = '';
563
        }
564
565
        $rsLogs = sql(
566
            "SELECT `cache_logs`.`user_id` AS `userid`,
567
                    `cache_logs`.`id` AS `id`,
568
                    `cache_logs`.`uuid` AS `uuid`,
569
                    `cache_logs`.`date` AS `date`,
570
                    `cache_logs`.`order_date` AS `order_date`,
571
                    `cache_logs`.`entry_last_modified`,
572
                    (`cache_logs`.`node` != 1 OR `cache_logs`.`entry_last_modified` != '2017-02-14 22:49:20')  /* see redmine #1109 */
573
                    AND DATEDIFF(`cache_logs`.`entry_last_modified`, `cache_logs`.`date_created`) >= 1 AS `late_modified`,
574
                    substr(`cache_logs`.`date`,12) AS `time`,  /* 00:00:01 = 00:00 logged, 00:00:00 = no time */
575
                    `cache_logs`.`type` AS `type`,
576
                    `cache_logs`.`oc_team_comment` AS `oc_team_comment`,
577
                    `cache_logs`.`needs_maintenance` AS `needs_maintenance`,
578
                    `cache_logs`.`listing_outdated` AS `listing_outdated`,
579
                    `cache_logs`.`text` AS `text`,
580
                    `cache_logs`.`text_html` AS `texthtml`,
581
                    `cache_logs`.`picture`,
582
                    " . $delfields . ",
583
                    `user`.`username` AS `username`,
584
                    IF(ISNULL(`cache_rating`.`cache_id`), 0, `cache_logs`.`type` IN (1,7)) AS `recommended`,
585
                    FALSE AS `cache_moved`
586
             FROM $table AS `cache_logs`
587
             INNER JOIN `user`
588
                 ON `user`.`user_id` = `cache_logs`.`user_id`
589
             LEFT JOIN `cache_rating`
590
                 ON `cache_logs`.`cache_id`=`cache_rating`.`cache_id`
591
                 AND `cache_logs`.`user_id`=`cache_rating`.`user_id`
592
                 AND `cache_logs`.`date`=`cache_rating`.`rating_date`
593
             " . $addjoin . "
594
             WHERE `cache_logs`.`cache_id`='&1'
595
             ORDER BY `cache_logs`.`order_date` DESC, `cache_logs`.`date_created` DESC, `id` DESC
596
             LIMIT &2, &3",
597
            $this->nCacheId,
598
            $start + 0,
599
            $count + 0
600
        );
601
602
        $logs = [];
603
        $coord_changes = (count($coords) > 1);
604
        if ($coord_changes) {
605
            $coordpos = 0;
606
            $current_coord = new coordinate($coords[0]['latitude'], $coords[0]['longitude']);
607
        }
608
        $displayed_coord_changes = 0;
609
610
        while ($rLog = sql_fetch_assoc($rsLogs)) {
611
            $pictures = [];
612
            $rsPictures = sql(
613
                "SELECT `url`, `title`, `uuid`, `id`, `spoiler`
614
                 FROM `pictures`
615
                 WHERE `object_id`='&1'
616
                 AND `object_type`=1
617
                 ORDER BY `seq`",
618
                $rLog['id']
619
            );
620
            while ($rPicture = sql_fetch_assoc($rsPictures)) {
621
                if (trim($rPicture['title']) == '') {
622
                    $rPicture['title'] = $translate->t('Picture', '', '', 0) . ' ' . (count($pictures) + 1);
623
                }
624
                $rPicture['url'] = use_current_protocol($rPicture['url']);
625
                $pictures[] = $rPicture;
626
            }
627
            sql_free_result($rsPictures);
628
            $rLog['pictures'] = $pictures;
629
            $rLog['text'] = use_current_protocol_in_html($rLog['text']);
630
631
            if ($coord_changes) {
632
                $newcoord = false;
633
                while ($coordpos < count($coords) && $coords[$coordpos]['date'] > $rLog['order_date']) {
0 ignored issues
show
Bug introduced by
The variable $coordpos 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...
634
                    if (!$newcoord) {
635
                        $newcoord = new coordinate($coords[$coordpos]['latitude'], $coords[$coordpos]['longitude']);
636
                    }
637
                    ++$coordpos;
638
                }
639
                if ($newcoord) {
640
                    if ($coordpos < count($coords)) {
641
                        $distance = geomath::calcDistance(
642
                            $newcoord->nLat,
643
                            $newcoord->nLon,
644
                            $coords[$coordpos]['latitude'],
645
                            $coords[$coordpos]['longitude']
646
                        );
647
                        if (abs($distance) > 0.005) {
648
                            $rLog['newcoord'] = $newcoord->getDecimalMinutes($protect_old_coords && $new != $current_coord);
0 ignored issues
show
Bug introduced by
The variable $new 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...
Bug introduced by
The variable $current_coord 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...
649
                            if ($protect_old_coords) {
650
                                $rLog['movedbykm'] = false;
651
                            } elseif ($distance <= 1) {
652
                                $rLog['movedbym'] = floor($distance * 1000);
653
                            } elseif ($distance < 10) {
654
                                $rLog['movedbykm'] = sprintf('%1.1f', $distance);
655
                            } else {
656
                                $rLog['movedbykm'] = round($distance);
657
                            }
658
                            $rLog['cache_moved'] = true;
659
                            ++$displayed_coord_changes;
660
                        }
661
                    } else {
662
                        // This is the original coord of the cache.
663
                        $rLog['newcoord'] = $newcoord->getDecimalMinutes($protect_old_coords);
664
                        $rLog['cache_moved'] = false;
665
                    }
666
                }
667
            }
668
669
            $logs[] = $rLog;
670
        }
671
        sql_free_result($rsLogs);
672
673
        // Append a dummy log entry for the original coordinate, if it was
674
        // not added to a a real log entry because there are logs older than the
675
        // OC cache listing (cmp. https://redmine.opencaching.de/issues/1102):
676
677
        if ($displayed_coord_changes > 0 && $coordpos < count($coords) && count($logs) > 0) {
678
            $coord = new coordinate($coords[$coordpos]['latitude'], $coords[$coordpos]['longitude']);
679
            $logs[] = [
680
                'newcoord' => $coord->getDecimalMinutes($protect_old_coords),
681
                'cache_moved' => false,
682
                'type' => false
683
            ];
684
        }
685
686
        return $logs;
687
    }
688
689
    /**
690
     * @param $userId
691
     * @param $reportReason
692
     * @param $reportNote
693
     * @return bool
694
     */
695
    public function report($userId, $reportReason, $reportNote)
696
    {
697
        sql(
698
            "INSERT INTO cache_reports (`cacheid`, `userid`, `reason`, `note`)
699
             VALUES(&1, &2, &3, '&4')",
700
            $this->nCacheId,
701
            $userId,
702
            $reportReason,
703
            $reportNote
704
        );
705
706
        return true;
707
    }
708
709
    /**
710
     * @param $userId
711
     * @return bool|string
712
     */
713
    public function addAdoption($userId)
714
    {
715
        if ($this->allowEdit() == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
716
            return "noaccess";
717
        }
718
719
        if (sql_value("SELECT COUNT(*) FROM `user` WHERE `user_id`='&1'", 0, $userId) == 0) {
720
            return "userunknown";
721
        }
722
723
        if (sql_value("SELECT COUNT(*) FROM `user` WHERE `user_id`='&1' AND `is_active_flag`=1", 0, $userId) == 0) {
724
            return "userdisabled";
725
        }
726
727
        // same user?
728
        if ($this->getUserId() == $userId) {
729
            return "self";
730
        }
731
732
        sql(
733
            "INSERT IGNORE INTO `cache_adoption` (`cache_id`, `user_id`)
734
             VALUES ('&1', '&2')",
735
            $this->nCacheId,
736
            $userId
737
        );
738
739
        return true;
740
    }
741
742
    /**
743
     * @param int $userId
744
     * @return bool
745
     */
746
    public function cancelAdoption($userId)
747
    {
748
        global $login;
749
750
        if ($this->allowEdit() == false && $login->userid != $userId) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
751
            return false;
752
        }
753
754
        sql(
755
            "DELETE FROM `cache_adoption`
756
             WHERE `user_id`='&1'
757
             AND `cache_id`='&2'",
758
            $userId,
759
            $this->nCacheId
760
        );
761
762
        return true;
763
    }
764
765
    /**
766
     * @param int $userId
767
     * @return bool
768
     */
769
    public function commitAdoption($userId)
770
    {
771
        global $login;
772
773
        // cache_adoption exists?
774
        if (sql_value(
775
                "SELECT COUNT(*) FROM `cache_adoption` WHERE `cache_id`='&1' AND `user_id`='&2'",
776
                0,
777
                $this->nCacheId,
778
                $userId
779
            ) == 0
780
        ) {
781
            return false;
782
        }
783
784
        // new user active?
785
        if (sql_value("SELECT `is_active_flag` FROM `user` WHERE `user_id`='&1'", 0, $userId) != 1) {
786
            return false;
787
        }
788
789
        sql(
790
            "INSERT INTO `logentries` (`module`, `eventid`, `userid`, `objectid1`, `objectid2`, `logtext`)
791
             VALUES ('cache', 5, '&1', '&2', '&3', '&4')",
792
            $login->userid,
793
            $this->nCacheId,
794
            0,
795
            'Cache ' . sql_escape($this->nCacheId) . ' has changed the owner from userid ' . sql_escape(
796
                $this->getUserId()
797
            ) . ' to ' . sql_escape($userId) . ' by ' . sql_escape($login->userid)
798
        );
799
        // Adoptions now are recorded by trigger in cache_adoptions table.
800
        // Recording adoptions in 'logentries' may be discarded after ensuring that the
801
        // log entries are not used anywhere.
802
        sql("UPDATE `caches` SET `user_id`='&1' WHERE `cache_id`='&2'", $userId, $this->nCacheId);
803
        sql("DELETE FROM `cache_adoption` WHERE `cache_id`='&1'", $this->nCacheId);
804
805
        $this->reCache->setValue('user_id', $userId);
806
807
        return true;
808
    }
809
810
    // checks if $userId has adopted this cache
811
    public function hasAdopted($userId)
812
    {
813
        // cache_adoption exists?
814
        return sql_value(
815
            "SELECT COUNT(*)
816
             FROM `cache_adoption`
817
             WHERE `cache_id`='&1'
818
             AND `user_id`='&2'",
819
            0,
820
            $this->nCacheId,
821
            $userId
822
        ) != 0;
823
    }
824
825
    // true if anyone can view the cache
826
    public function isPublic()
827
    {
828
        return (sql_value("SELECT `allow_user_view` FROM `cache_status` WHERE `id`='&1'", 0, $this->getStatus()) == 1);
829
    }
830
831
    public function allowView()
832
    {
833
        global $login;
834
835
        if ($this->isPublic()) {
836
            return true;
837
        }
838
839
        $login->verify();
840
841
        if (($login->admin & ADMIN_USER) == ADMIN_USER) {
842
            return true;
843
        } elseif ($this->getUserId() == $login->userid) {
844
            return true;
845
        }
846
847
        return false;
848
    }
849
850 View Code Duplication
    public function allowEdit()
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...
851
    {
852
        global $login;
853
854
        $login->verify();
855
        if ($this->getUserId() == $login->userid) {
856
            return true;
857
        }
858
859
        return false;
860
    }
861
862
    public function allowLog()
863
    {
864
        global $login;
865
866
        $login->verify();
867
        if ($this->getUserId() == $login->userid || $login->hasAdminPriv(ADMIN_USER)) {
868
            return true;
869
        }
870
871
        return (sql_value("SELECT `allow_user_log` FROM `cache_status` WHERE `id`='&1'", 0, $this->getStatus()) == 1);
872
    }
873
874
    public function isRecommendedByUser($nUserId)
875
    {
876
        return sql_value(
877
            "SELECT COUNT(*) FROM `cache_rating` WHERE `cache_id`='&1' AND `user_id`='&2'",
878
            0,
879
            $this->nCacheId,
880
            $nUserId
881
        ) > 0;
882
    }
883
884
    public function addRecommendation($nUserId, $logdate)
885
    {
886
        // rating_date will be set to NOW() by Insert-trigger
887
        sql(
888
            "INSERT IGNORE INTO `cache_rating` (`cache_id`, `user_id`, `rating_date`) VALUES ('&1', '&2', '&3')",
889
            $this->nCacheId,
890
            $nUserId,
891
            $logdate
892
        );
893
    }
894
895
    public function removeRecommendation($nUserId)
896
    {
897
        sql("DELETE FROM `cache_rating` WHERE `cache_id`='&1' AND `user_id`='&2'", $this->nCacheId, $nUserId);
898
    }
899
900
    // retrieves admin cache history data and stores it to template variables
901
    // for display by adminhistory.tpl and adminreports.tpl
902
    public function setTplHistoryData($exclude_report_id)
903
    {
904
        global $opt, $tpl;
905
906
        // (other) reports for this cache
907
        $rs = sql(
908
            "SELECT `cr`.`id`,
909
                    `cr`.`date_created`,
910
                    `cr`.`lastmodified`,
911
                    `cr`.`userid`,
912
                    `cr`.`adminid`,
913
                    `users`.`username` AS `usernick`,
914
                    `admins`.`username` AS `adminnick`,
915
                    IFNULL(`tt`.`text`, `crs`.`name`) AS `status`,
916
                    IFNULL(`tt2`.`text`, `crr`.`name`) AS `reason`
917
             FROM `cache_reports` AS `cr`
918
             LEFT JOIN `cache_report_reasons` AS `crr`
919
                 ON `cr`.`reason`=`crr`.`id`
920
             LEFT JOIN `user` AS `users`
921
                 ON `users`.`user_id`=`cr`.`userid`
922
             LEFT JOIN `user` AS `admins`
923
                 ON `admins`.`user_id`=`cr`.`adminid`
924
             LEFT JOIN `cache_report_status` AS `crs`
925
                 ON `cr`.`status`=`crs`.`id`
926
             LEFT JOIN `sys_trans_text` AS `tt`
927
                 ON `crs`.`trans_id`=`tt`.`trans_id`
928
                 AND `tt`.`lang`='&2'
929
             LEFT JOIN `sys_trans_text` AS `tt2`
930
                 ON `crr`.`trans_id`=`tt2`.`trans_id`
931
                 AND `tt2`.`lang`='&2'
932
             WHERE `cr`.`cacheid`='&1'
933
                 AND `cr`.`id`<>'&3'
934
             ORDER BY `cr`.`status`,`cr`.`id` DESC",
935
            $this->getCacheId(),
936
            $opt['template']['locale'],
937
            $exclude_report_id
938
        );
939
        $tpl->assign_rs('reports', $rs);
940
        sql_free_result($rs);
941
942
        // user; deleted logs
943
        $rs = sql("SELECT * FROM `caches` WHERE `cache_id`='&1'", $this->getCacheId());
944
        $rCache = sql_fetch_array($rs);
945
        $tpl->assign('cache', $rCache);
946
        sql_free_result($rs);
947
        $tpl->assign(
948
            'ownername',
949
            sql_value("SELECT `username` FROM `user` WHERE `user_id`='&1'", "", $rCache['user_id'])
950
        );
951
952
        $tpl->assign('deleted_logs', $this->getLogsArray(0, 1000, true));
953
954
        // status changes
955
        $rs = sql(
956
            "SELECT `csm`.`date_modified`,
957
                    `csm`.`old_state` AS `old_status_id`,
958
                    `csm`.`new_state` AS `new_status_id`,
959
                    `user`.`username`,
960
                    `user`.`user_id`,
961
                    IFNULL(`stt_old`.`text`,`cs_old`.`name`) AS `old_status`,
962
                    IFNULL(`stt_new`.`text`,`cs_new`.`name`) AS `new_status`
963
            FROM `cache_status_modified` `csm`
964
            LEFT JOIN `cache_status` `cs_old`
965
                ON `cs_old`.`id`=`csm`.`old_state`
966
            LEFT JOIN `sys_trans_text` `stt_old`
967
                ON `stt_old`.`trans_id`=`cs_old`.`trans_id`
968
                AND `stt_old`.`lang`='&2'
969
            LEFT JOIN `cache_status` `cs_new`
970
                ON `cs_new`.`id`=`csm`.`new_state`
971
            LEFT JOIN `sys_trans_text` `stt_new`
972
                ON `stt_new`.`trans_id`=`cs_new`.`trans_id`
973
                AND `stt_new`.`lang`='&2'
974
            LEFT JOIN `user`
975
                ON `user`.`user_id`=`csm`.`user_id`
976
            WHERE `cache_id`='&1'
977
            ORDER BY `date_modified` DESC",
978
            $this->getCacheId(),
979
            $opt['template']['locale']
980
        );
981
        $tpl->assign_rs('status_changes', $rs);
982
        sql_free_result($rs);
983
984
        // coordinate changes
985
        $rs = sql(
986
            "SELECT `cc`.`date_created`, `cc`.`longitude`, `cc`.`latitude`,
987
                          IFNULL(`admin`.`user_id`, `owner`.`user_id`) AS `user_id`,
988
                          IFNULL(`admin`.`username`, `owner`.`username`) AS `username`
989
                     FROM `cache_coordinates` `cc`
990
                LEFT JOIN `caches` ON `caches`.`cache_id`=`cc`.`cache_id`
991
                LEFT JOIN `user` `owner` ON `owner`.`user_id`=`caches`.`user_id`
992
                LEFT JOIN `user` `admin` ON `admin`.`user_id`=`cc`.`restored_by`
993
                    WHERE `cc`.`cache_id`='&1'
994
                 ORDER BY `cc`.`date_created` DESC",
995
            $this->getCacheId()
996
        );
997
        $coords = [];
998
        while ($rCoord = sql_fetch_assoc($rs)) {
999
            $coord = new coordinate($rCoord['latitude'], $rCoord['longitude']);
1000
            $coords[] = [
1001
                'date' => $rCoord['date_created'],
1002
                'coord' => $coord->getDecimalMinutes(),
1003
                'user_id' => $rCoord['user_id'],
1004
                'username' => $rCoord['username']
1005
            ];
1006
        }
1007
        sql_free_result($rs);
1008
        $tpl->assign('coordinates', $coords);
1009
1010
        // Adoptions
1011
        $rs = sql(
1012
            "SELECT `cache_adoptions`.`date`,
1013
                          `cache_adoptions`.`from_user_id`,
1014
                          `cache_adoptions`.`to_user_id`,
1015
                          `from_user`.`username` AS `from_username`,
1016
                          `to_user`.`username` AS `to_username`
1017
                     FROM `cache_adoptions`
1018
                LEFT JOIN `user` `from_user` ON `from_user`.`user_id`=`from_user_id`
1019
                LEFT JOIN `user` `to_user` ON `to_user`.`user_id`=`to_user_id`
1020
                    WHERE `cache_id`='&1'
1021
                 ORDER BY `cache_adoptions`.`date`, `cache_adoptions`.`id`",
1022
            $this->getCacheId()
1023
        );
1024
        $tpl->assign_rs('adoptions', $rs);
1025
        sql_free_result($rs);
1026
    }
1027
1028
    public function logTypeAllowed($logType, $oldLogType = 0)
1029
    {
1030
        // check if given logType is valid for this cache type
1031
        return logtype_ok($this->getCacheId(), $logType, $oldLogType);
1032
    }
1033
1034
    /**
1035
     * @param int $logId
1036
     * @param int $oldLogType
1037
     * @param int $newLogType
1038
     */
1039
    public function updateCacheStatusFromLatestLog($logId, $oldLogType, $newLogType)
1040
    {
1041
        if ($newLogType != $oldLogType) {
1042
            // get new cache-status property of the new log type
1043
            $cacheStatus = sql_value(
1044
                "SELECT `cache_status` FROM `log_types` WHERE `id`='&1'",
1045
                0,
1046
                $newLogType
1047
            );
1048
1049
            if ($cacheStatus != 0) {
1050
                // If the new log type is a status-changing type, it's easy -
1051
                // we can directly change the cache status:
1052
1053
                $this->setStatus($cacheStatus);
1054
            } else {
1055
                // If the new log type is not status-changing, but the old type was, the
1056
                // cache status may need to be recalculated. To keep things simple, we will
1057
                // always recalculate the cache status in this case.
1058
1059
                $cacheStatus = sql_value(
1060
                    "SELECT `cache_status` FROM `log_types` WHERE `id`='&1'",
1061
                    0,
1062
                    $oldLogType
1063
                );
1064
                if ($cacheStatus != 0) {
1065
                    // The only safe way to restore an old cache status is from table
1066
                    // cache_status_modified. This is available since April 2013. As we
1067
                    // do not allow status-changes by editing logs that are older than
1068
                    // half a year, this is ok.
1069
1070
                    // The cache status is updated in a separate operation immediatly
1071
                    // (usually within a millisecond or so) after saving a log, so we must
1072
                    // apply some time lag to be on the safe side. It should be safe to
1073
                    // assume that users will not edit the log type twice within <= 2 seconds:
1074
1075
                    $logCreated = sql_value(
1076
                        "SELECT `date_created` FROM `cache_logs` WHERE `id`='&1'",
1077
                        null,
1078
                        $logId
1079
                    );
1080
                    $oldCacheStatus = sql_value(
1081
                        "SELECT `old_state`
1082
                         FROM `cache_status_modified`
1083
                         WHERE `cache_id`='&1'
1084
                         AND '&2' <= `date_modified`
1085
                         AND TIMESTAMPDIFF(SECOND, '&2', `date_modified`) <= 2
1086
                         ORDER BY `date_modified` DESC
1087
                         LIMIT 1",
1088
                        0,
1089
                        $this->getCacheId(),
1090
                        $logCreated
1091
                    );
1092
1093
                    if ($oldCacheStatus > 0) {
1094
                        $this->setStatus($oldCacheStatus);
1095
                    }
1096
                }
1097
            }
1098
        }
1099
    }
1100
1101
    // $userLogType:
1102
    //   Logtype selected by the user, or null if not applicable
1103
1104
    public function getUserLogTypes($userLogType, $oldLogType = 0, $statusLogs = true)
1105
    {
1106
        $logTypes = [];
1107
1108
        $logtypeNames = get_logtype_names();
1109
        $allowedLogtypes = get_cache_log_types($this->getCacheId(), $oldLogType, $statusLogs);
1110
        $defaultLogType = $userLogType;
1111
        if (!logtype_ok($this->getCacheId(), $defaultLogType, $oldLogType, $statusLogs)) {
1112
            $defaultLogType = $allowedLogtypes[0];
1113
        }
1114
1115
        // prepare array
1116
        $i = 0;
1117
        foreach ($allowedLogtypes as $logtype) {
1118
            $logTypes[$i]['selected'] = ($logtype == $defaultLogType) ? true : false;
1119
            $logTypes[$i]['name'] = $logtypeNames[$logtype];
1120
            $logTypes[$i]['id'] = $logtype;
1121
            $i++;
1122
        }
1123
1124
        // return
1125
        return $logTypes;
1126
    }
1127
1128
    public function teamcommentAllowed($logType, $oldTeamComment = false)
1129
    {
1130
        // checks if teamcomment is allowed
1131
        return teamcomment_allowed($this->getCacheId(), $logType, $oldTeamComment);
1132
    }
1133
1134
    public function statusUserLogAllowed()
1135
    {
1136
        return sql_value(
1137
            "SELECT `cache_status`.`allow_user_log`
1138
             FROM `cache_status`,`caches`
1139
             WHERE `caches`.`status`=`cache_status`.`id`
1140
             AND `caches`.`cache_id`='&1'",
1141
            0,
1142
            $this->getCacheId()
1143
        ) == 1;
1144
    }
1145
1146
    /**
1147
     * @param $logId
1148
     * @return bool
1149
     */
1150
    public function statusChangeAllowedForLog($logId)
1151
    {
1152
        $latestLogId = sql_value(
1153
            "SELECT `id` FROM `cache_logs`
1154
             WHERE `cache_id`='&1' AND DATEDIFF(NOW(), `date_created`) < 180
1155
             ORDER BY `order_date` DESC, `date_created` DESC, `id` DESC
1156
             LIMIT 1",
1157
            0,
1158
            $this->nCacheId
1159
        );
1160
1161
        return ($logId == $latestLogId);
1162
    }
1163
}
1164