Passed
Pull Request — develop (#38)
by Pieter van der
03:27
created

Tiqr_StateStorage_Pdo::keyExists()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 4
c 3
b 0
f 0
dl 0
loc 7
ccs 4
cts 5
cp 0.8
rs 10
cc 2
nc 2
nop 1
crap 2.032
1
<?php
2
3
use Psr\Log\LoggerInterface;
4
5
/**
6
 * This file is part of the tiqr project.
7
 * 
8
 * The tiqr project aims to provide an open implementation for 
9
 * authentication using mobile devices. It was initiated by 
10
 * SURFnet and developed by Egeniq.
11
 *
12
 * More information: http://www.tiqr.org
13
 *
14
 * @author Patrick Honing <[email protected]>
15
 * 
16
 * @package tiqr
17
 *
18
 * @license New BSD License - See LICENSE file for details.
19
 *
20
 * @copyright (C) 2010-2012 SURFnet BV
21
 * 
22
 * 
23
 * Create SQL table (MySQL):
24
 * CREATE TABLE `tiqrstate` (`key` varchar(255) PRIMARY KEY,`expire` int,`value` text);
25
 * 
26
 */
27
28
29
class Tiqr_StateStorage_Pdo extends Tiqr_StateStorage_Abstract
30
{
31
    /**
32
     * @var PDO
33
     */
34
    protected $handle;
35
36
    /**
37
     * @var string
38
     */
39
    private $tablename;
40
41
    /**
42
     * @var int
43
     */
44
    private $cleanupProbability;
45
46
    /**
47
     * @param PDO $pdoInstance The PDO instance where all state storage operations are performed on
48
     * @param LoggerInterface
49
     * @param string $tablename The tablename that is used for storing and retrieving the state storage
50
     * @param float $cleanupProbability The probability the expired state storage items are removed on a 'setValue' call. Example usage: 0 = never, 0.5 = 50% chance, 1 = always
51
     *
52
     * @throws RuntimeException when an invalid cleanupProbability is configured
53
     */
54 5
    public function __construct(PDO $pdoInstance, LoggerInterface $logger, string $tablename, float $cleanupProbability)
55
    {
56 5
        if ($cleanupProbability < 0 || $cleanupProbability > 1) {
57 2
            throw new RuntimeException('The probability for removing the expired state should be expressed in a floating point value between 0 and 1.');
58
        }
59 5
        $this->cleanupProbability = $cleanupProbability;
60 5
        $this->tablename = $tablename;
61 5
        $this->handle = $pdoInstance;
62 5
        $this->logger = $logger;
63 5
    }
64
65 3
    private function keyExists($key)
66
    {
67 3
        $sth = $this->handle->prepare("SELECT `key` FROM ".$this->tablename." WHERE `key` = ?");
68 3
        if ($sth->execute(array($key))) {
69 3
            return $sth->fetchColumn();
70
        }
71
        $this->logger->info('The state storage key could not be found in the database');
72
    }
73
74 2
    private function cleanExpired() {
75 2
        $sth = $this->handle->prepare("DELETE FROM ".$this->tablename." WHERE `expire` < ? AND NOT `expire` = 0");
76 2
        $result = $sth->execute(array(time()));
77 2
        if (!$result || $sth->rowCount() === 0){
78
            // No exception is thrown here. The application can continue with expired state for now.
79 2
            $this->logger->error('Unable to remove expired keys from the pdo state storage');
80
        }
81 2
    }
82
    
83
    /**
84
     * (non-PHPdoc)
85
     * @see library/tiqr/Tiqr/StateStorage/Tiqr_StateStorage_Abstract::setValue()
86
     */
87 2
    public function setValue($key, $value, $expire=0)
88
    {
89 2
        if (((float) rand() /(float) getrandmax()) < $this->cleanupProbability) {
90 2
            $this->cleanExpired();
91
        }
92 2
        if ($this->keyExists($key)) {
93 1
            $sth = $this->handle->prepare("UPDATE ".$this->tablename." SET `value` = ?, `expire` = ? WHERE `key` = ?");
94
        } else {
95 2
            $sth = $this->handle->prepare("INSERT INTO ".$this->tablename." (`value`,`expire`,`key`) VALUES (?,?,?)");
96
        }
97
        // $expire == 0 means never expire
98 2
        if ($expire != 0) {
99 2
            $expire+=time();    // Store unix timestamp after which the expires
100
        }
101 2
        if (!$sth->execute(array(serialize($value),$expire,$key))) {
102
            throw new ReadWriteException(sprintf('Unable to store "%s" state to the PDO', $key));
103
        }
104 2
    }
105
        
106
    /**
107
     * (non-PHPdoc)
108
     * @see library/tiqr/Tiqr/StateStorage/Tiqr_StateStorage_Abstract::unsetValue()
109
     */
110 2
    public function unsetValue($key)
111
    {
112 2
        if ($this->keyExists($key)) {
113 1
            $sth = $this->handle->prepare("DELETE FROM " . $this->tablename . " WHERE `key` = ?");
114 1
            $result = $sth->execute(array($key));
115 1
            if (!$result || $sth->rowCount() === 0) {
116
                throw new ReadWriteException(
117
                    sprintf(
118
                        'Unable to unlink the "%s" value from state storage, key not found on pdo',
119
                        $key
120
                    )
121
                );
122
            }
123 1
            return;
124
        }
125 1
        $this->logger->info(sprintf('Unable to unlink the "%s" value from state storage, key does not exist on pdo', $key));
126 1
    }
127
    
128
    /**
129
     * (non-PHPdoc)
130
     * @see library/tiqr/Tiqr/StateStorage/Tiqr_StateStorage_Abstract::getValue()
131
     */
132 1
    public function getValue($key)
133
    {
134 1
        if ($this->keyExists($key)) {
135 1
            $sth = $this->handle->prepare("SELECT `value` FROM ".$this->tablename." WHERE `key` = ? AND (`expire` >= ? OR `expire` = 0)");
136 1
            if (false === $sth) {
137
                $this->logger->error('Unable to prepare the get key statement');
138
                return NULL;
139
            }
140 1
            if (false === $sth->execute(array($key, time())) ) {
141
                $this->logger->error('Unable to get key from the pdo state storage');
142
                return NULL;
143
            }
144 1
            $result = $sth->fetchColumn();
145 1
            return  unserialize($result);
146
        }
147 1
        $this->logger->info('Unable to find key in the pdo state storage');
148 1
        return NULL;
149
    }
150
}
151