<?php

/*
Plugin Name: CellarWeb Server Side Analytics
Plugin URI: http://cellarweb.com/wordpress-plugins/
Description: Allows using Google Analytics via server-side request. Many ad blockers block client-side Google Analytics, resulting in incomplete values. This plugin will always do analytics on any visit, even with ad blockers. User IP address is anonymized to comply with cwssa rules. No client-side cookies are used.
Version: 1.00
Tested up to: 5.9
Requires at least: 4.9.6
PHP Version: 5.4
Author: Rick Hellewell - CellarWeb.com
Author URI: http://CellarWeb.com
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
 */

/*
Copyright (c) 2016-2022 by Rick Hellewell and CellarWeb.com
All Rights Reserved

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.

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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA02110-1301USA

 */
//------------------------------------------------------------------------------
// GETTING STARTED start
//------------------------------------------------------------------------------
define("CWSSA_VERSION", "1.00 (24 Mar 2022)");
// check for required versions of WP and PHP
$min_wp  = '4.9.6';
$min_php = '5.4';
if (!CWSSA_is_requirements_met($min_wp, $min_php)) {
	add_action('admin_init', 'CWSSA_disable_plugin');
	add_action('admin_notices', 'CWSSA_show_notice_disabled_plugin');
	add_action('network_admin_init', 'CWSSA_disable_plugin');
	add_action('network_admin_notices', 'CWSSA_show_notice_disabled_plugin');
	CWSSA_deregister();
	return;
}

// insert into the header the code to display the banner
add_action('wp_footer', 'CWSSA_the_header');

// if we want to display an admin notice     (NOT USED)
function CWSSA_notice_page_created($msg = "an admin message") {
	echo esc_html__('<div class="notice notice-success is-dismissible">' . $msg . '</div>');
	return;
}

// ----------------------------------------------------------------
function CWSSA_output_empty() // (NOT USED)
{
	return;
}

/**
 * Generated by the WordPress Option Page generator
 * at http://jeremyhixon.com/wp-tools/option-page/
 */

class Simplecwssa {
	private $simple_cwssa_options;

	public function __construct() {
		add_action('admin_menu', array($this, 'simple_cwssa_add_plugin_page'));
		add_action('admin_init', array($this, 'simple_cwssa_page_init'));
	}

	public function simple_cwssa_add_plugin_page() {
		add_options_page(
			'CellarWeb Server Side Analytics', // page_title
			'Server Side Analytics Settings', // menu_title
			'manage_options', // capability
			'simple-cwssa', // menu_slug
			array($this, 'simple_cwssa_create_admin_page') // function
		);
	}

	public function simple_cwssa_create_admin_page() {
		$this->simple_cwssa_options = get_option('CWSSA_options');?>

        <div >
        <div class="CWSSA_options">
            <?php CWSSA_info_top();?>

                <form method="post" action="options.php">
                    <?php
settings_fields('simple_cwssa_option_group');
		do_settings_sections('simple-cwssa-admin');
		submit_button();
		?>
                </form>
                <?php CWSSA_footer(); // display bottom info stuff
		?>
    </div>
    </div>
    <div class='CWSSA_sidebar'>
        <?php CWSSA_sidebar();?>
    </div>

<?php
}

	public function simple_cwssa_page_init() {
		wp_register_style('CWSSA_namespace', plugins_url('/css/settings.css', __FILE__), array(), CWSSA_VERSION);
		wp_enqueue_style('CWSSA_namespace'); // gets the above css file in the proper spot
		register_setting(
			'simple_cwssa_option_group', // option_group
			'CWSSA_options', // option_name
			array($this, 'simple_cwssa_sanitize') // sanitize_callback
		);

		add_settings_section(
			'simple_cwssa_setting_section', // id
			'Information and Settings', // title
			array($this, 'simple_cwssa_section_info'), // callback
			'simple-cwssa-admin' // page
		);

		add_settings_field(
			'CWSSA_GA_ID_number', // id
			'Google Analytics ID number', // title
			array($this, 'CWSSA_GA_ID_number_callback'), // callback
			'simple-cwssa-admin', // page
			'simple_cwssa_setting_section' // section
		);
	}

	public function simple_cwssa_sanitize($input) {
		$sanitary_values = array();

		if (isset($input['CWSSA_GA_ID_number'])) {
			$sanitary_values['CWSSA_GA_ID_number'] = sanitize_text_field($input['CWSSA_GA_ID_number']);
		}

		return $sanitary_values;
	}

