commit | author | age
|
8bd4d9
|
1 |
<?php |
JK |
2 |
/** |
0868e0
|
3 |
* Klasa przechowująca dane przekazane przez użytkownika, |
JK |
4 |
* w szczególności jego ustawienia. |
8bd4d9
|
5 |
*/ |
JK |
6 |
class BotSession { |
|
7 |
/** |
6d8764
|
8 |
* Instancja PDO tworzona w metodzie {@link BotSession::init()}. |
JK |
9 |
* @var PDO $PDO |
|
10 |
*/ |
|
11 |
protected $PDO; |
|
12 |
|
|
13 |
/** |
|
14 |
* Katalog, w którym trzymane są dane sesyjne użytkowników. |
|
15 |
* @var string $sessionDir |
|
16 |
*/ |
|
17 |
protected $sessionDir; |
|
18 |
|
|
19 |
/** |
|
20 |
* Katalog, w którym trzymane są dane sesyjne użytkowników |
|
21 |
* z poprzedniej wersji bota. |
|
22 |
* @var string $legacySessionDir |
|
23 |
*/ |
|
24 |
protected $legacySessionDir; |
|
25 |
|
|
26 |
/** |
|
27 |
* Nazwa modułu (max. 40 znaków), którego zmienne klasa aktualnie przetwarza, |
|
28 |
* ustawiana metodą {@link BotSession::setClass()}. |
|
29 |
* @var string $class |
8bd4d9
|
30 |
*/ |
7b043b
|
31 |
protected $class = ''; |
8bd4d9
|
32 |
|
0868e0
|
33 |
/** |
JK |
34 |
* Pseudo-URL użytkownika. |
|
35 |
* @see BotUser |
6d8764
|
36 |
* @var string $user |
0868e0
|
37 |
*/ |
6d8764
|
38 |
protected $user; |
JK |
39 |
|
0868e0
|
40 |
/** |
6d8764
|
41 |
* Inicjuje klasę dla podanego użytkownika |
JK |
42 |
* @param string $user Pseudo-URL użytkownika |
|
43 |
* @param string $sessionDir Katalog z danymi, domyślnie BOT_TOPDIR/database |
|
44 |
* @param string $legacySessionDir Katalog z danymi ze starej wersji bota, domyślnie BOT_TOPDIR/db |
0868e0
|
45 |
*/ |
6d8764
|
46 |
public function __construct($user, $sessionDir = NULL, $legacySessionDir = NULL) { |
JK |
47 |
if(empty($sessionDir)) { |
|
48 |
$sessionDir = BOT_TOPDIR.'/database'; |
|
49 |
} |
|
50 |
if(empty($legacySessionDir)) { |
|
51 |
$legacySessionDir = BOT_TOPDIR.'/db'; |
|
52 |
} |
|
53 |
|
|
54 |
$this->user = $user; |
|
55 |
$this->sessionDir = $sessionDir; |
|
56 |
$this->legacySessionDir = $legacySessionDir; |
8bd4d9
|
57 |
} |
6d8764
|
58 |
|
JK |
59 |
/** |
|
60 |
* Sprawdza ustawienie pola {@link BotSession::$class} oraz, jeśli nie została wykonana wcześniej, |
|
61 |
* dokonuje inicjalizacji klasy. |
|
62 |
* Metoda ta winna być wywoływana przez każdą publiczną funkcję operującą na danych. |
|
63 |
* @throws Exception Wyjątek rzucany, gdy przed użyciem metody, nazwa klasy |
|
64 |
* nie została ustawiona metodą {@link BotSession::setClass()} |
|
65 |
*/ |
|
66 |
protected function init() { |
|
67 |
if(empty($this->class)) { |
|
68 |
throw new Exception('Przed użyciem mechanizmu sesji należy ustawić nazwę modułu za pomocą metody setClass - patrz "Poradnik tworzenia modułów", dział "Klasa BotMessage", rozdział "Pole $session".'); |
57117d
|
69 |
} |
JK |
70 |
|
8bd4d9
|
71 |
if($this->PDO) { |
6d8764
|
72 |
// Inicjalizacja została już przeprowadzona - wyjdź. |
8bd4d9
|
73 |
return; |
JK |
74 |
} |
6d8764
|
75 |
|
JK |
76 |
$dbFile = $this->sessionDir.'/'.sha1(sha1($this->user)).'.sqlite'; |
|
77 |
|
|
78 |
$this->PDO = new PDO('sqlite:'.$dbFile); |
|
79 |
$this->PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
|
80 |
$this->PDO->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_TO_STRING); |
|
81 |
|
|
82 |
$st = $this->PDO->query('SELECT COUNT(name) FROM sqlite_master WHERE type=\'table\' AND name=\'data\''); |
|
83 |
$num = $st->fetch(PDO::FETCH_NUM); |
|
84 |
$schemaExists = $num[0] > 0; |
|
85 |
|
|
86 |
if($schemaExists) { |
|
87 |
$this->updateDatabase(); |
|
88 |
} else { |
|
89 |
try { |
|
90 |
$this->createSchema(); |
|
91 |
$this->importLegacyData(); |
c661ee
|
92 |
} |
6d8764
|
93 |
catch(Exception $e) { |
JK |
94 |
// Import danych nie udał się - usuń pozostałości. |
|
95 |
if(file_exists($dbFile)) { |
|
96 |
@unlink($dbFile); |
8bd4d9
|
97 |
} |
6d8764
|
98 |
throw $e; |
8bd4d9
|
99 |
} |
JK |
100 |
} |
|
101 |
} |
|
102 |
|
0868e0
|
103 |
/** |
JK |
104 |
* Ustawia nazwę modułu/klasy, której zmienne będą przetwarzane |
|
105 |
* @param string $class Nazwa modułu |
|
106 |
*/ |
6d8764
|
107 |
public function setClass($class) { |
0868e0
|
108 |
$this->class = $class; |
JK |
109 |
} |
|
110 |
|
|
111 |
/** |
6d8764
|
112 |
* Pobiera zmienną o podanej nazwie (getter). |
JK |
113 |
* @param string $name Nazwa zmiennej. |
|
114 |
* @return mixed Wartość zmiennej lub NULL, jeśli zmienna nie istnieje. |
0868e0
|
115 |
*/ |
6d8764
|
116 |
public function __get($name) { |
8bd4d9
|
117 |
$this->init(); |
JK |
118 |
|
|
119 |
$st = $this->PDO->prepare('SELECT value FROM data WHERE class=? AND name=?'); |
|
120 |
$st->execute(array($this->class, $name)); |
|
121 |
$st = $st->fetch(PDO::FETCH_ASSOC); |
|
122 |
|
|
123 |
if(is_array($st)) { |
|
124 |
return unserialize($st['value']); |
|
125 |
} |
6d8764
|
126 |
|
JK |
127 |
return NULL; |
8bd4d9
|
128 |
} |
JK |
129 |
|
0868e0
|
130 |
/** |
6d8764
|
131 |
* Ustawia zmienną o podanej nazwie. |
JK |
132 |
* @param string $name Nazwa zmiennej. |
|
133 |
* @param mixed $value Wartość do ustawienia. |
0868e0
|
134 |
*/ |
6d8764
|
135 |
public function __set($name, $value) { |
8bd4d9
|
136 |
$this->init(); |
JK |
137 |
|
|
138 |
$st = $this->PDO->prepare('INSERT OR REPLACE INTO data (class, name, value) VALUES (?, ?, ?)'); |
|
139 |
$st->execute(array($this->class, $name, serialize($value))); |
|
140 |
} |
|
141 |
|
0868e0
|
142 |
/** |
JK |
143 |
* Sprawdza czy podana zmienna została ustawiona. |
6d8764
|
144 |
* @param string $name Nazwa zmiennej do sprawdzenia. |
0868e0
|
145 |
* @return bool Czy zmienna istnieje? |
JK |
146 |
*/ |
6d8764
|
147 |
public function __isset($name) { |
8bd4d9
|
148 |
$this->init(); |
JK |
149 |
|
|
150 |
$st = $this->PDO->prepare('SELECT COUNT(name) FROM data WHERE class=? AND name=?'); |
|
151 |
$st->execute(array($this->class, $name)); |
|
152 |
$st = $st->fetch(PDO::FETCH_NUM); |
|
153 |
|
6d8764
|
154 |
return ($st[0] > 0); |
8bd4d9
|
155 |
} |
JK |
156 |
|
0868e0
|
157 |
/** |
6d8764
|
158 |
* Usuwa zmienną o podanej nazwie. |
JK |
159 |
* @param string $name Nazwa zmiennej do usunięcia. |
0868e0
|
160 |
*/ |
6d8764
|
161 |
public function __unset($name) { |
8bd4d9
|
162 |
$this->init(); |
JK |
163 |
|
|
164 |
$st = $this->PDO->prepare('DELETE FROM data WHERE class=? AND name=?'); |
|
165 |
$st->execute(array($this->class, $name)); |
|
166 |
} |
|
167 |
|
0868e0
|
168 |
/** |
6d8764
|
169 |
* Dodaje tablicę zmiennych do danych użytkownika. |
JK |
170 |
* @param array $array Tablica zmiennych do dodania. |
0868e0
|
171 |
*/ |
6d8764
|
172 |
public function push($array) { |
JK |
173 |
$this->init(); |
|
174 |
|
8bd4d9
|
175 |
$this->PDO->beginTransaction(); |
JK |
176 |
foreach($array as $name => $value) { |
|
177 |
$this->__set($name, $value); |
|
178 |
} |
|
179 |
$this->PDO->commit(); |
|
180 |
} |
|
181 |
|
0868e0
|
182 |
/** |
6d8764
|
183 |
* Zwraca wszystkie ustawione zmienne dla modułu. |
JK |
184 |
* @return array Lista wszystkich zmiennych. |
0868e0
|
185 |
*/ |
6d8764
|
186 |
public function pull() { |
8bd4d9
|
187 |
$this->init(); |
JK |
188 |
|
|
189 |
$st = $this->PDO->prepare('SELECT name, value FROM data WHERE class=?'); |
|
190 |
$st->execute(array($this->class)); |
6d8764
|
191 |
$rows = $st->fetchAll(PDO::FETCH_ASSOC); |
8bd4d9
|
192 |
|
JK |
193 |
$return = array(); |
6d8764
|
194 |
foreach($rows as $row) { |
0868e0
|
195 |
$return[$row['name']] = unserialize($row['value']); |
8bd4d9
|
196 |
} |
JK |
197 |
|
|
198 |
return $return; |
|
199 |
} |
|
200 |
|
0868e0
|
201 |
/** |
JK |
202 |
* Usuwa wszystkie zmienne sesyjne danego modułu. |
|
203 |
*/ |
6d8764
|
204 |
public function truncate() { |
8bd4d9
|
205 |
$this->init(); |
JK |
206 |
|
|
207 |
$st = $this->PDO->prepare('DELETE FROM data WHERE class=?'); |
|
208 |
$st->execute(array($this->class)); |
|
209 |
} |
6d8764
|
210 |
|
JK |
211 |
/** |
|
212 |
* Aktualizuje schemat bazy danych oraz dane, w szczególności poprawia błędy |
|
213 |
* wprowadzone we wcześniejszych wersjach (np. brak ustawionej nazwy klasy). |
|
214 |
*/ |
|
215 |
private function updateDatabase() { |
|
216 |
$st = $this->PDO->query('SELECT value FROM data WHERE class=\'\' AND name=\'_version\''); |
|
217 |
$row = $st->fetch(PDO::FETCH_ASSOC); |
|
218 |
|
|
219 |
$version = 0; |
|
220 |
if (is_array($row)) { |
|
221 |
$version = (int)$row['value']; |
|
222 |
} |
|
223 |
|
|
224 |
$st->closeCursor(); |
|
225 |
|
|
226 |
switch($version) { |
|
227 |
case 1: |
|
228 |
$this->PDO->query('UPDATE data SET class=\'kino\' WHERE class=\'\' AND name=\'kino\''); |
|
229 |
$this->PDO->query('INSERT OR REPLACE INTO data (class, name, value) VALUES (\'\', \'_version\', 1)'); |
|
230 |
case 2: |
|
231 |
case 3: |
|
232 |
$this->PDO->query('DELETE FROM data WHERE class IS NULL AND name=\'user_struct\''); |
|
233 |
$this->PDO->query('INSERT OR REPLACE INTO data (class, name, value) VALUES (\'\', \'_version\', 4)'); |
|
234 |
break; |
|
235 |
} |
|
236 |
} |
|
237 |
|
|
238 |
/** |
|
239 |
* Tworzy schemat bazy danych sesyjnych. |
|
240 |
*/ |
|
241 |
private function createSchema() { |
|
242 |
$this->PDO->query( |
|
243 |
'CREATE TABLE data ( |
|
244 |
class VARCHAR(50) NOT NULL DEFAULT \'\', |
|
245 |
name VARCHAR(40) NOT NULL, |
|
246 |
value TEXT NOT NULL, |
|
247 |
PRIMARY KEY ( |
|
248 |
class ASC, |
|
249 |
name ASC |
|
250 |
) |
|
251 |
)' |
|
252 |
); |
|
253 |
$this->PDO->query('INSERT INTO data (class, name, value) VALUES (\'\', \'_version\', 4)'); |
|
254 |
} |
|
255 |
|
|
256 |
/** |
|
257 |
* Importuje dane użytkowników z poprzedniej wersji bota. |
|
258 |
*/ |
|
259 |
private function importLegacyData() { |
|
260 |
$userData = parse_url($this->user); |
|
261 |
$files = glob($this->legacySessionDir.'/*/'.$userData['user'].'.ggdb'); |
|
262 |
if(!$files) { |
|
263 |
return; |
|
264 |
} |
|
265 |
|
|
266 |
$this->PDO->beginTransaction(); |
|
267 |
$st = $this->PDO->prepare('INSERT OR REPLACE INTO data (class, name, value) VALUES (?, ?, ?)'); |
|
268 |
|
|
269 |
foreach($files as $file) { |
|
270 |
$data = unserialize(file_get_contents($file)); |
|
271 |
foreach($data as $name => $value) { |
|
272 |
$st->execute(array($this->class, $name, serialize($value))); |
|
273 |
} |
|
274 |
} |
|
275 |
$this->PDO->commit(); |
|
276 |
|
|
277 |
foreach($files as $file) { |
|
278 |
unlink($file); |
|
279 |
} |
|
280 |
} |
8bd4d9
|
281 |
} |