1<?php
2//
3// DokuWiki Onlinenumber Plugin
4//
5//
6// Original source of this plugin is PukiWiki.
7// Ported by Hokkaidoperson <dosankomali@yahoo.co.jp>
8//
9//
10// Original Licenses of this plugin:
11//
12// $Id: online.inc.php,v 1.12 2007/02/10 06:21:53 henoheno Exp $
13// Copyright (C)
14//   2002-2005, 2007 PukiWiki Developers Team
15//   2001-2002 Originally written by yu-ji
16// License: GPL v2 or (at your option) any later version
17//
18// Online plugin -- Just show the number 'users-on-line'
19
20// must be run within Dokuwiki
21if(!defined('DOKU_INC')) die();
22
23class syntax_plugin_onlinenumber extends DokuWiki_Syntax_Plugin {
24
25    function getType(){
26        return 'substition';
27    }
28
29    function getSort(){
30        return 160;
31    }
32
33
34        // Internal functions
35
36        // Check I am already online (recorded and not time-out)
37        // & $count == Number of online users
38        function plugin_online_check_online(& $count, $host = '')
39        {
40            if (! touch(PLUGIN_ONLINE_USER_LIST)) return FALSE;
41
42            // Open
43            $fp = @fopen(PLUGIN_ONLINE_USER_LIST, 'r');
44            if ($fp == FALSE) return FALSE;
45            set_file_buffer($fp, 0);
46
47            // Init
48            $count   = 0;
49            $found   = FALSE;
50            $matches = array();
51
52            flock($fp, LOCK_SH);
53
54            // Read
55            while (! feof($fp)) {
56                $line = fgets($fp, 512);
57                if ($line === FALSE) continue;
58
59                // Ignore invalid-or-outdated lines
60                if (! preg_match(PLUGIN_ONLINE_LIST_REGEX, $line, $matches) ||
61                    ($matches[2] + PLUGIN_ONLINE_TIMEOUT) <= UTIME ||
62                    $matches[2] > UTIME) continue;
63
64                ++$count;
65                if (! $found && $matches[1] == $host) $found = TRUE;
66            }
67
68            flock($fp, LOCK_UN);
69
70            if(! fclose($fp)) return FALSE;
71
72            if (! $found && $host != '') ++$count; // About you
73
74            return $found;
75        }
76
77        // Cleanup outdated records, Add/Replace new record, Return the number of 'users in N seconds'
78        // NOTE: Call this when plugin_online_check_online() returnes FALSE
79        function plugin_online_sweep_records($host = '')
80        {
81            // Open
82            $fp = @fopen(PLUGIN_ONLINE_USER_LIST, 'r+');
83            if ($fp == FALSE) return FALSE;
84            set_file_buffer($fp, 0);
85
86            flock($fp, LOCK_EX);
87
88            // Read to check
89            $lines = @file(PLUGIN_ONLINE_USER_LIST);
90            if ($lines === FALSE) $lines = array();
91
92            // Need modify?
93            $line_count = $count = count($lines);
94            $matches = array();
95            $dirty   = FALSE;
96            for ($i = 0; $i < $line_count; $i++) {
97                if (! preg_match(PLUGIN_ONLINE_LIST_REGEX, $lines[$i], $matches) ||
98                    ($matches[2] + PLUGIN_ONLINE_TIMEOUT) <= UTIME ||
99                    $matches[2] > UTIME ||
100                    $matches[1] == $host) {
101                    unset($lines[$i]); // Invalid or outdated or invalid date
102                    --$count;
103                    $dirty = TRUE;
104                }
105            }
106            if ($host != '' ) {
107                // Add new, at the top of the record
108                array_unshift($lines, strtr($host, "\n", '') . '|' . UTIME . "\n");
109                ++$count;
110                $dirty = TRUE;
111            }
112
113            if ($dirty) {
114                // Write
115                if (! ftruncate($fp, 0)) return FALSE;
116                rewind($fp);
117                fputs($fp, join('', $lines));
118            }
119
120            flock($fp, LOCK_UN);
121
122            if(! fclose($fp)) return FALSE;
123
124            return $count; // Number of lines == Number of users online
125        }
126
127    //Syntax: {{onlinenumber|texts following the number of online (when the number is 1)|texts following the number of online (when the number is 2 or more)
128    //The texts following the number of online are not required (If entered just {{onlinenumber}} , this will return only the number)
129
130    function connectTo($mode) {
131      $this->Lexer->addSpecialPattern('\{\{onlinenumber[^}]*\}\}',$mode,'plugin_onlinenumber');
132    }
133
134
135    function handle($match, $state, $pos, Doku_Handler $handler){
136
137        return explode('|', substr($match, strlen('{{onlinenumber|'), -2));
138
139    }
140
141    function render($mode, Doku_Renderer $renderer, $data) {
142        define('PLUGIN_ONLINE_TIMEOUT', $this->getConf('onlineseconds')); // Count users in N seconds
143
144        // List of 'IP-address|last-access-time(seconds)'
145        define('PLUGIN_ONLINE_USER_LIST', DOKU_PLUGIN . 'onlinenumber/user.dat');
146
147        // Regex of 'IP-address|last-access-time(seconds)'
148        define('PLUGIN_ONLINE_LIST_REGEX', '/^([^\|]+)\|([0-9]+)$/');
149
150        // UTIME ... universal time
151        define('UTIME', time() - date('Z'));
152
153
154        // Main process
155        static $count, $result, $base;
156
157        if (! isset($count)) {
158            if (isset($_SERVER['REMOTE_ADDR'])) {
159                $host  = & $_SERVER['REMOTE_ADDR'];
160            } else {
161                $host  = '';
162            }
163
164            // Try read
165            if ($this->plugin_online_check_online($count, $host)) {
166                $result = TRUE;
167            } else {
168                // Write
169                $result = $this->plugin_online_sweep_records($host);
170            }
171        }
172
173        if ($result) { // Integer
174            if ($count == 1) {
175                $renderer->doc .= htmlspecialchars($count) .htmlspecialchars($data[0]);
176            } else {
177                $renderer->doc .= htmlspecialchars($count) .htmlspecialchars($data[1]);
178            }
179        } else {
180            if (! isset($base)) $base = basename(PLUGIN_ONLINE_USER_LIST);
181            $error = $this->getLang('err1') . $base . $this->getLang('err2');
182            $renderer->doc .= htmlspecialchars($error); // String
183        }
184
185    }
186
187
188}
189