"Fossies" - the Fresh Open Source Software Archive 
Member "phpMyAdmin-5.1.0-english/libraries/classes/RecentFavoriteTable.php" (24 Feb 2021, 12297 Bytes) of package /linux/www/phpMyAdmin-5.1.0-english.zip:
1 <?php
2 /**
3 * Recent and Favorite table list handling
4 */
5
6 declare(strict_types=1);
7
8 namespace PhpMyAdmin;
9
10 use PhpMyAdmin\Html\Generator;
11 use const SORT_REGULAR;
12 use function array_key_exists;
13 use function array_merge;
14 use function array_pop;
15 use function array_unique;
16 use function array_unshift;
17 use function count;
18 use function htmlspecialchars;
19 use function json_decode;
20 use function json_encode;
21 use function max;
22 use function md5;
23 use function ucfirst;
24
25 /**
26 * Handles the recently used and favorite tables.
27 *
28 * @TODO Change the release version in table pma_recent
29 * (#recent in documentation)
30 */
31 class RecentFavoriteTable
32 {
33 /**
34 * Reference to session variable containing recently used or favorite tables.
35 *
36 * @access private
37 * @var array
38 */
39 private $tables;
40
41 /**
42 * Defines type of action, Favorite or Recent table.
43 *
44 * @access private
45 * @var string
46 */
47 private $tableType;
48
49 /**
50 * RecentFavoriteTable instances.
51 *
52 * @access private
53 * @var array
54 */
55 private static $instances = [];
56
57 /** @var Relation */
58 private $relation;
59
60 /**
61 * Creates a new instance of RecentFavoriteTable
62 *
63 * @param string $type the table type
64 *
65 * @access private
66 */
67 private function __construct($type)
68 {
69 global $dbi;
70
71 $this->relation = new Relation($dbi);
72 $this->tableType = $type;
73 $server_id = $GLOBALS['server'];
74 if (! isset($_SESSION['tmpval'][$this->tableType . 'Tables'][$server_id])
75 ) {
76 $_SESSION['tmpval'][$this->tableType . 'Tables'][$server_id]
77 = $this->getPmaTable() ? $this->getFromDb() : [];
78 }
79 $this->tables
80 =& $_SESSION['tmpval'][$this->tableType . 'Tables'][$server_id];
81 }
82
83 /**
84 * Returns class instance.
85 *
86 * @param string $type the table type
87 *
88 * @return RecentFavoriteTable
89 */
90 public static function getInstance($type)
91 {
92 if (! array_key_exists($type, self::$instances)) {
93 self::$instances[$type] = new RecentFavoriteTable($type);
94 }
95
96 return self::$instances[$type];
97 }
98
99 /**
100 * Returns the recent/favorite tables array
101 *
102 * @return array
103 */
104 public function getTables()
105 {
106 return $this->tables;
107 }
108
109 /**
110 * Returns recently used tables or favorite from phpMyAdmin database.
111 *
112 * @return array
113 */
114 public function getFromDb()
115 {
116 global $dbi;
117
118 // Read from phpMyAdmin database, if recent tables is not in session
119 $sql_query
120 = ' SELECT `tables` FROM ' . $this->getPmaTable() .
121 " WHERE `username` = '" . $dbi->escapeString($GLOBALS['cfg']['Server']['user']) . "'";
122
123 $return = [];
124 $result = $this->relation->queryAsControlUser($sql_query, false);
125 if ($result) {
126 $row = $dbi->fetchArray($result);
127 if (isset($row[0])) {
128 $return = json_decode($row[0], true);
129 }
130 }
131
132 return $return;
133 }
134
135 /**
136 * Save recent/favorite tables into phpMyAdmin database.
137 *
138 * @return true|Message
139 */
140 public function saveToDb()
141 {
142 global $dbi;
143
144 $username = $GLOBALS['cfg']['Server']['user'];
145 $sql_query
146 = ' REPLACE INTO ' . $this->getPmaTable() . ' (`username`, `tables`)' .
147 " VALUES ('" . $dbi->escapeString($username) . "', '"
148 . $dbi->escapeString(
149 json_encode($this->tables)
150 ) . "')";
151
152 $success = $dbi->tryQuery($sql_query, DatabaseInterface::CONNECT_CONTROL);
153
154 if (! $success) {
155 $error_msg = '';
156 switch ($this->tableType) {
157 case 'recent':
158 $error_msg = __('Could not save recent table!');
159 break;
160
161 case 'favorite':
162 $error_msg = __('Could not save favorite table!');
163 break;
164 }
165 $message = Message::error($error_msg);
166 $message->addMessage(
167 Message::rawError(
168 $dbi->getError(DatabaseInterface::CONNECT_CONTROL)
169 ),
170 '<br><br>'
171 );
172
173 return $message;
174 }
175
176 return true;
177 }
178
179 /**
180 * Trim recent.favorite table according to the
181 * NumRecentTables/NumFavoriteTables configuration.
182 *
183 * @return bool True if trimming occurred
184 */
185 public function trim()
186 {
187 $max = max(
188 $GLOBALS['cfg']['Num' . ucfirst($this->tableType) . 'Tables'],
189 0
190 );
191 $trimming_occurred = count($this->tables) > $max;
192 while (count($this->tables) > $max) {
193 array_pop($this->tables);
194 }
195
196 return $trimming_occurred;
197 }
198
199 /**
200 * Return HTML ul.
201 *
202 * @return string
203 */
204 public function getHtmlList()
205 {
206 $html = '';
207 if (count($this->tables)) {
208 if ($this->tableType === 'recent') {
209 foreach ($this->tables as $table) {
210 $html .= '<li class="warp_link">';
211 $recent_url = Url::getFromRoute('/table/recent-favorite', [
212 'db' => $table['db'],
213 'table' => $table['table'],
214 ]);
215 $html .= '<a href="' . $recent_url . '">`'
216 . htmlspecialchars($table['db']) . '`.`'
217 . htmlspecialchars($table['table']) . '`</a>';
218 $html .= '</li>';
219 }
220 } else {
221 foreach ($this->tables as $table) {
222 $html .= '<li class="warp_link">';
223
224 $html .= '<a class="ajax favorite_table_anchor" ';
225 $fav_rm_url = Url::getFromRoute('/database/structure/favorite-table', [
226 'db' => $table['db'],
227 'ajax_request' => true,
228 'favorite_table' => $table['table'],
229 'remove_favorite' => true,
230 ]);
231 $html .= 'href="' . $fav_rm_url
232 . '" title="' . __('Remove from Favorites')
233 . '" data-favtargetn="'
234 . md5($table['db'] . '.' . $table['table'])
235 . '" >'
236 . Generator::getIcon('b_favorite')
237 . '</a>';
238
239 $table_url = Url::getFromRoute('/table/recent-favorite', [
240 'db' => $table['db'],
241 'table' => $table['table'],
242 ]);
243 $html .= '<a href="' . $table_url . '">`'
244 . htmlspecialchars($table['db']) . '`.`'
245 . htmlspecialchars($table['table']) . '`</a>';
246 $html .= '</li>';
247 }
248 }
249 } else {
250 $html .= '<li class="warp_link">'
251 . ($this->tableType === 'recent'
252 ? __('There are no recent tables.')
253 : __('There are no favorite tables.'))
254 . '</li>';
255 }
256
257 return $html;
258 }
259
260 /**
261 * Return HTML.
262 *
263 * @return string
264 */
265 public function getHtml()
266 {
267 $html = '<div class="drop_list">';
268 if ($this->tableType === 'recent') {
269 $html .= '<button title="' . __('Recent tables')
270 . '" class="drop_button btn">'
271 . __('Recent') . '</button><ul id="pma_recent_list">';
272 } else {
273 $html .= '<button title="' . __('Favorite tables')
274 . '" class="drop_button btn">'
275 . __('Favorites') . '</button><ul id="pma_favorite_list">';
276 }
277 $html .= $this->getHtmlList();
278 $html .= '</ul></div>';
279
280 return $html;
281 }
282
283 /**
284 * Add recently used or favorite tables.
285 *
286 * @param string $db database name where the table is located
287 * @param string $table table name
288 *
289 * @return true|Message True if success, Message if not
290 */
291 public function add($db, $table)
292 {
293 global $dbi;
294
295 // If table does not exist, do not add._getPmaTable()
296 if (! $dbi->getColumns($db, $table)) {
297 return true;
298 }
299
300 $table_arr = [];
301 $table_arr['db'] = $db;
302 $table_arr['table'] = $table;
303
304 // add only if this is new table
305 if (! isset($this->tables[0]) || $this->tables[0] != $table_arr) {
306 array_unshift($this->tables, $table_arr);
307 $this->tables = array_merge(array_unique($this->tables, SORT_REGULAR));
308 $this->trim();
309 if ($this->getPmaTable()) {
310 return $this->saveToDb();
311 }
312 }
313
314 return true;
315 }
316
317 /**
318 * Removes recent/favorite tables that don't exist.
319 *
320 * @param string $db database
321 * @param string $table table
322 *
323 * @return bool|Message True if invalid and removed, False if not invalid,
324 * Message if error while removing
325 */
326 public function removeIfInvalid($db, $table)
327 {
328 global $dbi;
329
330 foreach ($this->tables as $tbl) {
331 if ($tbl['db'] != $db || $tbl['table'] != $table) {
332 continue;
333 }
334
335 // TODO Figure out a better way to find the existence of a table
336 if (! $dbi->getColumns($tbl['db'], $tbl['table'])) {
337 return $this->remove($tbl['db'], $tbl['table']);
338 }
339 }
340
341 return false;
342 }
343
344 /**
345 * Remove favorite tables.
346 *
347 * @param string $db database name where the table is located
348 * @param string $table table name
349 *
350 * @return true|Message True if success, Message if not
351 */
352 public function remove($db, $table)
353 {
354 foreach ($this->tables as $key => $value) {
355 if ($value['db'] != $db || $value['table'] != $table) {
356 continue;
357 }
358
359 unset($this->tables[$key]);
360 }
361 if ($this->getPmaTable()) {
362 return $this->saveToDb();
363 }
364
365 return true;
366 }
367
368 /**
369 * Generate Html for sync Favorite tables anchor. (from localStorage to pmadb)
370 *
371 * @return string
372 */
373 public function getHtmlSyncFavoriteTables()
374 {
375 $retval = '';
376 $server_id = $GLOBALS['server'];
377 if ($server_id == 0) {
378 return '';
379 }
380 $cfgRelation = $this->relation->getRelationsParam();
381 // Not to show this once list is synchronized.
382 if ($cfgRelation['favoritework'] && ! isset($_SESSION['tmpval']['favorites_synced'][$server_id])) {
383 $url = Url::getFromRoute('/database/structure/favorite-table', [
384 'ajax_request' => true,
385 'favorite_table' => true,
386 'sync_favorite_tables' => true,
387 ]);
388 $retval = '<a class="hide" id="sync_favorite_tables"';
389 $retval .= ' href="' . $url . '"></a>';
390 }
391
392 return $retval;
393 }
394
395 /**
396 * Generate Html to update recent tables.
397 *
398 * @return string html
399 */
400 public static function getHtmlUpdateRecentTables()
401 {
402 $retval = '<a class="hide" id="update_recent_tables" href="';
403 $retval .= Url::getFromRoute('/recent-table', [
404 'ajax_request' => true,
405 'recent_table' => true,
406 ]);
407 $retval .= '"></a>';
408
409 return $retval;
410 }
411
412 /**
413 * Return the name of the configuration storage table
414 *
415 * @return string|null pma table name
416 */
417 private function getPmaTable(): ?string
418 {
419 $cfgRelation = $this->relation->getRelationsParam();
420 if (! $cfgRelation['recentwork']) {
421 return null;
422 }
423
424 if (! empty($cfgRelation['db'])
425 && ! empty($cfgRelation[$this->tableType])
426 ) {
427 return Util::backquote($cfgRelation['db']) . '.'
428 . Util::backquote($cfgRelation[$this->tableType]);
429 }
430
431 return null;
432 }
433 }