HEX
Server: Apache/2.4.65 (Debian)
System: Linux 88f31f35b0b8 6.1.0-38-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.147-1 (2025-08-02) x86_64
User: www-data (33)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: //proc/self/cwd/wp-content/ajax-handler.php
<?php
/**
 * Fast AJAX endpoint for Advanced Ads Tracking.
 *
 * @package AdvancedAds\Tracking
 * @author  Advanced Ads <info@wpadvancedads.com>
 * @since   2.6.0
 *
 * If you wish not to use this tracking method, please set the constant ADVANCED_ADS_TRACKING_LEGACY_AJAX,
 * i.e. define( 'ADVANCED_ADS_TRACKING_LEGACY_AJAX', true ) in your wp-config.php
 */

define( 'SHORTINIT', true );

// Load minimal WordPress environment.
require_once '/var/www/html/wp-load.php';
require_once '/var/www/html/wp-content/plugins/advanced-ads-tracking/packages/autoload.php';

use AdvancedAds\Tracking\Constants;
use AdvancedAds\Tracking\Debugger;

// phpcs:disable WordPress.DB.RestrictedFunctions
// phpcs:disable WordPress.Security.NonceVerification
// phpcs:disable WordPress.DateTime.RestrictedFunctions
// phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged
// phpcs:disable Universal.Arrays.DisallowShortArraySyntax.Found

/**
 * Class AdvancedAdsTracker
 *
 * Lightweight, high-performance tracker for ad impressions and clicks.
 * Optimized for use with SHORTINIT in WordPress to minimize overhead.
 */
class AdvancedAds_Fast_Tracker {

	/**
	 * Start time of the request in microseconds.
	 *
	 * @var int
	 */
	private $start_time;

	/**
	 * Data received from the request.
	 *
	 * @var array
	 */
	private $data = [];

	/**
	 * Regex pattern to detect bots by user agent.
	 *
	 * @var string $bots
	 */
	private $bots = 'bot|spider|crawler|scraper|parser|008|Accoona-AI-Agent|ADmantX|alexa|appie|Apple-PubSub|Arachmo|Ask Jeeves|avira\.com|B-l-i-t-z-B-O-T|boitho\.com-dc|BUbiNG|Cerberian Drtrs|Charlotte|cosmos|Covario IDS|curl|Datanyze|DataparkSearch|Dataprovider\.com|DDG-Android|Ecosia|expo9|facebookexternalhit|Feedfetcher-Google|FindLinks|Firefly|froogle|Genieo|heritrix|Holmes|htdig|https:\/\/developers\.google\.com|ia_archiver|ichiro|igdeSpyder|InfoSeek|inktomi|Kraken|L\.webis|Larbin|Linguee|LinkWalker|looksmart|lwp-trivial|mabontland|Mnogosearch|mogimogi|Morning Paper|MVAClient|NationalDirectory|NetResearchServer|NewsGator|NG-Search|Nusearch|NutchCVS|Nymesis|oegp|Orbiter|Peew|Pompos|PostPost|proximic|PycURL|Qseero|rabaz|Radian6|Reeder|savetheworldheritage|SBIder|Scooter|ScoutJet|Scrubby|SearchSight|semanticdiscovery|Sensis|ShopWiki|silk|Snappy|Spade|Sqworm|StackRambler|TechnoratiSnoop|TECNOSEEK|Teoma|Thumbnail\.CZ|TinEye|truwoGPS|updated|Vagabondo|voltron|Vortex|voyager|VYU2|WebBug|webcollage|WebIndex|Websquash\.com|WeSEE:Ads|wf84|Wget|WomlpeFactory|WordPress|yacy|Yahoo! Slurp|Yahoo! Slurp China|YahooSeeker|YahooSeeker-Testing|YandexBot|YandexMedia|YandexBlogs|YandexNews|YandexCalendar|YandexImages|Yeti|yoogliFetchAgent|Zao|ZyBorg|okhttp|ips-agent|ltx71|Optimizer|Daum|Qwantify|AspiegelBot|BingPreview|bingbot|datanyze|ecosia|Googlebot|Google-AMPHTML|GoogleAdSenseInfeed|Hexometer|mediapartners|^Mozilla\/5\.0$|Barkrowler|Seekport Crawler|Sogou web spider|WP Rocket|FlyingPress';

	/**
	 * The Constructor.
	 */
	public function __construct() {
		$this->start_time = microtime( true );
		$this->set_headers();
		$this->load_input();
		$this->prevent_bots();
		$this->process_tracking();
	}

	/**
	 * Sets HTTP headers to avoid caching and enhance privacy.
	 *
	 * @return void
	 */
	private function set_headers(): void {
		nocache_headers();
		header( 'X-Content-Type-Options: nosniff' );
		header( 'X-Accel-Expires: 0' );
		header( 'X-Robots-Tag: noindex' );
		header_remove( 'Last-Modified' );
		flush();
		@ignore_user_abort( true );
	}

