Tiqr_StateStorage_File::getFilenameByKey()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 6
ccs 5
cts 5
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php 
2
/**
3
 * This file is part of the tiqr project.
4
 * 
5
 * The tiqr project aims to provide an open implementation for 
6
 * authentication using mobile devices. It was initiated by 
7
 * SURFnet and developed by Egeniq.
8
 *
9
 * More information: http://www.tiqr.org
10
 *
11
 * @author Ivo Jansch <[email protected]>
12
 * 
13
 * @package tiqr
14
 *
15
 * @license New BSD License - See LICENSE file for details.
16
 *
17
 * @copyright (C) 2010-2011 SURFnet BV
18
 */
19
20
use Psr\Log\LoggerInterface;
21
22
23
/**
24
 * File based implementation to store session state data. 
25
 * Note that it is more secure to use a memory based storage such as memcached.
26
 * This implementation is mostly for demo, test or experimental setups that 
27
 * do not have access to a memcache instance.
28
 * 
29
 * This StateStorage implementation has no options, files are always stored
30
 * in /tmp and prefixed with tiqr_state_*
31
 * 
32
 * @author ivo
33
 *
34
 */
35
class Tiqr_StateStorage_File implements Tiqr_StateStorage_StateStorageInterface, Tiqr_HealthCheck_Interface
36
{
37
    private $logger;
38
39
    private $path;
40
41 8
    public function __construct(string $path, LoggerInterface $logger)
42
    {
43 8
        $this->logger = $logger;
44 8
        $this->path = $path;
45
    }
46
47
    /**
48
     * @see Tiqr_StateStorage_StateStorageInterface::setValue()
49
     */
50 6
    public function setValue(string $key, $value, int $expire=0): void
51
    {
52 6
        if (empty($key)) {
53 1
            throw new InvalidArgumentException('Empty key not allowed');
54
        }
55
56 6
        $envelope = array("expire"=>$expire,
57 6
                          "createdAt"=>time(),
58 6
                          "value"=>$value);
59 6
        $filename = $this->getFilenameByKey($key);
60
        
61 6
        if (!file_put_contents($filename, serialize($envelope))) {
62
            throw new ReadWriteException(sprintf('Unable to store "%s" state to the filesystem', $key));
63
        }
64
    }
65
66
    /**
67
     * @see Tiqr_StateStorage_StateStorageInterface::unsetValue()
68
     */
69 3
    public function unsetValue(string $key): void
70
    {
71 3
        if (empty($key)) {
72
            throw new InvalidArgumentException('Empty key not allowed');
73
        }
74
75 3
        $filename = $this->getFilenameByKey($key);
76 3
        if (file_exists($filename) && !unlink($filename)) {
77
            throw new ReadWriteException(
78
                sprintf(
79
                    'Unable to unlink the "%s" value from state storage on filesystem',
80
                    $key
81
                )
82
            );
83
        }
84
    }
85
    
86
    /**
87
     * @see Tiqr_StateStorage_StateStorageInterface::getValue()
88
     */
89 5
    public function getValue(string $key)
90
    {
91 5
        if (empty($key)) {
92
            throw new InvalidArgumentException('Empty key not allowed');
93
        }
94
95 5
        $filename = $this->getFilenameByKey($key);
96 5
        if (file_exists($filename)) {
97 4
            $envelope = unserialize(file_get_contents($filename), ['allowed_classes' => false]);
98
            // This data is time-limited. If it's too old we discard it.
99 4
            if (($envelope["expire"] != 0) && time() - $envelope["createdAt"] > $envelope["expire"]) {
100
                $this->unsetValue($key);
101
                $this->logger->notice('Unable to retrieve the state storage value, it is expired');
102
                return null;
103
            }
104 4
            return $envelope["value"];
105
        }
106 3
        $this->logger->notice('Unable to retrieve the state storage value, file not found');
107 3
        return NULL;
108
    }
109
110 6
    private function getPath(): string
111
    {
112 6
        if (substr($this->path, -1)!=="/") {
113 6
            return $this->path . "/";
114
        }
115
        return $this->path;
116
    }
117
118
    /**
119
     * Determine the name of a temporary file to hold the contents of $key
120
     */
121 6
    private function getFilenameByKey(string $key): string
122
    {
123 6
        return sprintf(
124 6
            "%stiqr_state_%s",
125 6
            $this->getPath(),
126 6
            strtr(base64_encode($key), '+/', '-_')
127 6
        );
128
    }
129
130 8
    public function init(): void
131
    {
132
        # Nothing to do here
133 8
    }
134
135
    /**
136
     * @see Tiqr_HealthCheck_Interface::healthCheck()
137
     */
138 1
    public function healthCheck(string &$statusMessage = ''): bool
139
    {
140
        try {
141
            // Generate a random key and use it to store a value
142 1
            $key = bin2hex(random_bytes(16));
143 1
            $this->setValue($key, 'healthcheck', 10);
144 1
            $this->unsetValue($key);    // Cleanup
145
        } catch (Exception $e) {
146
            $statusMessage = 'Tiqr_StateStorage_File: error setting key: ' . $e->getMessage();
147
            return false;
148
        }
149
150 1
        return true;
151
    }
152
}
153