OSDN Git Service

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