HEX
Server: LiteSpeed
System: Linux server315.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: globfdxw (6114)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: /home/globfdxw/www/wp-content/plugins/kirki/includes/Ajax/Collaboration/Sender.php
<?php
/**
 * Collaboration server
 *
 * @package kirki
 */

namespace Kirki\Ajax\Collaboration;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

use Kirki\HelperFunctions;


/**
 * Sender class will send and manage collaboration data, also tracking send info.
 */
class  Sender {

	/**
	 * Sender instance which will send event-strem as content type
	 *
	 * @return void
	 */
	public function __construct() {
		header( 'Content-Type: text/event-stream' );
		header( 'Cache-Control: no-cache' );
		header( 'Connection: keep-alive' );
	}

	/**
	 * Start method will start sending to single client.
	 *
	 * @return void
	 */
	public function start() {
		$this->fetch_and_send_events();
	}

	/**
	 * This method will collect active events and send events to a perticular user.
	 * This mathod also seperate event using parent and parent_id.
	 *
	 * @return void
	 */
	private function fetch_and_send_events() {

		// Fetch events from your data source.
		$events = $this->get_custom_events(); // Implement this function to retrieve your custom events.

		foreach ( $events as $event ) {
			$event_data = $event['data'];

			$parent    = $event['parent'];
			$parent_id = $event['parent_id'];
			//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			echo "event: collaboration-$parent-$parent_id\n"; // Specify the event name.
			// this data is a json data. No need to Escape.
			//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			echo "data: $event_data\n\n";

			// Flush the output buffer to send the event immediately.
			ob_flush();
			flush();
		}
	}

	/**
	 * Get custom events.
	 * Remove same user and same session.
	 */
	private static function get_custom_events() {
		self::clean_expired_rows();
		// Get the current user's session ID.
		// phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotValidated
		$session_id = HelperFunctions::sanitize_text( sanitize_text_field( wp_unslash( $_GET['session_id'] ) ) );
		$events     = array();
		global $wpdb;
		$query = $wpdb->prepare(
			'SELECT * FROM %1s WHERE session_id != %s AND status = %d ORDER BY created_at ASC LIMIT %d OFFSET %d',
			$wpdb->prefix . KIRKI_COLLABORATION_TABLE,
			$session_id,
			1,
			10,
			0
		);
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
		$rows = $wpdb->get_results( $query, ARRAY_A );
		foreach ( $rows as &$row ) {
			if ( ! self::is_already_sent( $row['id'], $session_id ) ) {
				$events[] = $row;
				self::add_to_sent_tracking_table( $row['id'], $session_id );
			}
			self::delete_single_collaboration( $row );
		}

		return $events;
	}

	/**
	 * Add events send status data inside sent table for tracking.
	 *
	 * @param int    $collaboration_id collbaration table id.
	 * @param string $session_id user current session id.
	 * @return void
	 */
	private static function add_to_sent_tracking_table( $collaboration_id, $session_id ) {
		global $wpdb;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
		$wpdb->insert(
			$wpdb->prefix . KIRKI_COLLABORATION_TABLE . '_sent',
			array(
				'collaboration_id' => (int) $collaboration_id,
				'session_id'       => $session_id,
			),
			array(
				'%d',
				'%s',
			)
		);
	}

	/**
	 * Check event is already sent or not.
	 *
	 * @param int    $collaboration_id collbaration table id.
	 * @param string $session_id user current session id.
	 * @return bool
	 */
	private static function is_already_sent( $collaboration_id, $session_id ) {
		global $wpdb;
		$query = $wpdb->prepare(
			'SELECT * FROM %1s WHERE collaboration_id = %d AND session_id = %s',
			$wpdb->prefix . KIRKI_COLLABORATION_TABLE . '_sent',
			$collaboration_id,
			$session_id
		);
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
		$d = $wpdb->get_row( $query );
		if ( $d ) {
			return true;
		}
		return false;
	}

	/**
	 * Check event is already sent or not.
	 *
	 * @param array $collaboration collbaration table single row.
	 * @return void
	 */
	private static function delete_single_collaboration( $collaboration ) {
		global $wpdb;
		$collaboration_id   = $collaboration['id'];
		$my_session_id      = $collaboration['session_id'];
		$all_connected_rows = Collaboration::get_all_connected_rows();
		$flag               = true;

		if ( $all_connected_rows ) {
			foreach ( $all_connected_rows as $key => $row ) {
				if ( ! self::is_already_sent( $collaboration_id, $row->session_id ) && $row->session_id !== $my_session_id ) {
					$flag = false;
					break;
				}
			}
		}

		if ( $flag ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->delete( $wpdb->prefix . KIRKI_COLLABORATION_TABLE, array( 'id' => $collaboration_id ) );
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->delete( $wpdb->prefix . KIRKI_COLLABORATION_TABLE . '_sent', array( 'collaboration_id' => $collaboration_id ) );
		}
	}

	/**
	 * Clean expired row.
	 * expired if collboration data sent with in 60sec.
	 *
	 * @return void
	 */
	private static function clean_expired_rows() {
		global $wpdb;
		$sixty_seconds_ago = gmdate( 'Y-m-d H:i:s', strtotime( '-20 seconds' ) );
		$query1            = $wpdb->prepare(
			'DELETE FROM %1s WHERE updated_at <= %s',
			$wpdb->prefix . KIRKI_COLLABORATION_TABLE,
			$sixty_seconds_ago
		);
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
		$wpdb->query( $query1 );

		$query2 = $wpdb->prepare(
			'DELETE FROM %1s WHERE updated_at <= %s',
			$wpdb->prefix . KIRKI_COLLABORATION_TABLE . '_sent',
			$sixty_seconds_ago
		);
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
		$wpdb->query( $query2 );
	}

}