	public function simple_cwssa_section_info() {
		print '
<p>If you enter a Google Analytics ID Number, the plugin will use server-side commands to capture basic Google Analytics information to your GA account. This allows analytics tracking for visitors that have ad-blockers, an advantagethat gives you more accurate analytics data over the \'normal\' GA process of using client-side JavaScript code. And our GA process does not store any visitor\'s personal information anywhere.</p>
    <p>If you use Google Analytics, then you should be aware of their privacy policy, which could apply to your use of GA; see it here <a href="https://www.google.com/analytics/terms/us.html" target="_blank">https://www.google.com/analytics/terms/us.html</a> </p><p><b>Note: Only Googla Universal Analytics (UA-xxxxxxxx-x) are supported with this plugin.</b></p>';
	}

	public function CWSSA_GA_ID_number_callback() {
		$selected_page_option = get_option('CWSSA_options');
		$GA_ID                = $selected_page_option['CWSSA_GA_ID_number'];
		printf(
			'<input class="regular-text" type="text" name="CWSSA_options[CWSSA_GA_ID_number]" id="CWSSA_GA_ID_number" value="%s">',
			$GA_ID
		);
		print(' <p>Enter your GA ID number; it is not verified. If you don\'t want GA tracking, or use another process, leave this blank (although that\'s the whole point of this plugin).</p><p>Note that the standard GA JavaScript code is often blocked by ad blockers, which dilutes your analytics information. Using a server-side process to allow basic tracking for visitors even with ad blocking enabled on their browser.</p><p>The client information sent to GA includes only the visited page information, and anonymized IP address. No cookies are stored in the client\s browser.</p><p><b>Make sure you don\'t have another process that does Google Analytics, or you will double your GA stats.</b></p><p>After entering and saving your valid GA code, you should see data in the "Real Time" area of GA for your site. Page visits are usually shown within 15 seconds of the visit.</p>');
	}
}
if (is_admin()) {
	$simple_cwssa = new Simplecwssa();
}

// ----------------------------------------------------------------------------
// supporting functions
// ----------------------------------------------------------------------------
//  display the top info part of the settings page
// ----------------------------------------------------------------------------
function CWSSA_info_top() {
	?>
<div class="wrap" >
    <h2></h2>
<div align='center' class = 'CWSSA_header'>
    <div align='center'>
    <img src="<?php echo esc_html__(plugin_dir_url(__FILE__)); ?>assets/banner-1000x200.jpg" width="100%"  alt="" class='CWSSA_shadow'>
        <h2 align="center">Adds Server-side Google Analytics (GA) to Bypass Ad Blocking of Client-Side GA.</h2>
        <h5>Version <?php echo esc_html__(CWSSA_VERSION); ?></h5>
    </div>
    <hr />
</div>
</div>
<?php
}

