Completed
Push — master ( 066d89...19607d )
by De
01:54
created

PdoMysqlCollector::setGarbageCollector()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 6
rs 9.4286
cc 1
eloc 4
nc 1
nop 2
1
<?php
2
3
namespace Sokil\FraudDetector\Collector;
4
5
/**
6
 * Using memory table of MySQL storate as collector
7
 * Amount of space on memory table limited by `max_heap_table_size`, so set prefered value.
8
 */
9
class PdoMysqlCollector extends AbstractPdoCollector
10
{
11
    private $gcCheckInterval = 1200;
12
13
    private $gcSessionInterval = 1200;
14
15
    public function setGarbageCollector($checkInterval, $sessionInterval)
16
    {
17
        $this->gcCheckInterval = (int) $checkInterval;
18
        $this->gcSessionInterval = (int) $sessionInterval;
19
        return $this;
20
    }
21
22
    public function isRateLimitExceed()
23
    {
24
        $timeNow = microtime(true);
25
26
        $query = 'SELECT 1
27
            FROM ' . $this->getTableName() . '
28
            WHERE
29
                `key` = :key AND
30
                `expired` >= :timeNow AND
31
                `requestNum` >= :maxRequestNum';
32
33
        $parameters = array(
34
            ':key' => $this->key,
35
            ':maxRequestNum' => $this->requestNum,
36
            ':timeNow' => $timeNow,
37
        );
38
39
        try {
40
            $stmt = $this->pdo->prepare($query);
41
            $result = @$stmt->execute($parameters);
42
            if(!$result) {
43
                throw new \PDOException('Table not exists');
44
            }
45
        } catch (\PDOException $e) {
46
            // if exception occurs, than no table still created
47
            return false;
48
        }
49
50
        // if record found than key has exceed requests
51
        if(!$stmt->rowCount()) {
52
            return false;
53
        }
54
55
        return true;
56
    }
57
58
    private function createTable()
59
    {
60
        $this->pdo->query('
61
            CREATE TABLE ' . $this->getTableName() . '(
62
                `key` varchar(255) PRIMARY KEY NOT NULL,
63
                `requestNum` int NOT NULL DEFAULT 0,
64
                `expired` numeric(13, 3)
65
            ) ENGINE=Memory CHARSET=utf8;
66
        ');
67
68
    }
69
70
    public function collect()
71
    {
72
        $timeNow = microtime(true);
73
74
        // check if record already exists and get current values
75
        try {
76
            $query = '
77
                SELECT requestNum, expired
78
                FROM ' . $this->getTableName() . '
79
                WHERE `key` = :key
80
                FOR UPDATE';
81
82
            $stmt = $this->pdo->prepare($query);
83
            $result = @$stmt->execute(array(
84
                ':key' => $this->key,
85
            ));
86
87
            if(!$result) {
88
                throw new \PDOException('Table not exists');
89
            }
90
91
92
        } catch (\PDOException $e) {
93
            // table yet not created
94
            $this->createTable();
95
            $this->collect();
96
            return;
97
        }
98
99
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
100
101
        if(!$row) {
102
            // record not exists
103
            $query = '
104
                INSERT INTO ' . $this->getTableName() . '(`key`, `requestNum`, `expired`)
105
                VALUES (:key, 1, :expired)
106
                ON DUPLICATE KEY UPDATE requestNum = requestNum + 1
107
            ';
108
109
            $stmt = $this->pdo->prepare($query);
110
            $stmt->bindValue(':key', $this->key);
111
            $stmt->bindValue(':expired', $timeNow + $this->timeInterval);
112
            $stmt->execute();
113
114
            return;
115
116
        }
117
118
        $expiredTimestamp = (float) $row['expired'];
119
120
        if($timeNow <= $expiredTimestamp) {
121
            // in time slot - increment
122
            $query = '
123
                UPDATE ' . $this->getTableName() . '
124
                SET requestNum = requestNum + 1
125
                WHERE `key` = :key
126
            ';
127
            $parameters = array(
128
                ':key' => $this->key,
129
            );
130
        } else {
131
            //outside time slot - set new
132
            $query = '
133
                UPDATE ' . $this->getTableName() . '
134
                SET
135
                    requestNum = 1,
136
                    expired = :expired
137
                WHERE `key` = :key
138
            ';
139
            $parameters = array(
140
                ':key' => $this->key,
141
                ':expired' => $timeNow + $this->timeInterval,
142
            );
143
        }
144
145
        $stmt = $this->pdo->prepare($query);
146
        $stmt->execute($parameters);
147
148
149
        // garbage collector
150
        if($timeNow % $this->gcCheckInterval === 0) {
151
            $query = '
0 ignored issues
show
Unused Code introduced by
$query 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...
152
                DELETE FROM ' . $this->getTableName() . '
153
                WHERE expired < ' . ($timeNow - $this->gcSessionInterval);
154
        }
155
156
    }
157
}
158