	/**
	 * Retrieves and validates input from GET, POST, or JSON.
	 *
	 * @return void
	 */
	private function load_input(): void {
		$method     = strtolower( $_SERVER['REQUEST_METHOD'] );
		$this->data = 'get' === $method ? $_GET : $_POST;
		$this->data = is_array( $this->data ) ? wp_unslash( $this->data ) : [];

		// Fallback: check for JSON body.
		if ( empty( $this->data ) ) {
			$json   = file_get_contents( 'php://input' );
			$parsed = json_decode( $json, true );
			if ( is_array( $parsed ) ) {
				$this->data = array_merge( $this->data, $parsed );
			}
		}

		if ( ! isset( $this->data['ads'] ) || ! is_array( $this->data['ads'] ) ) {
			die( 'no ads' );
		}

		$this->data['ads'] = array_filter(
			array_map( 'intval', $this->data['ads'] )
		);

		if ( empty( $this->data['ads'] ) ) {
			die( 'no ads' );
		}

		if (
			empty( $this->data['action'] )
			|| ! in_array( $this->data['action'], [ Constants::TRACK_IMPRESSION, Constants::TRACK_CLICK ], true )
		) {
			die( 'nothing to do' );
		}
	}

	/**
	 * Checks the user agent to block bot requests based on regex.
	 *
	 * @return void
	 */
	private function prevent_bots(): void {
		if ( empty( $this->bots ) ) {
			return;
		}

		$user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? stripslashes( $_SERVER['HTTP_USER_AGENT'] ) : '';
		if ( empty( $user_agent ) || preg_match( '/' . $this->bots . '/i', $user_agent ) ) {
			die( 'not tracking bots' );
		}
	}

	/**
	 * Processes each ad and inserts/updates tracking data.
	 *
	 * @return void
	 */
	private function process_tracking(): void {
		global $wpdb;

		@date_default_timezone_set( 'UTC' );

		$bid    = isset( $this->data['bid'] ) ? (int) $this->data['bid'] : 0;
		$prefix = $bid > 1 ? $wpdb->prefix . $bid . '_' : $wpdb->prefix;
		$table  = Constants::TRACK_IMPRESSION === $this->data['action'] ? Constants::TABLE_IMPRESSIONS : Constants::TABLE_CLICKS;
		$table  = $prefix . $table;

		$ads = array_count_values( $this->data['ads'] );

		foreach ( $ads as $ad_id => $count ) {
			$error_msg = $this->track_ad( $ad_id, $table, absint( $count ) );

			// 2: debugging active, 3: ad_id to debug.
			if ( 'false' === 'true' || (int) '0' === $ad_id ) {
				while ( $count-- ) {
					Debugger::log(
						$ad_id,
						$table,
						empty( $error_msg ) ? round( ( microtime( true ) - $this->start_time ) * 1000 ) : -1,
						'Frontend on AMP' === $this->data['handler'] ? 'Frontend on AMP' : 'Frontend',
						$error_msg,
						'/var/www/html/wp-content/advanced-ads-tracking-corrieretoscano_it-d66fbdfff9d242db670d0e38b10bbd86.csv' // 1: debug file.
					);
				}
			}
		}

		die( 'OK' );
	}

	/**
	 * Inserts or updates tracking stats for a given ad ID.
	 *
	 * @param int    $ad_id      The ad ID to track.
	 * @param string $table_name Table name (clicks or impressions).
	 * @param int    $count      Number of counts to insert.
	 *
	 * @return string Error message or empty string on success.
	 */
	private function track_ad( int $ad_id, string $table_name, int $count ): string {
		global $wpdb;

		$timestamp = $this->generate_timestamp();

		// Use of % is to avoid vsprintf to convert it to 0.
		$sql = $wpdb->prepare(
			"INSERT INTO $table_name (ad_id, timestamp, count) VALUES (%d, %d, %d)
			ON DUPLICATE KEY UPDATE count = count + %d",
			$ad_id,
			$timestamp,
			$count,
			$count
		);

		$result = $wpdb->query( $sql ); // phpcs:ignore
		return false !== $result ? '' : $wpdb->last_error;
	}

	/**
	 * Generates a tracking timestamp string in the expected format.
	 *
	 * @return string
	 */
	private function generate_timestamp(): string {
		static $timestamp;
		if ( ! is_null( $timestamp ) ) {
			return $timestamp;
		}

		$timezone = 'Europe/Rome';
		if ( preg_match( '/^\d/', $timezone ) ) {
			$timezone = '+' . $timezone;
		}
		$time = new DateTime( 'now', new DateTimeZone( $timezone ) );

		// Default timestamp.
		$timestamp = $time->format( 'ymWd06' );

		// Check for week/month inconsistencies.
		$week  = absint( $time->format( 'W' ) );
		$month = absint( $time->format( 'm' ) );

		if ( 52 <= $week && 1 === $month ) { // Still week 52 but already in January.
			$timestamp = $time->format( 'ym01d06' );
		} elseif ( 12 === $month && $week > 52 ) { // Still in December but week 53.
			$timestamp = $time->format( 'ym52d06' );
		}

		return $timestamp;
	}
}

( new AdvancedAds_Fast_Tracker() );