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 | ?> |