// ----------------------------------------------------------------------------
//  settings page sidebar content
// ----------------------------------------------------------------------------
function CWSSA_sidebar() {
	?>
    <h3 align="center">But wait, there's more!</h3>
    <p><b>Need to stop Comment spam?</b> We've got a plugin that does that - install it and comment spam will stop immediately. Very effective. Does not require any other actions or configuration, and your comment form will look the same. It just works! See details here: <a href="https://wordpress.org/plugins/block-comment-spam-bots/" target="_blank" title="Block Comment Spam Bots">Block Comment Spam Bots</a> .</p>
<p><b>Plus these Contact Form spam-blocking plugins:</b></p>
<p><b>If you want to block bots from your contact form</b>, head over to our <a href="https://www.FormSpammerTrap.com" target="_blank" title="FormSpammerTrap - blocks Contact form spammers">FormSpammerTrap</a> site. <i>Works on WP and non-WP sites.</i> Takes a bit of programming, but we can help with that. Full docs and implementation instructions. Just request the free code via the site's Contact form. It's the most powerful and effective way to block Contact Form spammers!</p>
    <p><a href="https://wordpress.org/plugins/formspammertrap-for-comments/" target="_blank"><strong>FormSpammerTrap for Comments</strong></a>: reduces spam without captchas, silly questions, or hidden fields - which don't always work. You can also customize the look of your comment form. Uses the same techniques as our Block Comment Spam Bots plugin. </p>
    <p><a href="https://wordpress.org/plugins/formspammertrap-for-contact-form-7/" target="_blank"><strong>FormSpammerTrap for Contact Form 7</strong></a>: reduces spam when you use Contact Form 7 forms. All you do is add a little shortcode to the contact form.</p>
    <hr />
   <p>For <strong>multisites</strong>, we've got:
    <ul>
        <li><strong><a href="https://wordpress.org/plugins/multisite-comment-display/" target="_blank">Multisite Comment Display</a></strong> to show all comments from all subsites.</li>
        <li><strong><a href="https://wordpress.org/plugins/multisite-post-reader/" target="_blank">Multisite Post Reader</a></strong> to show all posts from all subsites.</li>
        <li><strong><a href="https://wordpress.org/plugins/multisite-media-display/" target="_blank">Multisite Media Display</a></strong> shows all media from all subsites with a simple shortcode. You can click on an item to edit that item. </li>
    </ul>
    </p>
    <hr />
    <p><b>Other Plugins</b></p>
     <p>We've got a <a href="https://wordpress.org/plugins/simple-cwssa/" target="_blank"><strong>CellarWeb Server Side Analytics</strong></a> plugin that displays a cwssa banner ('cookie consent') for the user to acknowledge. And it creates a generic Privacy page, and will put that Privacy Page link at the bottom of all pages.</p>
<p><b>An option will do server-side Google Analytics (GA).</b> Did you know what GA is blocked by many ad-blockers - diluting the accuracy of your analytics? This will ensure that every visitor access is captured by GA - and with anonymized information that doesn't store personal information.</p>
    <p>How about our <strong><a href="https://wordpress.org/plugins/url-smasher/" target="_blank">URL Smasher</a></strong> which automatically shortens URLs in pages/posts/comments?</p>
<p><b>Or one that automatically adds your Affiliate link to all Amazon links - in posts and comments?</b> That's what our Amazolinkentor plugin does, and you can get it <a href="https://wordpress.org/plugins/amazolinkenator/" target="_blank" title="Automatic Affiliate Code Insertion">here</a>.</p>
    <hr />
    <p><strong>They are all free and fully featured!</strong></p>
    <hr />
    <p>I don't drink coffee, but if you are inclined to donate any amount because you like my WordPress plugins, go right ahead! I'll grab a nice hot chocolate, and maybe a blueberry muffin.  Maybe another bag of Cherry Jelly Belliees. And a nice <a href="https://wordpress.org/plugins/simple-cwssa/#reviews" target="_blank" title="CellarWeb Server Side Analytics Plugin Reviews page">review on the plugin page</a> is always appreciated! Or just contact us at <a href="https://cellarweb.com/contactus/" target="_blank">https://cellarweb.com/contactus/</a>. </p>
    <div align="center">
        <?php CWSSA_donate_button();?>
    </div>
    <p align='center'><b>Thanks!  <a href="https://www.RichardHellewell.com" target="_blank" title="Richard Hellewell author site">Richard Hellewell</a>, somewhere opposite Mutiny Bay WA.</b></p>
    <hr />
    <p><strong>Privacy Notice</strong>: This plugin does not store or use any personal information or cookies.</p>
<?php
CWSSA_cellarweb_logo();

	return;
}

// ============================================================================
// footer for settings page
// ----------------------------------------------------------------------------
function CWSSA_footer() {
	?>
    <hr><h3 align='center' class='CWSSA_larger_text'><b>Thanks for using our Server Side Analytics plugin!  Tell your friends!</b></h3>
<hr><div style="background-color:#9FE8FF !important; padding:10px;color:black !important; ">
    <p align="center"><strong>Copyright &copy; 2016- <?php echo esc_html__(date('Y')); ?> by Rick Hellewell and <a href="http://CellarWeb.com" title="CellarWeb" >CellarWeb.com</a> , All Rights Reserved. Released under GPL2 license. <a href="http://cellarweb.com/contact-us/" target="_blank" title="Contact Us">Contact us page</a>.</strong></p>
</div>
<hr><br>
<?php
return;
}

