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
|
|||
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 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.