OwlCyberSecurity - MANAGER
Edit File: Analytics.php
<?php /** * Copyright (с) Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2022 All Rights Reserved * * Licensed under CLOUD LINUX LICENSE AGREEMENT * https://www.cloudlinux.com/legal/ */ namespace CloudLinux\SmartAdvice\App\Service; /** * Smart Advice analytics service. */ class Analytics { /** * API base URL. */ const API_BASE_URL = 'https://x-ray-advice.cloudlinux.com/api/analytics/'; /** * API endpoint handling redirects. */ const ENDPOINT_REDIRECT = 'redirect'; /** * API endpoint logging events. */ const ENDPOINT_SEND = 'events'; /** * API endpoint for analytics pixel. */ const ENDPOINT_PIXEL = 'pixel'; /** * Salt used to generate session data. * * @var string */ private $salt = ''; /** * Environment. * * @var string */ private $environment; /** * Server IP. * * @var string */ private $ip_address = ''; /** * Constructor. * * @param string $environment Environment. */ public function __construct( $environment ) { $this->environment = $environment; add_filter( 'cl_smart_advice_socket_data', array( $this, 'extend_socket_data' ), 10, 3 ); add_action( 'cl_smart_advice_subscription', array( $this, 'subscription' ), 20, 1 ); } /** * Appends analytics information to the advice data. * * @param array $data Data to send to socket. * @param string $method Method name. * @param array $args Original method arguments. * * @return array */ public function extend_socket_data( $data, $method, $args ) { $data['analytics_data'] = wp_json_encode( array_merge( $this->get_session_data(), array( 'event' => 'advice_' . $method, ) ) ); return $data; } /** * Report successful payment. * * @param string $advice_id id. * * @since 0.1-11 */ public function subscription( $advice_id ) { // Grab analytics data for the logged in user. $session_data = $this->get_session_data(); // Report successful payment. $this->send_event( wp_get_current_user()->user_email, $advice_id, 'awp_purchase_done', $session_data['user_hash'], $session_data['journey_id'] ); } /** * Get API URL. * * @return string */ private function get_api_url() { $result = self::API_BASE_URL; if ( defined( 'CL_ANALYTICS_API_URL' ) ) { $result = CL_ANALYTICS_API_URL; } elseif ( 'development' === $this->environment ) { $result = 'https://x-ray-staging.cloudlinux.com/api/analytics/'; } return trailingslashit( $result ); } /** * Get endpoint URL. * * @param string $endpoint Endpoint name. * * @return string */ public function get_endpoint_url( $endpoint ) { return $this->get_api_url() . $endpoint; } /** * Get redirect link. * * @param string $email Email address. * @param string $advice_id Advice ID. * @param string $event Event name. * @param string $redirect_url Redirect URL. * * @return string */ public function get_redirect_link( $email, $advice_id, $event, $redirect_url ) { $url_params = $this->build_common_event_params( $email, $advice_id, $event, 'mail_client' ); $url_params['redirect_url'] = $redirect_url; return $this->get_endpoint_url( self::ENDPOINT_REDIRECT ) . '?' . http_build_query( $url_params ); } /** * Sends event to the analytics service. * * @param string $email Email address. * @param string $advice_id Advice ID. * @param string $event Event name. * @param string $user_hash User hash. * @param string $journey_id Journey ID. * * @return array|\WP_Error The response or WP_Error on failure. */ public function send_event( $email, $advice_id, $event, $user_hash = null, $journey_id = null ) { $request_data = $this->build_common_event_params( $email, $advice_id, $event, 'wp_smartadvice', $user_hash, $journey_id ); $request_data['src_ip'] = $this->serverIp(); $result = wp_remote_post( $this->get_endpoint_url( self::ENDPOINT_SEND ), array( 'headers' => array( 'Content-Type' => 'application/json; charset=utf-8' ), 'timeout' => 2, 'redirection' => 2, 'blocking' => false, 'sslverify' => false, 'body' => wp_json_encode( $request_data ), ) ); if ( is_wp_error( $result ) ) { do_action( 'cl_smart_advice_set_error', E_ERROR, 'Error sending Analytics event: ' . $result->get_error_message(), __FILE__, __LINE__, array( 'to' => $email, 'advice_id' => $advice_id, 'event' => $event, ) ); } return $result; } /** * Gets URL of the analytics pixel image. * * @param string $email Email address. * @param string $advice_id Advice ID. * @param string $event Event name. * * @return string */ public function get_pixel_url( $email, $advice_id, $event ) { $url_params = $this->build_common_event_params( $email, $advice_id, $event, 'mail_client' ); return $this->get_endpoint_url( self::ENDPOINT_PIXEL ) . '?' . http_build_query( $url_params ); } /** * Get salt. * * @return string */ public function get_salt() { if ( empty( $this->salt ) ) { $this->salt = (string) time(); } return $this->salt; } /** * Build common event params. * * @param string $email Email address. * @param string $advice_id Advice ID. * @param string $event Event name. * @param string $source Source. * @param string $user_hash User hash. * @param string $journey_id Journey ID. * * @return array */ private function build_common_event_params( $email, $advice_id, $event, $source, $user_hash = null, $journey_id = null ) { $result = array( 'advice_id' => $advice_id, 'event' => $event, 'source' => $source, ); if ( ! empty( $email ) ) { $result['user_hash'] = ( ! empty( $user_hash ) ) ? $user_hash : md5( $email ); $result['journey_id'] = ( ! empty( $journey_id ) ) ? $journey_id : md5( $this->get_salt() . '|' . $email ); } return $result; } /** * Retrieves correct analytics session data. * * Session data is retrieved either from the meta of current user or generated fresh. If there is fresh session info * in the request data, it has been already stored in the user meta during `admin_init` hook. * * @return array Session data. */ public function get_session_data() { // Check user meta. $meta = get_user_meta( get_current_user_id(), 'clsat_session', true ); if ( is_array( $meta ) && array_key_exists( 'expires', $meta ) ) { if ( $meta['expires'] > time() ) { return $this->fill_missing_session_data( $meta['data'] ); } else { delete_user_meta( get_current_user_id(), 'clsat_session' ); } } // Generate fresh session data. $result = array( 'user_hash' => md5( wp_get_current_user()->user_email ), 'journey_id' => md5( $this->get_salt() . '|' . wp_get_current_user()->user_email ), ); $this->update_session_data( $result ); return $result; } /** * Retrieves correct analytics session data for js. * * @return array Session data. */ public function get_js_session_data() { $result = $this->get_session_data(); $result['src_ip'] = $this->serverIp(); return $result; } /** * Updates analytics session data for the current user. * * @param array $data Session data. * * @return void */ private function update_session_data( $data ) { $meta = array( 'data' => $data, 'expires' => time() + 60 * 60 * 24, // 24 hours ); update_user_meta( get_current_user_id(), 'clsat_session', $meta ); } /** * Initializes analytics session. * * @param array $params Request parameters, unsanitized. * * @return array */ public function init_session( $params ) { $result = $this->extract_session_params( $params ); if ( ! empty( $result ) ) { $this->update_session_data( $result ); } return $result; } /** * Extracts analytics session params. * * @param array $params Request parameters, unsanitized. * * @return array */ public function extract_session_params( $params ) { $session_param_names = array( 'user_hash', 'journey_id', 'variant_id' ); // Check received params. $result = array(); foreach ( $session_param_names as $param_name ) { if ( ! empty( $params[ $param_name ] ) ) { $result[ $param_name ] = sanitize_text_field( $params[ $param_name ] ); } } return $result; } /** * Fills missing mandatory session data. * * @param array $data Session data. * * @return array */ private function fill_missing_session_data( $data ) { if ( ! array_key_exists( 'user_hash', $data ) ) { $data['user_hash'] = md5( wp_get_current_user()->user_email ); } if ( ! array_key_exists( 'journey_id', $data ) ) { $data['journey_id'] = md5( $this->get_salt() . '|' . wp_get_current_user()->user_email ); } return $data; } /** * Get current user IP Address. * * @return string */ public function serverIp() { if ( ! empty( $this->ip_address ) ) { return $this->ip_address; } foreach ( array( 'HTTP_CF_CONNECTING_IP', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'SERVER_ADDR' ) as $key ) { if ( isset( $_SERVER[ $key ] ) ) { $ip_address = filter_var( sanitize_text_field( wp_unslash( $_SERVER[ $key ] ) ), FILTER_VALIDATE_IP ); if ( is_string( $ip_address ) ) { $this->ip_address = $ip_address; return $this->ip_address; } } } if ( function_exists( 'gethostbyname' ) && function_exists( 'gethostname' ) ) { $hostname = gethostname(); if ( is_string( $hostname ) ) { $ip = gethostbyname( $hostname ); if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) { $this->ip_address = $ip; } } } return $this->ip_address; } }