PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / 1.0.3
Post Views Counter v1.0.3
1.7.13 1.7.12 1.7.11 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.2 1.3.2.1 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.7.10 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9
post-views-counter / includes / counter.php
post-views-counter / includes Last commit date
columns.php 12 years ago counter.php 12 years ago cron.php 12 years ago frontend.php 11 years ago functions.php 12 years ago query.php 12 years ago settings.php 12 years ago update.php 12 years ago widgets.php 12 years ago
counter.php
411 lines
1 <?php
2 if(!defined('ABSPATH')) exit;
3
4 new Post_Views_Counter_Counter();
5
6 class Post_Views_Counter_Counter
7 {
8 private $cookie = array(
9 'exists' => false,
10 'visited_posts' => array(),
11 'expiration' => 0
12 );
13
14
15 public function __construct()
16 {
17 // sets instance
18 Post_Views_Counter()->add_instance('counter', $this);
19
20 // actions
21 add_action('plugins_loaded', array(&$this, 'check_cookie'), 1);
22 add_action('wp', array(&$this, 'check_post'));
23 add_action('deleted_post', array(&$this, 'delete_post_views'));
24 add_action('wp_ajax_pvc-check-post', array(&$this, 'check_post_ajax'));
25 add_action('wp_ajax_nopriv_pvc-check-post', array(&$this, 'check_post_ajax'));
26 }
27
28
29 /**
30 * Removes post views from database when post is deleted
31 */
32 public function delete_post_views($post_id)
33 {
34 global $wpdb;
35
36 $wpdb->delete($wpdb->prefix.'post_views', array('id' => $post_id), array('%d'));
37 }
38
39
40 /**
41 * Checks whether user has excluded roles
42 */
43 public function is_user_roles_excluded($option)
44 {
45 $user = wp_get_current_user();
46
47 if(empty($user))
48 return false;
49
50 $roles = (array)$user->roles;
51
52 if(!empty($roles))
53 {
54 foreach($roles as $role)
55 {
56 if(in_array($role, $option, true))
57 return true;
58 }
59 }
60
61 return false;
62 }
63
64
65 /**
66 * Gets timestamp convertion
67 */
68 public function get_timestamp($type, $number, $timestamp = true)
69 {
70 $converter = array(
71 'minutes' => 60,
72 'hours' => 3600,
73 'days' => 86400,
74 'weeks' => 604800,
75 'months' => 2592000,
76 'years' => 946080000
77 );
78
79 return ($timestamp ? current_time('timestamp', true) : 0) + $number * $converter[$type];
80 }
81
82
83 /**
84 * Checks whether to count visit via AJAX request
85 */
86 public function check_post_ajax()
87 {
88 if(isset($_POST['action'], $_POST['post_id'], $_POST['pvc_nonce'], $_POST['post_type']) && $_POST['action'] === 'pvc-check-post' && ($post_id = (int)$_POST['post_id']) > 0 && wp_verify_nonce($_POST['pvc_nonce'], 'pvc-check-post') !== false && Post_Views_Counter()->get_attribute('options', 'general', 'counter_mode') === 'js')
89 {
90 // gets countable post types
91 $post_types = Post_Views_Counter()->get_attribute('options', 'general', 'post_types_count');
92
93 // gets post type
94 $post_type = get_post_type($post_id);
95
96 // whether to count this post type
97 if(empty($post_types) || empty($post_type) || $post_type !== $_POST['post_type'] || !in_array($post_type, $post_types, true))
98 exit;
99
100 // gets excluded ips
101 $excluded_ips = Post_Views_Counter()->get_attribute('options', 'general', 'exclude_ips');
102
103 // whether to count this ip
104 if(!empty($excluded_ips) && filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && in_array($_SERVER['REMOTE_ADDR'], $excluded_ips, true))
105 exit;
106
107 // gets groups to check them faster
108 $groups = Post_Views_Counter()->get_attribute('options', 'general', 'exclude', 'groups');
109
110 // whether to count this user
111 if(is_user_logged_in())
112 {
113 // exclude logged in users?
114 if(in_array('users', $groups, true))
115 exit;
116 // exclude specific roles?
117 elseif(in_array('roles', $groups, true) && $this->is_user_roles_excluded(Post_Views_Counter()->get_attribute('options', 'general', 'exclude', 'roles')))
118 exit;
119 }
120 // exclude guests?
121 elseif(in_array('guests', $groups, true))
122 exit;
123
124 // whether to count robots
125 if($this->is_robot())
126 exit;
127
128 // cookie already existed?
129 if($this->cookie['exists'])
130 {
131 // post already viewed but not expired?
132 if(in_array($post_id, array_keys($this->cookie['visited_posts']), true) && current_time('timestamp', true) < $this->cookie['visited_posts'][$post_id])
133 {
134 // updates cookie but do not count visit
135 $this->save_cookie($post_id, $this->cookie, false);
136
137 exit;
138 }
139 else
140 // updates cookie
141 $this->save_cookie($post_id, $this->cookie);
142 }
143 else
144 // sets new cookie
145 $this->save_cookie($post_id);
146
147 // count visit
148 $this->count_visit($post_id);
149 }
150
151 exit;
152 }
153
154
155 /**
156 *
157 */
158 public function check_post()
159 {
160 // do not count admin entries
161 if(is_admin())
162 return;
163
164 // do we use PHP as counter?
165 if(Post_Views_Counter()->get_attribute('options', 'general', 'counter_mode') === 'php')
166 {
167 $post_types = Post_Views_Counter()->get_attribute('options', 'general', 'post_types_count');
168
169 // whether to count this post type
170 if(empty($post_types) || !is_singular($post_types))
171 return;
172
173 $ips = Post_Views_Counter()->get_attribute('options', 'general', 'exclude_ips');
174
175 // whether to count this ip
176 if(!empty($ips) && filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && in_array($_SERVER['REMOTE_ADDR'], $ips, true))
177 return;
178
179 // gets groups to check them faster
180 $groups = Post_Views_Counter()->get_attribute('options', 'general', 'exclude', 'groups');
181
182 // whether to count this user
183 if(is_user_logged_in())
184 {
185 // exclude logged in users?
186 if(in_array('users', $groups, true))
187 return;
188 // exclude specific roles?
189 elseif(in_array('roles', $groups, true) && $this->is_user_roles_excluded(Post_Views_Counter()->get_attribute('options', 'general', 'exclude', 'roles')))
190 return;
191 }
192 // exclude guests?
193 elseif(in_array('guests', $groups, true))
194 return;
195
196 // whether to count robots
197 if($this->is_robot())
198 return;
199
200 // gets post id
201 $id = get_the_ID();
202
203 // cookie already existed?
204 if($this->cookie['exists'])
205 {
206 // post already viewed but not expired?
207 if(in_array($id, array_keys($this->cookie['visited_posts']), true) && current_time('timestamp', true) < $this->cookie['visited_posts'][$id])
208 {
209 // updates cookie but do not count visit
210 $this->save_cookie($id, $this->cookie, false);
211
212 return;
213 }
214 else
215 // updates cookie
216 $this->save_cookie($id, $this->cookie);
217 }
218 else
219 // sets new cookie
220 $this->save_cookie($id);
221
222 // count visit
223 $this->count_visit($id);
224 }
225 }
226
227
228 /**
229 * Initializes cookie session
230 */
231 public function check_cookie()
232 {
233 // do not run in admin except ajax requests
234 if(is_admin() && !(defined('DOING_AJAX') && DOING_AJAX))
235 return;
236
237 // is cookie set?
238 if(isset($_COOKIE['pvc_visits']) && !empty($_COOKIE['pvc_visits']))
239 {
240 $visited_posts = $expirations = array();
241
242 foreach($_COOKIE['pvc_visits'] as $content)
243 {
244 // valid cookie?
245 if(preg_match('/^(([0-9]+b[0-9]+a?)+)$/', $content) === 1)
246 {
247 // gets single id with expiration
248 $expiration_ids = explode('a', $content);
249
250 // checks every expiration => id pair
251 foreach($expiration_ids as $pair)
252 {
253 $pair = explode('b', $pair);
254 $expirations[] = (int)$pair[0];
255 $visited_posts[(int)$pair[1]] = (int)$pair[0];
256 }
257 }
258 }
259
260 $this->cookie = array(
261 'exists' => true,
262 'visited_posts' => $visited_posts,
263 'expiration' => max($expirations)
264 );
265 }
266 }
267
268
269 /**
270 *
271 */
272 private function save_cookie($id, $cookie = array(), $expired = true)
273 {
274 $expiration = $this->get_timestamp(Post_Views_Counter()->get_attribute('options', 'general', 'time_between_counts', 'type'), Post_Views_Counter()->get_attribute('options', 'general', 'time_between_counts', 'number'));
275
276 // is it new cookie?
277 if(empty($cookie))
278 {
279 // sets cookie
280 setcookie('pvc_visits[0]', $expiration.'b'.$id, $expiration, COOKIEPATH, COOKIE_DOMAIN, (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? true : false), true);
281 }
282 else
283 {
284 if($expired)
285 {
286 // adds new id or changes expiration date if id already exists
287 $cookie['visited_posts'][$id] = $expiration;
288 }
289
290 // creates copy for better foreach performance
291 $visited_posts_expirations = $cookie['visited_posts'];
292
293 // gets current gmt time
294 $time = current_time('timestamp', true);
295
296 // checks whether viewed id has expired - no need to keep it in cookie (less size)
297 foreach($visited_posts_expirations as $post_id => $post_expiration)
298 {
299 if($time > $post_expiration)
300 unset($cookie['visited_posts'][$post_id]);
301 }
302
303 // sets new last expiration date if needed
304 $cookie['expiration'] = max($cookie['visited_posts']);
305
306 $cookies = $imploded = array();
307
308 // creates pairs
309 foreach($cookie['visited_posts'] as $id => $exp)
310 {
311 $imploded[] = $exp.'b'.$id;
312 }
313
314 // splits cookie into chunks (4000 bytes to make sure it is safe for every browser)
315 $chunks = str_split(implode('a', $imploded), 4000);
316
317 // more then one chunk?
318 if(count($chunks) > 1)
319 {
320 $last_id = '';
321
322 foreach($chunks as $chunk_id => $chunk)
323 {
324 // new chunk
325 $chunk_c = $last_id.$chunk;
326
327 // is it full-length chunk?
328 if(strlen($chunk) === 4000)
329 {
330 // gets last part
331 $last_part = strrchr($chunk_c, 'a');
332
333 // gets last id
334 $last_id = substr($last_part, 1);
335
336 // adds new full-lenght chunk
337 $cookies[$chunk_id] = substr($chunk_c, 0, strlen($chunk_c) - strlen($last_part));
338 }
339 else
340 // adds last chunk
341 $cookies[$chunk_id] = $chunk_c;
342 }
343 }
344 else
345 // only one chunk
346 $cookies[] = $chunks[0];
347
348 foreach($cookies as $key => $value)
349 {
350 // sets cookie
351 setcookie('pvc_visits['.$key.']', $value, $cookie['expiration'], COOKIEPATH, COOKIE_DOMAIN, (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? true : false), true);
352 }
353 }
354 }
355
356
357 /**
358 *
359 */
360 private function count_visit($id)
361 {
362 global $wpdb;
363
364 // gets day, week, month and year
365 $date = explode('-', date('W-d-m-Y', current_time('timestamp')));
366
367 foreach(array(
368 0 => $date[3].$date[2].$date[1], // day like 20140324
369 1 => $date[3].$date[0], // week like 201439
370 2 => $date[3].$date[2], // month like 201405
371 3 => $date[3], // year like 2014
372 4 => 'total' // total views
373 ) as $type => $period)
374 {
375 // updates views
376 $wpdb->query(
377 $wpdb->prepare("
378 INSERT INTO ".$wpdb->prefix."post_views (id, type, period, count)
379 VALUES (%d, %d, %s, 1)
380 ON DUPLICATE KEY UPDATE count = count + 1",
381 $id,
382 $type,
383 $period
384 )
385 );
386 }
387 }
388
389
390 /**
391 * Checks whether visitor is a bot
392 */
393 private function is_robot()
394 {
395 if(!isset($_SERVER['HTTP_USER_AGENT']) || (isset($_SERVER['HTTP_USER_AGENT']) && trim($_SERVER['HTTP_USER_AGENT']) === ''))
396 return false;
397
398 $robots = array(
399 'bot', 'b0t', 'Acme.Spider', 'Ahoy! The Homepage Finder', 'Alkaline', 'Anthill', 'Walhello appie', 'Arachnophilia', 'Arale', 'Araneo', 'ArchitextSpider', 'Aretha', 'ARIADNE', 'arks', 'AskJeeves', 'ASpider (Associative Spider)', 'ATN Worldwide', 'AURESYS', 'BackRub', 'Bay Spider', 'Big Brother', 'Bjaaland', 'BlackWidow', 'Die Blinde Kuh', 'Bloodhound', 'BSpider', 'CACTVS Chemistry Spider', 'Calif', 'Cassandra', 'Digimarc Marcspider/CGI', 'ChristCrawler.com', 'churl', 'cIeNcIaFiCcIoN.nEt', 'CMC/0.01', 'Collective', 'Combine System', 'Web Core / Roots', 'Cusco', 'CyberSpyder Link Test', 'CydralSpider', 'Desert Realm Spider', 'DeWeb(c) Katalog/Index', 'DienstSpider', 'Digger', 'Direct Hit Grabber', 'DownLoad Express', 'DWCP (Dridus\' Web Cataloging Project)', 'e-collector', 'EbiNess', 'Emacs-w3 Search Engine', 'ananzi', 'esculapio', 'Esther', 'Evliya Celebi', 'FastCrawler', 'Felix IDE', 'Wild Ferret Web Hopper #1, #2, #3', 'FetchRover', 'fido', 'KIT-Fireball', 'Fish search', 'Fouineur', 'Freecrawl', 'FunnelWeb', 'gammaSpider, FocusedCrawler', 'gazz', 'GCreep', 'GetURL', 'Golem', 'Grapnel/0.01 Experiment', 'Griffon', 'Gromit', 'Northern Light Gulliver', 'Harvest', 'havIndex', 'HI (HTML Index) Search', 'Hometown Spider Pro', 'ht://Dig', 'HTMLgobble', 'Hyper-Decontextualizer', 'IBM_Planetwide', 'Popular Iconoclast', 'Ingrid', 'Imagelock', 'IncyWincy', 'Informant', 'Infoseek Sidewinder', 'InfoSpiders', 'Inspector Web', 'IntelliAgent', 'Iron33', 'Israeli-search', 'JavaBee', 'JCrawler', 'Jeeves', 'JumpStation', 'image.kapsi.net', 'Katipo', 'KDD-Explorer', 'Kilroy', 'LabelGrabber', 'larbin', 'legs', 'Link Validator', 'LinkScan', 'LinkWalker', 'Lockon', 'logo.gif Crawler', 'Lycos', 'Mac WWWWorm', 'Magpie', 'marvin/infoseek', 'Mattie', 'MediaFox', 'MerzScope', 'NEC-MeshExplorer', 'MindCrawler', 'mnoGoSearch search engine software', 'moget', 'MOMspider', 'Monster', 'Motor', 'Muncher', 'Muninn', 'Muscat Ferret', 'Mwd.Search', 'Internet Shinchakubin', 'NDSpider', 'Nederland.zoek', 'NetCarta WebMap Engine', 'NetMechanic', 'NetScoop', 'newscan-online', 'NHSE Web Forager', 'Nomad', 'nzexplorer', 'ObjectsSearch', 'Occam', 'HKU WWW Octopus', 'OntoSpider', 'Openfind data gatherer', 'Orb Search', 'Pack Rat', 'PageBoy', 'ParaSite', 'Patric', 'pegasus', 'The Peregrinator', 'PerlCrawler 1.0', 'Phantom', 'PhpDig', 'PiltdownMan', 'Pioneer', 'html_analyzer', 'Portal Juice Spider', 'PGP Key Agent', 'PlumtreeWebAccessor', 'Poppi', 'PortalB Spider', 'GetterroboPlus Puu', 'Raven Search', 'RBSE Spider', 'RoadHouse Crawling System', 'ComputingSite Robi/1.0', 'RoboCrawl Spider', 'RoboFox', 'Robozilla', 'RuLeS', 'Scooter', 'Sleek', 'Search.Aus-AU.COM', 'SearchProcess', 'Senrigan', 'SG-Scout', 'ShagSeeker', 'Shai\'Hulud', 'Sift', 'Site Valet', 'SiteTech-Rover', 'Skymob.com', 'SLCrawler', 'Inktomi Slurp', 'Smart Spider', 'Snooper', 'Spanner', 'Speedy Spider', 'spider_monkey', 'Spiderline Crawler', 'SpiderMan', 'SpiderView(tm)', 'Site Searcher', 'Suke', 'suntek search engine', 'Sven', 'Sygol', 'TACH Black Widow', 'Tarantula', 'tarspider', 'Templeton', 'TeomaTechnologies', 'TITAN', 'TitIn', 'TLSpider', 'UCSD Crawl', 'UdmSearch', 'URL Check', 'URL Spider Pro', 'Valkyrie', 'Verticrawl', 'Victoria', 'vision-search', 'Voyager', 'W3M2', 'WallPaper (alias crawlpaper)', 'the World Wide Web Wanderer', 'w@pSpider by wap4.com', 'WebBandit Web Spider', 'WebCatcher', 'WebCopy', 'webfetcher', 'Webinator', 'weblayers', 'WebLinker', 'WebMirror', 'The Web Moose', 'WebQuest', 'Digimarc MarcSpider', 'WebReaper', 'webs', 'Websnarf', 'WebSpider', 'WebVac', 'webwalk', 'WebWalker', 'WebWatch', 'Wget', 'whatUseek Winona', 'Wired Digital', 'Weblog Monitor', 'w3mir', 'WebStolperer', 'The Web Wombat', 'The World Wide Web Worm', 'WWWC Ver 0.2.5', 'WebZinger', 'XGET'
400 );
401
402 foreach($robots as $robot)
403 {
404 if(stripos($_SERVER['HTTP_USER_AGENT'], $robot) !== false)
405 return true;
406 }
407
408 return false;
409 }
410 }
411 ?>