| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- <?php
- /**
- * This class represents an event used to record a Tracks event
- *
- * @package WooCommerce\Tracks
- */
- use Automattic\Jetpack\Constants;
- defined( 'ABSPATH' ) || exit;
- /**
- * WC_Tracks_Event class.
- */
- class WC_Tracks_Event {
- /**
- * Event name regex.
- */
- const EVENT_NAME_REGEX = '/^(([a-z0-9]+)_){2}([a-z0-9_]+)$/';
- /**
- * Property name regex.
- */
- const PROP_NAME_REGEX = '/^[a-z_][a-z0-9_]*$/';
- /**
- * Error message as WP_Error.
- *
- * @var WP_Error
- */
- public $error;
- /**
- * WC_Tracks_Event constructor.
- *
- * @param array $event Event properties.
- */
- public function __construct( $event ) {
- $_event = self::validate_and_sanitize( $event );
- if ( is_wp_error( $_event ) ) {
- $this->error = $_event;
- return;
- }
- foreach ( $_event as $key => $value ) {
- $this->{$key} = $value;
- }
- }
- /**
- * Record Tracks event
- *
- * @return bool Always returns true.
- */
- public function record() {
- if ( wp_doing_ajax() || Constants::is_true( 'REST_REQUEST' ) ) {
- return WC_Tracks_Client::record_event( $this );
- }
- return WC_Tracks_Footer_Pixel::record_event( $this );
- }
- /**
- * Annotate the event with all relevant info.
- *
- * @param array $event Event arguments.
- * @return bool|WP_Error True on success, WP_Error on failure.
- */
- public static function validate_and_sanitize( $event ) {
- $event = (object) $event;
- // Required.
- if ( ! $event->_en ) {
- return new WP_Error( 'invalid_event', 'A valid event must be specified via `_en`', 400 );
- }
- // Delete non-routable addresses otherwise geoip will discard the record entirely.
- if ( property_exists( $event, '_via_ip' ) && preg_match( '/^192\.168|^10\./', $event->_via_ip ) ) {
- unset( $event->_via_ip );
- }
- $validated = array(
- 'browser_type' => WC_Tracks_Client::BROWSER_TYPE,
- );
- $_event = (object) array_merge( (array) $event, $validated );
- // If you want to block property names, do it here.
- // Make sure we have an event timestamp.
- if ( ! isset( $_event->_ts ) ) {
- $_event->_ts = WC_Tracks_Client::build_timestamp();
- }
- return $_event;
- }
- /**
- * Build a pixel URL that will send a Tracks event when fired.
- * On error, returns an empty string ('').
- *
- * @return string A pixel URL or empty string ('') if there were invalid args.
- */
- public function build_pixel_url() {
- if ( $this->error ) {
- return '';
- }
- $args = get_object_vars( $this );
- // Request Timestamp and URL Terminator must be added just before the HTTP request or not at all.
- unset( $args['_rt'], $args['_'] );
- $validated = self::validate_and_sanitize( $args );
- if ( is_wp_error( $validated ) ) {
- return '';
- }
- return esc_url_raw( WC_Tracks_Client::PIXEL . '?' . http_build_query( $validated ) );
- }
- /**
- * Check if event name is valid.
- *
- * @param string $name Event name.
- * @return false|int
- */
- public static function event_name_is_valid( $name ) {
- return preg_match( self::EVENT_NAME_REGEX, $name );
- }
- /**
- * Check if a property name is valid.
- *
- * @param string $name Event property.
- * @return false|int
- */
- public static function prop_name_is_valid( $name ) {
- return preg_match( self::PROP_NAME_REGEX, $name );
- }
- /**
- * Check event names
- *
- * @param object $event An event object.
- */
- public static function scrutinize_event_names( $event ) {
- if ( ! self::event_name_is_valid( $event->_en ) ) {
- return;
- }
- $allowed_key_names = array(
- 'anonId',
- 'Browser_Type',
- );
- foreach ( array_keys( (array) $event ) as $key ) {
- if ( in_array( $key, $allowed_key_names, true ) ) {
- continue;
- }
- if ( ! self::prop_name_is_valid( $key ) ) {
- return;
- }
- }
- }
- }
|