Issues (25)

DBConnector.class.php (1 issue)

Severity
1
<?php namespace palma;
2
3
// Copyright (C) 2014 Universitätsbibliothek Mannheim
4
// See file LICENSE for license details.
5
6
// Authors: Alexander Wagner, Stefan Weil
7
8
require_once('globals.php');
9
10
class DBConnector extends \SQLite3
11
{
12
    const SQL_CREATE_TABLES = <<< eod
13
BEGIN EXCLUSIVE TRANSACTION;
14
PRAGMA foreign_keys = ON;
15
16
CREATE TABLE IF NOT EXISTS setting (
17
  key VARCHAR (10) PRIMARY KEY,
18
  value VARCHAR (20)
19
);
20
INSERT OR IGNORE INTO setting VALUES ('layout', 'g1x1');
21
INSERT OR IGNORE INTO setting VALUES ('pin', '');
22
23
CREATE TABLE IF NOT EXISTS user (
24
  userid INTEGER PRIMARY KEY,
25
  name VARCHAR (30) UNIQUE,
26
  count INTEGER,
27
  enabled INTEGER
28
);
29
30
-- Table with user name, IP address and device type (laptop, tablet, mobile).
31
CREATE TABLE IF NOT EXISTS address (
32
  userid INTEGER,
33
  address VARCHAR (30),
34
  device VARCHAR (6),
35
  FOREIGN KEY(userid) REFERENCES user(userid)
36
);
37
38
-- TODO: Entry 'userid' in table 'window' should refer to user(userid):
39
-- userid INTEGER REFERENCES user(userid)
40
-- The software currently does not handle this correctly, so we had to remove
41
-- the reference because it fails with pragma foreign_keys.
42
CREATE TABLE IF NOT EXISTS window (
43
  id INTEGER PRIMARY KEY,
44
  win_id VARCHAR (3),
45
  section INTEGER,
46
  state VARCHAR (10),
47
  file VARCHAR (255),
48
  handler VARCHAR (255),
49
  userid INTEGER,
50
  date DATETIME
51
);
52
END TRANSACTION;
53
eod;
54
55
    const SQL_RESET_TABLES = <<< eod
56
            DROP TABLE address;
57
            DROP TABLE setting;
58
            DROP TABLE IF EXISTS settings;
59
            DROP TABLE user;
60
            DROP TABLE window;
61
eod;
62
63
    // TODO: allow additional flags for constructor:
64
    // $flags = SQLITE3_OPEN_READWRITE|SQLITE3_OPEN_CREATE
65
    // $encryption_key
66
    public function __construct($filename = false)
67
    {
68
        if (!$filename) {
69
            $filename = 'palma.db';
70
        }
71
        trace("DBConnector db file = $filename");
72
        parent::__construct($filename);
73
74
        // Wait up to 10000 ms when the database is locked.
75
        $this->busyTimeout(10000);
76
77
        // Create any missing tables.
78
        $this->exec(self::SQL_CREATE_TABLES);
79
    }
80
81
    public function resetTables()
82
    {
83
        $this->exec(self::SQL_RESET_TABLES . self::SQL_CREATE_TABLES);
84
    }
85
86
    public function countWindows()
87
    {
88
        $numRows = $this->querySingle('SELECT count(*) FROM window WHERE state="active"');
89
        return $numRows;
90
    }
91
92
    public function nextID()
93
    {
94
        // Find the first unused monitor section and return its number.
95
        $quadrant_ids = array(1, 2, 3, 4);
96
        $window_db_ids = array();
97
98
        $window_keys = @$this->query('SELECT DISTINCT(id) FROM window');
99
        while ($row = $window_keys->fetchArray()) {
100
            array_push($window_db_ids, $row['id']);
101
        }
102
        $window_keys->finalize();
103
        //~ trace("ids in QD " . serialize($quadrant_ids));
104
        //~ trace("ids in DB " . serialize($window_db_ids));
105
106
        $next_ids = array_values(array_diff($quadrant_ids, $window_db_ids));
107
        //~ trace("ids in NXT " . serialize($next_ids));
108
        if (count($next_ids) > 0) {
109
            $next = $next_ids[0];
110
        } else {
111
            $next = $this->querySingle('SELECT MAX(id) FROM window') + 1;
112
        }
113
        return $next;
114
    }
115
116
    public function ipAddress()
117
    {
118
        $ip = 'unknown';
119
        if (isset($_SERVER['HTTP_X_FORWARED_FOR'])) {
120
            // Server is hidden behind a proxy.
121
            // Proxy for loopback ip might indicate spoofing
122
            if (!in_array($_SERVER['HTTP_X_FORWARED_FOR'], array('127.0.0.1', '::1'))) {
123
                $ip = $_SERVER['HTTP_X_FORWARED_FOR'];
124
            }
125
        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
126
            // Client has direct access to the server.
127
            $ip = $_SERVER['REMOTE_ADDR'];
128
        }
129
        return $ip;
130
    }
131
132
    public function checkPermission()
133
    {
134
        // Check whether the remote IP address is allowed to run commands.
135
        // Only localhost or hosts of registered users are allowed.
136
        $ip = $this->ipAddress();
137
        // Currently PalMA also makes local connections.
138
        $ip_list = array('127.0.0.1', '::1');
139
        $rows = $this->query("SELECT address FROM address");
140
        while ($row = $rows->fetchArray(SQLITE3_ASSOC)) {
141
            array_push($ip_list, $row['address']);
142
        }
143
        $rows->finalize();
144
        $allowed = in_array($ip, $ip_list);
145
        return $allowed;
146
    }
147
148
    public function addUser($username, $address, $device = 'laptop')
149
    {
150
        // Add a new user with his/her address and the device to the database.
151
        // TODO: Support more than one address for a given username.
152
        $this->exec("INSERT OR IGNORE INTO user VALUES (NULL, '$username', 1, 0)");
153
        $usercount = $this->querySingle("SELECT COUNT(*) FROM user");
154
        $userid = $this->querySingle("SELECT userid from user where name='".$username."'");
155
        $this->exec("INSERT INTO address VALUES ('$userid', '$address', '$device')");
156
        trace("user $username connected with $device, $usercount user(s) now connected");
157
        if ($usercount == 1) {
158
            // First user connected. Always enable this person.
159
            $this->enableUser($username);
160
        }
161
    }
162
163
    public function delUser($username, $address)
0 ignored issues
show
The parameter $address is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

163
    public function delUser($username, /** @scrutinizer ignore-unused */ $address)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
164
    {
165
        // Remove an existing user with his/her address from the database.
166
        // TODO: Support more than one address for a given username.
167
        $ip = $this->ipAddress();
168
        $userid = $this->querySingle("SELECT userid from user where name='$username'");
169
        // Kill VNC connection associated with the user
170
        $this->deleteVNCWindow($userid);
171
        $this->exec("DELETE FROM address WHERE userid = '$userid' AND address = '$ip'");
172
        // TODO: Remove user only when no address refers to it.
173
        $this->exec("DELETE FROM user WHERE userid = '$userid'");
174
        $usercount = $this->querySingle("SELECT COUNT(*) FROM user");
175
        trace("user $username disconnected, $usercount user(s) now connected");
176
        if ($usercount == 0) {
177
            // Last user disconnected.
178
            // Clean some tables, just to be sure that nothing is left.
179
            $this->exec("DELETE FROM address; DELETE FROM window;");
180
        }
181
    }
182
183
    public function enableUser($username)
184
    {
185
        $state = $this->exec("UPDATE user SET enabled=1 WHERE name='$username'");
186
        if (!$state) {
187
            trace("enableUser($username) failed");
188
        }
189
    }
190
191
    public function getUsers()
192
    {
193
        $users = array();
194
        $rows = $this->query("SELECT name FROM user");
195
        while ($row = $rows->fetchArray(SQLITE3_ASSOC)) {
196
            array_push($users, $row['name']);
197
        }
198
        $rows->finalize();
199
        return $users;
200
    }
201
202
    public function checkUser($username)
203
    {
204
        $users = $this->getUsers();
205
        // empty db (e.g. after PalMA restart) or old session
206
        if (count($users) === 0 || !in_array($username, $users)) {
207
            return false;
208
        }
209
        return true;
210
    }
211
212
    public function getWindows()
213
    {
214
        // Get list of all windows, ordered by their section.
215
        $window_objs = array();
216
        $windows = @$this->query('SELECT * FROM window ORDER BY section ASC');
217
        while ($row = $windows->fetchArray()) {
218
            array_push($window_objs, $row);
219
        }
220
        $windows->finalize();
221
222
        return $window_objs;
223
    }
224
225
    public function getWindowIDBySection($section)
226
    {
227
        $id = $this->querySingle("SELECT win_id FROM window WHERE section='$section'");
228
        return $id;
229
    }
230
231
    public function getVNCClientInfo()
232
    {
233
234
        $info = array();
235
236
        $i = @$this->query('SELECT * FROM window WHERE handler="vnc"');
237
        while ($row = $i->fetchArray()) {
238
            array_push($info, $row);
239
        }
240
        $i->finalize();
241
242
        return $info;
243
    }
244
245
    /*
246
    public function getVNC_ClientWindowIDs() {
247
        $ids = array();
248
        $rows = @$this->query('SELECT win_id FROM window WHERE handler="vnc"');
249
        while ($row = $rows->fetchArray()) {
250
            array_push($ids, $row['win_id']);
251
        }
252
        $rows->finalize();
253
        return $ids;
254
    }
255
    */
256
257
    public function getWindowState($window_id)
258
    {
259
        $state = @$this->querySingle('SELECT state FROM window WHERE win_id="'.$window_id.'"');
260
        return $state;
261
    }
262
263
    public function setWindowState($window_id, $state)
264
    {
265
        $this->exec('UPDATE window SET state="'.$state.'" WHERE win_id="'.$window_id.'"');
266
    }
267
268
    public function insertWindow($window)
269
    {
270
        // transfer ob complete window object/array necessary
271
        $sql = 'INSERT INTO window (id, win_id, section, state, file, handler, userid, date) ' .
272
                'VALUES ' . '("' .
273
                $window[0] . '", "' . $window[1] . '", "' .
274
                $window[2] . '", "' . $window[3] . '", "' .
275
                $window[4] . '", "' . $window[5] . '", "' .
276
                $window[6] . '", "' . $window[7] . '")';
277
        $new = $this->exec($sql);
278
        trace("insertWindow sql=$sql, result=$new");
279
    }
280
281
    public function deleteWindow($window_id)
282
    {
283
        $this->exec('DELETE FROM window WHERE win_id="'.$window_id.'"');
284
    }
285
286
    public function deleteVNCWindow($userid)
287
    {
288
        $winid = $this->querySingle('SELECT win_id FROM window WHERE handler="vnc" AND userid="'.$userid.'"');
289
        require_once('control.php');
290
        wmClose($winid);
291
        $this->deleteWindow($winid);
292
        //$this->exec('DELETE FROM window WHERE handler="vnc" AND userid="'.$userid.'"');
293
    }
294
295
    public function deleteDebug($table, $id, $gt)
296
    {
297
        $this->exec('DELETE FROM '.$table.' WHERE '.$id.' >"'.$gt.'"');
298
    }
299
300
    public function updateWindow($window_id, $field, $value)
301
    {
302
        $this->exec('UPDATE window SET '.$field.'="'.$value.'" WHERE win_id="'.$window_id.'"');
303
    }
304
}
305