OSDN Git Service

BugTrack/684 Don't show MenuBar right after unfreezing a page
[pukiwiki/pukiwiki.git] / plugin / counter.inc.php
1 <?php
2 // PukiWiki - Yet another WikiWikiWeb clone
3 // counter.inc.php
4 // Copyright
5 //   2002-2017 PukiWiki Development Team
6 //   2002 Y.MASUI GPL2 http://masui.net/pukiwiki/ masui@masui.net
7 // License: GPL2
8 //
9 // Counter plugin (per page)
10
11 // Counter file's suffix
12 define('PLUGIN_COUNTER_SUFFIX', '.count');
13 // Use Database (1) or not (0)
14 define('PLUGIN_COUNTER_USE_DB', 0);
15 // Database Connection setting
16 define('PLUGIN_COUNTER_DB_CONNECT_STRING', 'sqlite:counter/counter.db');
17 define('PLUGIN_COUNTER_DB_USERNAME', '');
18 define('PLUGIN_COUNTER_DB_PASSWORD', '');
19 $plugin_counter_db_options = null;
20 // For MySQL
21 // $plugin_counter_db_options = array(PDO::MYSQL_ATTR_INIT_COMMAND =>
22 //   "SET NAMES utf8mb4 COLLATE utf8mb4_bin");
23
24 define('PLUGIN_COUNTER_DB_TABLE_NAME_PREFIX', '');
25
26 if (PLUGIN_COUNTER_USE_DB) {
27         ini_set('default_socket_timeout', 2);
28 }
29
30 // Report one
31 function plugin_counter_inline()
32 {
33         global $vars;
34
35         // BugTrack2/106: Only variables can be passed by reference from PHP 5.0.5
36         $args = func_get_args(); // with array_shift()
37
38         $arg = strtolower(array_shift($args));
39         switch ($arg) {
40         case ''     : $arg = 'total'; /*FALLTHROUGH*/
41         case 'total': /*FALLTHROUGH*/
42         case 'today': /*FALLTHROUGH*/
43         case 'yesterday':
44                 $counter = plugin_counter_get_count($vars['page']);
45                 return $counter[$arg];
46         default:
47                 return '&counter([total|today|yesterday]);';
48         }
49 }
50
51 // Report all
52 function plugin_counter_convert()
53 {
54         global $vars;
55
56         $counter = plugin_counter_get_count($vars['page']);
57         return <<<EOD
58 <div class="counter">
59 Counter:   {$counter['total']},
60 today:     {$counter['today']},
61 yesterday: {$counter['yesterday']}
62 </div>
63 EOD;
64 }
65
66 // Return a summary
67 function plugin_counter_get_count($page)
68 {
69         global $vars, $plugin_counter_db_options;
70         static $counters = array();
71         static $default;
72         $page_counter_t = PLUGIN_COUNTER_DB_TABLE_NAME_PREFIX . 'page_counter';
73
74         if (! isset($default))
75                 $default = array(
76                         'total'     => 0,
77                         'date'      => get_date('Y/m/d'),
78                         'today'     => 0,
79                         'yesterday' => 0,
80                         'ip'        => '');
81
82         if (! is_page($page)) return $default;
83         if (isset($counters[$page])) return $counters[$page];
84
85         // Set default
86         $counters[$page] = $default;
87         $modify = FALSE;
88         $c = & $counters[$page];
89
90         if (PLUGIN_COUNTER_USE_DB) {
91                 if (SOURCE_ENCODING !== 'UTF-8') {
92                         die('counter.inc.php: Database counter is only available in UTF-8 mode');
93                 }
94                 $is_new_page = false;
95                 try {
96                         $pdo = new PDO(PLUGIN_COUNTER_DB_CONNECT_STRING,
97                                 PLUGIN_COUNTER_DB_USERNAME, PLUGIN_COUNTER_DB_PASSWORD,
98                                 $plugin_counter_db_options);
99                         $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
100                         $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
101                         $pdo->setAttribute(PDO::ATTR_TIMEOUT, 5);
102                         $stmt = $pdo->prepare(
103 "SELECT total, update_date,
104    today_viewcount, yesterday_viewcount, remote_addr
105  FROM $page_counter_t
106  WHERE page_name = ?"
107                         );
108                         $stmt->execute(array($page));
109                         $r = $stmt->fetch();
110                         if ($r === false) {
111                                 $is_new_page = true;
112                         } else {
113                                 $c['ip'] = $r['remote_addr'];
114                                 $c['date'] = $r['update_date'];
115                                 $c['yesterday'] = intval($r['yesterday_viewcount']);
116                                 $c['today'] = intval($r['today_viewcount']);
117                                 $c['total'] = intval($r['total']);
118                                 $stmt->closeCursor();
119                         }
120                 } catch (Exception $e) {
121                         // Error occurred
122                         $db_error = '(DBError)';
123                         return array(
124                                 'total' => $db_error,
125                                 'date' => $db_error,
126                                 'today' => $db_error,
127                                 'yesterday' => $db_error,
128                                 'ip' => $db_error);
129                 }
130         } else {
131                 // Open
132                 $file = COUNTER_DIR . encode($page) . PLUGIN_COUNTER_SUFFIX;
133                 pkwk_touch_file($file);
134                 $fp = fopen($file, 'r+')
135                         or die('counter.inc.php: Cannot open COUNTER_DIR/' . basename($file));
136                 set_file_buffer($fp, 0);
137                 flock($fp, LOCK_EX);
138                 rewind($fp);
139
140                 // Read
141                 foreach (array_keys($default) as $key) {
142                         // Update
143                         $c[$key] = rtrim(fgets($fp, 256));
144                         if (feof($fp)) break;
145                 }
146         }
147
148         // Anothoer day?
149         $remote_addr = $_SERVER['REMOTE_ADDR'];
150         $count_up = FALSE;
151         if ($c['date'] != $default['date']) {
152                 $modify = TRUE;
153                 $is_yesterday = ($c['date'] == get_date('Y/m/d', UTIME - 24 * 60 * 60));
154                 $c[$page]['ip']        = $remote_addr;
155                 $c['date']      = $default['date'];
156                 $c['yesterday'] = $is_yesterday ? $c['today'] : 0;
157                 $c['today']     = 1;
158                 $c['total']++;
159                 $count_up = TRUE;
160         } else if ($c['ip'] != $remote_addr) {
161                 // Not the same host
162                 $modify = TRUE;
163                 $c['ip']        = $remote_addr;
164                 $c['today']++;
165                 $c['total']++;
166                 $count_up = TRUE;
167         }
168
169         if (PLUGIN_COUNTER_USE_DB) {
170                 if ($modify && $vars['cmd'] == 'read') {
171                         try {
172                                 if ($is_new_page) {
173                                         // Insert
174                                         $add_stmt = $pdo->prepare(
175 "INSERT INTO $page_counter_t
176    (page_name, total, update_date, today_viewcount,
177    yesterday_viewcount, remote_addr)
178  VALUES (?, ?, ?, ?, ?, ?)"
179                                         );
180                                         $r_add = $add_stmt->execute(array($page, $c['total'],
181                                                 $c['date'], $c['today'], $c['yesterday'], $c['ip']));
182                                 } else if ($count_up) {
183                                         // Update on counting up 'total'
184                                         $upd_stmt = $pdo->prepare(
185 "UPDATE $page_counter_t
186  SET total = total + 1,
187    update_date = ?,
188    today_viewcount = ?,
189    yesterday_viewcount = ?,
190    remote_addr = ?
191  WHERE page_name = ?"
192                                         );
193                                         $r_upd = $upd_stmt->execute(array($c['date'],
194                                                 $c['today'], $c['yesterday'], $c['ip'], $page));
195                                 }
196                         } catch (PDOException $e) {
197                                 foreach (array_keys($c) as $key) {
198                                         $c[$key] .= '(DBError)';
199                                 }
200                         }
201                 }
202         } else {
203                 // Modify
204                 if ($modify && $vars['cmd'] == 'read') {
205                         rewind($fp);
206                         ftruncate($fp, 0);
207                         foreach (array_keys($default) as $key)
208                                 fputs($fp, $c[$key] . "\n");
209                 }
210                 // Close
211                 flock($fp, LOCK_UN);
212                 fclose($fp);
213         }
214         return $c;
215 }
216
217 function plugin_counter_get_popular_list($today, $except, $max) {
218         if (PLUGIN_COUNTER_USE_DB === 0) {
219                 return plugin_counter_get_popular_list_file($today, $except, $max);
220         } else {
221                 return plugin_counter_get_popular_list_db($today, $except, $max);
222         }
223 }
224
225 function plugin_counter_get_popular_list_file($today, $except, $max) {
226         global $whatsnew;
227         $counters = array();
228         $except_quote = str_replace('#', '\#', $except);
229         foreach (get_existpages(COUNTER_DIR, '.count') as $file=>$page) {
230                 if (($except != '' && preg_match("#$except_quote#", $page)) ||
231                                 $page == $whatsnew || check_non_list($page) ||
232                                 ! is_page($page))
233                         continue;
234
235                 $array = file(COUNTER_DIR . $file);
236                 $count = rtrim($array[0]);
237                 $date  = rtrim($array[1]);
238                 $today_count = rtrim($array[2]);
239
240                 if ($today) {
241                         // $pageが数値に見える(たとえばencode('BBS')=424253)とき、
242                         // array_splice()によってキー値が変更されてしまうのを防ぐ
243                         // ため、キーに '_' を連結する
244                         if ($today == $date) $counters['_' . $page] = $today_count;
245                 } else {
246                         $counters['_' . $page] = $count;
247                 }
248         }
249
250         asort($counters, SORT_NUMERIC);
251
252         // BugTrack2/106: Only variables can be passed by reference from PHP 5.0.5
253         $counters = array_reverse($counters, TRUE); // with array_splice()
254         $counters = array_splice($counters, 0, $max);
255         return $counters;
256 }
257
258 function plugin_counter_get_popular_list_db($today, $except, $max) {
259         global $whatsnew;
260         $page_counter_t = PLUGIN_COUNTER_DB_TABLE_NAME_PREFIX . 'page_counter';
261         if ($today) {
262                 $order_by_c = 'today_viewcount';
263         } else {
264                 $order_by_c = 'total';
265         }
266         $counters = array();
267         try {
268                 $pdo = new PDO(PLUGIN_COUNTER_DB_CONNECT_STRING,
269                         PLUGIN_COUNTER_DB_USERNAME, PLUGIN_COUNTER_DB_PASSWORD,
270                         $plugin_counter_db_options);
271                 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
272                 $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
273                 $pdo->setAttribute(PDO::ATTR_TIMEOUT, 5);
274                 if ($today) {
275                         $stmt = $pdo->prepare(
276 "SELECT page_name, total, update_date,
277    today_viewcount, yesterday_viewcount
278  FROM $page_counter_t
279  WHERE update_date = ?
280  ORDER BY $order_by_c DESC
281  LIMIT ?"
282                         );
283                 } else {
284                         $stmt = $pdo->prepare(
285 "SELECT page_name, total, update_date,
286    today_viewcount, yesterday_viewcount
287  FROM $page_counter_t
288  ORDER BY $order_by_c DESC
289  LIMIT ?"
290                         );
291                 }
292                 $except_quote = str_replace('#', '\#', $except);
293                 $limit = $max + 100;
294                 if ($today) {
295                         $stmt->execute(array($today, $limit));
296                 } else {
297                         $stmt->execute(array($limit));
298                 }
299                 foreach ($stmt as $r) {
300                         $page = $r['page_name'];
301                         if (($except != '' && preg_match("#$except_quote#", $page)) ||
302                                         $page == $whatsnew || check_non_list($page) ||
303                                         ! is_page($page)) {
304                                 continue;
305                         }
306                         if ($today) {
307                                 $counters['_' . $page] = $r['today_viewcount'];
308                         } else {
309                                 $counters['_' . $page] = $r['total'];
310                         }
311                 }
312                 $stmt->closeCursor();
313                 return array_splice($counters, 0, $max);
314         } catch (Exception $e) {
315                 die('counter.inc.php: Error occurred on getting pupular pages');
316         }
317 }
318
319 function plugin_counter_page_rename($pages) {
320         global $plugin_counter_db_options;
321         if (PLUGIN_COUNTER_USE_DB !== 0) {
322                 $page_counter_t = PLUGIN_COUNTER_DB_TABLE_NAME_PREFIX . 'page_counter';
323                 $pdo = new PDO(PLUGIN_COUNTER_DB_CONNECT_STRING,
324                         PLUGIN_COUNTER_DB_USERNAME, PLUGIN_COUNTER_DB_PASSWORD,
325                         $plugin_counter_db_options);
326                 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
327                 $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
328                 $stmt_delete = $pdo->prepare(
329 "DELETE FROM $page_counter_t
330  WHERE page_name = ?"
331                 );
332                 $stmt_rename = $pdo->prepare(
333 "UPDATE $page_counter_t
334  SET page_name = ?
335  WHERE page_name = ?"
336                 );
337                 foreach ($pages as $old_name=>$new_name) {
338                         $stmt_delete->execute(array($new_name));
339                         $stmt_rename->execute(array($new_name, $old_name));
340                 }
341         }
342 }
343
344 /**
345  * php -r "include 'plugin/counter.inc.php'; plugin_counter_tool_setup_table();"
346  */
347 function plugin_counter_tool_setup_table() {
348         global $plugin_counter_db_options;
349         $page_counter_t = PLUGIN_COUNTER_DB_TABLE_NAME_PREFIX . 'page_counter';
350         $pdo = new PDO(PLUGIN_COUNTER_DB_CONNECT_STRING,
351                 PLUGIN_COUNTER_DB_USERNAME, PLUGIN_COUNTER_DB_PASSWORD,
352                 $plugin_counter_db_options);
353         $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
354         $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
355         $r = $pdo->exec(
356 "CREATE TABLE $page_counter_t (
357    page_name VARCHAR(190) PRIMARY KEY,
358    total INTEGER NOT NULL,
359    update_date VARCHAR(20) NOT NULL,
360    today_viewcount INTEGER NOT NULL,
361    yesterday_viewcount INTEGER NOT NULL,
362    remote_addr VARCHAR(100)
363  )"
364         );
365         echo "OK\n";
366 }