Skip to content

Commit

Permalink
Version bump, PHP version requirement upped
Browse files Browse the repository at this point in the history
Mostly small updates to documentation. New helper functions were added to improve the getIpAddress function.
  • Loading branch information
ericsizemore committed Jun 11, 2023
1 parent ffff535 commit fc0488b
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 42 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Usage is fairly simple once installed. Simply add the following code to the page

### Requirements

- Simple Counter works with PHP 7.0.0 or above.
- Simple Counter works with PHP 8.0.0 or above.

### Submitting bugs and feature requests

Expand Down Expand Up @@ -81,7 +81,7 @@ branches for both of these features and send two requests.

### Author

Eric Sizemore - <[email protected]> - <http://www.secondversion.com>
Eric Sizemore - <[email protected]> - <https://www.secondversion.com>

### License

Expand Down
142 changes: 102 additions & 40 deletions counter.php
Original file line number Diff line number Diff line change
@@ -1,53 +1,66 @@
<?php

/**
* @author Eric Sizemore <[email protected]>
* @package SV's Simple Counter
* @link http://www.secondversion.com/downloads/
* @version 4.0.3
* @copyright (C) 2006 - 2021 Eric Sizemore
* @license GNU Lesser General Public License
*
* SV's Simple Counter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
* SV's Simple Counter - A simple web hit counter.
*
* @author Eric Sizemore <[email protected]>
* @package SV's Simple Counter
* @link https://www.secondversion.com/
* @version 4.0.4
* @copyright (C) 2006 - 2023 Eric Sizemore
* @license GNU Lesser General Public License
*/
namespace Esi\SimpleCounter;

use Exception;

/**
* Main class that processes the counter.
* SV's Simple Counter - A simple web hit counter.
*
* @author Eric Sizemore <[email protected]>
* @package SV's Simple Counter
* @link https://www.secondversion.com/
* @version 4.0.4
* @copyright (C) 2006 - 2023 Eric Sizemore
* @license GNU Lesser General Public License
*
* Copyright (C) 2006 - 2023 Eric Sizemore. All rights reserved.
*
* SV's Simple Counter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class Counter
{
/** User Configuration **/

// Log file locations/paths.
const COUNT_FILE = 'counter/logs/counter.txt';
const IP_FILE = 'counter/logs/ips.txt';
private const COUNT_FILE = 'counter/logs/counter.txt';
private const IP_FILE = 'counter/logs/ips.txt';

// Use file locking?
const USE_FLOCK = true;
private const USE_FLOCK = true;

// Count only unique visitors?
const ONLY_UNIQUE = true;
private const ONLY_UNIQUE = true;

// Show count as images?
const USE_IMAGES = false;
private const USE_IMAGES = false;

// Path to the images.
const IMAGE_DIR = 'counter/images/';
private const IMAGE_DIR = 'counter/images/';

// Image extension.
const IMAGE_EXT = '.gif';
private const IMAGE_EXT = '.gif';

/** End User Configuration **/

Expand Down Expand Up @@ -88,9 +101,10 @@ public static function getInstance(): self
*/
private function getIpAddress(bool $trustProxyHeaders = false): string
{
// Pretty self-explanatory. Try to get an 'accurate' IP
$ip = $_SERVER['REMOTE_ADDR'];

if ($trustProxyHeaders === false) {
if ($trustProxyHeaders) {
return $ip;
}

Expand All @@ -106,49 +120,97 @@ private function getIpAddress(bool $trustProxyHeaders = false): string

if (!empty($ips)) {
foreach ($ips AS $val) {
if (
\inet_ntop(\inet_pton($val)) == $val
AND !\preg_match("#^(10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.|fe80:|fe[c-f][0-f]:|f[c-d][0-f]{2}:)#i", $val)
) {
if (\inet_ntop(\inet_pton($val)) == $val AND self::isPublicIp($val)) {
$ip = $val;
break;
}
}
}
unset($ips);

if (!$ip AND isset($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
}
return $ip;
}

// --- getIpAddress helpers --- //
/**
* isPrivateIp()
*
* Determines if an IP address is within the private range.
*
* @param string $ipaddress IP address to check.
* @return bool
*/
private function isPrivateIp(string $ipaddress): bool
{
return !(bool)\filter_var(
$ipaddress,
\FILTER_VALIDATE_IP,
\FILTER_FLAG_IPV4 | \FILTER_FLAG_IPV6 | \FILTER_FLAG_NO_PRIV_RANGE
);
}

/**
* isReservedIp()
*
* Determines if an IP address is within the reserved range.
*
* @param string $ipaddress IP address to check.
* @return bool
*/
private function isReservedIp(string $ipaddress): bool
{
return !(bool)\filter_var(
$ipaddress,
\FILTER_VALIDATE_IP,
\FILTER_FLAG_IPV4 | \FILTER_FLAG_IPV6 | \FILTER_FLAG_NO_RES_RANGE
);
}

/**
* isPublicIp()
*
* Determines if an IP address is not within the private or reserved ranges.
*
* @param string $ipaddress IP address to check.
* @return bool
*/
private function isPublicIp(string $ipaddress): bool
{
return (bool)(!self::isPrivateIp($ipaddress) AND !self::isReservedIp($ipaddress));
}

/**
* We use this function to open and read/write to files.
*
* @param string $file Filename
* @param string $mode Mode (r, w, a, etc..)
* @param string $data If writing to the file, the data to write
* @return mixed
*
* @throws Exception
*/
private function readWriteFile(string $file, string $mode, string $data = '')
private function readWriteFile(string $file, string $mode, string $data = ''): mixed
{
if (!\file_exists($file) OR !\is_writable($file)) {
throw new \Exception(\sprintf("'%s' does not exist or is not writable.", $file));
throw new Exception(\sprintf("'%s' does not exist or is not writable.", $file));
}

if (!($fp = \fopen($file, $mode))) {
throw new \Exception(\sprintf("'%s' could not be opened.", $file));
throw new Exception(\sprintf("'%s' could not be opened.", $file));
}

$return = null;

if (self::USE_FLOCK AND \flock($fp, LOCK_EX)) {
if (self::USE_FLOCK AND \flock($fp, \LOCK_EX)) {
if ($mode == 'r') {
$return = \fread($fp, \filesize($file));
} else {
\fwrite($fp, $data);
}
\flock($fp, LOCK_UN);
\flock($fp, \LOCK_UN);
} else {
if ($mode == 'r') {
$return = \fread($fp, \filesize($file));
Expand Down Expand Up @@ -176,7 +238,7 @@ public function process()
$ip = self::getIpAddress();

$ips = \trim(self::readWriteFile(self::IP_FILE, 'r'));
$ips = \preg_split("#\n#", $ips, -1, PREG_SPLIT_NO_EMPTY);
$ips = \preg_split("#\n#", $ips, -1, \PREG_SPLIT_NO_EMPTY);

// They've not visited before
if (!\in_array($ip, $ips)) {
Expand All @@ -191,7 +253,7 @@ public function process()

// Do we want to display the # visitors as graphics?
if (self::USE_IMAGES) {
$count = \preg_split('##', $count, -1, PREG_SPLIT_NO_EMPTY);
$count = \preg_split('##', $count, -1, \PREG_SPLIT_NO_EMPTY);
$length = \count($count);

for ($i = 0; $i < $length; $i++) {
Expand Down

0 comments on commit fc0488b

Please sign in to comment.