// ----------------------------------------------------------------------------
// display the copyright info part of the adminpage
// ----------------------------------------------------------------------------
function CWSSA_info_bottom() {
	CWSSA_create_page_button(); // show the create the privacy page button
	// print copyright with current year, never needs updating
	$xstartyear    = "2016";
	$xname         = "Rick Hellewell";
	$xcompanylink1 = ' <a href="http://CellarWeb.com" title="CellarWeb" >CellarWeb.com</a>';
	echo esc_html__('<hr><div style="background-color:#9FE8FF;padding-left:15px;padding:10px 0 10px 0;margin:15px 0 15px 0;">
    <p align="center"><strong>Copyright &copy; ' . $xstartyear . '- ' . date("Y") . ' by ' . $xname . ' and ' . $xcompanylink1);
	echo esc_html__(' , All Rights Reserved. Released under GPL2 license. <a href="http://cellarweb.com/contact-us/" target="_blank" title="Contact Us">Contact us page</a>.</strong></p></div><hr>');
	return;
}

// ----------------------------------------------------------------------------
function CWSSA_cellarweb_logo() {
	?>
 <p align="center"><a href="https://www.cellarweb.com" target="_blank" title="CellarWeb.com site"><img src="<?php echo esc_html__(plugin_dir_url(__FILE__)); ?>assets/cellarweb-logo-2022.jpg"  width="90%" class="CWSSA_shadow" ></a></p>
 <?php
return;
}

// ----------------------------------------------------------------------------
// PayPal donation button for settings sidebar (as of 25 Jan 2022)
function CWSSA_donate_button() {
	?>
<form action="https://www.paypal.com/donate" method="post" target="_top">
    <input type="hidden" name="hosted_button_id" value="TT8CUV7DJ2SRN" />
    <input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif" border="0" name="submit" title="PayPal - The safer, easier way to pay online!" alt="Donate with PayPal button" />
    <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
</form>

<?php
return;
}

// ----------------------------------------------------------------------------
function CWSSA_button_admin_page() {
	// This function creates the output for the admin page.
	// The check_admin_referer is a WordPress function that does some security
	// checking and is recommended good practice.
	global $CWSSA_submit_html; // text for html button
	global $CWSSA_submit_create_page; // text for html button
	// General check for user permissions.
	if (!current_user_can('manage_options')) {
		wp_die(__('You do not have sufficient privileges to access this page.'));
	}
	// Start building the page
	echo esc_html__('<div class="wrap">');
	echo esc_html__('<hr>');
	echo esc_html__('<div style="border:thin solid #000; padding: 5px 15px 5px 15px;margin-left: 15px;max-width:800px;list-style:none !important;">');
	echo esc_html__("<p>A simple way to add server-side Google Anlaytics, for those visitors that use ad-blocking, if you fill in your GA user ID below and Save Settings.</p>");

	// form starts here if we want a button to do anything
	echo esc_html__('<form action="options.php" method="post">');
	settings_fields('CWSSA_options');
	do_settings_section('CWSSA_options');

	?>
<?php
submit_button($CWSSA_submit_html, 'button-primary', 'CWSSA_button');
	echo esc_html__('</form>');
	echo esc_html__("<hr style=\"border-top: 3px solid #2ebc57;\" />");
	echo esc_html__('<hr>');
}

// ----------------------------------------------------------------------------
// register/deregister/uninstall options (nothing happens here, but is here anyway
function CWSSA_register() {
	return;
}

function CWSSA_deregister() {
	return;
}

function CWSSA_uninstall() {
	return;
}

//----------------------------------------------------------------------------
// delete old generated files
function CWSSA_delete_old_files() {
	return true;
}

// ----------------------------------------------------------------------------
// check if at least WP 4.6 and PHP version at least 5.3
// based on https://www.sitepoint.com/preventing-wordpress-plugin-incompatibilities/
function CWSSA_is_requirements_met($min_wp = '4.6', $min_php = '5.4') {
	// Check for WordPress version
	if (version_compare(get_bloginfo('version'), $min_wp, '<')) {
		return false;
	}
	// Check the PHP version
	if (version_compare(PHP_VERSION, $min_php, '<')) {
		return false;
	}
	return true;
}

// ----------------------------------------------------------------------------
// disable plugin if WP/PHP versions are not enough
function CWSSA_disable_plugin() {
	if (is_plugin_active(plugin_basename(__FILE__))) {
		deactivate_plugins(plugin_basename(__FILE__));
		// Hide the default "Plugin activated" notice
		if (isset($_GET['activate'])) {
			unset($_GET['activate']);
		}
	}
}

// ----------------------------------------------------------------------------
// show notice that plugin was deactivated because WP/PHP versions not enough
function CWSSA_show_notice_disabled_plugin() {
	echo esc_html__('<div class="notice notice-error is-dismissible"><h3><strong>CellarWeb Server Side Analytics</strong></h3><p> cannot be activated - requires at least WordPress 4.6 and PHP 5.4.&nbsp;&nbsp;&nbsp;Plugin automatically deactivated.</p></div>');
	return;
}

// ----------------------------------------------------------------------------
// admin notice if something failed
function CWSSA_admin_notice_generic_error($theerrors = array('Something did not work correctly!')) {
	foreach ($the_errors as $the_error) {
		echo esc_html__("<div class='notice notice-error is-dismissible'><h3><strong>CellarWeb Server Side Analytics</strong></h3><p> - Error: $the_error .</p></div>");
	}
	return;
}

// ----------------------------------------------------------------------------
// this adds the two functions to the head section via the hook for public pages
function CWSSA_the_header() {
	$CWSSA_analytics_ID = '';
	$CWSSA_options      = get_option('CWSSA_options');
	$CWSSA_GA_ID        = $CWSSA_options['CWSSA_GA_ID_number'];
	// do se rver-side analytics if enabled by a GA ID on settings screen
	if ($CWSSA_GA_ID) {
		CWSSA_analytics($CWSSA_GA_ID);
	}
	return;
}

//------------------------------------------------------------------------------
//  post analytics using server-side post
function CWSSA_analytics() {
	global $wp;
	$options = get_option('CWSSA_options');
	// CWSSA_print_array($options);
	$GA_code = $options['CWSSA_GA_ID_number']; // CWSSA_GA_ID_number
	// get the GA ID from the options table
	$url = 'https://www.google-analytics.com/collect?';
	if (empty($GA_code)) {;return false;}
	if (wp_get_referer()) {$page_referrer = wp_get_referer();} else { $page_referrer = "";}
	$page_referrer = urlencode($page_referrer);
	// create a unique value to send with the request
	//   use session_id value set in CW2021_session_init()
	//       or CW2021_guidv4()  if seesion not started (should never happen)
	$user_id = (session_id()) ? session_id() : CW2021_guidv4();
	// filter the remote ip address
	$ip =  (filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP)) ? $_SERVER['REMOTE_ADDR'] : "";
	// force anoymize IP addresses just in case GA doesn't do it right
	$uip = CWSSA_anon_IP($ip);
	// get and filter referring page
	$referer = wp_validate_redirect(wp_get_referer()) ;

	// get full url including page and query
	$current_url =   sanitize_url($_SERVER['REQUEST_URI']); // can't use get_permalink, which doesn't work for the home page. And it is secure (not modifiable by visitor) so doesn't need sanitation. See https://stackoverflow.com/a/6474936/1466973

	// create a unique value to send with the request
	//   use session_id value set in CWSSA_session_init()
	//       or CWSSA_guidv4()  if seesion not started (should never happen)
	$user_id = (session_id()) ? session_id() : CWSSA_guidv4();
	// force anoymize IP addresses just in case GA doesn't do it right
	$uip = CWSSA_anon_IP($_SERVER['REMOTE_ADDR']);
	// build the data array that GA wants
	$referer = wp_validate_redirect(wp_get_referer()) ;

	// build the data array that GA wants
	$data = array(
		'v' => 1,
		'tid' => $GA_code, // site GA id code UA-xxxxxxxxxx ; change this
		'cid' => $user_id, // customer ID (cookie or session id)
		't' => 'pageview', // type of access
		'dp' => $current_url, // page name
		'aip' => '0', //anonymize the IP address   - don't need to, since we already did, so force no anonymize
		'uip' => $uip, // used for geo data in analytics , pre-anonymized just in case
		'ds' => 'web', // datasource, optional, set to 'web'
		'dr' => $referer, // referring page
		'z' => CWSSA_guidv4(), // cache buster, MUST BE LAST parameter!
	);
	$fields_string = http_build_query($data);
	// do the request the "WordPress way"  (don't use CURL)
	// send the post via wp_remote_post

	$response = wp_remote_post($url . $fields_string);
	return $response;
}

//------------------------------------------------------------------------------
// Anonymize the visitor IP
function CWSSA_anon_IP($ip) {
	return preg_replace(
		array('/\.\d*$/', '/[\da-f]*:[\da-f]*$/'),
		array('.0', '0000:0000'),
		$ip
	);
}

//------------------------------------------------------------------------------
// creates a guid for use by the GA post to send unique user id
function CWSSA_guidv4() {
	if (function_exists('com_create_guid') === true) {
		return trim(com_create_guid(), '{}');
	}

	$data    = openssl_random_pseudo_bytes(16);
	$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
	$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
	return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}


// -------------------------------------------------------------------------------

// ===============================================================================
// ALL DONE!!
// ===============================================================================
