Shared security patch analysis results
AI Used: claude_cli haiku--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/elex-helpdesk-customer-support-ticket-system.php 2025-12-21 09:35:59.417065320 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/elex-helpdesk-customer-support-ticket-system.php 2025-12-21 09:36:35.223290788 +0000@@ -1,368 +1,368 @@-<?php -/** - * Plugin Name: ELEX HelpDesk & Customer Support Ticket System - * Plugin URI: https://elextensions.com/plugin/wsdesk-wordpress-helpdesk-plugin-free-version/ - * Description: Enhances your customer service and enables efficient handling of customer issues. - * Version: 3.3.4 - * Author: ELEXtensions - * Author URI: https://elextensions.com/ - * Text Domain: wsdesk - * Domain Path: /lang - */ -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -if ( ! defined( 'WSDESK_PLUGIN_TYPE' ) ) { - define( 'WSDESK_PLUGIN_TYPE', 'basic' ); -} - -if ( defined( 'EH_CRM_VERSION' ) ) { - deactivate_plugins( plugin_basename( __FILE__ ) ); - $activated_plugins = (array) get_option( 'active_plugins' ); - $wsdesk_plugins = array( - 'wsdesk-premium/wsdesk.php' => "PREMIUM Version of WSDesk Plugin is activated. Please deactivate the PREMIUM Version of WSDesk before activating BASIC version.<br>Don't worry! Your ticket and settings data will be retained.<br>Go back to <a href='" . esc_html( admin_url( 'plugins.php' ) ) . "'>plugins page</a>", - 'wsdesk-basic/wsdesk.php' => "BASIC Version of WSDesk Plugin is activated. Please deactivate the BASIC Version of WSDesk before activating PREMIUM version.<br>Don't worry! Your ticket and settings data will be retained.<br>Go back to <a href='" . esc_html( admin_url( 'plugins.php' ) ) . "'>plugins page</a>", - 'elex-helpdesk-customer-support-ticket-system/elex-wordpress-helpdesk.php' => "BASIC Version of WSDesk Plugin is activated. Please deactivate the BASIC Version of WSDesk before activating PREMIUM version.<br>Don't worry! Your ticket and settings data will be retained.<br>Go back to <a href='" . esc_html( admin_url( 'plugins.php' ) ) . "'>plugins page</a>", - 'elex-wordpress-helpdesk/elex-wordpress-helpdesk.php' => "BASIC Version of WSDesk Plugin is activated. Please deactivate the BASIC Version of WSDesk before activating PREMIUM version.<br>Don't worry! Your ticket and settings data will be retained.<br>Go back to <a href='" . esc_html( admin_url( 'plugins.php' ) ) . "'>plugins page</a>", - 'wsdesk-helpdesk-customer-support-ticket-system/wsdesk.php' => "WooCommerce Version of WSDesk Plugin is activated. Please deactivate the WooCommerce Version of WSDesk before activating BASIC version.<br>Don't worry! Your ticket and settings data will be retained.<br>Go back to <a href='" . esc_html( admin_url( 'plugins.php' ) ) . "'>plugins page</a>", - ); - $current_wsdesk_plugin = plugin_basename( __FILE__ ); - - foreach ( $wsdesk_plugins as $wsdesk_plugin => $error_msg ) { - - if ( $current_wsdesk_plugin === $wsdesk_plugin ) { - continue; - } - if ( in_array( $wsdesk_plugin, $activated_plugins, true ) ) { - wp_die( wp_kses_post( $error_msg ) ); - } - } - return; -} else { - - if ( ! defined( 'EH_CRM_VERSION' ) ) { - define( 'EH_CRM_VERSION', '3.1.2' ); - } - if ( ! defined( 'EH_CRM_MAIN_URL' ) ) { - define( 'EH_CRM_MAIN_URL', plugin_dir_url( __FILE__ ) ); - } - if ( ! defined( 'EH_CRM_MAIN_PATH' ) ) { - define( 'EH_CRM_MAIN_PATH', plugin_dir_path( __FILE__ ) ); - } - if ( ! defined( 'EH_CRM_MAIN_IMG' ) ) { - define( 'EH_CRM_MAIN_IMG', EH_CRM_MAIN_URL . 'assets/img/' ); - } - if ( ! defined( 'EH_CRM_MAIN_CSS' ) ) { - define( 'EH_CRM_MAIN_CSS', EH_CRM_MAIN_URL . 'assets/css/' ); - } - if ( ! defined( 'EH_CRM_MAIN_JS' ) ) { - define( 'EH_CRM_MAIN_JS', EH_CRM_MAIN_URL . 'assets/js/' ); - } - if ( ! defined( 'EH_CRM_MAIN_VENDOR' ) ) { - define( 'EH_CRM_MAIN_VENDOR', EH_CRM_MAIN_PATH . 'vendor/' ); - } - if ( ! defined( 'EH_CRM_MAIN_VIEWS' ) ) { - define( 'EH_CRM_MAIN_VIEWS', EH_CRM_MAIN_PATH . 'views/' ); - } - if ( ! defined( 'EH_CRM_WOO_STATUS' ) ) { - if ( in_array( 'woocommerce/woocommerce.php', get_option( 'active_plugins' ), true ) ) { - define( 'EH_CRM_WOO_STATUS', true ); - } else { - define( 'EH_CRM_WOO_STATUS', false ); - } - } - if ( ! defined( 'EH_CRM_EDD_STATUS' ) ) { - if ( in_array( 'easy-digital-downloads/easy-digital-downloads.php', get_option( 'active_plugins' ), true ) ) { - define( 'EH_CRM_EDD_STATUS', true ); - } else { - define( 'EH_CRM_EDD_STATUS', false ); - } - } - - if ( ! defined( 'EH_CRM_PAY_FOR_SUPPORT_STATUS' ) ) { - if ( in_array( 'wsdesk-pay-for-support/wsdesk-pay-for-support.php', get_option( 'active_plugins' ) ) ) { - define( 'EH_CRM_PAY_FOR_SUPPORT_STATUS', true ); - } else { - define( 'EH_CRM_PAY_FOR_SUPPORT_STATUS', false ); - } - } - - if ( ! defined( 'EH_CRM_WSDESK_SIGNATURE_STATUS' ) ) { - if ( in_array( 'wsdesk-agent-signature-add-on/wsdesk-agent-signature-add-on.php', get_option( 'active_plugins' ) ) ) { - define( 'EH_CRM_WSDESK_SIGNATURE_STATUS', true ); - } else { - define( 'EH_CRM_WSDESK_SIGNATURE_STATUS', false ); - } - } - if ( ! defined( 'EH_CRM_WSDESK_SMS_NOTIFICATION_STATUS' ) ) { - if ( in_array( 'wsdesk-sms-notification-addon/wsdesk-sms-notification-addon.php', get_option( 'active_plugins' ) ) ) { - define( 'EH_CRM_WSDESK_SMS_NOTIFICATION_STATUS', true ); - } else { - define( 'EH_CRM_WSDESK_SMS_NOTIFICATION_STATUS', false ); - } - } - - // review component - if ( ! function_exists( 'get_plugin_data' ) ) { - require_once ABSPATH . 'wp-admin/includes/plugin.php'; - } - include_once __DIR__ . '/review_and_troubleshoot_notify/review-and-troubleshoot-notify-class.php'; - $data = get_plugin_data( __FILE__ , false, false ); - $data['name'] = $data['Name']; - $data['basename'] = plugin_basename( __FILE__ ); - $data['documentation_url'] = 'https://elextensions.com/knowledge-base/set-up-wsdesk-wordpress-helpdesk-plugin/'; - $data['support_url'] = 'https://wordpress.org/support/plugin/elex-helpdesk-customer-support-ticket-system/'; - $data['rating_url'] = 'https://elextensions.com/plugin/wsdesk-wordpress-helpdesk-plugin-free-version/#reviews'; - - new \Elex_Review_Components( $data ); - - require_once ABSPATH . 'wp-admin/includes/plugin.php' ; - require_once __DIR__ . '/vendor/autoload.php' ; - - // Enter your plugin unique option name below $option_name variable - add_action( 'admin_init', 'wsdesk_welcome' ); - register_activation_hook( __FILE__, 'eh_crm_install' ); - register_deactivation_hook( __FILE__, 'wsdesk_deactivate_work' ); - add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'wsdesk_action_link' ); - add_filter( 'plugin_row_meta', 'wsdesk_plugin_row_meta', 10, 2 ); - add_action( 'plugins_loaded', 'eh_crm_update_function' ); - add_action( 'init', 'wsdesk_lang_loader' ); - add_action( 'init', 'register_woocommerce_redirect_url' ); - - function register_woocommerce_redirect_url() { - if ( ! is_plugin_active( 'woocommerce/woocommerce.php' ) ) { - return; - } - - $login_redirect_url = isset( $_GET['redirect_to'] ) ? sanitize_text_field( $_GET['redirect_to'] ) : false; - - if ( ! $login_redirect_url ) { - return; - } - - add_filter( - 'woocommerce_login_redirect', - function () use ( $login_redirect_url ) { - return $login_redirect_url; - } - ); - } - - function wsdesk_lang_loader() { - load_plugin_textdomain( 'wsdesk', false, dirname( plugin_basename( __FILE__ ) ) . '/lang' ); - } - require_once EH_CRM_MAIN_PATH . 'includes/class-crm-public-functions.php' ; - - function eh_crm_update_function() { - global $base; - if ( get_option( 'wsdesk_version_' . $base ) !== EH_CRM_VERSION ) { - require_once EH_CRM_MAIN_PATH . 'includes/class-crm-install-functions.php' ; - EH_CRM_Install::update_tables( $base ); - } - } - - function wsdesk_deactivate_work() { - $cron = new EH_CRM_Cron_Setup(); - $cron->crawler_schedule_terminate(); - delete_option( 'wsdesk_pack', '' ); - } - - function eh_crm_install( $network_wide ) { - require_once ABSPATH . 'wp-admin/includes/upgrade.php' ; - require_once EH_CRM_MAIN_PATH . 'includes/class-crm-install-functions.php' ; - global $wpdb; - if ( is_multisite() ) { - // Get all blogs in the network and activate plugin on each one - $blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ); - foreach ( $blog_ids as $blog_id ) { - switch_to_blog( $blog_id ); - if ( is_plugin_active( plugin_basename( __FILE__ ) ) || $network_wide ) { - EH_CRM_Install::install_tables(); - } - restore_current_blog(); - } - } else { - EH_CRM_Install::install_tables(); - } - $shown = get_option( 'wsdesk_setup_wizard', 'not' ); - if ( 'not' === $shown ) { - set_transient( '_wsdesk_welcome_screen_activation_redirect', true, 30 ); - } - } - - function wsdesk_welcome() { - if ( ! get_transient( '_wsdesk_welcome_screen_activation_redirect' ) && get_option( 'wsdesk_setup_wizard', 'not' ) == 'shown' ) { - return; - } - delete_transient( '_wsdesk_welcome_screen_activation_redirect' ); - wp_safe_redirect( - add_query_arg( - array( - 'page' => 'wsdesk-setup', - '_wpnonce' => wp_create_nonce( 'wsdesk-setup' ), - ), - admin_url( 'index.php' ) - ) - ); - } - - - function wsdesk_wizard_includes() { - if ( ! empty( $_GET['page'] ) ) { - switch ( $_GET['page'] ) { - case 'wsdesk-setup': - include_once EH_CRM_MAIN_VIEWS . 'welcome/welcome.php'; - break; - case 'wsdesk_print': - include_once EH_CRM_MAIN_VIEWS . 'tickets/wsdesk_print.php'; - break; - } - } - } - - function wsdesk_action_link( $links ) { - $plugin_links = array( - '<a href="' . admin_url( 'admin.php?page=wsdesk_tickets' ) . '">' . __( 'Tickets', 'wsdesk' ) . '</a>', - '<a href="' . admin_url( 'admin.php?page=wsdesk_settings' ) . '">' . __( 'Settings', 'wsdesk' ) . '</a>', - ); - array_push( $plugin_links, '<a onclick="return confirm(' . "'You are about to perform factory reset of WSDesk. This will delete all data permanently. This action is irreversible. This action can only be performed if you have \'DROP\' privilege for your database. Proceed?'" . ');" href="' . admin_url( 'admin.php?page=wsdesk_factory_reset' ) . '">' . __( 'Factory Reset', 'wsdesk' ) . '</a>' ); - if ( array_key_exists( 'deactivate', $links ) ) { - $links['deactivate'] = str_replace( '<a', '<a class="wsdesk-deactivate-link"', $links['deactivate'] ); - } - return array_merge( $plugin_links, $links ); - } - - function wsdesk_plugin_row_meta( $links, $file ) { - if ( plugin_basename( __FILE__ ) === $file ) { - $row_meta = array( - '<a href="https://elextensions.com/set-up-wsdesk-wordpress-helpdesk-plugin/" target="_blank">' . __( 'Docs', 'wsdesk' ) . '</a>', - '<a href="https://elextensions.com/support/" target="_blank">' . __( 'Support', 'wsdesk' ) . '</a>', - '<a href="https://elextensions.com/wsdesk-wordpress-helpdesk-plugin-basic-version-changelog/" target="_blank">' . __( 'Changelog', 'wsdesk' ) . '</a>', - ); - return array_merge( $links, $row_meta ); - } - return (array) $links; - } - - function eh_crm_run() { - if ( ! class_exists( 'CRM_Init_Handler' ) ) { - if ( ! defined( 'EH_CRM_WOO_VENDOR' ) ) { - $wsdesk_logged_user = wp_get_current_user(); - $vendor_roles = eh_crm_get_settingsmeta( 0, 'woo_vendor_roles' ); - if ( empty( $vendor_roles ) ) { - $vendor_roles = array(); - } - $result = array_intersect( $vendor_roles, $wsdesk_logged_user->roles ); - if ( ! empty( $result ) ) { - define( 'EH_CRM_WOO_VENDOR', $wsdesk_logged_user->ID ); - } else { - define( 'EH_CRM_WOO_VENDOR', false ); - } - } - require_once EH_CRM_MAIN_PATH . 'includes/class-crm-init-handler.php' ; - require_once EH_CRM_MAIN_PATH . 'includes/class-crm-js-translation.php' ; - require_once EH_CRM_MAIN_PATH . 'includes/class-crm-ajax-functions.php' ; - require_once EH_CRM_MAIN_PATH . 'includes/class-crm-settings-handler.php' ; - require_once EH_CRM_MAIN_PATH . 'includes/Mailbox.php' ; - require_once EH_CRM_MAIN_PATH . 'includes/IncomingMail.php' ; - require_once EH_CRM_MAIN_PATH . 'includes/class-crm-archive-ajax-functions.php' ; - new EH_CRM_Init_Handler(); - $selected_views = eh_crm_get_settings( array( 'slug' => 'labels_view' ) ); - if ( empty( $selected_views ) ) { - $views_settings = array( - 'labels_view' => array( - 'title' => 'Labels', - 'filter' => 'yes', - 'type' => 'view', - 'vendor' => '', - ), - 'agents_view' => array( - 'title' => 'Agents', - 'filter' => 'yes', - 'type' => 'view', - 'vendor' => '', - ), - 'tags_view' => array( - 'title' => 'Tags', - 'filter' => 'yes', - 'type' => 'view', - 'vendor' => '', - ), - 'users_view' => array( - 'title' => 'Users', - 'filter' => 'yes', - 'type' => 'view', - 'vendor' => '', - ), - ); - foreach ( $views_settings as $key => $value ) { - eh_crm_insert_settings( $value, null, $key ); - } - eh_crm_update_settingsmeta( 0, 'selected_views', array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) ); - } - $wsdesk_powered_by_status = eh_crm_get_settingsmeta( '0', 'wsdesk_powered_by_status' ); - if ( 'disable' === $wsdesk_powered_by_status ) { - define( 'WSDESK_POWERED_SUPPORT', true ); - define( 'WSDESK_POWERED_EMAIL', true ); - } - } - } - add_action( 'init', 'eh_crm_run', 99 ); - add_action( 'init', 'wsdesk_wizard_includes', 100 ); - require_once EH_CRM_MAIN_PATH . 'includes/class-crm-email-oauth.php' ; - require_once EH_CRM_MAIN_PATH . 'includes/class-crm-cron-setup.php' ; - new EH_CRM_Cron_Setup(); - - if ( isset( $_GET['page'] ) ) { //code for factory reset - if ( is_admin() ) { - if ( 'wsdesk_factory_reset' === $_GET['page'] ) { - - require_once EH_CRM_MAIN_PATH . 'includes/class-crm-init-handler.php' ; - - deactivate_plugins( plugin_basename( __FILE__ ) ); - - EH_CRM_Init_Handler::factory_reset(); - - header( 'Location: ' . admin_url( 'plugins.php' ) ); - exit; - } - } - } - if ( is_plugin_active( 'wsdesk-premium/wsdesk.php' ) ) { - $debug_status = eh_crm_get_settingsmeta( 0, 'wsdesk_debug_status' ); - if ( 'enable' === $debug_status ) { - eh_crm_db_debug_error_log( ' ------------- WSDesk Debug Mode Started ------------- ' ); - eh_crm_db_debug_error_log( ' ------------- Tickets Table Started ------------- ' ); - eh_crm_db_collation( 'wsdesk_tickets' ); - eh_crm_db_debug_error_log( ' ------------- Tickets Table Ended ------------- ' ); - eh_crm_db_debug_error_log( ' ------------- Settings Table Started ------------- ' ); - eh_crm_db_collation( 'wsdesk_settings' ); - eh_crm_db_debug_error_log( ' ------------- Settings Table Ended ------------- ' ); - eh_crm_db_debug_error_log( ' ------------- Ticketsmeta Table Started ------------- ' ); - eh_crm_db_collation( 'wsdesk_ticketsmeta' ); - eh_crm_db_debug_error_log( ' ------------- Ticketsmeta Ticketsmeta Ended ------------- ' ); - eh_crm_db_debug_error_log( ' ------------- Settingsmeta Table Started ------------- ' ); - eh_crm_db_collation( 'wsdesk_settingsmeta' ); - eh_crm_db_debug_error_log( ' ------------- Settingsmeta Table Ended ------------- ' ); - eh_crm_db_debug_error_log( ' ------------- WSDesk Debug Mode Ended ------------- ' ); - } - } - add_action( 'admin_bar_menu', 'elex_wsdesk_admin_bar', 900 ); - - function elex_wsdesk_admin_bar( $wp_admin_bar ) { - $admin_bar_args = array( - 'id' => 'wsdesk_tickets', - 'parent' => 'site-name', - 'href' => admin_url( 'admin.php?page=wsdesk_tickets' ), - 'title' => __( 'WSDesk Tickets', 'wsdesk' ), - ); - $wp_admin_bar->add_node( $admin_bar_args ); - } - - //Enqueue the Dashicons script - add_action( 'wp_enqueue_scripts', 'load_dashicons_front_end' ); - function load_dashicons_front_end() { - wp_enqueue_style( 'dashicons' ); - } -} +<?php+/**+ * Plugin Name: ELEX HelpDesk & Customer Support Ticket System+ * Plugin URI: https://elextensions.com/plugin/wsdesk-wordpress-helpdesk-plugin-free-version/+ * Description: Enhances your customer service and enables efficient handling of customer issues.+ * Version: 3.3.5+ * Author: ELEXtensions+ * Author URI: https://elextensions.com/+ * Text Domain: wsdesk+ * Domain Path: /lang+ */+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++if ( ! defined( 'WSDESK_PLUGIN_TYPE' ) ) {+ define( 'WSDESK_PLUGIN_TYPE', 'basic' );+}++if ( defined( 'EH_CRM_VERSION' ) ) {+ deactivate_plugins( plugin_basename( __FILE__ ) );+ $activated_plugins = (array) get_option( 'active_plugins' );+ $wsdesk_plugins = array(+ 'wsdesk-premium/wsdesk.php' => "PREMIUM Version of WSDesk Plugin is activated. Please deactivate the PREMIUM Version of WSDesk before activating BASIC version.<br>Don't worry! Your ticket and settings data will be retained.<br>Go back to <a href='" . esc_html( admin_url( 'plugins.php' ) ) . "'>plugins page</a>",+ 'wsdesk-basic/wsdesk.php' => "BASIC Version of WSDesk Plugin is activated. Please deactivate the BASIC Version of WSDesk before activating PREMIUM version.<br>Don't worry! Your ticket and settings data will be retained.<br>Go back to <a href='" . esc_html( admin_url( 'plugins.php' ) ) . "'>plugins page</a>",+ 'elex-helpdesk-customer-support-ticket-system/elex-wordpress-helpdesk.php' => "BASIC Version of WSDesk Plugin is activated. Please deactivate the BASIC Version of WSDesk before activating PREMIUM version.<br>Don't worry! Your ticket and settings data will be retained.<br>Go back to <a href='" . esc_html( admin_url( 'plugins.php' ) ) . "'>plugins page</a>",+ 'elex-wordpress-helpdesk/elex-wordpress-helpdesk.php' => "BASIC Version of WSDesk Plugin is activated. Please deactivate the BASIC Version of WSDesk before activating PREMIUM version.<br>Don't worry! Your ticket and settings data will be retained.<br>Go back to <a href='" . esc_html( admin_url( 'plugins.php' ) ) . "'>plugins page</a>",+ 'wsdesk-helpdesk-customer-support-ticket-system/wsdesk.php' => "WooCommerce Version of WSDesk Plugin is activated. Please deactivate the WooCommerce Version of WSDesk before activating BASIC version.<br>Don't worry! Your ticket and settings data will be retained.<br>Go back to <a href='" . esc_html( admin_url( 'plugins.php' ) ) . "'>plugins page</a>",+ );+ $current_wsdesk_plugin = plugin_basename( __FILE__ );+ + foreach ( $wsdesk_plugins as $wsdesk_plugin => $error_msg ) {+ + if ( $current_wsdesk_plugin === $wsdesk_plugin ) {+ continue;+ }+ if ( in_array( $wsdesk_plugin, $activated_plugins, true ) ) {+ wp_die( wp_kses_post( $error_msg ) );+ }+ }+ return;+} else {++ if ( ! defined( 'EH_CRM_VERSION' ) ) {+ define( 'EH_CRM_VERSION', '3.1.2' );+ }+ if ( ! defined( 'EH_CRM_MAIN_URL' ) ) {+ define( 'EH_CRM_MAIN_URL', plugin_dir_url( __FILE__ ) );+ }+ if ( ! defined( 'EH_CRM_MAIN_PATH' ) ) {+ define( 'EH_CRM_MAIN_PATH', plugin_dir_path( __FILE__ ) );+ }+ if ( ! defined( 'EH_CRM_MAIN_IMG' ) ) {+ define( 'EH_CRM_MAIN_IMG', EH_CRM_MAIN_URL . 'assets/img/' );+ }+ if ( ! defined( 'EH_CRM_MAIN_CSS' ) ) {+ define( 'EH_CRM_MAIN_CSS', EH_CRM_MAIN_URL . 'assets/css/' );+ }+ if ( ! defined( 'EH_CRM_MAIN_JS' ) ) {+ define( 'EH_CRM_MAIN_JS', EH_CRM_MAIN_URL . 'assets/js/' );+ }+ if ( ! defined( 'EH_CRM_MAIN_VENDOR' ) ) {+ define( 'EH_CRM_MAIN_VENDOR', EH_CRM_MAIN_PATH . 'vendor/' );+ }+ if ( ! defined( 'EH_CRM_MAIN_VIEWS' ) ) {+ define( 'EH_CRM_MAIN_VIEWS', EH_CRM_MAIN_PATH . 'views/' );+ }+ if ( ! defined( 'EH_CRM_WOO_STATUS' ) ) {+ if ( in_array( 'woocommerce/woocommerce.php', get_option( 'active_plugins' ), true ) ) {+ define( 'EH_CRM_WOO_STATUS', true );+ } else {+ define( 'EH_CRM_WOO_STATUS', false );+ }+ }+ if ( ! defined( 'EH_CRM_EDD_STATUS' ) ) {+ if ( in_array( 'easy-digital-downloads/easy-digital-downloads.php', get_option( 'active_plugins' ), true ) ) {+ define( 'EH_CRM_EDD_STATUS', true );+ } else {+ define( 'EH_CRM_EDD_STATUS', false );+ }+ }++ if ( ! defined( 'EH_CRM_PAY_FOR_SUPPORT_STATUS' ) ) {+ if ( in_array( 'wsdesk-pay-for-support/wsdesk-pay-for-support.php', get_option( 'active_plugins' ) ) ) {+ define( 'EH_CRM_PAY_FOR_SUPPORT_STATUS', true );+ } else {+ define( 'EH_CRM_PAY_FOR_SUPPORT_STATUS', false );+ }+ }++ if ( ! defined( 'EH_CRM_WSDESK_SIGNATURE_STATUS' ) ) {+ if ( in_array( 'wsdesk-agent-signature-add-on/wsdesk-agent-signature-add-on.php', get_option( 'active_plugins' ) ) ) {+ define( 'EH_CRM_WSDESK_SIGNATURE_STATUS', true );+ } else {+ define( 'EH_CRM_WSDESK_SIGNATURE_STATUS', false );+ }+ }+ if ( ! defined( 'EH_CRM_WSDESK_SMS_NOTIFICATION_STATUS' ) ) {+ if ( in_array( 'wsdesk-sms-notification-addon/wsdesk-sms-notification-addon.php', get_option( 'active_plugins' ) ) ) {+ define( 'EH_CRM_WSDESK_SMS_NOTIFICATION_STATUS', true );+ } else {+ define( 'EH_CRM_WSDESK_SMS_NOTIFICATION_STATUS', false );+ }+ }++ // review component+ if ( ! function_exists( 'get_plugin_data' ) ) {+ require_once ABSPATH . 'wp-admin/includes/plugin.php';+ }+ include_once __DIR__ . '/review_and_troubleshoot_notify/review-and-troubleshoot-notify-class.php';+ $data = get_plugin_data( __FILE__ , false, false );+ $data['name'] = $data['Name'];+ $data['basename'] = plugin_basename( __FILE__ );+ $data['documentation_url'] = 'https://elextensions.com/knowledge-base/set-up-wsdesk-wordpress-helpdesk-plugin/';+ $data['support_url'] = 'https://wordpress.org/support/plugin/elex-helpdesk-customer-support-ticket-system/';+ $data['rating_url'] = 'https://elextensions.com/plugin/wsdesk-wordpress-helpdesk-plugin-free-version/#reviews';++ new \Elex_Review_Components( $data );++ require_once ABSPATH . 'wp-admin/includes/plugin.php' ;+ require_once __DIR__ . '/vendor/autoload.php' ;++ // Enter your plugin unique option name below $option_name variable+ add_action( 'admin_init', 'wsdesk_welcome' );+ register_activation_hook( __FILE__, 'eh_crm_install' );+ register_deactivation_hook( __FILE__, 'wsdesk_deactivate_work' );+ add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'wsdesk_action_link' );+ add_filter( 'plugin_row_meta', 'wsdesk_plugin_row_meta', 10, 2 );+ add_action( 'plugins_loaded', 'eh_crm_update_function' );+ add_action( 'init', 'wsdesk_lang_loader' );+ add_action( 'init', 'register_woocommerce_redirect_url' );++ function register_woocommerce_redirect_url() {+ if ( ! is_plugin_active( 'woocommerce/woocommerce.php' ) ) {+ return;+ }++ $login_redirect_url = isset( $_GET['redirect_to'] ) ? sanitize_text_field( $_GET['redirect_to'] ) : false;++ if ( ! $login_redirect_url ) {+ return;+ }++ add_filter(+ 'woocommerce_login_redirect',+ function () use ( $login_redirect_url ) {+ return $login_redirect_url;+ }+ );+ }++ function wsdesk_lang_loader() {+ load_plugin_textdomain( 'wsdesk', false, dirname( plugin_basename( __FILE__ ) ) . '/lang' );+ }+ require_once EH_CRM_MAIN_PATH . 'includes/class-crm-public-functions.php' ;++ function eh_crm_update_function() {+ global $base;+ if ( get_option( 'wsdesk_version_' . $base ) !== EH_CRM_VERSION ) {+ require_once EH_CRM_MAIN_PATH . 'includes/class-crm-install-functions.php' ;+ EH_CRM_Install::update_tables( $base );+ }+ }++ function wsdesk_deactivate_work() {+ $cron = new EH_CRM_Cron_Setup();+ $cron->crawler_schedule_terminate();+ delete_option( 'wsdesk_pack', '' );+ }++ function eh_crm_install( $network_wide ) {+ require_once ABSPATH . 'wp-admin/includes/upgrade.php' ;+ require_once EH_CRM_MAIN_PATH . 'includes/class-crm-install-functions.php' ;+ global $wpdb;+ if ( is_multisite() ) {+ // Get all blogs in the network and activate plugin on each one+ $blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );+ foreach ( $blog_ids as $blog_id ) {+ switch_to_blog( $blog_id );+ if ( is_plugin_active( plugin_basename( __FILE__ ) ) || $network_wide ) {+ EH_CRM_Install::install_tables();+ }+ restore_current_blog();+ }+ } else {+ EH_CRM_Install::install_tables();+ }+ $shown = get_option( 'wsdesk_setup_wizard', 'not' );+ if ( 'not' === $shown ) {+ set_transient( '_wsdesk_welcome_screen_activation_redirect', true, 30 );+ }+ }++ function wsdesk_welcome() {+ if ( ! get_transient( '_wsdesk_welcome_screen_activation_redirect' ) && get_option( 'wsdesk_setup_wizard', 'not' ) == 'shown' ) {+ return;+ }+ delete_transient( '_wsdesk_welcome_screen_activation_redirect' );+ wp_safe_redirect(+ add_query_arg(+ array(+ 'page' => 'wsdesk-setup',+ '_wpnonce' => wp_create_nonce( 'wsdesk-setup' ),+ ),+ admin_url( 'index.php' )+ )+ );+ }+ ++ function wsdesk_wizard_includes() {+ if ( ! empty( $_GET['page'] ) ) {+ switch ( $_GET['page'] ) {+ case 'wsdesk-setup':+ include_once EH_CRM_MAIN_VIEWS . 'welcome/welcome.php';+ break;+ case 'wsdesk_print':+ include_once EH_CRM_MAIN_VIEWS . 'tickets/wsdesk_print.php';+ break;+ }+ }+ }++ function wsdesk_action_link( $links ) {+ $plugin_links = array(+ '<a href="' . admin_url( 'admin.php?page=wsdesk_tickets' ) . '">' . __( 'Tickets', 'wsdesk' ) . '</a>',+ '<a href="' . admin_url( 'admin.php?page=wsdesk_settings' ) . '">' . __( 'Settings', 'wsdesk' ) . '</a>',+ );+ array_push( $plugin_links, '<a onclick="return confirm(' . "'You are about to perform factory reset of WSDesk. This will delete all data permanently. This action is irreversible. This action can only be performed if you have \'DROP\' privilege for your database. Proceed?'" . ');" href="' . admin_url( 'admin.php?page=wsdesk_factory_reset' ) . '">' . __( 'Factory Reset', 'wsdesk' ) . '</a>' );+ if ( array_key_exists( 'deactivate', $links ) ) {+ $links['deactivate'] = str_replace( '<a', '<a class="wsdesk-deactivate-link"', $links['deactivate'] );+ }+ return array_merge( $plugin_links, $links );+ }++ function wsdesk_plugin_row_meta( $links, $file ) {+ if ( plugin_basename( __FILE__ ) === $file ) {+ $row_meta = array(+ '<a href="https://elextensions.com/set-up-wsdesk-wordpress-helpdesk-plugin/" target="_blank">' . __( 'Docs', 'wsdesk' ) . '</a>',+ '<a href="https://elextensions.com/support/" target="_blank">' . __( 'Support', 'wsdesk' ) . '</a>',+ '<a href="https://elextensions.com/wsdesk-wordpress-helpdesk-plugin-basic-version-changelog/" target="_blank">' . __( 'Changelog', 'wsdesk' ) . '</a>',+ );+ return array_merge( $links, $row_meta );+ }+ return (array) $links;+ }++ function eh_crm_run() {+ if ( ! class_exists( 'CRM_Init_Handler' ) ) {+ if ( ! defined( 'EH_CRM_WOO_VENDOR' ) ) {+ $wsdesk_logged_user = wp_get_current_user();+ $vendor_roles = eh_crm_get_settingsmeta( 0, 'woo_vendor_roles' );+ if ( empty( $vendor_roles ) ) {+ $vendor_roles = array();+ }+ $result = array_intersect( $vendor_roles, $wsdesk_logged_user->roles );+ if ( ! empty( $result ) ) {+ define( 'EH_CRM_WOO_VENDOR', $wsdesk_logged_user->ID );+ } else {+ define( 'EH_CRM_WOO_VENDOR', false );+ }+ }+ require_once EH_CRM_MAIN_PATH . 'includes/class-crm-init-handler.php' ;+ require_once EH_CRM_MAIN_PATH . 'includes/class-crm-js-translation.php' ;+ require_once EH_CRM_MAIN_PATH . 'includes/class-crm-ajax-functions.php' ;+ require_once EH_CRM_MAIN_PATH . 'includes/class-crm-settings-handler.php' ;+ require_once EH_CRM_MAIN_PATH . 'includes/Mailbox.php' ;+ require_once EH_CRM_MAIN_PATH . 'includes/IncomingMail.php' ;+ require_once EH_CRM_MAIN_PATH . 'includes/class-crm-archive-ajax-functions.php' ;+ new EH_CRM_Init_Handler();+ $selected_views = eh_crm_get_settings( array( 'slug' => 'labels_view' ) );+ if ( empty( $selected_views ) ) {+ $views_settings = array(+ 'labels_view' => array(+ 'title' => 'Labels',+ 'filter' => 'yes',+ 'type' => 'view',+ 'vendor' => '',+ ),+ 'agents_view' => array(+ 'title' => 'Agents',+ 'filter' => 'yes',+ 'type' => 'view',+ 'vendor' => '',+ ),+ 'tags_view' => array(+ 'title' => 'Tags',+ 'filter' => 'yes',+ 'type' => 'view',+ 'vendor' => '',+ ),+ 'users_view' => array(+ 'title' => 'Users',+ 'filter' => 'yes',+ 'type' => 'view',+ 'vendor' => '',+ ),+ );+ foreach ( $views_settings as $key => $value ) {+ eh_crm_insert_settings( $value, null, $key );+ }+ eh_crm_update_settingsmeta( 0, 'selected_views', array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) );+ }+ $wsdesk_powered_by_status = eh_crm_get_settingsmeta( '0', 'wsdesk_powered_by_status' );+ if ( 'disable' === $wsdesk_powered_by_status ) {+ define( 'WSDESK_POWERED_SUPPORT', true );+ define( 'WSDESK_POWERED_EMAIL', true );+ }+ }+ }+ add_action( 'init', 'eh_crm_run', 99 );+ add_action( 'init', 'wsdesk_wizard_includes', 100 );+ require_once EH_CRM_MAIN_PATH . 'includes/class-crm-email-oauth.php' ;+ require_once EH_CRM_MAIN_PATH . 'includes/class-crm-cron-setup.php' ;+ new EH_CRM_Cron_Setup();++ if ( isset( $_GET['page'] ) ) { //code for factory reset+ if ( is_admin() ) {+ if ( 'wsdesk_factory_reset' === $_GET['page'] ) {++ require_once EH_CRM_MAIN_PATH . 'includes/class-crm-init-handler.php' ;++ deactivate_plugins( plugin_basename( __FILE__ ) );++ EH_CRM_Init_Handler::factory_reset();++ header( 'Location: ' . admin_url( 'plugins.php' ) );+ exit;+ }+ }+ }+ if ( is_plugin_active( 'wsdesk-premium/wsdesk.php' ) ) {+ $debug_status = eh_crm_get_settingsmeta( 0, 'wsdesk_debug_status' );+ if ( 'enable' === $debug_status ) {+ eh_crm_db_debug_error_log( ' ------------- WSDesk Debug Mode Started ------------- ' );+ eh_crm_db_debug_error_log( ' ------------- Tickets Table Started ------------- ' );+ eh_crm_db_collation( 'wsdesk_tickets' );+ eh_crm_db_debug_error_log( ' ------------- Tickets Table Ended ------------- ' );+ eh_crm_db_debug_error_log( ' ------------- Settings Table Started ------------- ' );+ eh_crm_db_collation( 'wsdesk_settings' );+ eh_crm_db_debug_error_log( ' ------------- Settings Table Ended ------------- ' );+ eh_crm_db_debug_error_log( ' ------------- Ticketsmeta Table Started ------------- ' );+ eh_crm_db_collation( 'wsdesk_ticketsmeta' );+ eh_crm_db_debug_error_log( ' ------------- Ticketsmeta Ticketsmeta Ended ------------- ' );+ eh_crm_db_debug_error_log( ' ------------- Settingsmeta Table Started ------------- ' );+ eh_crm_db_collation( 'wsdesk_settingsmeta' );+ eh_crm_db_debug_error_log( ' ------------- Settingsmeta Table Ended ------------- ' );+ eh_crm_db_debug_error_log( ' ------------- WSDesk Debug Mode Ended ------------- ' );+ }+ }+ add_action( 'admin_bar_menu', 'elex_wsdesk_admin_bar', 900 );++ function elex_wsdesk_admin_bar( $wp_admin_bar ) {+ $admin_bar_args = array(+ 'id' => 'wsdesk_tickets',+ 'parent' => 'site-name',+ 'href' => admin_url( 'admin.php?page=wsdesk_tickets' ),+ 'title' => __( 'WSDesk Tickets', 'wsdesk' ),+ );+ $wp_admin_bar->add_node( $admin_bar_args );+ }++ //Enqueue the Dashicons script+ add_action( 'wp_enqueue_scripts', 'load_dashicons_front_end' );+ function load_dashicons_front_end() {+ wp_enqueue_style( 'dashicons' );+ }+}
Vulnerability Existed: no CWE Name: N/A - N/A - elex-helpdesk-customer-support-ticket-system.php - All lines Old Code: N/A Fixed Code: N/A Explanation: This diff represents a version bump from 3.3.4 to 3.3.5 with only line ending changes (LF vs CRLF). The actual code content is identical between versions. There are no security fixes, vulnerability introductions, or code logic changes. The only modification is the version number in the plugin header (line 5: `Version: 3.3.4` → `Version: 3.3.5`). No vulnerabilities were addressed in this update.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Formatter/Cast/CasterContract.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Formatter/Cast/CasterContract.php 2025-12-21 09:36:35.231291286 +0000@@ -1,14 +1,14 @@-<?php -namespace WSDesk\Formatter\Cast; - -interface CasterContract { - - /** - * Cast given value respectively and return - * - * @param mixed $value - * @param string $key - * @retunrn mixed - */ - public static function cast( $value, $key); -} +<?php+namespace WSDesk\Formatter\Cast;++interface CasterContract {++ /**+ * Cast given value respectively and return+ *+ * @param mixed $value+ * @param string $key+ * @retunrn mixed+ */+ public static function cast( $value, $key);+}
Vulnerability Existed: no No Security Vulnerabilities Detected - File Format/Whitespace Change Only Explanation: This diff represents a line-ending or whitespace normalization change only. The file content is functionally identical between versions 3.3.4 and 3.3.5. The changes appear to be converting line endings (likely from CRLF to LF) or normalizing whitespace formatting. The file itself is a PHP interface definition (`CasterContract`) that declares a single static method `cast()`. There are no: - Input validation vulnerabilities - SQL injection risks - Command injection risks - Path traversal issues - Authentication/authorization flaws - Cryptographic weaknesses - Injection attacks of any kind The only issue present in the code is a documentation typo (`@retunrn` should be `@return`), which is not a security vulnerability. This typo exists in both versions and is not fixed by this change. No security fixes or security-related changes are present in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Formatter/Cast/FieldCaster.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Formatter/Cast/FieldCaster.php 2025-12-21 09:36:35.231291286 +0000@@ -1,14 +1,14 @@-<?php -namespace WSDesk\Formatter\Cast; - -use WSDesk\Tickets\TicketField; - -class FieldCaster implements CasterContract { - - public static function cast( $value, $key ) { - - $ticket_field = new TicketField( $key, $value ); - - return $ticket_field->get_labels(); - } -} +<?php+namespace WSDesk\Formatter\Cast;++use WSDesk\Tickets\TicketField;++class FieldCaster implements CasterContract {++ public static function cast( $value, $key ) {++ $ticket_field = new TicketField( $key, $value );++ return $ticket_field->get_labels();+ }+}
Vulnerability Existed: no Explanation: This diff contains only whitespace/line ending changes (converting line endings from CRLF to LF or adjusting indentation). The actual code logic remains identical between versions 3.3.4 and 3.3.5. No security fixes, vulnerability introductions, or functional changes are present in this file modification. The code itself does not exhibit security vulnerabilities in either version: - The `FieldCaster` class simply instantiates a `TicketField` object and returns labels - There is no direct user input sanitization concern visible in this isolated method - No SQL injection, XSS, or command injection vectors are present in this code - The parameters `$value` and `$key` are passed to `TicketField` constructor without problematic usage patterns visible here **Summary:** This is a non-functional change (formatting only). No security analysis is applicable.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Formatter/Cast/ObjectCaster.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Formatter/Cast/ObjectCaster.php 2025-12-21 09:36:35.231291286 +0000@@ -1,10 +1,10 @@-<?php -namespace WSDesk\Formatter\Cast; - -class ObjectCaster implements CasterContract { - - public static function cast( $value, $key ) { - $value = maybe_unserialize( $value ); - return is_array( $value ) ? array_values( $value ) : array(); - } -} +<?php+namespace WSDesk\Formatter\Cast;++class ObjectCaster implements CasterContract {++ public static function cast( $value, $key ) {+ $value = maybe_unserialize( $value );+ return is_array( $value ) ? array_values( $value ) : array();+ }+}
Vulnerability Existed: no
[No Security Vulnerability] - [N/A] - includes/Formatter/Cast/ObjectCaster.php [1-10]
Old Code:
```php
<?php
namespace WSDesk\Formatter\Cast;
class ObjectCaster implements CasterContract {
public static function cast( $value, $key ) {
$value = maybe_unserialize( $value );
return is_array( $value ) ? array_values( $value ) : array();
}
}
```
Fixed Code:
```php
<?php
namespace WSDesk\Formatter\Cast;
class ObjectCaster implements CasterContract {
public static function cast( $value, $key ) {
$value = maybe_unserialize( $value );
return is_array( $value ) ? array_values( $value ) : array();
}
}
```
Explanation:
This diff contains only whitespace and line ending changes (converting to Unix line endings). The actual code logic remains identical between versions. The `maybe_unserialize()` function (WordPress's built-in safe deserialization function) is already being used correctly, and the code properly validates the result with `is_array()` before processing. No security vulnerabilities are introduced or fixed in this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Formatter/Cast/TimestampCaster.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Formatter/Cast/TimestampCaster.php 2025-12-21 09:36:35.231291286 +0000@@ -1,15 +1,15 @@-<?php -namespace WSDesk\Formatter\Cast; - -class TimestampCaster implements CasterContract { - - public static function cast( $value, $key ) { - if ( 'ticket_date' === $key ) { - $value = get_date_from_gmt( $value ); - } - - $dt = date_create( $value ); - - return $dt->format( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ); - } -} +<?php+namespace WSDesk\Formatter\Cast;++class TimestampCaster implements CasterContract {++ public static function cast( $value, $key ) {+ if ( 'ticket_date' === $key ) {+ $value = get_date_from_gmt( $value );+ }++ $dt = date_create( $value );++ return $dt->format( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) );+ }+}
Vulnerability Existed: no Explanation: The diff shows only formatting/whitespace changes (line ending normalization from CRLF to LF). No functional code modifications were made. The code remains identical in logic and functionality: - The `cast()` method still processes timestamp values without additional validation - The `date_create()` function call remains unchanged (returns a DateTime object or false) - The `format()` call on the DateTime object is still executed without null/error checking - WordPress functions `get_date_from_gmt()`, `get_option()` remain unchanged While the code itself has potential security/robustness issues (no validation of `date_create()` return value, potential for fatal errors if false is returned), these issues existed in version 3.3.4 and were not fixed in 3.3.5. This diff represents a code cleanup only, with no security fixes applied.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Formatter/Formatter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Formatter/Formatter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,60 +1,60 @@-<?php -namespace WSDesk\Formatter; - -use Illuminate\Support\Fluent; - -class Formatter extends Fluent { - - /** - * List of castable attributes - * - * @var array - */ - protected $casts = []; - - /** - * Convert to an array - * - * @return array - */ - public function toArray() { - $data = []; - foreach ( $this->attributes as $key => $value ) { - $data[ $key ] = $this->castable( $key ) ? $this->castAttribute( $key ) : $value; - } - - return $data; - } - - public function castable( $key ) { - if ( isset( $this->casts[ $key ] ) ) { - return true; - } - - return false; - } - - public function get( $key, $default = null ) { - if ( array_key_exists( $key, $this->casts ) ) { - return $this->castAttribute( $key ); - } - - return parent::get( $key, $default ); - } - - /** - * Cast an attributes value - * - * @var string $key - * @return mixed - */ - public function castAttribute( $key ) { - $class = 'WSDesk\\Formatter\\Cast\\' . ucfirst( $this->casts[ $key ] ) . 'Caster'; - - if ( class_exists( $class ) ) { - return $class::cast( $this->attributes[ $key ], $key ); - } - - return $this->attributes[ $key ]; - } -} +<?php+namespace WSDesk\Formatter;++use Illuminate\Support\Fluent;++class Formatter extends Fluent {++ /**+ * List of castable attributes+ *+ * @var array+ */+ protected $casts = [];++ /**+ * Convert to an array+ *+ * @return array+ */+ public function toArray() {+ $data = [];+ foreach ( $this->attributes as $key => $value ) {+ $data[ $key ] = $this->castable( $key ) ? $this->castAttribute( $key ) : $value;+ }++ return $data;+ }++ public function castable( $key ) {+ if ( isset( $this->casts[ $key ] ) ) {+ return true;+ }++ return false;+ }++ public function get( $key, $default = null ) {+ if ( array_key_exists( $key, $this->casts ) ) {+ return $this->castAttribute( $key );+ }++ return parent::get( $key, $default );+ }++ /**+ * Cast an attributes value+ *+ * @var string $key+ * @return mixed+ */+ public function castAttribute( $key ) {+ $class = 'WSDesk\\Formatter\\Cast\\' . ucfirst( $this->casts[ $key ] ) . 'Caster';++ if ( class_exists( $class ) ) {+ return $class::cast( $this->attributes[ $key ], $key );+ }++ return $this->attributes[ $key ];+ }+}
Vulnerability Existed: no Explanation: This diff shows only line ending changes (CRLF to LF conversion) with no functional code modifications. The actual PHP code logic remains identical between versions 3.3.4 and 3.3.5. While the `castAttribute` method contains a dynamic class instantiation pattern on line 52 that could theoretically be vulnerable to arbitrary class loading if user input controls the `$key` parameter, this vulnerability (if it exists) is not being fixed in this diff—it remains in both versions unchanged. No security fixes are present in this revision.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/IncomingMail.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/IncomingMail.php 2025-12-21 09:36:35.231291286 +0000@@ -1,76 +1,76 @@-<?php namespace EH_CRM_PhpImap; - -/** Class used to intend the Incoming Mails - * - * @see https://github.com/barbushin/php-imap - */ -class EH_CRM_IncomingMail { - - - public $id; - public $date; - public $headersRaw; - public $headers; - public $subject; - - public $fromName; - public $fromAddress; - - public $to = array(); - public $toString; - public $cc = array(); - public $bcc = array(); - public $replyTo = array(); - - public $messageId; - - public $textPlain; - public $textHtml; - /** Incoming mail attachment - * - * @var IncomingMailAttachment[] - */ - protected $attachments = array(); - - public function addAttachment( EH_CRM_IncomingMailAttachment $attachment ) { - $this->attachments[ $attachment->id ] = $attachment; - } - - /** Incoming mail attachment - * - * @return IncomingMailAttachment[] - */ - public function getAttachments() { - return $this->attachments; - } - - /** - * Get array of internal HTML links placeholders - * - * @return array attachmentId => link placeholder - */ - public function getInternalLinksPlaceholders() { - return preg_match_all( '/=["\'](ci?d:([\w\.%*@-]+))["\']/i', $this->textHtml, $matches ) ? array_combine( $matches[2], $matches[1] ) : array(); - - } - - public function replaceInternalLinks( $baseUri ) { - $baseUri = rtrim( $baseUri, '\\/' ) . '/'; - $fetchedHtml = $this->textHtml; - foreach ( $this->getInternalLinksPlaceholders() as $attachmentId => $placeholder ) { - if ( isset( $this->attachments[ $attachmentId ] ) ) { - $fetchedHtml = str_replace( $placeholder, $baseUri . basename( $this->attachments[ $attachmentId ]->filePath ), $fetchedHtml ); - } - } - return $fetchedHtml; - } -} - -class EH_CRM_IncomingMailAttachment { - - - public $id; - public $name; - public $filePath; - public $disposition; -} +<?php namespace EH_CRM_PhpImap;++/** Class used to intend the Incoming Mails+ * + * @see https://github.com/barbushin/php-imap+ */+class EH_CRM_IncomingMail {+++ public $id;+ public $date;+ public $headersRaw;+ public $headers;+ public $subject;++ public $fromName;+ public $fromAddress;++ public $to = array();+ public $toString;+ public $cc = array();+ public $bcc = array();+ public $replyTo = array();++ public $messageId;++ public $textPlain;+ public $textHtml;+ /** Incoming mail attachment+ *+ * @var IncomingMailAttachment[] + */+ protected $attachments = array();++ public function addAttachment( EH_CRM_IncomingMailAttachment $attachment ) {+ $this->attachments[ $attachment->id ] = $attachment;+ }++ /** Incoming mail attachment+ * + * @return IncomingMailAttachment[]+ */+ public function getAttachments() {+ return $this->attachments;+ }++ /**+ * Get array of internal HTML links placeholders+ *+ * @return array attachmentId => link placeholder+ */+ public function getInternalLinksPlaceholders() {+ return preg_match_all( '/=["\'](ci?d:([\w\.%*@-]+))["\']/i', $this->textHtml, $matches ) ? array_combine( $matches[2], $matches[1] ) : array();++ }++ public function replaceInternalLinks( $baseUri ) {+ $baseUri = rtrim( $baseUri, '\\/' ) . '/';+ $fetchedHtml = $this->textHtml;+ foreach ( $this->getInternalLinksPlaceholders() as $attachmentId => $placeholder ) {+ if ( isset( $this->attachments[ $attachmentId ] ) ) {+ $fetchedHtml = str_replace( $placeholder, $baseUri . basename( $this->attachments[ $attachmentId ]->filePath ), $fetchedHtml );+ }+ }+ return $fetchedHtml;+ }+}++class EH_CRM_IncomingMailAttachment {+++ public $id;+ public $name;+ public $filePath;+ public $disposition;+}
Vulnerability Existed: no Explanation: This diff shows only whitespace/line ending changes (CRLF to LF conversion). The actual code logic and structure remain identical between versions 3.3.4 and 3.3.5. No security fixes were applied in this change. The code itself has potential security concerns that predate this diff: - Line 58: The `replaceInternalLinks()` function uses `basename()` but doesn't validate the `$baseUri` parameter, which could be exploited if user-controlled - Line 57: The regex pattern and attachment ID validation could be bypassable depending on the source of `$this->textHtml` However, since no code logic was modified in this diff, no security fixes were implemented.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Mailbox.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Mailbox.php 2025-12-21 09:36:35.231291286 +0000@@ -1,704 +1,704 @@-<?php namespace EH_CRM_PhpImap; - -use stdClass; - -/** Class used for crm mailbox - * - * @see https://github.com/barbushin/php-imap - */ -class EH_CRM_Mailbox { - - - protected $imapPath; - protected $imapLogin; - protected $imapPassword; - protected $imapOptions = 0; - protected $imapRetriesNum = 0; - protected $imapParams = array(); - protected $serverEncoding; - protected $attachmentsDir = null; - protected $expungeOnDisconnect = true; - private $imapStream; - - /** Construct of the class - * - * @param string $imapPath - * @param string $login - * @param string $password - * @param string $attachmentsDir - * @param string $serverEncoding - * @throws Exception - */ - public function __construct( $imapPath, $login, $password, $attachmentsDir = null, $serverEncoding = 'UTF-8' ) { - $this->setImapPath( $imapPath ); - $this->imapLogin = $login; - $this->imapPassword = $password; - $this->serverEncoding = strtoupper( $serverEncoding ); - if ( $attachmentsDir ) { - if ( ! is_dir( $attachmentsDir ) ) { - throw new Exception( 'Directory "' . $attachmentsDir . '" not found' ); - } - $this->attachmentsDir = rtrim( realpath( $attachmentsDir ), '\\/' ); - } - } - - /** - * Set custom connection arguments of imap_open method. See http://php.net/imap_open - * - * @param int $options - * @param int $retriesNum - * @param array $params - */ - public function setConnectionArgs( $options = 0, $retriesNum = 0, array $params = null ) { - $this->imapOptions = $options; - $this->imapRetriesNum = $retriesNum; - $this->imapParams = $params; - } - - /** - * Set custom folder for attachments in case you want to have tree of folders for each email - * i.e. a/1 b/1 c/1 where a,b,c - senders, i.e. [email protected] - * - * @param string $dir folder where to save attachments - * - * @return void - */ - public function setAttachmentsDir( $dir ) { - $this->attachmentsDir = $dir; - } - - /** - * Get IMAP mailbox connection stream - * - * @param bool $forceConnection Initialize connection if it's not initialized - * @return null|resource - */ - public function getImapStream( $forceConnection = true ) { - if ( $forceConnection ) { - if ( $this->imapStream && ( ! is_resource( $this->imapStream ) || ! imap_ping( $this->imapStream ) ) ) { - $this->disconnect(); - $this->imapStream = null; - } - if ( ! $this->imapStream ) { - $this->imapStream = $this->initImapStream(); - } - } - return $this->imapStream; - } - - /** - * Switch mailbox without opening a new connection - * - * @param string $imapPath - */ - public function switchMailbox( $imapPath = '' ) { - $this->imapPath = $imapPath; - $imapStream = @imap_reopen( $this->getImapStream(), $imapPath ); - if ( ! $imapStream ) { - throw new Exception( "Couldn't switch mailbox: " . imap_last_error() ); - } - } - - protected function initImapStream() { - $imapStream = @imap_open( $this->imapPath, $this->imapLogin, $this->imapPassword, $this->imapOptions, $this->imapRetriesNum, array( 'DISABLE_AUTHENTICATOR' => 'GSSAPI' ) ); - - if ( ! $imapStream ) { - $lastError = imap_last_error(); - imap_errors(); - throw new Exception( 'Connection error: ' . $lastError ); - } - return $imapStream; - } - - protected function disconnect() { - $imapStream = $this->getImapStream( false ); - if ( $imapStream && is_resource( $imapStream ) ) { - imap_close( $imapStream, $this->expungeOnDisconnect ? CL_EXPUNGE : 0 ); - } - } - - /** - * Sets 'expunge on disconnect' parameter - * - * @param bool $isEnabled - */ - public function setExpungeOnDisconnect( $isEnabled ) { - $this->expungeOnDisconnect = $isEnabled; - } - - /** - * Get information about the current mailbox. - * - * Returns the information in an object with following properties: - * Date - current system time formatted according to RFC2822 - * Driver - protocol used to access this mailbox: POP3, IMAP, NNTP - * Mailbox - the mailbox name - * Nmsgs - number of mails in the mailbox - * Recent - number of recent mails in the mailbox - * - * @return stdClass - */ - public function checkMailbox() { - return imap_check( $this->getImapStream() ); - } - - /** - * Creates a new mailbox specified by mailbox. - * - * @return bool - */ - - public function createMailbox() { - return imap_createmailbox( $this->getImapStream(), imap_utf7_encode( $this->imapPath ) ); - } - - /** - * Gets status information about the given mailbox. - * - * This function returns an object containing status information. - * The object has the following properties: messages, recent, unseen, uidnext, and uidvalidity. - * - * @return stdClass if the box doesn't exist - */ - - public function statusMailbox() { - return imap_status( $this->getImapStream(), $this->imapPath, SA_ALL ); - } - - - /** - * Gets listing the folders - * - * This function returns an object containing listing the folders. - * The object has the following properties: messages, recent, unseen, uidnext, and uidvalidity. - * - * @return array listing the folders - */ - - public function getListingFolders() { - $folders = imap_list( $this->getImapStream(), $this->imapPath, '*' ); - foreach ( $folders as $key => $folder ) { - if ( function_exists( 'mb_convert_encoding' ) ) { - $folder = str_replace( $this->imapPath, '', mb_convert_encoding( $folder, 'UTF-8', 'UTF7-IMAP' ) ); - } else { - $folder = str_replace( $this->imapPath, '', imap_utf7_decode( $folder ) ); - } - $folders[ $key ] = $folder; - } - return $folders; - } - - - /** - * This function uses imap_search() to perform a search on the mailbox currently opened in the given IMAP stream. - * For example, to match all unanswered mails sent by Mom, you'd use: "UNANSWERED FROM mom". - * - * @param string $criteria See http://php.net/imap_search for a complete list of available criteria - * @return array mailsIds (or empty array) - */ - public function searchMailbox( $criteria = 'ALL', $charset = 'UTF-8' ) { - $mailsIds = imap_search( $this->getImapStream(), $criteria, SE_UID, $charset ); - return $mailsIds ? $mailsIds : array(); - } - - /** - * Save mail body. - * - * @return bool - */ - public function saveMail( $mailId, $filename = 'email.eml' ) { - return imap_savebody( $this->getImapStream(), $filename, $mailId, '', FT_UID ); - } - - /** - * Marks mails listed in mailId for deletion. - * - * @return bool - */ - public function deleteMail( $mailId ) { - return imap_delete( $this->getImapStream(), $mailId, FT_UID ); - } - - /** - * Moves mails listed in mailId into new mailbox - * - * @return bool - */ - public function moveMail( $mailId, $mailBox ) { - return imap_mail_move( $this->getImapStream(), $mailId, $mailBox, CP_UID ) && $this->expungeDeletedMails(); - } - - /** - * Copys mails listed in mailId into new mailbox - * - * @return bool - */ - public function copyMail( $mailId, $mailBox ) { - return imap_mail_copy( $this->getImapStream(), $mailId, $mailBox, CP_UID ) && $this->expungeDeletedMails(); - } - - /** - * Deletes all the mails marked for deletion by imap_delete(), imap_mail_move(), or imap_setflag_full(). - * - * @return bool - */ - public function expungeDeletedMails() { - return imap_expunge( $this->getImapStream() ); - } - - /** - * Add the flag \Seen to a mail. - * - * @return bool - */ - public function markMailAsRead( $mailId ) { - return $this->setFlag( array( $mailId ), '\\Seen' ); - } - - /** - * Remove the flag \Seen from a mail. - * - * @return bool - */ - public function markMailAsUnread( $mailId ) { - return $this->clearFlag( array( $mailId ), '\\Seen' ); - } - - /** - * Add the flag \Flagged to a mail. - * - * @return bool - */ - public function markMailAsImportant( $mailId ) { - return $this->setFlag( array( $mailId ), '\\Flagged' ); - } - - /** - * Add the flag \Seen to a mails. - * - * @return bool - */ - public function markMailsAsRead( array $mailId ) { - return $this->setFlag( $mailId, '\\Seen' ); - } - - /** - * Remove the flag \Seen from some mails. - * - * @return bool - */ - public function markMailsAsUnread( array $mailId ) { - return $this->clearFlag( $mailId, '\\Seen' ); - } - - /** - * Add the flag \Flagged to some mails. - * - * @return bool - */ - public function markMailsAsImportant( array $mailId ) { - return $this->setFlag( $mailId, '\\Flagged' ); - } - - /** - * Causes a store to add the specified flag to the flags set for the mails in the specified sequence. - * - * @param array $mailsIds - * @param string $flag which you can set are \Seen, \Answered, \Flagged, \Deleted, and \Draft as defined by RFC2060. - * @return bool - */ - public function setFlag( array $mailsIds, $flag ) { - return imap_setflag_full( $this->getImapStream(), implode( ',', $mailsIds ), $flag, ST_UID ); - } - - /** - * Cause a store to delete the specified flag to the flags set for the mails in the specified sequence. - * - * @param array $mailsIds - * @param string $flag which you can set are \Seen, \Answered, \Flagged, \Deleted, and \Draft as defined by RFC2060. - * @return bool - */ - public function clearFlag( array $mailsIds, $flag ) { - return imap_clearflag_full( $this->getImapStream(), implode( ',', $mailsIds ), $flag, ST_UID ); - } - - /** - * Fetch mail headers for listed mails ids - * - * Returns an array of objects describing one mail header each. The object will only define a property if it exists. The possible properties are: - * subject - the mails subject - * from - who sent it - * to - recipient - * date - when was it sent - * message_id - Mail-ID - * references - is a reference to this mail id - * in_reply_to - is a reply to this mail id - * size - size in bytes - * uid - UID the mail has in the mailbox - * msgno - mail sequence number in the mailbox - * recent - this mail is flagged as recent - * flagged - this mail is flagged - * answered - this mail is flagged as answered - * deleted - this mail is flagged for deletion - * seen - this mail is flagged as already read - * draft - this mail is flagged as being a draft - * - * @param array $mailsIds - * @return array - */ - public function getMailsInfo( array $mailsIds ) { - $mails = imap_fetch_overview( $this->getImapStream(), implode( ',', $mailsIds ), FT_UID ); - if ( is_array( $mails ) && count( $mails ) ) { - foreach ( $mails as &$mail ) { - if ( isset( $mail->subject ) ) { - $mail->subject = $this->decodeMimeStr( $mail->subject, $this->serverEncoding ); - } - if ( isset( $mail->from ) ) { - $mail->from = $this->decodeMimeStr( $mail->from, $this->serverEncoding ); - } - if ( isset( $mail->to ) ) { - $mail->to = $this->decodeMimeStr( $mail->to, $this->serverEncoding ); - } - } - } - return $mails; - } - - /** - * Get information about the current mailbox. - * - * Returns an object with following properties: - * Date - last change (current datetime) - * Driver - driver - * Mailbox - name of the mailbox - * Nmsgs - number of messages - * Recent - number of recent messages - * Unread - number of unread messages - * Deleted - number of deleted messages - * Size - mailbox size - * - * @return object Object with info | FALSE on failure - */ - - public function getMailboxInfo() { - return imap_mailboxmsginfo( $this->getImapStream() ); - } - - /** - * Gets mails ids sorted by some criteria - * - * Criteria can be one (and only one) of the following constants: - * SORTDATE - mail Date - * SORTARRIVAL - arrival date (default) - * SORTFROM - mailbox in first From address - * SORTSUBJECT - mail subject - * SORTTO - mailbox in first To address - * SORTCC - mailbox in first cc address - * SORTSIZE - size of mail in octets - * - * @param int $criteria - * @param bool $reverse - * @return array Mails ids - */ - public function sortMails( $criteria = SORTARRIVAL, $reverse = true ) { - return imap_sort( $this->getImapStream(), $criteria, $reverse, SE_UID ); - } - - /** - * Get mails count in mail box - * - * @return int - */ - public function countMails() { - return imap_num_msg( $this->getImapStream() ); - } - - /** - * Retrieve the quota settings per user - * - * @return array - FALSE in the case of call failure - */ - protected function getQuota() { - return imap_get_quotaroot( $this->getImapStream(), 'INBOX' ); - } - - /** - * Return quota limit in KB - * - * @return int - FALSE in the case of call failure - */ - public function getQuotaLimit() { - $quota = $this->getQuota(); - if ( is_array( $quota ) ) { - $quota = $quota['STORAGE']['limit']; - } - return $quota; - } - - /** - * Return quota usage in KB - * - * @return int - FALSE in the case of call failure - */ - public function getQuotaUsage() { - $quota = $this->getQuota(); - if ( is_array( $quota ) ) { - $quota = $quota['STORAGE']['usage']; - } - return $quota; - } - - /** - * Get raw mail data - * - * @param $msgId - * @param bool $markAsSeen - * @return mixed - */ - public function getRawMail( $msgId, $markAsSeen = true ) { - $options = FT_UID; - if ( ! $markAsSeen ) { - $options |= FT_PEEK; - } - - return imap_fetchbody( $this->getImapStream(), $msgId, '', $options ); - } - - /** - * Get mail data - * - * @param $mailId - * @param bool $markAsSeen - * @return IncomingMail - */ - public function getMail( $mailId, $markAsSeen = true ) { - $headersRaw = imap_fetchheader( $this->getImapStream(), $mailId, FT_UID ); - $head = imap_rfc822_parse_headers( $headersRaw ); - - $mail = new EH_CRM_IncomingMail(); - $mail->headersRaw = $headersRaw; - $mail->headers = $head; - $mail->id = $mailId; - $mail->date = gmdate( 'd-M-Y h:i:s A', isset( $head->date ) ? strtotime( preg_replace( '/\(.*?\)/', '', $head->date ) ) : time() ); - $mail->subject = isset( $head->subject ) ? $this->decodeMimeStr( $head->subject, $this->serverEncoding ) : null; - $mail->fromName = isset( $head->from[0]->personal ) ? $this->decodeMimeStr( $head->from[0]->personal, $this->serverEncoding ) : null; - $mail->fromAddress = strtolower( $head->from[0]->mailbox . '@' . $head->from[0]->host ); - - if ( isset( $head->to ) ) { - $toStrings = array(); - foreach ( $head->to as $to ) { - if ( ! empty( $to->mailbox ) && ! empty( $to->host ) ) { - $toEmail = strtolower( $to->mailbox . '@' . $to->host ); - $toName = isset( $to->personal ) ? $this->decodeMimeStr( $to->personal, $this->serverEncoding ) : null; - $toStrings[] = $toName ? "$toName <$toEmail>" : $toEmail; - $mail->to[ $toEmail ] = $toName; - } - } - $mail->toString = implode( ', ', $toStrings ); - } - - if ( isset( $head->cc ) ) { - foreach ( $head->cc as $cc ) { - $mail->cc[ strtolower( $cc->mailbox . '@' . $cc->host ) ] = isset( $cc->personal ) ? $this->decodeMimeStr( $cc->personal, $this->serverEncoding ) : null; - } - } - - if ( isset( $head->bcc ) ) { - foreach ( $head->bcc as $bcc ) { - $mail->bcc[ strtolower( $bcc->mailbox . '@' . $bcc->host ) ] = isset( $bcc->personal ) ? $this->decodeMimeStr( $bcc->personal, $this->serverEncoding ) : null; - } - } - - if ( isset( $head->reply_to ) ) { - foreach ( $head->reply_to as $replyTo ) { - $mail->replyTo[ strtolower( $replyTo->mailbox . '@' . $replyTo->host ) ] = isset( $replyTo->personal ) ? $this->decodeMimeStr( $replyTo->personal, $this->serverEncoding ) : null; - } - } - - if ( isset( $head->message_id ) ) { - $mail->messageId = $head->message_id; - } - - $mailStructure = imap_fetchstructure( $this->getImapStream(), $mailId, FT_UID ); - - if ( empty( $mailStructure->parts ) ) { - $this->initMailPart( $mail, $mailStructure, 0, $markAsSeen ); - } else { - foreach ( $mailStructure->parts as $partNum => $partStructure ) { - $this->initMailPart( $mail, $partStructure, $partNum + 1, $markAsSeen ); - } - } - - return $mail; - } - - protected function initMailPart( EH_CRM_IncomingMail $mail, $partStructure, $partNum, $markAsSeen = true ) { - $options = FT_UID; - if ( ! $markAsSeen ) { - $options |= FT_PEEK; - } - $data = $partNum ? imap_fetchbody( $this->getImapStream(), $mail->id, $partNum, $options ) : imap_body( $this->getImapStream(), $mail->id, $options ); - if ( 1 == $partStructure->encoding ) { - $data = imap_utf8( $data ); - } elseif ( 2 == $partStructure->encoding ) { - $data = imap_binary( $data ); - } elseif ( 3 == $partStructure->encoding ) { - $data = preg_replace( '~[^a-zA-Z0-9+=/]+~s', '', $data ); // https://github.com/barbushin/php-imap/issues/88 - $data = imap_base64( $data ); - } elseif ( 4 == $partStructure->encoding ) { - $data = quoted_printable_decode( $data ); - } - - $params = array(); - if ( ! empty( $partStructure->parameters ) ) { - foreach ( $partStructure->parameters as $param ) { - $params[ strtolower( $param->attribute ) ] = $param->value; - } - } - if ( ! empty( $partStructure->dparameters ) ) { - foreach ( $partStructure->dparameters as $param ) { - $paramName = strtolower( preg_match( '~^(.*?)\*~', $param->attribute, $matches ) ? $matches[1] : $param->attribute ); - if ( isset( $params[ $paramName ] ) ) { - $params[ $paramName ] .= $param->value; - } else { - $params[ $paramName ] = $param->value; - } - } - } - - // attachments - $attachmentId = $partStructure->ifid - ? trim( $partStructure->id, ' <>' ) - : ( isset( $params['filename'] ) || isset( $params['name'] ) ? mt_rand() . mt_rand() : null ); - - // ignore contentId on body when mail isn't multipart (https://github.com/barbushin/php-imap/issues/71) - if ( ! $partNum && TYPETEXT === $partStructure->type ) { - $attachmentId = null; - } - - if ( $attachmentId ) { - if ( empty( $params['filename'] ) && empty( $params['name'] ) ) { - $fileName = $attachmentId . '.' . strtolower( $partStructure->subtype ); - } else { - $fileName = ! empty( $params['filename'] ) ? $params['filename'] : $params['name']; - $fileName = $this->decodeMimeStr( $fileName, $this->serverEncoding ); - $fileName = $this->decodeRFC2231( $fileName, $this->serverEncoding ); - } - $ext = pathinfo( $fileName, PATHINFO_EXTENSION ); - if ( ! in_array( $ext, array( 'php', 'exe', 'sh', 'js' ) ) ) { - $attachment = new EH_CRM_IncomingMailAttachment(); - $attachment->id = $attachmentId; - $attachment->name = time() . '_' . $fileName; - $attachment->disposition = ( isset( $partStructure->disposition ) ? $partStructure->disposition : null ); - if ( $this->attachmentsDir ) { - $fileSysName = time() . '_' . $fileName; - $attachment->filePath = $this->attachmentsDir . DIRECTORY_SEPARATOR . $fileSysName; - - if ( strlen( $attachment->filePath ) > 255 ) { - $ext = pathinfo( $attachment->filePath, PATHINFO_EXTENSION ); - $attachment->filePath = substr( $attachment->filePath, 0, 255 - 1 - strlen( $ext ) ) . '.' . $ext; - } - $file_name = $attachment->filePath; - - $ifp = fopen( $file_name, 'w' ); - fwrite( $ifp, $data ); - fclose( $ifp ); - - } - $mail->addAttachment( $attachment ); - } - } else { - if ( ! empty( $params['charset'] ) ) { - $data = $this->convertStringEncoding( $data, $params['charset'], $this->serverEncoding ); - } - if ( 0 == $partStructure->type && $data ) { - if ( strtolower( $partStructure->subtype ) == 'plain' ) { - $mail->textPlain .= $data; - } else { - $mail->textHtml .= $data; - } - } elseif ( 2 == $partStructure->type && $data ) { - $mail->textPlain .= trim( $data ); - } - } - if ( ! empty( $partStructure->parts ) ) { - foreach ( $partStructure->parts as $subPartNum => $subPartStructure ) { - if ( 2 == $partStructure->type && 'RFC822' == $partStructure->subtype ) { - $this->initMailPart( $mail, $subPartStructure, $partNum, $markAsSeen ); - } else { - $this->initMailPart( $mail, $subPartStructure, $partNum . '.' . ( $subPartNum + 1 ), $markAsSeen ); - } - } - } - } - - protected function decodeMimeStr( $string, $charset = 'utf-8' ) { - $newString = ''; - $elements = imap_mime_header_decode( $string ); - for ( $i = 0; $i < count( $elements ); $i++ ) { - if ( 'default' == $elements[ $i ]->charset ) { - $elements[ $i ]->charset = 'iso-8859-1'; - } - $newString .= $this->convertStringEncoding( $elements[ $i ]->text, $elements[ $i ]->charset, $charset ); - } - return $newString; - } - - public function isUrlEncoded( $string ) { - $hasInvalidChars = preg_match( '#[^%a-zA-Z0-9\-_\.\+]#', $string ); - $hasEscapedChars = preg_match( '#%[a-zA-Z0-9]{2}#', $string ); - return ! $hasInvalidChars && $hasEscapedChars; - } - - protected function decodeRFC2231( $string, $charset = 'utf-8' ) { - if ( preg_match( "/^(.*?)'.*?'(.*?)$/", $string, $matches ) ) { - $encoding = $matches[1]; - $data = $matches[2]; - if ( $this->isUrlEncoded( $data ) ) { - $string = $this->convertStringEncoding( urldecode( $data ), $encoding, $charset ); - } - } - return $string; - } - - /** - * Converts a string from one encoding to another. - * - * @param string $string - * @param string $fromEncoding - * @param string $toEncoding - * @return string Converted string if conversion was successful, or the original string if not - */ - protected function convertStringEncoding( $string, $fromEncoding, $toEncoding ) { - $convertedString = null; - if ( $string && $fromEncoding != $toEncoding ) { - $convertedString = @iconv( $fromEncoding, $toEncoding . '//IGNORE', $string ); - if ( ! $convertedString && extension_loaded( 'mbstring' ) ) { - $convertedString = @mb_convert_encoding( $string, $toEncoding, $fromEncoding ); - } - } - return $convertedString ? $string : $string; - } - - public function __destruct() { - $this->disconnect(); - } - - /** Function used to set image path - * - * @param $imapPath - * @return void - */ - protected function setImapPath( $imapPath ) { - if ( function_exists( 'mb_convert_encoding' ) ) { - $this->imapPath = mb_convert_encoding( $imapPath, 'UTF7-IMAP', 'UTF-8' ); - } else { - $this->imapPath = imap_utf7_encode( $imapPath ); - } - } -} - -class Exception extends \Exception { - - -} +<?php namespace EH_CRM_PhpImap;++use stdClass;++/** Class used for crm mailbox+ * + * @see https://github.com/barbushin/php-imap+ */+class EH_CRM_Mailbox {+++ protected $imapPath;+ protected $imapLogin;+ protected $imapPassword;+ protected $imapOptions = 0;+ protected $imapRetriesNum = 0;+ protected $imapParams = array();+ protected $serverEncoding;+ protected $attachmentsDir = null;+ protected $expungeOnDisconnect = true;+ private $imapStream;++ /** Construct of the class+ * + * @param string $imapPath+ * @param string $login+ * @param string $password+ * @param string $attachmentsDir+ * @param string $serverEncoding+ * @throws Exception+ */+ public function __construct( $imapPath, $login, $password, $attachmentsDir = null, $serverEncoding = 'UTF-8' ) {+ $this->setImapPath( $imapPath );+ $this->imapLogin = $login;+ $this->imapPassword = $password;+ $this->serverEncoding = strtoupper( $serverEncoding );+ if ( $attachmentsDir ) {+ if ( ! is_dir( $attachmentsDir ) ) {+ throw new Exception( 'Directory "' . $attachmentsDir . '" not found' );+ }+ $this->attachmentsDir = rtrim( realpath( $attachmentsDir ), '\\/' );+ }+ }++ /**+ * Set custom connection arguments of imap_open method. See http://php.net/imap_open+ *+ * @param int $options+ * @param int $retriesNum+ * @param array $params+ */+ public function setConnectionArgs( $options = 0, $retriesNum = 0, array $params = null ) {+ $this->imapOptions = $options;+ $this->imapRetriesNum = $retriesNum;+ $this->imapParams = $params;+ }++ /**+ * Set custom folder for attachments in case you want to have tree of folders for each email+ * i.e. a/1 b/1 c/1 where a,b,c - senders, i.e. [email protected]+ *+ * @param string $dir folder where to save attachments+ *+ * @return void+ */+ public function setAttachmentsDir( $dir ) {+ $this->attachmentsDir = $dir;+ }++ /**+ * Get IMAP mailbox connection stream+ *+ * @param bool $forceConnection Initialize connection if it's not initialized+ * @return null|resource+ */+ public function getImapStream( $forceConnection = true ) {+ if ( $forceConnection ) {+ if ( $this->imapStream && ( ! is_resource( $this->imapStream ) || ! imap_ping( $this->imapStream ) ) ) {+ $this->disconnect();+ $this->imapStream = null;+ }+ if ( ! $this->imapStream ) {+ $this->imapStream = $this->initImapStream();+ }+ }+ return $this->imapStream;+ }++ /**+ * Switch mailbox without opening a new connection+ *+ * @param string $imapPath+ */+ public function switchMailbox( $imapPath = '' ) {+ $this->imapPath = $imapPath;+ $imapStream = @imap_reopen( $this->getImapStream(), $imapPath );+ if ( ! $imapStream ) {+ throw new Exception( "Couldn't switch mailbox: " . imap_last_error() );+ }+ }++ protected function initImapStream() {+ $imapStream = @imap_open( $this->imapPath, $this->imapLogin, $this->imapPassword, $this->imapOptions, $this->imapRetriesNum, array( 'DISABLE_AUTHENTICATOR' => 'GSSAPI' ) );++ if ( ! $imapStream ) {+ $lastError = imap_last_error();+ imap_errors();+ throw new Exception( 'Connection error: ' . $lastError );+ }+ return $imapStream;+ }++ protected function disconnect() {+ $imapStream = $this->getImapStream( false );+ if ( $imapStream && is_resource( $imapStream ) ) {+ imap_close( $imapStream, $this->expungeOnDisconnect ? CL_EXPUNGE : 0 );+ }+ }++ /**+ * Sets 'expunge on disconnect' parameter+ *+ * @param bool $isEnabled+ */+ public function setExpungeOnDisconnect( $isEnabled ) {+ $this->expungeOnDisconnect = $isEnabled;+ }++ /**+ * Get information about the current mailbox.+ *+ * Returns the information in an object with following properties:+ * Date - current system time formatted according to RFC2822+ * Driver - protocol used to access this mailbox: POP3, IMAP, NNTP+ * Mailbox - the mailbox name+ * Nmsgs - number of mails in the mailbox+ * Recent - number of recent mails in the mailbox+ *+ * @return stdClass+ */+ public function checkMailbox() {+ return imap_check( $this->getImapStream() );+ }++ /**+ * Creates a new mailbox specified by mailbox.+ *+ * @return bool+ */++ public function createMailbox() {+ return imap_createmailbox( $this->getImapStream(), imap_utf7_encode( $this->imapPath ) );+ }++ /**+ * Gets status information about the given mailbox.+ *+ * This function returns an object containing status information.+ * The object has the following properties: messages, recent, unseen, uidnext, and uidvalidity.+ *+ * @return stdClass if the box doesn't exist+ */++ public function statusMailbox() {+ return imap_status( $this->getImapStream(), $this->imapPath, SA_ALL );+ }+++ /**+ * Gets listing the folders+ *+ * This function returns an object containing listing the folders.+ * The object has the following properties: messages, recent, unseen, uidnext, and uidvalidity.+ *+ * @return array listing the folders+ */++ public function getListingFolders() {+ $folders = imap_list( $this->getImapStream(), $this->imapPath, '*' );+ foreach ( $folders as $key => $folder ) {+ if ( function_exists( 'mb_convert_encoding' ) ) {+ $folder = str_replace( $this->imapPath, '', mb_convert_encoding( $folder, 'UTF-8', 'UTF7-IMAP' ) );+ } else {+ $folder = str_replace( $this->imapPath, '', imap_utf7_decode( $folder ) );+ }+ $folders[ $key ] = $folder;+ }+ return $folders;+ }+++ /**+ * This function uses imap_search() to perform a search on the mailbox currently opened in the given IMAP stream.+ * For example, to match all unanswered mails sent by Mom, you'd use: "UNANSWERED FROM mom".+ *+ * @param string $criteria See http://php.net/imap_search for a complete list of available criteria+ * @return array mailsIds (or empty array)+ */+ public function searchMailbox( $criteria = 'ALL', $charset = 'UTF-8' ) {+ $mailsIds = imap_search( $this->getImapStream(), $criteria, SE_UID, $charset );+ return $mailsIds ? $mailsIds : array();+ }++ /**+ * Save mail body.+ *+ * @return bool+ */+ public function saveMail( $mailId, $filename = 'email.eml' ) {+ return imap_savebody( $this->getImapStream(), $filename, $mailId, '', FT_UID );+ }++ /**+ * Marks mails listed in mailId for deletion.+ *+ * @return bool+ */+ public function deleteMail( $mailId ) {+ return imap_delete( $this->getImapStream(), $mailId, FT_UID );+ }++ /**+ * Moves mails listed in mailId into new mailbox+ *+ * @return bool+ */+ public function moveMail( $mailId, $mailBox ) {+ return imap_mail_move( $this->getImapStream(), $mailId, $mailBox, CP_UID ) && $this->expungeDeletedMails();+ }++ /**+ * Copys mails listed in mailId into new mailbox+ *+ * @return bool+ */+ public function copyMail( $mailId, $mailBox ) {+ return imap_mail_copy( $this->getImapStream(), $mailId, $mailBox, CP_UID ) && $this->expungeDeletedMails();+ }++ /**+ * Deletes all the mails marked for deletion by imap_delete(), imap_mail_move(), or imap_setflag_full().+ *+ * @return bool+ */+ public function expungeDeletedMails() {+ return imap_expunge( $this->getImapStream() );+ }++ /**+ * Add the flag \Seen to a mail.+ *+ * @return bool+ */+ public function markMailAsRead( $mailId ) {+ return $this->setFlag( array( $mailId ), '\\Seen' );+ }++ /**+ * Remove the flag \Seen from a mail.+ *+ * @return bool+ */+ public function markMailAsUnread( $mailId ) {+ return $this->clearFlag( array( $mailId ), '\\Seen' );+ }++ /**+ * Add the flag \Flagged to a mail.+ *+ * @return bool+ */+ public function markMailAsImportant( $mailId ) {+ return $this->setFlag( array( $mailId ), '\\Flagged' );+ }++ /**+ * Add the flag \Seen to a mails.+ *+ * @return bool+ */+ public function markMailsAsRead( array $mailId ) {+ return $this->setFlag( $mailId, '\\Seen' );+ }++ /**+ * Remove the flag \Seen from some mails.+ *+ * @return bool+ */+ public function markMailsAsUnread( array $mailId ) {+ return $this->clearFlag( $mailId, '\\Seen' );+ }+
Vulnerability Existed: no No Vulnerabilities Detected - CWE Summary **File: includes/Mailbox.php** **Analysis:** The provided diff shows a line-ending normalization change (CRLF → LF) across the entire file between version 3.3.4 and 3.3.5. The actual code content remains identical—only whitespace/line-ending characters have changed. After analyzing the code for security vulnerabilities: 1. **No new vulnerabilities introduced** - The code content is unchanged 2. **No existing vulnerabilities fixed** - No security-related code modifications were made 3. **This is a formatting/normalization commit** - purely administrative **Code Review Notes:** While the diff itself contains no security fixes, the existing codebase does have several security observations worth noting (though not relevant to this particular change): - **Arbitrary file attachment handling** (lines ~520-540): Filename handling uses `time() . '_' . $fileName` which prevents certain attacks but the file extension check is limited to `['php', 'exe', 'sh', 'js']`. Other dangerous extensions could slip through. - **Encoding conversion logic** (lines ~615-622): The `convertStringEncoding()` function has unusual fallback logic that may not handle encoding errors properly. - **String validation** (line ~599): The `isUrlEncoded()` function's regex check could be more robust. However, none of these represent changes in this diff—they are pre-existing conditions in the 3.3.4 → 3.3.5 transition. **Conclusion:** This is a normalization commit with no security impact.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Response.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Response.php 2025-12-21 09:36:35.231291286 +0000@@ -1,11 +1,11 @@-<?php - -namespace WSDesk; - -class Response { - - public static function json( $data ) { - header( 'Content-type:application/json;charset=utf-8' ); - die( json_encode( $data ) ); - } -} +<?php++namespace WSDesk;++class Response {++ public static function json( $data ) {+ header( 'Content-type:application/json;charset=utf-8' );+ die( json_encode( $data ) );+ }+}
Vulnerability Existed: no Explanation: This diff contains only whitespace changes (line ending normalization from LF to CRLF or similar formatting adjustments). No actual code modifications were made to the `Response.php` file. The `Response::json()` method remains functionally identical: - Still sets the `Content-Type` header to `application/json` - Still uses `json_encode()` without any sanitization or escaping parameters - Still uses `die()` to terminate execution While the underlying code does have a potential security consideration (the method accepts arbitrary data and JSON-encodes it without validation), this particular diff introduces no security fixes or changes. The vulnerability (if any exists in how this method is used elsewhere) was neither introduced nor fixed in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Settings/SettingsItem.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Settings/SettingsItem.php 2025-12-21 09:36:35.231291286 +0000@@ -1,33 +1,33 @@-<?php -namespace WSDesk\Settings; - -use Illuminate\Support\Arr; -use Illuminate\Support\Fluent; - -class SettingsItem extends Fluent { - public function get_meta() { - if ( $this->get( 'meta' , false ) === false ) { - $this->meta = new Fluent( eh_crm_get_settingsmeta( $this->settings_id ) ); - } - - return $this->get( 'meta', new Fluent() ); - } - - public static function find_by_slug( $slug ) { - $settings = new SettingsRepository(); - - $item = Arr::first( - $settings->filter( - array( - 'slug' => $slug, - ) - ) - ); - - if ( $item ) { - return new self( $item ); - } - - return null; - } -} +<?php+namespace WSDesk\Settings;++use Illuminate\Support\Arr;+use Illuminate\Support\Fluent;++class SettingsItem extends Fluent {+ public function get_meta() {+ if ( $this->get( 'meta' , false ) === false ) {+ $this->meta = new Fluent( eh_crm_get_settingsmeta( $this->settings_id ) );+ }++ return $this->get( 'meta', new Fluent() );+ }++ public static function find_by_slug( $slug ) {+ $settings = new SettingsRepository();++ $item = Arr::first(+ $settings->filter(+ array(+ 'slug' => $slug,+ )+ )+ );++ if ( $item ) {+ return new self( $item );+ }++ return null;+ }+}
Vulnerability Existed: no Explanation: This diff contains only whitespace and line ending changes (converting from Unix LF to DOS CRLF line endings). The actual code content remains identical between versions 3.3.4 and 3.3.5. No security fixes or vulnerabilities are present in this change. The code itself does not appear to introduce new security issues: - The `find_by_slug()` method filters settings by slug without directly executing user input - The `get_meta()` method retrieves metadata through a function call without obvious injection vectors - No SQL queries, file operations, or unsafe string handling is visible in this snippet Since there are no functional code changes, there are no security vulnerabilities to report in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Settings/SettingsRepository.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Settings/SettingsRepository.php 2025-12-21 09:36:35.231291286 +0000@@ -1,115 +1,115 @@-<?php -namespace WSDesk\Settings; - -use Illuminate\Support\Arr; - -class SettingsRepository { - - const TABLE_NAME = 'wsdesk_settings'; - const TABLE_META_NAME = 'wsdesk_settingsmeta'; - const CACHE_TIME = 60 * 30; - - public function get() { - $settings = wp_cache_get( self::class, 'wsdesk' ); - - if ( false === $settings ) { - $settings = array_values( - array_map( - function ( $setting ) { - return (array) $setting; - }, - wpFluent()->table( self::TABLE_NAME )->get() - ) - ); - - wp_cache_set( self::class, $settings, 'wsdesk', self::CACHE_TIME ); - } - - return $settings; - } - - public function filter( array $filters ) { - return array_values( - array_filter( - $this->get(), - function ( $item ) use ( $filters ) { - foreach ( $filters as $key => $value ) { - if ( $item[ $key ] != $value ) { - return false; - } - } - return true; - } - ) - ); - } - - public function getLabels() { - $filter = [ - 'type' => 'label', - ]; - return $this->filter( $filter ); - } - - public function getFilterableLabels() { - $filter = [ - 'type' => 'label', - 'filter' => 'yes', - ]; - return $this->filter( $filter ); - } - - public function getTags() { - $filter = [ - 'type' => 'tag', - ]; - return $this->filter( $filter ); - } - - public function getFilterableTags() { - $filter = [ - 'type' => 'tag', - 'filter' => 'yes', - ]; - return $this->filter( $filter ); - } - - public function getTemplates() { - $filter = [ - 'type' => 'template', - ]; - return $this->filter( $filter ); - } - - public function getFields() { - $filter = [ - 'type' => 'field', - ]; - return $this->filter( $filter ); - } - - public function getViews() { - $filter = [ - 'type' => 'view', - ]; - - return $this->filter( $filter ); - } - - public function getFilterableViews() { - $filter = [ - 'type' => 'view', - 'filter' => 'yes', - ]; - - return $this->filter( $filter ); - } - - public function getView( $slug ) { - $filter = [ - 'type' => 'view', - 'slug' => $slug, - ]; - return Arr::first( $this->filter( $filter ) ); - } -} +<?php+namespace WSDesk\Settings;++use Illuminate\Support\Arr;++class SettingsRepository {++ const TABLE_NAME = 'wsdesk_settings';+ const TABLE_META_NAME = 'wsdesk_settingsmeta';+ const CACHE_TIME = 60 * 30;++ public function get() {+ $settings = wp_cache_get( self::class, 'wsdesk' );++ if ( false === $settings ) {+ $settings = array_values(+ array_map(+ function ( $setting ) {+ return (array) $setting;+ },+ wpFluent()->table( self::TABLE_NAME )->get()+ )+ );++ wp_cache_set( self::class, $settings, 'wsdesk', self::CACHE_TIME );+ }++ return $settings;+ }++ public function filter( array $filters ) {+ return array_values(+ array_filter(+ $this->get(),+ function ( $item ) use ( $filters ) {+ foreach ( $filters as $key => $value ) {+ if ( $item[ $key ] != $value ) {+ return false;+ }+ }+ return true;+ }+ )+ );+ }++ public function getLabels() {+ $filter = [+ 'type' => 'label',+ ];+ return $this->filter( $filter );+ }++ public function getFilterableLabels() {+ $filter = [+ 'type' => 'label',+ 'filter' => 'yes',+ ];+ return $this->filter( $filter );+ }++ public function getTags() {+ $filter = [+ 'type' => 'tag',+ ];+ return $this->filter( $filter );+ }++ public function getFilterableTags() {+ $filter = [+ 'type' => 'tag',+ 'filter' => 'yes',+ ];+ return $this->filter( $filter );+ }++ public function getTemplates() {+ $filter = [+ 'type' => 'template',+ ];+ return $this->filter( $filter );+ }++ public function getFields() {+ $filter = [+ 'type' => 'field',+ ];+ return $this->filter( $filter );+ }++ public function getViews() {+ $filter = [+ 'type' => 'view',+ ];++ return $this->filter( $filter );+ }++ public function getFilterableViews() {+ $filter = [+ 'type' => 'view',+ 'filter' => 'yes',+ ];++ return $this->filter( $filter );+ }++ public function getView( $slug ) {+ $filter = [+ 'type' => 'view',+ 'slug' => $slug,+ ];+ return Arr::first( $this->filter( $filter ) );+ }+}
Vulnerability Existed: no **Explanation:** This diff shows only a line-ending change (LF vs CRLF conversion) from version 3.3.4 to 3.3.5 of the elex-helpdesk-customer-support-ticket-system plugin. The actual code logic remains identical - no functional changes, security fixes, or vulnerabilities were introduced or addressed. The file contains no new security vulnerabilities and addresses no existing vulnerabilities. The code itself has potential weaknesses (type juggling with `!=` operator, potential array key access without isset checks, and lack of input validation for the `$slug` parameter), but these are pre-existing conditions not modified by this update.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/AgentFilter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/AgentFilter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,57 +1,57 @@-<?php -namespace WSDesk\Tickets\Filters; - -use Illuminate\Support\Arr; -use WSDesk\Tickets\TicketRepository; - -class AgentFilter implements FilterContract { - - public function filter( $query, $filters ) { - - if ( wsdesk_can_access_other_tickets() === false ) { - $filters['view']['agents'] = array( get_current_user_id() ); - } - - if ( Arr::has( $filters, 'view.agents' ) === false ) { - return $query; - } - - $agents = Arr::get( $filters, 'view.agents' ); - - if ( count( $agents ) === 0 ) { - return $query; - } - - $subQuery = 'select 1 from ' . $this->getQualifiedTableName( TicketRepository::TABLE_TICKETS_META ); - $subQuery .= ' where ' . $this->getQualifiedTableName( TicketRepository::TABLE_TICKETS ) . '.ticket_id = ' . $this->getQualifiedTableName( TicketRepository::TABLE_TICKETS_META ) . '.ticket_id'; - $subQuery .= ' and meta_key = "ticket_assignee"'; - - if ( count( $agents ) === 1 && current( $agents ) === 'null' ) { - $subQuery .= ' and meta_value = "' . serialize( [] ) . '" '; - } else { - $agents = is_array( $agents ) ? $agents : [ $agents ]; - - $subQuery .= ' and ('; - $subQuery .= implode( - ' or ', - array_map( - function ( $tag ) { - return ' meta_value like \'%"' . $tag . '"%\' '; - }, - $agents - ) - ); - $subQuery .= ')'; - } - - $query->where( \wpFluent()->raw( 'exists (' . $subQuery . ')' ) ); - - return $query; - } - - protected function getQualifiedTableName( $table ) { - global $wpdb; - - return $wpdb->prefix . $table; - } -} +<?php+namespace WSDesk\Tickets\Filters;++use Illuminate\Support\Arr;+use WSDesk\Tickets\TicketRepository;++class AgentFilter implements FilterContract {++ public function filter( $query, $filters ) {++ if ( wsdesk_can_access_other_tickets() === false ) {+ $filters['view']['agents'] = array( get_current_user_id() );+ }++ if ( Arr::has( $filters, 'view.agents' ) === false ) {+ return $query;+ }++ $agents = Arr::get( $filters, 'view.agents' );++ if ( count( $agents ) === 0 ) {+ return $query;+ }++ $subQuery = 'select 1 from ' . $this->getQualifiedTableName( TicketRepository::TABLE_TICKETS_META );+ $subQuery .= ' where ' . $this->getQualifiedTableName( TicketRepository::TABLE_TICKETS ) . '.ticket_id = ' . $this->getQualifiedTableName( TicketRepository::TABLE_TICKETS_META ) . '.ticket_id';+ $subQuery .= ' and meta_key = "ticket_assignee"';++ if ( count( $agents ) === 1 && current( $agents ) === 'null' ) {+ $subQuery .= ' and meta_value = "' . serialize( [] ) . '" ';+ } else {+ $agents = is_array( $agents ) ? $agents : [ $agents ];++ $subQuery .= ' and (';+ $subQuery .= implode(+ ' or ',+ array_map(+ function ( $tag ) {+ return ' meta_value like \'%"' . $tag . '"%\' ';+ },+ $agents+ )+ );+ $subQuery .= ')';+ }++ $query->where( \wpFluent()->raw( 'exists (' . $subQuery . ')' ) );++ return $query;+ }++ protected function getQualifiedTableName( $table ) {+ global $wpdb;++ return $wpdb->prefix . $table;+ }+}
Vulnerability Existed: yes
FALSE POSITIVE
SQL Injection - CWE-89 - includes/Tickets/Filters/AgentFilter.php Lines 35-41
Old Code:
```php
$subQuery .= implode(
' or ',
array_map(
function ( $tag ) {
return ' meta_value like \'%"' . $tag . '"%\' ';
},
$agents
)
);
```
Fixed Code:
```php
$subQuery .= implode(
' or ',
array_map(
function ( $tag ) {
return ' meta_value like \'%"' . $tag . '"%\' ';
},
$agents
)
);
```
Explanation:
The code contains a SQL Injection vulnerability. User-controlled agent data from the `$agents` array is directly concatenated into the SQL query string without any sanitization or parameterized query handling. The `$tag` variable (derived from user input via `$agents`) is embedded directly into the LIKE clause: `' meta_value like \'%"' . $tag . '"%\' '`. An attacker could inject malicious SQL by providing specially crafted agent values containing SQL syntax. The code should use prepared statements with placeholders (e.g., `$wpdb->prepare()`) instead of string concatenation. Additionally, the `serialize([])` on line 30 and the hardcoded `meta_key = "ticket_assignee"` value on line 27 also represent potential concerns, though the primary vulnerability is the unescaped agent data in the LIKE clause.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/BlockFilter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/BlockFilter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,66 +1,66 @@-<?php -namespace WSDesk\Tickets\Filters; - -use Illuminate\Support\Arr; -use WSDesk\Tickets\TicketRepository; - -class BlockFilter implements FilterContract { - - public function filter( $query, $filters ) { - if ( 'eh_crm_ticket_multiple_delete' === Arr::get( $filters, 'action' ) ) { - return $query; - } - - $blocked_emails = eh_crm_get_settingsmeta( 0, 'email_block_filters' ); - $blocked_subjects = eh_crm_get_settingsmeta( 0, 'subject_block_filters' ); - - if ( ! $blocked_emails && ! $blocked_subjects ) { - return $query; - } - - if ( ! is_array( $blocked_emails ) ) { - $blocked_emails = array(); - } - - if ( ! is_array( $blocked_subjects ) ) { - $blocked_subjects = array(); - } - - $blocked_emails = array_filter( - $blocked_emails, - function ( $mode ) { - return ( strpos( $mode, 'receive' ) > -1 ); - } - ); - - if ( count( $blocked_emails ) ) { - $query->whereNotIn( TicketRepository::TABLE_TICKETS . '.ticket_email', array_keys( $blocked_emails ) ); - } - - if ( count( $blocked_subjects ) === 0 ) { - return $query; - } - - $query->where( - function ( $query ) use ( $blocked_subjects ) { - foreach ( $blocked_subjects as $subject => $mode ) { - $subject = trim( $subject ); - if ( 'Anywhere' === $mode ) { - $query->where( 'ticket_title', 'not like', '%' . $subject . '%' ); - } else { - $query->where( 'ticket_title', 'not like', $subject . '%' ); - } - } - } - ); - - return $query; - } - - protected function getQualifiedTableName( $table ) { - global $wpdb; - - return $wpdb->prefix . $table; - } -} - +<?php+namespace WSDesk\Tickets\Filters;++use Illuminate\Support\Arr;+use WSDesk\Tickets\TicketRepository;++class BlockFilter implements FilterContract {++ public function filter( $query, $filters ) {+ if ( 'eh_crm_ticket_multiple_delete' === Arr::get( $filters, 'action' ) ) {+ return $query;+ }++ $blocked_emails = eh_crm_get_settingsmeta( 0, 'email_block_filters' );+ $blocked_subjects = eh_crm_get_settingsmeta( 0, 'subject_block_filters' );++ if ( ! $blocked_emails && ! $blocked_subjects ) {+ return $query;+ }++ if ( ! is_array( $blocked_emails ) ) {+ $blocked_emails = array();+ }++ if ( ! is_array( $blocked_subjects ) ) {+ $blocked_subjects = array();+ }++ $blocked_emails = array_filter(+ $blocked_emails,+ function ( $mode ) {+ return ( strpos( $mode, 'receive' ) > -1 );+ }+ );++ if ( count( $blocked_emails ) ) {+ $query->whereNotIn( TicketRepository::TABLE_TICKETS . '.ticket_email', array_keys( $blocked_emails ) );+ }++ if ( count( $blocked_subjects ) === 0 ) {+ return $query;+ }++ $query->where(+ function ( $query ) use ( $blocked_subjects ) {+ foreach ( $blocked_subjects as $subject => $mode ) {+ $subject = trim( $subject );+ if ( 'Anywhere' === $mode ) {+ $query->where( 'ticket_title', 'not like', '%' . $subject . '%' );+ } else {+ $query->where( 'ticket_title', 'not like', $subject . '%' );+ }+ }+ }+ );++ return $query;+ }++ protected function getQualifiedTableName( $table ) {+ global $wpdb;++ return $wpdb->prefix . $table;+ }+}+
Vulnerability Existed: no No Security Vulnerability Detected - includes/Tickets/Filters/BlockFilter.php (All lines) Old Code: Lines 1-66 (original version) Fixed Code: Lines 1-66 (updated version) Explanation: The diff shows only a line ending change (conversion from Unix LF to Unix LF format, with the file being reformatted). There are no functional code changes between version 3.3.4 and 3.3.5. The code structure, logic flow, and security controls remain identical. The file contains no newly introduced security fixes because the actual code implementation has not changed—only whitespace/line ending formatting has been adjusted.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/FilterContract.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/FilterContract.php 2025-12-21 09:36:35.231291286 +0000@@ -1,7 +1,7 @@-<?php -namespace WSDesk\Tickets\Filters; - -interface FilterContract { - - public function filter( $query, array $filters); -} +<?php+namespace WSDesk\Tickets\Filters;++interface FilterContract {++ public function filter( $query, array $filters);+}
Vulnerability Existed: no
No Vulnerabilities Detected - [N/A] - includes/Tickets/Filters/FilterContract.php [1-7]
Old Code:
```php
<?php
namespace WSDesk\Tickets\Filters;
interface FilterContract {
public function filter( $query, array $filters);
}
```
Fixed Code:
```php
<?php
namespace WSDesk\Tickets\Filters;
interface FilterContract {
public function filter( $query, array $filters);
}
```
Explanation:
This diff contains only whitespace/formatting changes (line ending normalization from CRLF to LF). No security vulnerabilities exist in either version. The code is a simple interface definition with no security-sensitive operations, input validation, or data handling that could introduce vulnerabilities. The interface contract itself remains functionally identical.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/GlobalSearchFilter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/GlobalSearchFilter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,37 +1,37 @@-<?php -namespace WSDesk\Tickets\Filters; - -use Illuminate\Support\Arr; - -class GlobalSearchFilter { - - public function filter( $query, $filters, $repo ) { - if ( ! Arr::get( $filters, 'search.value' ) ) { - return $query; - } - - $query->where( - function ( $query ) use ( $filters, $repo ) { - $search = Arr::get( $filters, 'search.value' ); - $query->where( 'ticket_id', 'like', $search . '%' ); - $query->orWhere( 'ticket_title', 'like', '%' . Arr::get( $filters, 'search.value' ) . '%' ); - $query->orWhere( 'ticket_content', 'like', '%' . Arr::get( $filters, 'search.value' ) . '%' ); - $query->orWhere( 'ticket_email', 'like', '%' . Arr::get( $filters, 'search.value' ) . '%' ); - - $subQuery = 'select 1 from ' . $this->getQualifiedTableName( $repo::TABLE_TICKETS_META ); - $subQuery .= ' where ' . $this->getQualifiedTableName( $repo::TABLE_TICKETS ) . '.ticket_id = ' . $this->getQualifiedTableName( $repo::TABLE_TICKETS_META ) . '.ticket_id'; - $subQuery .= ' and meta_value like "%%?%%"'; - - $query->orWhere( \wpFluent()->raw( 'exists (' . $subQuery . ')', $search ) ); - } - ); - - return $query; - } - - protected function getQualifiedTableName( $table ) { - global $wpdb; - - return $wpdb->prefix . $table; - } -} +<?php+namespace WSDesk\Tickets\Filters;++use Illuminate\Support\Arr;++class GlobalSearchFilter {++ public function filter( $query, $filters, $repo ) {+ if ( ! Arr::get( $filters, 'search.value' ) ) {+ return $query;+ }++ $query->where(+ function ( $query ) use ( $filters, $repo ) {+ $search = Arr::get( $filters, 'search.value' );+ $query->where( 'ticket_id', 'like', $search . '%' );+ $query->orWhere( 'ticket_title', 'like', '%' . Arr::get( $filters, 'search.value' ) . '%' );+ $query->orWhere( 'ticket_content', 'like', '%' . Arr::get( $filters, 'search.value' ) . '%' );+ $query->orWhere( 'ticket_email', 'like', '%' . Arr::get( $filters, 'search.value' ) . '%' );++ $subQuery = 'select 1 from ' . $this->getQualifiedTableName( $repo::TABLE_TICKETS_META );+ $subQuery .= ' where ' . $this->getQualifiedTableName( $repo::TABLE_TICKETS ) . '.ticket_id = ' . $this->getQualifiedTableName( $repo::TABLE_TICKETS_META ) . '.ticket_id';+ $subQuery .= ' and meta_value like "%%?%%"';++ $query->orWhere( \wpFluent()->raw( 'exists (' . $subQuery . ')', $search ) );+ }+ );++ return $query;+ }++ protected function getQualifiedTableName( $table ) {+ global $wpdb;++ return $wpdb->prefix . $table;+ }+}
Vulnerability Existed: no
Explanation:
The diff shows only line ending changes (CRLF to LF conversion) with no functional code modifications. The code itself contains a SQL injection vulnerability, but since the actual code logic remains identical between versions 3.3.4 and 3.3.5, this diff does not represent a security fix.
The underlying vulnerability in this code is that the `$search` parameter is passed to a raw SQL query without proper parameterization:
- Line 25: `$query->orWhere( \wpFluent()->raw( 'exists (' . $subQuery . ')', $search ) );`
The search value is concatenated into the SQL string rather than being properly escaped or parameterized, which could allow SQL injection if user input is not sanitized elsewhere. However, since this vulnerability exists in both versions and the diff contains no functional changes, this is not a security fix between these two versions.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/LabelFilter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/LabelFilter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,38 +1,38 @@-<?php -namespace WSDesk\Tickets\Filters; - -use Illuminate\Support\Arr; - -class LabelFilter { - - public function filter( $query, $filters, $repo ) { - $labels = Arr::get( $filters, 'view.labels', false ); - - if ( ! $labels ) { - return $query; - } - - $labels = is_array( $labels ) ? $labels : [ $labels ]; - - $query->where( - function ( $query ) use ( $labels, $repo ) { - foreach ( $labels as $label ) { - $subQuery = 'select 1 from ' . $this->getQualifiedTableName( $repo::TABLE_TICKETS_META ); - $subQuery .= ' where ' . $this->getQualifiedTableName( $repo::TABLE_TICKETS ) . '.ticket_id = ' . $this->getQualifiedTableName( $repo::TABLE_TICKETS_META ) . '.ticket_id'; - $subQuery .= ' and meta_key = "ticket_label"'; - $subQuery .= ' and meta_value in (?)'; - - $query->orWhere( \wpFluent()->raw( 'exists (' . $subQuery . ')', $label ) ); - } - } - ); - - return $query; - } - - protected function getQualifiedTableName( $table ) { - global $wpdb; - - return $wpdb->prefix . $table; - } -} +<?php+namespace WSDesk\Tickets\Filters;++use Illuminate\Support\Arr;++class LabelFilter {++ public function filter( $query, $filters, $repo ) {+ $labels = Arr::get( $filters, 'view.labels', false );++ if ( ! $labels ) {+ return $query;+ }++ $labels = is_array( $labels ) ? $labels : [ $labels ];++ $query->where(+ function ( $query ) use ( $labels, $repo ) {+ foreach ( $labels as $label ) {+ $subQuery = 'select 1 from ' . $this->getQualifiedTableName( $repo::TABLE_TICKETS_META );+ $subQuery .= ' where ' . $this->getQualifiedTableName( $repo::TABLE_TICKETS ) . '.ticket_id = ' . $this->getQualifiedTableName( $repo::TABLE_TICKETS_META ) . '.ticket_id';+ $subQuery .= ' and meta_key = "ticket_label"';+ $subQuery .= ' and meta_value in (?)';++ $query->orWhere( \wpFluent()->raw( 'exists (' . $subQuery . ')', $label ) );+ }+ }+ );++ return $query;+ }++ protected function getQualifiedTableName( $table ) {+ global $wpdb;++ return $wpdb->prefix . $table;+ }+}
Vulnerability Existed: no Explanation: This diff shows only line ending changes (CRLF to LF conversion) with no actual code modifications. The security characteristics of the code remain identical between versions 3.3.4 and 3.3.5. The code itself contains a potential SQL injection vulnerability that exists in both versions, but this is a pre-existing issue, not a fix: - The `$label` variable is passed to a raw SQL query via `wpFluent()->raw()` without proper parameterization - While the placeholder `(?)` suggests intent to use prepared statements, the implementation appears incomplete However, since the diff contains no code changes, this is **not a security fix** - it's a line ending normalization only.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/RequestorFilter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/RequestorFilter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,17 +1,17 @@-<?php -namespace WSDesk\Tickets\Filters; - -use Illuminate\Support\Arr; - -class RequestorFilter implements FilterContract { - - public function filter( $query, $filters ) { - if ( ! Arr::get( $filters, 'requestor' ) ) { - return $query; - } - - $query->where( 'ticket_email', 'like', '%' . Arr::get( $filters, 'requestor' ) . '%' ); - - return $query; - } -} +<?php+namespace WSDesk\Tickets\Filters;++use Illuminate\Support\Arr;++class RequestorFilter implements FilterContract {++ public function filter( $query, $filters ) {+ if ( ! Arr::get( $filters, 'requestor' ) ) {+ return $query;+ }++ $query->where( 'ticket_email', 'like', '%' . Arr::get( $filters, 'requestor' ) . '%' );++ return $query;+ }+}
Vulnerability Existed: no
No Vulnerability - Line Endings Change Only - includes/Tickets/Filters/RequestorFilter.php [Lines 1-17]
[Old Code]
```php
<?php
namespace WSDesk\Tickets\Filters;
use Illuminate\Support\Arr;
class RequestorFilter implements FilterContract {
public function filter( $query, $filters ) {
if ( ! Arr::get( $filters, 'requestor' ) ) {
return $query;
}
$query->where( 'ticket_email', 'like', '%' . Arr::get( $filters, 'requestor' ) . '%' );
return $query;
}
}
```
[Fixed Code]
```php
<?php
namespace WSDesk\Tickets\Filters;
use Illuminate\Support\Arr;
class RequestorFilter implements FilterContract {
public function filter( $query, $filters ) {
if ( ! Arr::get( $filters, 'requestor' ) ) {
return $query;
}
$query->where( 'ticket_email', 'like', '%' . Arr::get( $filters, 'requestor' ) . '%' );
return $query;
}
}
```
Explanation:
This diff contains only line ending changes (CRLF to LF conversion) with no functional code modifications. The underlying SQL injection vulnerability in the `RequestorFilter::filter()` method remains unfixed. The code continues to use the `like` operator with unsanitized user input from `Arr::get( $filters, 'requestor' )` concatenated directly into the query without proper parameter binding or escaping. While Laravel's query builder's `where()` method with parameterized queries would provide protection, the current implementation using string concatenation with `'%' . ... . '%'` exposes the application to SQL injection attacks. This diff does not address that vulnerability.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/Sorter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/Sorter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,37 +1,37 @@-<?php -namespace WSDesk\Tickets\Filters; - -use Illuminate\Support\Arr; - -class Sorter implements FilterContract { - - protected $columns = [ - 'ticket_id', - 'ticket_date', - 'ticket_updated', - ]; - - public function filter( $query, $filters ) { - // If the request has view filter then we are not able to sort manually or else the group will be broken - if ( Arr::has( $filters, 'view.views' ) ) { - return $query; - } - $column = Arr::get( $filters, 'sort.column' ); - - if ( ! $column ) { - return $query; - } - - if ( ! in_array( $column, $this->columns ) ) { - return $query; - } - - if ( 'ticket_date' === $column ) { - $column = \wpFluent()->raw( 'STR_TO_DATE(`ticket_date`, \'%%b %%d, %%Y %%r\')' ); - } - - $query->orderBy( $column, Arr::get( $filters, 'sort.dir', 'asc' ) ); - - return $query; - } -} +<?php+namespace WSDesk\Tickets\Filters;++use Illuminate\Support\Arr;++class Sorter implements FilterContract {++ protected $columns = [+ 'ticket_id',+ 'ticket_date',+ 'ticket_updated',+ ];++ public function filter( $query, $filters ) {+ // If the request has view filter then we are not able to sort manually or else the group will be broken+ if ( Arr::has( $filters, 'view.views' ) ) {+ return $query;+ }+ $column = Arr::get( $filters, 'sort.column' );++ if ( ! $column ) {+ return $query;+ }++ if ( ! in_array( $column, $this->columns ) ) {+ return $query;+ }++ if ( 'ticket_date' === $column ) {+ $column = \wpFluent()->raw( 'STR_TO_DATE(`ticket_date`, \'%%b %%d, %%Y %%r\')' );+ }++ $query->orderBy( $column, Arr::get( $filters, 'sort.dir', 'asc' ) );++ return $query;+ }+}
Vulnerability Existed: no Explanation: This diff shows only whitespace changes (line ending normalization from CRLF to LF). The actual code logic remains identical between versions 3.3.4 and 3.3.5. There are no security fixes or vulnerabilities introduced/removed in this change. The code itself implements proper input validation: - The `$column` parameter is validated against a whitelist (`$this->columns`) using `in_array()` - The `sort.dir` parameter is passed directly to `orderBy()`, but this is a common pattern in query builders where direction values are typically restricted to 'asc'/'desc' internally - No SQL injection vulnerability exists due to the whitelist validation on the column name This is purely a formatting/line-ending change with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/SubjectFilter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/SubjectFilter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,17 +1,17 @@-<?php -namespace WSDesk\Tickets\Filters; - -use Illuminate\Support\Arr; - -class SubjectFilter implements FilterContract { - - public function filter( $query, $filters ) { - if ( ! Arr::get( $filters, 'subject' ) ) { - return $query; - } - - $query->where( 'ticket_title', 'like', '%' . Arr::get( $filters, 'subject' ) . '%' ); - - return $query; - } -} +<?php+namespace WSDesk\Tickets\Filters;++use Illuminate\Support\Arr;++class SubjectFilter implements FilterContract {++ public function filter( $query, $filters ) {+ if ( ! Arr::get( $filters, 'subject' ) ) {+ return $query;+ }++ $query->where( 'ticket_title', 'like', '%' . Arr::get( $filters, 'subject' ) . '%' );++ return $query;+ }+}
Vulnerability Existed: no Explanation: This diff contains only whitespace and line ending changes (converting to Unix-style line endings). The actual code logic remains identical between versions 3.3.4 and 3.3.5. While the underlying code does contain a **SQL Injection vulnerability** (CWE-89) in the `where()` clause that uses user input (`$filters['subject']`) directly without parameterized queries, this vulnerability is not being fixed in this diff. The vulnerable code exists in both the old and new versions: ```php $query->where( 'ticket_title', 'like', '%' . Arr::get( $filters, 'subject' ) . '%' ); ``` This line concatenates user-supplied input directly into the SQL query without using Laravel's parameter binding. The proper fix would be: ```php $query->where( 'ticket_title', 'like', '%' . $subject . '%' ); ``` using bound parameters, but no such change is present in this diff. This appears to be a formatting/whitespace update only, not a security patch.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/TagFilter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/TagFilter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,45 +1,45 @@-<?php -namespace WSDesk\Tickets\Filters; - -use Illuminate\Support\Arr; -use WSDesk\Tickets\TicketRepository; - -class TagFilter implements FilterContract { - - public function filter( $query, $filters ) { - $tags = Arr::get( $filters, 'view.tags' ); - - if ( ! $tags ) { - return $query; - } - - $tags = is_array( $tags ) ? $tags : [ $tags ]; - - $subQuery = 'select 1 from ' . $this->getQualifiedTableName( TicketRepository::TABLE_TICKETS_META ); - $subQuery .= ' where ' . $this->getQualifiedTableName( TicketRepository::TABLE_TICKETS ) . '.ticket_id = ' . $this->getQualifiedTableName( TicketRepository::TABLE_TICKETS_META ) . '.ticket_id'; - $subQuery .= ' and meta_key = "ticket_tags"'; - $subQuery .= ' and ('; - - $subQuery .= implode( - ' or ', - array_map( - function ( $tag ) { - return ' meta_value like \'%"' . $tag . '"%\' '; - }, - $tags - ) - ); - - $subQuery .= ')'; - - $query->where( \wpFluent()->raw( 'exists (' . $subQuery . ')' ) ); - - return $query; - } - - protected function getQualifiedTableName( $table ) { - global $wpdb; - - return $wpdb->prefix . $table; - } -} +<?php+namespace WSDesk\Tickets\Filters;++use Illuminate\Support\Arr;+use WSDesk\Tickets\TicketRepository;++class TagFilter implements FilterContract {++ public function filter( $query, $filters ) {+ $tags = Arr::get( $filters, 'view.tags' );++ if ( ! $tags ) {+ return $query;+ }++ $tags = is_array( $tags ) ? $tags : [ $tags ];++ $subQuery = 'select 1 from ' . $this->getQualifiedTableName( TicketRepository::TABLE_TICKETS_META );+ $subQuery .= ' where ' . $this->getQualifiedTableName( TicketRepository::TABLE_TICKETS ) . '.ticket_id = ' . $this->getQualifiedTableName( TicketRepository::TABLE_TICKETS_META ) . '.ticket_id';+ $subQuery .= ' and meta_key = "ticket_tags"';+ $subQuery .= ' and (';++ $subQuery .= implode(+ ' or ',+ array_map(+ function ( $tag ) {+ return ' meta_value like \'%"' . $tag . '"%\' ';+ },+ $tags+ )+ );++ $subQuery .= ')';++ $query->where( \wpFluent()->raw( 'exists (' . $subQuery . ')' ) );++ return $query;+ }++ protected function getQualifiedTableName( $table ) {+ global $wpdb;++ return $wpdb->prefix . $table;+ }+}
Vulnerability Existed: yes
FALSE POSITIVE
SQL Injection - CWE-89 - includes/Tickets/Filters/TagFilter.php Lines 26-31
Old Code:
```php
array_map(
function ( $tag ) {
return ' meta_value like \'%"' . $tag . '"%\' ';
},
$tags
)
```
Fixed Code:
```php
array_map(
function ( $tag ) {
return ' meta_value like \'%"' . $tag . '"%\' ';
},
$tags
)
```
Explanation:
No security fix was applied in this diff. The code remains vulnerable to SQL injection. The `$tag` variable is directly concatenated into the SQL query string without any escaping or parameterization. User-controlled input from `$filters['view.tags']` flows directly into the SQL query via the `LIKE` clause. An attacker could inject SQL by providing tags containing SQL metacharacters (e.g., `' OR '1'='1`), which would be embedded unescaped into the subquery. The proper fix would require either using parameterized queries with bound parameters or properly escaping the tag values using `$wpdb->esc_like()` or similar functions before concatenation.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/TicketCreatedFilter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/TicketCreatedFilter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,34 +1,34 @@-<?php -namespace WSDesk\Tickets\Filters; - -use DateTime; -use Illuminate\Support\Arr; - -class TicketCreatedFilter implements FilterContract { - - public function filter( $query, $filters ) { - $dates = Arr::get( $filters, 'created_at' ); - - if ( ! $dates ) { - return $query; - } - - if ( ! is_array( $dates ) || count( $dates ) !== 2 ) { - return $query; - } - - list($start_date, $end_date) = $dates; - - $start_date = new DateTime( $start_date ); - $start_date->setTime( 0, 0, 0 ); - - $end_date = new DateTime( $end_date ); - $end_date->setTime( 11, 59, 59 ); - - $dates = array( get_gmt_from_date( $start_date->format( 'Y-m-d H:i:s' ) ), get_gmt_from_date( $end_date->format( 'Y-m-d H:i:s' ) ) ); - - $query->where( \wpFluent()->raw( 'STR_TO_DATE(ticket_date, \'%%b %%d, %%Y %%r\') between ? and ?', $dates ) ); - - return $query; - } -} +<?php+namespace WSDesk\Tickets\Filters;++use DateTime;+use Illuminate\Support\Arr;++class TicketCreatedFilter implements FilterContract {++ public function filter( $query, $filters ) {+ $dates = Arr::get( $filters, 'created_at' );++ if ( ! $dates ) {+ return $query;+ }++ if ( ! is_array( $dates ) || count( $dates ) !== 2 ) {+ return $query;+ }++ list($start_date, $end_date) = $dates;++ $start_date = new DateTime( $start_date );+ $start_date->setTime( 0, 0, 0 );++ $end_date = new DateTime( $end_date );+ $end_date->setTime( 11, 59, 59 );++ $dates = array( get_gmt_from_date( $start_date->format( 'Y-m-d H:i:s' ) ), get_gmt_from_date( $end_date->format( 'Y-m-d H:i:s' ) ) );++ $query->where( \wpFluent()->raw( 'STR_TO_DATE(ticket_date, \'%%b %%d, %%Y %%r\') between ? and ?', $dates ) );++ return $query;+ }+}
Vulnerability Existed: no The diff shows only whitespace changes (line ending normalization from CRLF to LF), with no actual code modifications. The security posture of the code remains unchanged. The underlying code itself contains a potential SQL injection vulnerability at line 32 through the use of raw SQL with `\wpFluent()->raw()`, but this vulnerability was not introduced or fixed in this diff - it existed in both versions and remains unfixed. Since the question asks specifically about security fixes in this diff, and no code changes were made: **No security fixes are present in this diff.**
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/TicketIdFilter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/TicketIdFilter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,22 +1,22 @@-<?php -namespace WSDesk\Tickets\Filters; - -use Illuminate\Support\Arr; - -class TicketIdFilter implements FilterContract { - - public function filter( $query, $filters ) { - $ticket_id = Arr::get( $filters, 'ticket_id' ); - if ( ! $ticket_id ) { - return $query; - } - - if ( is_array( $ticket_id ) ) { - $query->whereIn( 'ticket_id', $ticket_id ); - } else { - $query->where( 'ticket_id', 'like', '%' . trim( $ticket_id ) . '%' ); - } - - return $query; - } -} +<?php+namespace WSDesk\Tickets\Filters;++use Illuminate\Support\Arr;++class TicketIdFilter implements FilterContract {++ public function filter( $query, $filters ) {+ $ticket_id = Arr::get( $filters, 'ticket_id' );+ if ( ! $ticket_id ) {+ return $query;+ }++ if ( is_array( $ticket_id ) ) {+ $query->whereIn( 'ticket_id', $ticket_id );+ } else {+ $query->where( 'ticket_id', 'like', '%' . trim( $ticket_id ) . '%' );+ }++ return $query;+ }+}
Vulnerability Existed: no Explanation: This diff shows only line ending changes (CRLF to LF conversion) with no functional code modifications. The code structure, logic, and security properties remain identical between versions 3.3.4 and 3.3.5. The underlying code itself does not contain security vulnerabilities: - The `whereIn()` method properly escapes values when used with array input - The `where()` method with parameterized queries (using `like` operator) properly escapes the `$ticket_id` value, preventing SQL injection - The `trim()` function is safely applied to the user input before being passed to the parameterized query The line ending normalization is a non-security code quality improvement with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/TicketUpdatedFilter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/TicketUpdatedFilter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,23 +1,23 @@-<?php -namespace WSDesk\Tickets\Filters; - -use Illuminate\Support\Arr; - -class TicketUpdatedFilter implements FilterContract { - - public function filter( $query, $filters ) { - $dates = Arr::get( $filters, 'ticket_updated' ); - - if ( ! $dates ) { - return $query; - } - - if ( ! is_array( $dates ) || count( $dates ) != 2 ) { - return $query; - } - - $query->whereBetween( 'ticket_updated', $dates[0], $dates[1] ); - - return $query; - } -} +<?php+namespace WSDesk\Tickets\Filters;++use Illuminate\Support\Arr;++class TicketUpdatedFilter implements FilterContract {++ public function filter( $query, $filters ) {+ $dates = Arr::get( $filters, 'ticket_updated' );++ if ( ! $dates ) {+ return $query;+ }++ if ( ! is_array( $dates ) || count( $dates ) != 2 ) {+ return $query;+ }++ $query->whereBetween( 'ticket_updated', $dates[0], $dates[1] );++ return $query;+ }+}
Vulnerability Existed: no Explanation: This diff shows only a line ending change (CRLF to LF conversion) with no functional code modifications. The code itself does not contain security vulnerabilities that are being fixed in this update. However, it should be noted that the underlying code has a potential security issue that is NOT addressed in this diff: **Unaddressed Issue - SQL Injection Risk:** The `whereBetween()` method is being called with user-supplied `$dates[0]` and `$dates[1]` values without proper validation. While the code checks that `$dates` is an array with 2 elements, it does not validate that these elements are proper date values. If an attacker can manipulate the filter input, they could potentially inject malicious SQL. However, this vulnerability existed in version 3.3.4 and is NOT being fixed in version 3.3.5 (as evidenced by the identical functional code). Since the diff itself represents no security fixes (only formatting changes), the answer is **no vulnerability was fixed in this update**.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/UserFilter.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/UserFilter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,35 +1,35 @@-<?php -namespace WSDesk\Tickets\Filters; - -use Illuminate\Support\Arr; - -class UserFilter implements FilterContract { - - public function filter( $query, $filters ) { - $slug = Arr::get( $filters, 'view.users' ); - - if ( ! $slug ) { - return $query; - } - - $slug = is_array( $slug ) ? $slug : [ $slug ]; - - $query->where( - function ( $query ) use ( $slug ) { - foreach ( $slug as $userType ) { - $subQuery = 'select user_email from ' . $this->getQualifiedTableName( 'users' ); - - $query->where( \wpFluent()->raw( 'ticket_email ' . ( 'guest' === $userType ? 'not in' : 'in' ) . ' (' . $subQuery . ')' ) ); - } - } - ); - - return $query; - } - - protected function getQualifiedTableName( $table ) { - global $wpdb; - - return $wpdb->prefix . $table; - } -} +<?php+namespace WSDesk\Tickets\Filters;++use Illuminate\Support\Arr;++class UserFilter implements FilterContract {++ public function filter( $query, $filters ) {+ $slug = Arr::get( $filters, 'view.users' );++ if ( ! $slug ) {+ return $query;+ }++ $slug = is_array( $slug ) ? $slug : [ $slug ];++ $query->where(+ function ( $query ) use ( $slug ) {+ foreach ( $slug as $userType ) {+ $subQuery = 'select user_email from ' . $this->getQualifiedTableName( 'users' );++ $query->where( \wpFluent()->raw( 'ticket_email ' . ( 'guest' === $userType ? 'not in' : 'in' ) . ' (' . $subQuery . ')' ) );+ }+ }+ );++ return $query;+ }++ protected function getQualifiedTableName( $table ) {+ global $wpdb;++ return $wpdb->prefix . $table;+ }+}
Vulnerability Existed: yes
TRUE POSITIVE
SQL Injection - CWE-89 - includes/Tickets/Filters/UserFilter.php - Line 21
Old Code:
```php
$subQuery = 'select user_email from ' . $this->getQualifiedTableName( 'users' );
$query->where( \wpFluent()->raw( 'ticket_email ' . ( 'guest' === $userType ? 'not in' : 'in' ) . ' (' . $subQuery . ')' ) );
```
Fixed Code:
```php
$subQuery = 'select user_email from ' . $this->getQualifiedTableName( 'users' );
$query->where( \wpFluent()->raw( 'ticket_email ' . ( 'guest' === $userType ? 'not in' : 'in' ) . ' (' . $subQuery . ')' ) );
```
Explanation:
The diff shows no actual code changes - only line ending conversions (CRLF to LF). The underlying SQL injection vulnerability remains unfixed. The code constructs a raw SQL query by concatenating strings without parameterized queries or prepared statements. The `$userType` value is directly concatenated into the SQL string after a ternary operator. Additionally, the `$subQuery` is built by concatenating user-controlled table names without validation. The use of `wpFluent()->raw()` bypasses query builder protections and executes raw SQL, making this vulnerable to SQL injection attacks. A proper fix would require using parameterized queries or the query builder's parameter binding methods instead of raw SQL concatenation.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/View/Assignee.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/View/Assignee.php 2025-12-21 09:36:35.231291286 +0000@@ -1,42 +1,42 @@-<?php - -namespace WSDesk\Tickets\Filters\View; - -use WpFluent\QueryBuilder\QueryBuilderHandler; -use WSDesk\Tickets\TicketRepository; - -class Assignee { - - protected $query; - - /** - * Apply filter based on given condition - * - * @param string $condition Condition either IN or NOT IN - * @param string - * - * @return QueryBuilderHandler - */ - public function __construct( $condition, $value ) { - - $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ); - - $this->query->where( 'meta_key', 'ticket_assignee' ); - - if ( 'un' === $value ) { - $value = serialize( [] ); - } - - if ( 'in' === $condition ) { - $this->query->where( \wpFluent()->raw( 'meta_value like \'%"' . $value . '"%\' ' ) ); - } else { - $this->query->where( \wpFluent()->raw( 'meta_value not like \'%"' . $value . '"%\' ' ) ); - } - - return $this->query; - } - - public function __toString() { - return $this->query->select( 'ticket_id' )->getQuery()->getRawSql(); - } -} +<?php++namespace WSDesk\Tickets\Filters\View;++use WpFluent\QueryBuilder\QueryBuilderHandler;+use WSDesk\Tickets\TicketRepository;++class Assignee {++ protected $query;++ /**+ * Apply filter based on given condition+ *+ * @param string $condition Condition either IN or NOT IN+ * @param string+ *+ * @return QueryBuilderHandler+ */+ public function __construct( $condition, $value ) {++ $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META );++ $this->query->where( 'meta_key', 'ticket_assignee' );++ if ( 'un' === $value ) {+ $value = serialize( [] );+ }++ if ( 'in' === $condition ) {+ $this->query->where( \wpFluent()->raw( 'meta_value like \'%"' . $value . '"%\' ' ) );+ } else {+ $this->query->where( \wpFluent()->raw( 'meta_value not like \'%"' . $value . '"%\' ' ) );+ }++ return $this->query;+ }++ public function __toString() {+ return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();+ }+}
Vulnerability Existed: yes
FALSE POSITIVE
SQL Injection - CWE-89 - includes/Tickets/Filters/View/Assignee.php Lines 32-34
Old Code:
```php
if ( 'in' === $condition ) {
$this->query->where( \wpFluent()->raw( 'meta_value like \'%"' . $value . '"%\' ' ) );
} else {
$this->query->where( \wpFluent()->raw( 'meta_value not like \'%"' . $value . '"%\' ' ) );
}
```
Fixed Code:
```php
if ( 'in' === $condition ) {
$this->query->where( \wpFluent()->raw( 'meta_value like \'%"' . $value . '"%\' ' ) );
} else {
$this->query->where( \wpFluent()->raw( 'meta_value not like \'%"' . $value . '"%\' ' ) );
}
```
Explanation:
This diff appears to only contain line ending changes (CRLF to LF conversion), with no actual code modifications. The underlying SQL injection vulnerability remains unpatched. The `$value` parameter is directly concatenated into a raw SQL query string without any parameterization or escaping. An attacker could inject malicious SQL by passing crafted input to the `$condition` and `$value` parameters. The proper fix would be to use parameterized queries instead of string concatenation: `$this->query->where( 'meta_value', 'like', '%"' . esc_sql($value) . '"%' )` or use the query builder's parameter binding mechanism. Since no actual code changes were made, the vulnerability still exists in version 3.3.5.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/View/CustomField.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/View/CustomField.php 2025-12-21 09:36:35.231291286 +0000@@ -1,39 +1,39 @@-<?php - -namespace WSDesk\Tickets\Filters\View; - -use WpFluent\QueryBuilder\QueryBuilderHandler; -use WSDesk\Tickets\TicketRepository; - -class CustomField { - /** Class used to fetch data as per given condition - * - * @var QueryBuilderHandler $query - */ - protected $query; - - /** - * Apply filter based on given condition - * - * @param string $field The field to the filter apply for - * @param string $condition Condition either CONTAINS or NONE - * @param string $value - * - * @return QueryBuilder - */ - public function __construct( $field, $condition, $value ) { - - $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ); - - $compare = 'none' === $condition ? 'not like' : 'like'; - - $this->query->where( 'meta_key', '=', $field ); - $this->query->where( 'meta_value', $compare, '%' . $value . '%' ); - - return $this->query; - } - - public function __toString() { - return $this->query->select( 'ticket_id' )->getQuery()->getRawSql(); - } -} +<?php++namespace WSDesk\Tickets\Filters\View;++use WpFluent\QueryBuilder\QueryBuilderHandler;+use WSDesk\Tickets\TicketRepository;++class CustomField {+ /** Class used to fetch data as per given condition+ * + * @var QueryBuilderHandler $query+ */+ protected $query;++ /**+ * Apply filter based on given condition+ *+ * @param string $field The field to the filter apply for+ * @param string $condition Condition either CONTAINS or NONE+ * @param string $value+ *+ * @return QueryBuilder+ */+ public function __construct( $field, $condition, $value ) {++ $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META );++ $compare = 'none' === $condition ? 'not like' : 'like';++ $this->query->where( 'meta_key', '=', $field );+ $this->query->where( 'meta_value', $compare, '%' . $value . '%' );++ return $this->query;+ }++ public function __toString() {+ return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();+ }+}
Vulnerability Existed: no Explanation: The provided diff shows only line ending changes (CRLF to LF conversion), with no actual code modifications. The functionality remains identical: 1. The code uses parameterized queries via the QueryBuilder (`where()` method with bound parameters), which properly prevents SQL injection regardless of the `$value` input. 2. No input validation or sanitization logic was added or removed - the security posture is unchanged. 3. The `%` wildcards are part of the LIKE pattern logic, not user-controlled SQL syntax. Since there are no substantive code changes, there are no security fixes to analyze. The file maintains the same SQL injection protection through the QueryBuilder's parameter binding mechanism in both versions.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/View/Description.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/View/Description.php 2025-12-21 09:36:35.231291286 +0000@@ -1,37 +1,37 @@-<?php - -namespace WSDesk\Tickets\Filters\View; - -use WpFluent\QueryBuilder\QueryBuilderHandler; -use WSDesk\Tickets\TicketRepository; - -class Description { - /** Class used to fetch data as per given condition - * - * @var QueryBuilderHandler $query - */ - protected $query; - - /** - * Apply filter based on given condition - * - * @param string $condition Condition either CONTAINS or NONE - * @param string $value - * - * @return QueryBuilder - */ - public function __construct( $condition, $value ) { - - $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS ); - - $compare = 'none' === $condition ? 'not like' : 'like'; - - $this->query->where( 'ticket_content', $compare, '%' . $value . '%' ); - - return $this->query; - } - - public function __toString() { - return $this->query->select( 'ticket_id' )->getQuery()->getRawSql(); - } -} +<?php++namespace WSDesk\Tickets\Filters\View;++use WpFluent\QueryBuilder\QueryBuilderHandler;+use WSDesk\Tickets\TicketRepository;++class Description {+ /** Class used to fetch data as per given condition+ * + * @var QueryBuilderHandler $query+ */+ protected $query;++ /**+ * Apply filter based on given condition+ *+ * @param string $condition Condition either CONTAINS or NONE+ * @param string $value+ *+ * @return QueryBuilder+ */+ public function __construct( $condition, $value ) {++ $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS );++ $compare = 'none' === $condition ? 'not like' : 'like';++ $this->query->where( 'ticket_content', $compare, '%' . $value . '%' );++ return $this->query;+ }++ public function __toString() {+ return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();+ }+}
Vulnerability Existed: no No Security Vulnerability Detected - File: includes/Tickets/Filters/View/Description.php Explanation: This diff shows only line ending changes (CRLF to LF conversion) with no actual code modifications. The file content remains functionally identical between versions 3.3.4 and 3.3.5. While the underlying code does contain a potential SQL injection vulnerability (the `$value` parameter is directly concatenated into the query using `'%' . $value . '%'` without proper parameterization via the QueryBuilder), this vulnerability was NOT introduced or fixed in this update—it existed in both versions. The diff itself represents no security changes, only formatting normalization.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/View/Email.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/View/Email.php 2025-12-21 09:36:35.231291286 +0000@@ -1,37 +1,37 @@-<?php - -namespace WSDesk\Tickets\Filters\View; - -use WpFluent\QueryBuilder\QueryBuilderHandler; -use WSDesk\Tickets\TicketRepository; - -class Email { - /** Class used to configure email - * - * @var QueryBuilderHandler $query - */ - protected $query; - - /** - * Apply filter based on given condition - * - * @param string $condition Condition either CONTAINS or NONE - * @param string $value - * - * @return QueryBuilder - */ - public function __construct( $condition, $value ) { - - $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS ); - - $compare = 'none' === $condition ? 'not like' : 'like'; - - $this->query->where( 'ticket_email', $compare, '%' . $value . '%' ); - - return $this->query; - } - - public function __toString() { - return $this->query->select( 'ticket_id' )->getQuery()->getRawSql(); - } -} +<?php++namespace WSDesk\Tickets\Filters\View;++use WpFluent\QueryBuilder\QueryBuilderHandler;+use WSDesk\Tickets\TicketRepository;++class Email {+ /** Class used to configure email+ *+ * @var QueryBuilderHandler $query+ */+ protected $query;++ /**+ * Apply filter based on given condition+ *+ * @param string $condition Condition either CONTAINS or NONE+ * @param string $value+ *+ * @return QueryBuilder+ */+ public function __construct( $condition, $value ) {++ $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS );++ $compare = 'none' === $condition ? 'not like' : 'like';++ $this->query->where( 'ticket_email', $compare, '%' . $value . '%' );++ return $this->query;+ }++ public function __toString() {+ return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();+ }+}
Vulnerability Existed: no
No vulnerabilities identified - [File] includes/Tickets/Filters/View/Email.php [All lines]
Old Code:
```php
<?php
namespace WSDesk\Tickets\Filters\View;
use WpFluent\QueryBuilder\QueryBuilderHandler;
use WSDesk\Tickets\TicketRepository;
class Email {
/** Class used to configure email
*
* @var QueryBuilderHandler $query
*/
protected $query;
/**
* Apply filter based on given condition
*
* @param string $condition Condition either CONTAINS or NONE
* @param string $value
*
* @return QueryBuilder
*/
public function __construct( $condition, $value ) {
$this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS );
$compare = 'none' === $condition ? 'not like' : 'like';
$this->query->where( 'ticket_email', $compare, '%' . $value . '%' );
return $this->query;
}
public function __toString() {
return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();
}
}
```
Fixed Code:
```php
<?php
namespace WSDesk\Tickets\Filters\View;
use WpFluent\QueryBuilder\QueryBuilderHandler;
use WSDesk\Tickets\TicketRepository;
class Email {
/** Class used to configure email
*
* @var QueryBuilderHandler $query
*/
protected $query;
/**
* Apply filter based on given condition
*
* @param string $condition Condition either CONTAINS or NONE
* @param string $value
*
* @return QueryBuilder
*/
public function __construct( $condition, $value ) {
$this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS );
$compare = 'none' === $condition ? 'not like' : 'like';
$this->query->where( 'ticket_email', $compare, '%' . $value . '%' );
return $this->query;
}
public function __toString() {
return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();
}
}
```
Explanation:
The diff shows only whitespace/line-ending changes (converting line endings from Unix/DOS to Unix format). The actual code logic remains identical between versions 3.3.4 and 3.3.5. No security vulnerabilities are introduced or fixed in this change. The code uses parameterized queries via the WpFluent QueryBuilder, which properly handles SQL injection prevention through parameter binding.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/View/ForwardedEmail.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/View/ForwardedEmail.php 2025-12-21 09:36:35.231291286 +0000@@ -1,41 +1,41 @@-<?php - -namespace WSDesk\Tickets\Filters\View; - -use WpFluent\QueryBuilder\QueryBuilderHandler; -use WSDesk\Tickets\TicketRepository; - -class ForwardedEmail { - /** Used to send Forwarded Email - * - * @var QueryBuilderHandler $query - */ - protected $query; - - /** - * Apply filter based on given condition - * - * @param string $condition Condition either IN or NOT IN - * @param string - * - * @return QueryBuilder - */ - public function __construct( $condition, $value ) { - - $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ); - - $this->query->where( 'meta_key', 'ticket_forwarded' ); - - if ( 'in' === $condition ) { - $this->query->where( 'meta_value', '=', $value ); - } else { - $this->query->where( 'meta_value', '<>', $value ); - } - - return $this->query; - } - - public function __toString() { - return $this->query->select( 'ticket_id' )->getQuery()->getRawSql(); - } -} +<?php++namespace WSDesk\Tickets\Filters\View;++use WpFluent\QueryBuilder\QueryBuilderHandler;+use WSDesk\Tickets\TicketRepository;++class ForwardedEmail {+ /** Used to send Forwarded Email+ * + * @var QueryBuilderHandler $query+ */+ protected $query;++ /**+ * Apply filter based on given condition+ *+ * @param string $condition Condition either IN or NOT IN+ * @param string+ *+ * @return QueryBuilder+ */+ public function __construct( $condition, $value ) {++ $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META );++ $this->query->where( 'meta_key', 'ticket_forwarded' );++ if ( 'in' === $condition ) {+ $this->query->where( 'meta_value', '=', $value );+ } else {+ $this->query->where( 'meta_value', '<>', $value );+ }++ return $this->query;+ }++ public function __toString() {+ return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();+ }+}
Vulnerability Existed: no Explanation: This diff contains only a line-ending normalization change (converting from Unix LF to Windows CRLF line endings, or vice versa). The actual code content remains identical between versions 3.3.4 and 3.3.5. No security fixes were applied, and no vulnerabilities were introduced or resolved. The functional logic, including the query building, condition handling, and parameter passing, is unchanged.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/View/Label.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/View/Label.php 2025-12-21 09:36:35.231291286 +0000@@ -1,41 +1,41 @@-<?php - -namespace WSDesk\Tickets\Filters\View; - -use WpFluent\QueryBuilder\QueryBuilderHandler; -use WSDesk\Tickets\TicketRepository; - -class Label { - /** Class used to fetch ticket lebel and meta - * - * @var QueryBuilderHandler $query - */ - protected $query; - - /** - * Apply filter based on given condition - * - * @param string $condition Condition either IN or NOT IN - * @param string - * - * @return QueryBuilder - */ - public function __construct( $condition, $value ) { - - $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ); - - $this->query->where( 'meta_key', 'ticket_label' ); - - if ( 'in' === $condition ) { - $this->query->where( 'meta_value', '=', $value ); - } else { - $this->query->where( 'meta_value', '<>', $value ); - } - - return $this->query; - } - - public function __toString() { - return $this->query->select( 'ticket_id' )->getQuery()->getRawSql(); - } -} +<?php++namespace WSDesk\Tickets\Filters\View;++use WpFluent\QueryBuilder\QueryBuilderHandler;+use WSDesk\Tickets\TicketRepository;++class Label {+ /** Class used to fetch ticket lebel and meta+ * + * @var QueryBuilderHandler $query+ */+ protected $query;++ /**+ * Apply filter based on given condition+ *+ * @param string $condition Condition either IN or NOT IN+ * @param string+ *+ * @return QueryBuilder+ */+ public function __construct( $condition, $value ) {++ $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META );++ $this->query->where( 'meta_key', 'ticket_label' );++ if ( 'in' === $condition ) {+ $this->query->where( 'meta_value', '=', $value );+ } else {+ $this->query->where( 'meta_value', '<>', $value );+ }++ return $this->query;+ }++ public function __toString() {+ return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();+ }+}
Vulnerability Existed: no Explanation: This diff shows only whitespace changes (line ending normalization from CRLF to LF). The actual code content remains identical between versions 3.3.4 and 3.3.5. No security fixes or modifications have been made to the functional code. The code itself contains a potential SQL injection vulnerability (the `$value` parameter is passed directly to the query builder without validation), but this vulnerability exists in both versions equally and is not addressed by this diff. The changes are purely formatting-related with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/View/Source.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/View/Source.php 2025-12-21 09:36:35.231291286 +0000@@ -1,41 +1,41 @@-<?php - -namespace WSDesk\Tickets\Filters\View; - -use WpFluent\QueryBuilder\QueryBuilderHandler; -use WSDesk\Tickets\TicketRepository; - -class Source { - /** Class used to fetch data as per given condition - * - * @var QueryBuilderHandler $query - */ - protected $query; - - /** - * Apply filter based on given condition - * - * @param string $condition Condition either IN or NOT IN - * @param string - * - * @return QueryBuilder - */ - public function __construct( $condition, $value ) { - - $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ); - - $this->query->where( 'meta_key', 'ticket_source' ); - - if ( 'in' === $condition ) { - $this->query->where( 'meta_value', '=', $value ); - } else { - $this->query->where( 'meta_value', '<>', $value ); - } - - return $this->query; - } - - public function __toString() { - return $this->query->select( 'ticket_id' )->getQuery()->getRawSql(); - } -} +<?php++namespace WSDesk\Tickets\Filters\View;++use WpFluent\QueryBuilder\QueryBuilderHandler;+use WSDesk\Tickets\TicketRepository;++class Source {+ /** Class used to fetch data as per given condition+ * + * @var QueryBuilderHandler $query+ */+ protected $query;++ /**+ * Apply filter based on given condition+ *+ * @param string $condition Condition either IN or NOT IN+ * @param string+ *+ * @return QueryBuilder+ */+ public function __construct( $condition, $value ) {++ $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META );++ $this->query->where( 'meta_key', 'ticket_source' );++ if ( 'in' === $condition ) {+ $this->query->where( 'meta_value', '=', $value );+ } else {+ $this->query->where( 'meta_value', '<>', $value );+ }++ return $this->query;+ }++ public function __toString() {+ return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();+ }+}
Vulnerability Existed: no
No Security Vulnerability Detected - File: includes/Tickets/Filters/View/Source.php [Lines 1-41]
Old Code:
```php
<?php
namespace WSDesk\Tickets\Filters\View;
use WpFluent\QueryBuilder\QueryBuilderHandler;
use WSDesk\Tickets\TicketRepository;
class Source {
/** Class used to fetch data as per given condition
*
* @var QueryBuilderHandler $query
*/
protected $query;
/**
* Apply filter based on given condition
*
* @param string $condition Condition either IN or NOT IN
* @param string
*
* @return QueryBuilder
*/
public function __construct( $condition, $value ) {
$this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META );
$this->query->where( 'meta_key', 'ticket_source' );
if ( 'in' === $condition ) {
$this->query->where( 'meta_value', '=', $value );
} else {
$this->query->where( 'meta_value', '<>', $value );
}
return $this->query;
}
public function __toString() {
return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();
}
}
```
Fixed Code:
```php
<?php
namespace WSDesk\Tickets\Filters\View;
use WpFluent\QueryBuilder\QueryBuilderHandler;
use WSDesk\Tickets\TicketRepository;
class Source {
/** Class used to fetch data as per given condition
*
* @var QueryBuilderHandler $query
*/
protected $query;
/**
* Apply filter based on given condition
*
* @param string $condition Condition either IN or NOT IN
* @param string
*
* @return QueryBuilder
*/
public function __construct( $condition, $value ) {
$this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META );
$this->query->where( 'meta_key', 'ticket_source' );
if ( 'in' === $condition ) {
$this->query->where( 'meta_value', '=', $value );
} else {
$this->query->where( 'meta_value', '<>', $value );
}
return $this->query;
}
public function __toString() {
return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();
}
}
```
Explanation:
This diff contains only a line ending normalization change (from CRLF to LF line endings). The actual code logic remains identical with no modifications to security-sensitive operations. The code uses parameterized queries via the WpFluent query builder, which provides protection against SQL injection. No security vulnerabilities are present in either version, and no security fixes are being applied in this update.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/View/Subject.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/View/Subject.php 2025-12-21 09:36:35.231291286 +0000@@ -1,37 +1,37 @@-<?php - -namespace WSDesk\Tickets\Filters\View; - -use WpFluent\QueryBuilder\QueryBuilderHandler; -use WSDesk\Tickets\TicketRepository; - -class Subject { - /** Class used to fetch data as per given condition - * - * @var QueryBuilderHandler $query - */ - protected $query; - - /** - * Apply filter based on given condition - * - * @param string $condition Condition either CONTAINS or NONE - * @param string $value - * - * @return QueryBuilder - */ - public function __construct( $condition, $value ) { - - $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS ); - - $compare = 'none' === $condition ? 'not like' : 'like'; - - $this->query->where( 'ticket_title', $compare, '%' . $value . '%' ); - - return $this->query; - } - - public function __toString() { - return $this->query->select( 'ticket_id' )->getQuery()->getRawSql(); - } -} +<?php++namespace WSDesk\Tickets\Filters\View;++use WpFluent\QueryBuilder\QueryBuilderHandler;+use WSDesk\Tickets\TicketRepository;++class Subject {+ /** Class used to fetch data as per given condition+ * + * @var QueryBuilderHandler $query+ */+ protected $query;++ /**+ * Apply filter based on given condition+ *+ * @param string $condition Condition either CONTAINS or NONE+ * @param string $value+ *+ * @return QueryBuilder+ */+ public function __construct( $condition, $value ) {++ $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS );++ $compare = 'none' === $condition ? 'not like' : 'like';++ $this->query->where( 'ticket_title', $compare, '%' . $value . '%' );++ return $this->query;+ }++ public function __toString() {+ return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();+ }+}
Vulnerability Existed: no
No Vulnerabilities Detected - File: includes/Tickets/Filters/View/Subject.php
Explanation:
The diff shows only formatting changes (line ending normalization from CRLF to LF), with no actual code modifications. The underlying code structure remains identical:
1. **SQL Injection Risk (CWE-89)**: While the code uses string concatenation with user input (`'%' . $value . '%'`), the `wpFluent()` query builder's `where()` method with parameterized queries handles proper escaping and binding. This is a framework-level protection mechanism.
2. **Input Validation**: The code does accept a `$value` parameter without explicit validation, but:
- The query builder framework sanitizes input
- The comparison operators are controlled ('like' or 'not like')
- This is a filter operation within an admin/support ticket context with expected framework protections
3. **No Security Changes**: Since this is purely a line-ending normalization diff with zero functional code changes, there are no security fixes or regressions introduced in this update.
The code follows WordPress plugin conventions and relies on the WpFluent query builder's built-in protections against SQL injection.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/View/Tag.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/View/Tag.php 2025-12-21 09:36:35.231291286 +0000@@ -1,46 +1,46 @@-<?php - -namespace WSDesk\Tickets\Filters\View; - -use WpFluent\QueryBuilder\QueryBuilderHandler; -use WSDesk\Tickets\TicketRepository; - -class Tag { - /** Class used to fetch data as per given condition - * - * @var QueryBuilderHandler $query - */ - protected $query; - - /** - * Apply filter based on given condition - * - * @param string $condition Condition either ATLEAST or ALL or NONE - * @param array $value - * - * @return QueryBuilder - */ - public function __construct( $condition, $value ) { - - $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ); - - $this->query->where( 'meta_key', 'ticket_tags' ); - - $this->query->where( - function ( $query ) use ( $condition, $value ) { - foreach ( $value as $tag ) { - $func = 'atleast' === $condition ? 'orWhere' : 'where'; - $compare = 'none' === $condition ? 'not like' : 'like'; - - $query->{$func}( 'meta_value', $compare, '%"' . $tag . '"%' ); - } - } - ); - - return $this->query; - } - - public function __toString() { - return $this->query->select( 'ticket_id' )->getQuery()->getRawSql(); - } -} +<?php++namespace WSDesk\Tickets\Filters\View;++use WpFluent\QueryBuilder\QueryBuilderHandler;+use WSDesk\Tickets\TicketRepository;++class Tag {+ /** Class used to fetch data as per given condition+ * + * @var QueryBuilderHandler $query+ */+ protected $query;++ /**+ * Apply filter based on given condition+ *+ * @param string $condition Condition either ATLEAST or ALL or NONE+ * @param array $value+ *+ * @return QueryBuilder+ */+ public function __construct( $condition, $value ) {++ $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META );++ $this->query->where( 'meta_key', 'ticket_tags' );++ $this->query->where(+ function ( $query ) use ( $condition, $value ) {+ foreach ( $value as $tag ) {+ $func = 'atleast' === $condition ? 'orWhere' : 'where';+ $compare = 'none' === $condition ? 'not like' : 'like';++ $query->{$func}( 'meta_value', $compare, '%"' . $tag . '"%' );+ }+ }+ );++ return $this->query;+ }++ public function __toString() {+ return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();+ }+}
Vulnerability Existed: not sure
SQL Injection - CWE-89 - includes/Tickets/Filters/View/Tag.php Lines 35
Old Code:
```php
$query->{$func}( 'meta_value', $compare, '%"' . $tag . '"%' );
```
Fixed Code:
```php
$query->{$func}( 'meta_value', $compare, '%"' . $tag . '"%' );
```
Explanation:
The diff shows only whitespace/line ending changes (CRLF to LF conversion) with no functional code modifications. The underlying SQL injection vulnerability pattern remains unchanged. The code concatenates the `$tag` variable directly into a LIKE query string without proper parameterization or escaping. While WpFluent's QueryBuilder may provide some protection through prepared statements at the database layer, the concatenation of user-supplied input (`$tag`) into the query pattern string is a potential SQL injection vector if the QueryBuilder doesn't properly handle the pattern parameter. However, without visibility into how WpFluent implements parameter binding for LIKE clauses, it's uncertain whether this is actually vulnerable or if the framework provides adequate protection. The diff itself contains no security fixes—only formatting changes.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/View/WooProduct.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/View/WooProduct.php 2025-12-21 09:36:35.231291286 +0000@@ -1,42 +1,42 @@-<?php - -namespace WSDesk\Tickets\Filters\View; - -use WSDesk\Tickets\TicketRepository; - -class WooProduct { - - /** Class used to filter the data - * - * @var QueryBuilderHandler $query - */ - - protected $query; - - /** - * Apply filter based on given condition - * - * @param string $condition Condition either IN or NOT IN - * @param string - * - * @return QueryBuilder - */ - public function __construct( $condition, $value ) { - - $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ); - - $this->query->where( 'meta_key', 'woo_product' ); - - if ( 'in' === $condition ) { - $this->query->where( 'meta_value', '=', $value ); - } else { - $this->query->where( 'meta_value', '<>', $value ); - } - - return $this->query; - } - - public function __toString() { - return $this->query->select( 'ticket_id' )->getQuery()->getRawSql(); - } -} +<?php++namespace WSDesk\Tickets\Filters\View;++use WSDesk\Tickets\TicketRepository;++class WooProduct {++ /** Class used to filter the data+ * + * @var QueryBuilderHandler $query+ */++ protected $query;++ /**+ * Apply filter based on given condition+ *+ * @param string $condition Condition either IN or NOT IN+ * @param string+ *+ * @return QueryBuilder+ */+ public function __construct( $condition, $value ) {++ $this->query = wpFluent()->table( TicketRepository::TABLE_TICKETS_META );++ $this->query->where( 'meta_key', 'woo_product' );++ if ( 'in' === $condition ) {+ $this->query->where( 'meta_value', '=', $value );+ } else {+ $this->query->where( 'meta_value', '<>', $value );+ }++ return $this->query;+ }++ public function __toString() {+ return $this->query->select( 'ticket_id' )->getQuery()->getRawSql();+ }+}
Vulnerability Existed: no Explanation: This diff contains only whitespace changes (line ending conversions from CRLF to LF or similar normalization). The actual code logic remains identical between versions 3.3.4 and 3.3.5. There are no security fixes present in this diff. The code itself does not appear to contain security vulnerabilities that would require fixing: - The `$condition` parameter is validated with a strict equality check (`'in' ===`) - The database query uses parameterized WHERE clauses via the query builder (wpFluent), which provides SQL injection protection - No user input is directly concatenated into the query - The `getRawSql()` method in `__toString()` is used for display/logging purposes, not for query execution Since this is purely a formatting change with no code logic modifications, there are no security vulnerabilities to report.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Filters/ViewsFilter.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Filters/ViewsFilter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,281 +1,281 @@-<?php -namespace WSDesk\Tickets\Filters; - -use Illuminate\Support\Arr; -use WSDesk\Tickets\Filters\View\CustomField; -use Illuminate\Support\Str; -use WSDesk\Settings\SettingsItem; -use WSDesk\Tickets\Filters\View\ForwardedEmail; -use WSDesk\Tickets\Filters\View\Description; -use WSDesk\Tickets\Filters\View\Subject; -use WSDesk\Tickets\Filters\View\Email; -use WSDesk\Tickets\Filters\View\Tag; -use WSDesk\Tickets\Filters\View\Assignee; -use WSDesk\Tickets\Filters\View\Label; -use WSDesk\Settings\SettingsRepository; -use WSDesk\Tickets\Filters\View\Source; -use WSDesk\Tickets\Filters\View\WooProduct; -use WSDesk\Tickets\TicketRepository; - -class ViewsFilter implements FilterContract { - - public $view_filters = array( - 'ticket_label' => Label::class, - 'ticket_assignee' => Assignee::class, - 'ticket_tags' => Tag::class, - 'ticket_email' => Email::class, - 'request_email' => Email::class, - 'ticket_title' => Subject::class, - 'request_title' => Subject::class, - 'ticket_description' => Description::class, - 'request_description' => Description::class, - 'ticket_forwarded' => ForwardedEmail::class, - 'ticket_source' => Source::class, - 'woo_product' => WooProduct::class, - ); - - public function filter( $query, $filters ) { - if ( ! Arr::has( $filters, 'view.views' ) ) { - return $query; - } - - $slug = Arr::get( $filters, 'view.views' ); - - $slug = is_array( $slug ) ? $slug : [ $slug ]; - - if ( 0 === count( $slug ) ) { - return $query; - } - - $query->where( - function ( $query ) use ( $slug ) { - foreach ( $slug as $view_slug ) { - $query = $this->applyCustomViewFilter( $query, $view_slug ); - } - } - ); - - $this->apply_view_groups( $query, $filters ); - - return $query; - } - - /** - * Apply custom views filters from view slug - * - * @param QueryBuilderHandler $query - * @param string $view_slug - * - * @return QueryBuilderHandler - */ - public function applyCustomViewFilter( $query, $view_slug ) { - - $settings = new SettingsRepository(); - - $view = $settings->getView( $view_slug ); - - if ( null === $view ) { - return $query; - } - - $meta = eh_crm_get_settingsmeta( $view['settings_id'] ); - - $query->where( - function ( $query ) use ( $meta ) { - $globalFunc = ( 'and' === $meta['view_format'] ) ? 'where' : 'orWhere'; - - foreach ( $meta['view_conditions'] as $group => $filters ) { - $groupFunc = ( 'or' === $group ) ? 'orWhere' : 'where'; - - $query->{$globalFunc}( - function ( $query ) use ( $groupFunc, $filters ) { - $query = $this->applyGroupFilters( $query, $groupFunc, $filters ); - } - ); - } - } - ); - - return $query; - } - - public function applyGroupFilters( $query, $groupFunc, $filters ) { - foreach ( $filters as $filter ) { - $subQuery = $this->getSubQueryByType( $filter ); - - if ( $subQuery ) { - $query->{$groupFunc}( \wpFluent()->raw( 'ticket_id in (' . $subQuery->__toString() . ')' ) ); - } - } - - return $query; - - } - - public function getSubQueryByType( $filter ) { - $type = $filter['type']; - - if ( Arr::has( $this->view_filters, $type ) ) { - $class = Arr::get( $this->view_filters, $type ); - - return new $class( - $filter['operator'], - $filter['value'] - ); - } - - if ( Str::startsWith( $type, 'field_' ) ) { - return new CustomField( - $filter['type'], - $filter['operator'], - $filter['value'] - ); - } - - return false; - } - - public function apply_view_groups( $query, $filters ) { - - $view_slug = Arr::get( $filters, 'view.views.0' ); - - if ( trim( $view_slug ) === '' || ! $view_slug ) { - return $view_slug; - } - - $settings = new SettingsRepository(); - $view = $settings->getView( $view_slug ); - - if ( null === $view ) { - return $query; - } - - $view_meta = eh_crm_get_settingsmeta( $view['settings_id'] ); - - if ( 'ticket_assignee' === $view_meta['view_group'] ) { - $repo = new TicketRepository(); - $metaSubQuery = wpFluent()->table( $repo::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_assignee' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $whereSubQuery = $repo->getAdminUserQuery()->select( [ 'user_id' ] )->getQuery()->getRawSql(); - - $assignee_query = '(SELECT wp_agent_view_ticketsmeta.ticket_id as wp_agent_view_ticket_id, users.display_name as view_group_title '; - $assignee_query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users'; - $assignee_query .= ' left join (' . $metaSubQuery . ' ) as wp_agent_view_ticketsmeta on meta_value like concat(\'%"\',users.id,\'"%\')'; - $assignee_query .= ' where users.id in (' . $whereSubQuery . ')'; - $assignee_query .= ' UNION select ticket_meta.ticket_id as wp_agent_view_ticket_id, "Unassigned" as view_group_title from'; - $assignee_query .= ' ' . wpFluent()->addTablePrefix( 'wsdesk_ticketsmeta', false ) . ' as ticket_meta'; - $assignee_query .= ' where meta_key = "ticket_assignee" and meta_value = "' . serialize( [] ) . '"'; - $assignee_query .= ' ) as ' . wpFluent()->addTablePrefix( 'agent_view_group', false ); - - $query->LeftJoin( \wpFluent()->raw( $assignee_query ), 'agent_view_group.wp_agent_view_ticket_id', '=', $repo::TABLE_TICKETS . '.ticket_id' ); - $query->orderBy( \wpFluent()->raw( 'view_group_title, ticket_updated' ), 'desc' ); - - return $query; - } - - if ( 'ticket_label' === $view_meta['view_group'] ) { - $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_label' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $label_query = '(SELECT wp_wsdesk_ticketsmeta.ticket_id as view_group_ticket_id, wp_wsdesk_settings.title as view_group_title '; - $label_query .= ' FROM ' . wpFluent()->addTablePrefix( 'wsdesk_settings', false ) . ' as wp_wsdesk_settings'; - $label_query .= ' LEFT JOIN (' . $metaSubQuery . ' ) as wp_wsdesk_ticketsmeta on wp_wsdesk_ticketsmeta.meta_value = wp_wsdesk_settings.slug'; - $label_query .= ' where wp_wsdesk_settings.type = "label" '; - $label_query .= ' ) as ' . wpFluent()->addTablePrefix( 'view_group', false ); - - - $query->leftJoin( \wpFluent()->raw( $label_query ), 'view_group.view_group_ticket_id', '=', TicketRepository::TABLE_TICKETS . '.ticket_id' ); - $query->orderBy( \wpFluent()->raw( 'view_group_title, ticket_updated' ), 'desc' ); - - return $query; - } - - if ( 'ticket_tags' === $view_meta['view_group'] ) { - $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )->where( 'meta_key', 'ticket_tags' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery()->getRawSql(); - - $tags_query = '(SELECT wp_wsdesk_ticketsmeta.ticket_id as view_group_ticket_id, wp_wsdesk_settings.title as view_group_title '; - $tags_query .= ' FROM ' . wpFluent()->addTablePrefix( 'wsdesk_settings', false ) . ' as wp_wsdesk_settings'; - $tags_query .= ' left JOIN (' . $metaSubQuery . ') as wp_wsdesk_ticketsmeta'; - $tags_query .= ' on wp_wsdesk_ticketsmeta.meta_value like concat(\'%"\',wp_wsdesk_settings.slug, \'"%\')'; - $tags_query .= ' where wp_wsdesk_settings.type = "tag" '; - $tags_query .= ' ) as ' . wpFluent()->addTablePrefix( 'view_group', false ); - - $query->leftJoin( \wpFluent()->raw( $tags_query ), 'view_group.view_group_ticket_id', '=', TicketRepository::TABLE_TICKETS . '.ticket_id' ); - $query->orderBy( \wpFluent()->raw( 'view_group_title, ticket_updated' ), 'desc' ); - - return $query; - } - - if ( 'request_title' === $view_meta['view_group'] ) { - $query->select( '*', \wpFluent()->raw( 'ticket_title as view_group_title' ) ); - $query->orderBy( \wpFluent()->raw( 'view_group_title, ticket_updated' ), 'desc' ); - - return $query; - } - - if ( 'request_email' === $view_meta['view_group'] ) { - $query->select( '*', \wpFluent()->raw( 'ticket_email as view_group_title' ) ); - $query->orderBy( \wpFluent()->raw( 'view_group_title, ticket_updated' ), 'desc' ); - - return $query; - } - - $settings_item = SettingsItem::find_by_slug( $view_meta['view_group'] ); - - if ( $settings_item && 'field' === $settings_item->get( 'type' ) ) { - - if ( in_array( $settings_item->get_meta()->get( 'field_type' ), array( 'select', 'checkbox', 'radio' ) ) ) { - $tmp_table_name = 'wsdesk_tmp_' . $settings_item->get( 'slug' ); - - $sql = 'create temporary table if not exists ' . wpFluent()->addTablePrefix( $tmp_table_name, false ); - $sql .= ' ( - view_group_slug varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL , - view_group_title varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL - ) '; - $sql .= wpFluent()->db()->get_charset_collate(); - - wpFluent()->statement( $sql ); - - if ( wpFluent()->table( $tmp_table_name )->count() === 0 ) { - $values = []; - - foreach ( $settings_item->get_meta()->get( 'field_values' ) as $slug => $title ) { - $values[] = [ - 'view_group_slug' => $slug, - 'view_group_title' => $title, - ]; - } - - wpFluent()->table( $tmp_table_name )->insert( $values ); - } - - $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', $view_meta['view_group'] ) - ->select( \wpFluent()->raw( 'ticket_id as view_group_ticket_id' ), $tmp_table_name . '.view_group_title' ) - ->join( $tmp_table_name, TicketRepository::TABLE_TICKETS_META . '.meta_value', '=', $tmp_table_name . '.view_group_slug' ) - ->getQuery() - ->getRawSql(); - } else { - $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', $view_meta['view_group'] ) - ->select( \wpFluent()->raw( 'ticket_id as view_group_ticket_id, meta_value as view_group_title' ) ) - ->getQuery() - ->getRawSql(); - } - - $query->leftJoin( \wpFluent()->raw( '(' . $metaSubQuery . ') as ' . wpFluent()->addTablePrefix( 'view_group', false ) ), 'view_group.view_group_ticket_id', '=', TicketRepository::TABLE_TICKETS . '.ticket_id' ); - $query->orderBy( \wpFluent()->raw( 'view_group_title, ticket_updated' ), 'desc' ); - } - - return $query; - } -} +<?php+namespace WSDesk\Tickets\Filters;++use Illuminate\Support\Arr;+use WSDesk\Tickets\Filters\View\CustomField;+use Illuminate\Support\Str;+use WSDesk\Settings\SettingsItem;+use WSDesk\Tickets\Filters\View\ForwardedEmail;+use WSDesk\Tickets\Filters\View\Description;+use WSDesk\Tickets\Filters\View\Subject;+use WSDesk\Tickets\Filters\View\Email;+use WSDesk\Tickets\Filters\View\Tag;+use WSDesk\Tickets\Filters\View\Assignee;+use WSDesk\Tickets\Filters\View\Label;+use WSDesk\Settings\SettingsRepository;+use WSDesk\Tickets\Filters\View\Source;+use WSDesk\Tickets\Filters\View\WooProduct;+use WSDesk\Tickets\TicketRepository;++class ViewsFilter implements FilterContract {++ public $view_filters = array(+ 'ticket_label' => Label::class,+ 'ticket_assignee' => Assignee::class,+ 'ticket_tags' => Tag::class,+ 'ticket_email' => Email::class,+ 'request_email' => Email::class,+ 'ticket_title' => Subject::class,+ 'request_title' => Subject::class,+ 'ticket_description' => Description::class,+ 'request_description' => Description::class,+ 'ticket_forwarded' => ForwardedEmail::class,+ 'ticket_source' => Source::class,+ 'woo_product' => WooProduct::class,+ );++ public function filter( $query, $filters ) {+ if ( ! Arr::has( $filters, 'view.views' ) ) {+ return $query;+ }++ $slug = Arr::get( $filters, 'view.views' );++ $slug = is_array( $slug ) ? $slug : [ $slug ];++ if ( 0 === count( $slug ) ) {+ return $query;+ }++ $query->where(+ function ( $query ) use ( $slug ) {+ foreach ( $slug as $view_slug ) {+ $query = $this->applyCustomViewFilter( $query, $view_slug );+ }+ }+ );++ $this->apply_view_groups( $query, $filters );++ return $query;+ }++ /**+ * Apply custom views filters from view slug+ *+ * @param QueryBuilderHandler $query+ * @param string $view_slug+ *+ * @return QueryBuilderHandler+ */+ public function applyCustomViewFilter( $query, $view_slug ) {++ $settings = new SettingsRepository();++ $view = $settings->getView( $view_slug );++ if ( null === $view ) {+ return $query;+ }++ $meta = eh_crm_get_settingsmeta( $view['settings_id'] );++ $query->where(+ function ( $query ) use ( $meta ) {+ $globalFunc = ( 'and' === $meta['view_format'] ) ? 'where' : 'orWhere';++ foreach ( $meta['view_conditions'] as $group => $filters ) {+ $groupFunc = ( 'or' === $group ) ? 'orWhere' : 'where';++ $query->{$globalFunc}(+ function ( $query ) use ( $groupFunc, $filters ) {+ $query = $this->applyGroupFilters( $query, $groupFunc, $filters );+ }+ );+ }+ }+ );++ return $query;+ }++ public function applyGroupFilters( $query, $groupFunc, $filters ) {+ foreach ( $filters as $filter ) {+ $subQuery = $this->getSubQueryByType( $filter );++ if ( $subQuery ) {+ $query->{$groupFunc}( \wpFluent()->raw( 'ticket_id in (' . $subQuery->__toString() . ')' ) );+ }+ }++ return $query;++ }++ public function getSubQueryByType( $filter ) {+ $type = $filter['type'];++ if ( Arr::has( $this->view_filters, $type ) ) {+ $class = Arr::get( $this->view_filters, $type );++ return new $class(+ $filter['operator'],+ $filter['value']+ );+ }++ if ( Str::startsWith( $type, 'field_' ) ) {+ return new CustomField(+ $filter['type'],+ $filter['operator'],+ $filter['value']+ );+ }++ return false;+ }++ public function apply_view_groups( $query, $filters ) {++ $view_slug = Arr::get( $filters, 'view.views.0' );++ if ( trim( $view_slug ) === '' || ! $view_slug ) {+ return $view_slug;+ }++ $settings = new SettingsRepository();+ $view = $settings->getView( $view_slug );++ if ( null === $view ) {+ return $query;+ }++ $view_meta = eh_crm_get_settingsmeta( $view['settings_id'] );++ if ( 'ticket_assignee' === $view_meta['view_group'] ) {+ $repo = new TicketRepository();+ $metaSubQuery = wpFluent()->table( $repo::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_assignee' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $whereSubQuery = $repo->getAdminUserQuery()->select( [ 'user_id' ] )->getQuery()->getRawSql();++ $assignee_query = '(SELECT wp_agent_view_ticketsmeta.ticket_id as wp_agent_view_ticket_id, users.display_name as view_group_title ';+ $assignee_query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users';+ $assignee_query .= ' left join (' . $metaSubQuery . ' ) as wp_agent_view_ticketsmeta on meta_value like concat(\'%"\',users.id,\'"%\')';+ $assignee_query .= ' where users.id in (' . $whereSubQuery . ')';+ $assignee_query .= ' UNION select ticket_meta.ticket_id as wp_agent_view_ticket_id, "Unassigned" as view_group_title from';+ $assignee_query .= ' ' . wpFluent()->addTablePrefix( 'wsdesk_ticketsmeta', false ) . ' as ticket_meta';+ $assignee_query .= ' where meta_key = "ticket_assignee" and meta_value = "' . serialize( [] ) . '"';+ $assignee_query .= ' ) as ' . wpFluent()->addTablePrefix( 'agent_view_group', false );++ $query->LeftJoin( \wpFluent()->raw( $assignee_query ), 'agent_view_group.wp_agent_view_ticket_id', '=', $repo::TABLE_TICKETS . '.ticket_id' );+ $query->orderBy( \wpFluent()->raw( 'view_group_title, ticket_updated' ), 'desc' );++ return $query;+ }++ if ( 'ticket_label' === $view_meta['view_group'] ) {+ $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_label' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $label_query = '(SELECT wp_wsdesk_ticketsmeta.ticket_id as view_group_ticket_id, wp_wsdesk_settings.title as view_group_title ';+ $label_query .= ' FROM ' . wpFluent()->addTablePrefix( 'wsdesk_settings', false ) . ' as wp_wsdesk_settings';+ $label_query .= ' LEFT JOIN (' . $metaSubQuery . ' ) as wp_wsdesk_ticketsmeta on wp_wsdesk_ticketsmeta.meta_value = wp_wsdesk_settings.slug';+ $label_query .= ' where wp_wsdesk_settings.type = "label" ';+ $label_query .= ' ) as ' . wpFluent()->addTablePrefix( 'view_group', false );+++ $query->leftJoin( \wpFluent()->raw( $label_query ), 'view_group.view_group_ticket_id', '=', TicketRepository::TABLE_TICKETS . '.ticket_id' );+ $query->orderBy( \wpFluent()->raw( 'view_group_title, ticket_updated' ), 'desc' );++ return $query;+ }++ if ( 'ticket_tags' === $view_meta['view_group'] ) {+ $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )->where( 'meta_key', 'ticket_tags' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()->getRawSql();++ $tags_query = '(SELECT wp_wsdesk_ticketsmeta.ticket_id as view_group_ticket_id, wp_wsdesk_settings.title as view_group_title ';+ $tags_query .= ' FROM ' . wpFluent()->addTablePrefix( 'wsdesk_settings', false ) . ' as wp_wsdesk_settings';+ $tags_query .= ' left JOIN (' . $metaSubQuery . ') as wp_wsdesk_ticketsmeta';+ $tags_query .= ' on wp_wsdesk_ticketsmeta.meta_value like concat(\'%"\',wp_wsdesk_settings.slug, \'"%\')';+ $tags_query .= ' where wp_wsdesk_settings.type = "tag" ';+ $tags_query .= ' ) as ' . wpFluent()->addTablePrefix( 'view_group', false );++ $query->leftJoin( \wpFluent()->raw( $tags_query ), 'view_group.view_group_ticket_id', '=', TicketRepository::TABLE_TICKETS . '.ticket_id' );+ $query->orderBy( \wpFluent()->raw( 'view_group_title, ticket_updated' ), 'desc' );++ return $query;+ }++ if ( 'request_title' === $view_meta['view_group'] ) {+ $query->select( '*', \wpFluent()->raw( 'ticket_title as view_group_title' ) );+ $query->orderBy( \wpFluent()->raw( 'view_group_title, ticket_updated' ), 'desc' );++ return $query;+ }++ if ( 'request_email' === $view_meta['view_group'] ) {+ $query->select( '*', \wpFluent()->raw( 'ticket_email as view_group_title' ) );+ $query->orderBy( \wpFluent()->raw( 'view_group_title, ticket_updated' ), 'desc' );++ return $query;+ }++ $settings_item = SettingsItem::find_by_slug( $view_meta['view_group'] );++ if ( $settings_item && 'field' === $settings_item->get( 'type' ) ) {++ if ( in_array( $settings_item->get_meta()->get( 'field_type' ), array( 'select', 'checkbox', 'radio' ) ) ) {+ $tmp_table_name = 'wsdesk_tmp_' . $settings_item->get( 'slug' );++ $sql = 'create temporary table if not exists ' . wpFluent()->addTablePrefix( $tmp_table_name, false );+ $sql .= ' (+ view_group_slug varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL ,+ view_group_title varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL+ ) ';+ $sql .= wpFluent()->db()->get_charset_collate();++ wpFluent()->statement( $sql );++ if ( wpFluent()->table( $tmp_table_name )->count() === 0 ) {+ $values = [];++ foreach ( $settings_item->get_meta()->get( 'field_values' ) as $slug => $title ) {+ $values[] = [+ 'view_group_slug' => $slug,+ 'view_group_title' => $title,+ ];+ }++ wpFluent()->table( $tmp_table_name )->insert( $values );+ }++ $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', $view_meta['view_group'] )+ ->select( \wpFluent()->raw( 'ticket_id as view_group_ticket_id' ), $tmp_table_name . '.view_group_title' )+ ->join( $tmp_table_name, TicketRepository::TABLE_TICKETS_META . '.meta_value', '=', $tmp_table_name . '.view_group_slug' )+ ->getQuery()+ ->getRawSql();+ } else {+ $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', $view_meta['view_group'] )+ ->select( \wpFluent()->raw( 'ticket_id as view_group_ticket_id, meta_value as view_group_title' ) )+ ->getQuery()+ ->getRawSql();+ }++ $query->leftJoin( \wpFluent()->raw( '(' . $metaSubQuery . ') as ' . wpFluent()->addTablePrefix( 'view_group', false ) ), 'view_group.view_group_ticket_id', '=', TicketRepository::TABLE_TICKETS . '.ticket_id' );+ $query->orderBy( \wpFluent()->raw( 'view_group_title, ticket_updated' ), 'desc' );+ }++ return $query;+ }+}
## Security Analysis Results **Vulnerability Existed:** no **Analysis Summary:** The diff provided shows only formatting/whitespace changes (line ending conversions from Unix LF to the same format). The actual code logic remains completely identical between versions 3.3.4 and 3.3.5 - no functional code modifications are present. **Vulnerabilities Present:** None identified The code maintains the same security characteristics as the original: - Uses parameterized query building through wpFluent ORM (protects against SQL injection) - Relies on the underlying framework's `raw()` method which assumes SQL construction safety - No new or removed validation logic - No changes to input handling or sanitization Since there are no functional code changes, there are no new security fixes or vulnerabilities introduced in this version update.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Formatter/TicketFormatter.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Formatter/TicketFormatter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,13 +1,13 @@-<?php - -namespace WSDesk\Tickets\Formatter; - -use WSDesk\Formatter\Formatter; - -class TicketFormatter extends Formatter { - - protected $casts = [ - 'ticket_updated' => 'timestamp', - 'ticket_date' => 'timestamp', - ]; -} +<?php++namespace WSDesk\Tickets\Formatter;++use WSDesk\Formatter\Formatter;++class TicketFormatter extends Formatter {++ protected $casts = [+ 'ticket_updated' => 'timestamp',+ 'ticket_date' => 'timestamp',+ ];+}
Vulnerability Existed: no Explanation: This diff contains only whitespace changes (line ending normalization from CRLF to LF or similar line ending standardization). The actual code structure, logic, and functionality remain completely unchanged. No security fixes are present in this diff, and no vulnerabilities are being addressed. The file is a simple PHP class definition for `TicketFormatter` that extends `Formatter` and defines timestamp casts for two properties. This is a low-risk utility class with no security-sensitive operations. The whitespace normalization does not introduce, fix, or modify any security-related code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Formatter/TicketMetaFormatter.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Formatter/TicketMetaFormatter.php 2025-12-21 09:36:35.231291286 +0000@@ -1,33 +1,33 @@-<?php - -namespace WSDesk\Tickets\Formatter; - -use WSDesk\Formatter\Formatter; -use WSDesk\Settings\SettingsRepository; - -class TicketMetaFormatter extends Formatter { - - protected $casts = [ - 'ticket_assignee' => 'object', - 'ticket_bcc' => 'object', - 'ticket_cc' => 'object', - 'ticket_tags' => 'object', - 'ticket_attachment' => 'object', - ]; - - public function toArray() { - $this->fieldCasts(); - - return parent::toArray(); - } - - public function fieldCasts() { - $settings = new SettingsRepository(); - - $fields = $settings->getFields(); - - foreach ( $fields as $field ) { - $this->casts[ $field['slug'] ] = 'field'; - } - } -} +<?php++namespace WSDesk\Tickets\Formatter;++use WSDesk\Formatter\Formatter;+use WSDesk\Settings\SettingsRepository;++class TicketMetaFormatter extends Formatter {++ protected $casts = [+ 'ticket_assignee' => 'object',+ 'ticket_bcc' => 'object',+ 'ticket_cc' => 'object',+ 'ticket_tags' => 'object',+ 'ticket_attachment' => 'object',+ ];++ public function toArray() {+ $this->fieldCasts();++ return parent::toArray();+ }++ public function fieldCasts() {+ $settings = new SettingsRepository();++ $fields = $settings->getFields();++ foreach ( $fields as $field ) {+ $this->casts[ $field['slug'] ] = 'field';+ }+ }+}
Vulnerability Existed: no Explanation: This diff shows only a line-ending change (CRLF to LF conversion) with no actual code modifications. The file content remains functionally identical across all 33 lines. There are no security fixes, no new security vulnerabilities introduced, and no changes to the logic, variable handling, or data processing that would constitute a security issue. The diff represents a code formatting/standardization change only (converting Windows-style line endings to Unix-style line endings), which has no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/Reports.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/Reports.php 2025-12-21 09:36:35.231291286 +0000@@ -1,83 +1,83 @@-<?php - -namespace WSDesk\Tickets; - -use WSDesk\Tickets\TicketReportRepository; -use Illuminate\Support\Arr; -use WSDesk\Response; - -class Reports { - protected $repo; - - public function __construct() { - $this->repo = new TicketReportRepository(); - } - - public static function init() { - $self = new self(); - add_action( 'wp_ajax_wsdesk_avg_time_taken_to_resolve', array( $self, 'avg_time_taken_to_resolve' ) ); - add_action( 'wp_ajax_wsdesk_no_of_tickets_per_agent_per_day', array( $self, 'wsdesk_no_of_tickets_per_agent_per_day' ) ); - add_action( 'wp_ajax_wsdesk_no_of_replies_by_agent_per_day', array( $self, 'wsdesk_no_of_replies_by_agent_per_day' ) ); - add_action( 'wp_ajax_wsdesk_no_of_tickets_per_status', array( $self, 'no_of_tickets_per_status' ) ); - add_action( 'wp_ajax_wsdesk_no_of_tickets_per_tag', array( $self, 'no_of_tickets_per_tag' ) ); - add_action( 'wp_ajax_wsdesk_agent_satisfication_score', array( $self, 'statisfication_score' ) ); - add_action( 'wp_ajax_wsdesk_agent_avg_reply_time', array( $self, 'avg_reply_time' ) ); - - // Listener for resolve status - add_action( 'wsdesk_on_add_update_ticket_meta', array( $self, 'add_ticket_resolve_time_meta' ) ); - } - - public function avg_time_taken_to_resolve() { - $data = $this->repo->getAvgResolveTime( $_REQUEST ); - - Response::json( $data ); - } - - public function wsdesk_no_of_tickets_per_agent_per_day() { - $data = $this->repo->getCountByAgentsPerDay( $_REQUEST ); - - Response::json( $data ); - } - - public function wsdesk_no_of_replies_by_agent_per_day() { - $data = $this->repo->getReplyCountByAgentsPerDay( $_REQUEST ); - - Response::json( $data ); - } - - public function no_of_tickets_per_status() { - $data = $this->repo->getCountByStatus( $_REQUEST ); - - Response::json( $data ); - } - - public function no_of_tickets_per_tag() { - $data = $this->repo->getCountByTag( $_REQUEST ); - - Response::json( $data ); - } - - public function statisfication_score() { - $data = $this->repo->satisficationScore( $_REQUEST ); - - Response::json( $data ); - } - - public function avg_reply_time() { - $data = $this->repo->getAvgReplyTimeByAgents( $_REQUEST ); - - Response::json( $data ); - } - - public function add_ticket_resolve_time_meta( $payload ) { - $status_slug = 'label_LL02'; - - if ( Arr::get( $payload, 'meta_key' ) !== 'ticket_label' ) { - return; - } - - if ( Arr::get( $payload, 'meta_value' ) === $status_slug ) { - eh_crm_update_ticketmeta( $payload['ticket_id'], 'resolved_at', gmdate( 'Y-m-d H:i:s' ), false ); - } - } -} +<?php++namespace WSDesk\Tickets;++use WSDesk\Tickets\TicketReportRepository;+use Illuminate\Support\Arr;+use WSDesk\Response;++class Reports {+ protected $repo;++ public function __construct() {+ $this->repo = new TicketReportRepository();+ }++ public static function init() {+ $self = new self();+ add_action( 'wp_ajax_wsdesk_avg_time_taken_to_resolve', array( $self, 'avg_time_taken_to_resolve' ) );+ add_action( 'wp_ajax_wsdesk_no_of_tickets_per_agent_per_day', array( $self, 'wsdesk_no_of_tickets_per_agent_per_day' ) );+ add_action( 'wp_ajax_wsdesk_no_of_replies_by_agent_per_day', array( $self, 'wsdesk_no_of_replies_by_agent_per_day' ) );+ add_action( 'wp_ajax_wsdesk_no_of_tickets_per_status', array( $self, 'no_of_tickets_per_status' ) );+ add_action( 'wp_ajax_wsdesk_no_of_tickets_per_tag', array( $self, 'no_of_tickets_per_tag' ) );+ add_action( 'wp_ajax_wsdesk_agent_satisfication_score', array( $self, 'statisfication_score' ) );+ add_action( 'wp_ajax_wsdesk_agent_avg_reply_time', array( $self, 'avg_reply_time' ) );++ // Listener for resolve status+ add_action( 'wsdesk_on_add_update_ticket_meta', array( $self, 'add_ticket_resolve_time_meta' ) );+ }++ public function avg_time_taken_to_resolve() {+ $data = $this->repo->getAvgResolveTime( $_REQUEST );++ Response::json( $data );+ }++ public function wsdesk_no_of_tickets_per_agent_per_day() {+ $data = $this->repo->getCountByAgentsPerDay( $_REQUEST );++ Response::json( $data );+ }++ public function wsdesk_no_of_replies_by_agent_per_day() {+ $data = $this->repo->getReplyCountByAgentsPerDay( $_REQUEST );++ Response::json( $data );+ }++ public function no_of_tickets_per_status() {+ $data = $this->repo->getCountByStatus( $_REQUEST );++ Response::json( $data );+ }++ public function no_of_tickets_per_tag() {+ $data = $this->repo->getCountByTag( $_REQUEST );++ Response::json( $data );+ }++ public function statisfication_score() {+ $data = $this->repo->satisficationScore( $_REQUEST );++ Response::json( $data );+ }++ public function avg_reply_time() {+ $data = $this->repo->getAvgReplyTimeByAgents( $_REQUEST );++ Response::json( $data );+ }++ public function add_ticket_resolve_time_meta( $payload ) {+ $status_slug = 'label_LL02';++ if ( Arr::get( $payload, 'meta_key' ) !== 'ticket_label' ) {+ return;+ }++ if ( Arr::get( $payload, 'meta_value' ) === $status_slug ) {+ eh_crm_update_ticketmeta( $payload['ticket_id'], 'resolved_at', gmdate( 'Y-m-d H:i:s' ), false );+ }+ }+}
# Security Analysis Report ## Summary No security vulnerabilities were introduced or fixed in this diff. ## Detailed Analysis **Vulnerability Existed:** no **Assessment:** This diff contains only whitespace/line-ending changes (converting line endings from LF to CRLF or similar formatting normalization). The actual code content remains identical between versions 3.3.4 and 3.3.5. While the code itself contains potential security concerns (direct use of `$_REQUEST` without sanitization in AJAX handlers), these issues existed in both versions and are not addressed by this diff. This diff does not introduce or fix any vulnerabilities. **Note on Pre-existing Issues:** The following security concerns exist in both versions but are outside the scope of this diff analysis: - Direct access to `$_REQUEST` without proper sanitization (lines 31, 36, 41, 46, 51, 56, 61) - Missing nonce verification for AJAX endpoints - Potential CSRF vulnerability in AJAX handlers However, these are pre-existing issues not modified by this patch.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/TicketArchiveRepository.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/TicketArchiveRepository.php 2025-12-21 09:36:35.231291286 +0000@@ -1,600 +1,600 @@-<?php -namespace WSDesk\Tickets; - -use Illuminate\Support\Arr; -use Illuminate\Support\Collection; -use Illuminate\Support\Str; -use WSDesk\Tickets\Filters\RequestorFilter; -use WSDesk\Tickets\Filters\Sorter; -use WSDesk\Tickets\Filters\SubjectFilter; -use WSDesk\Tickets\Filters\TicketIdFilter; -use WSDesk\Tickets\Filters\TicketCreatedFilter; -use WSDesk\Tickets\Filters\TicketUpdatedFilter; -use WSDesk\Tickets\Formatter\TicketFormatter; -use WpFluent\QueryBuilder\QueryBuilderHandler; -use WSDesk\Settings\SettingsRepository; -use WSDesk\Tickets\Filters\AgentFilter; -use WSDesk\Tickets\Filters\BlockFilter; -use WSDesk\Tickets\Filters\GlobalSearchFilter; -use WSDesk\Tickets\Filters\LabelFilter; -use WSDesk\Tickets\Filters\TagFilter; -use WSDesk\Tickets\Filters\UserFilter; -use WSDesk\Tickets\Filters\ViewsFilter; -use WSDesk\Tickets\Formatter\TicketMetaFormatter; - -class TicketArchiveRepository extends TicketRepository { - - const TABLE_TICKETS = 'wsdesk_archived_tickets'; - const TABLE_TICKETS_META = 'wsdesk_archived_ticketsmeta'; - - /** - * Get query builder - * - * @return QueryBuilderHandler - */ - public function query() { - return wpFluent()->table( self::TABLE_TICKETS )->where( 'ticket_parent', 0 ); - } - - public function get( array $filters ) { - $query = $this->applyFilter( $filters ); - - $query = $query->limit( Arr::get( $filters, 'length', $this->limit ) ) - ->offset( Arr::get( $filters, 'start', 0 ) ); - - $tickets = $query->get(); - - $meta = $this->getTicketsMeta( $tickets ); - - $assignees = $this->getAssigneesFromMeta( $meta ); - - $messages = $this->getLatestMessage( $tickets ); - - $replyCount = $this->getReplyCount( $tickets ); - - $labelsCount = $this->getCountByLabels( 'select 1' , false, false ); - - $viewGroups = $this->getViewGroupColums( $filters ); - - $tickets = array_map( - function ( $ticket ) use ( $meta, $assignees, $messages, $replyCount, $labelsCount, $viewGroups ) { - $ticket = new TicketFormatter( $ticket ); - $ticketMeta = $meta->get( $ticket->ticket_id, new Collection() ); - - $ticket->reply_count = Arr::pluck( - Arr::where( - $replyCount, - function ( $count ) use ( $ticket ) { - return (int) $ticket->ticket_id === (int) $count->ticket_parent; - } - ), - 'count', - 'ticket_category' - ); - - $ticket->assignees = Arr::pluck( - Arr::where( - $assignees, - function ( $assignee ) use ( $ticketMeta ) { - return $ticketMeta->has( 'ticket_assignee' ) && in_array( (int) $assignee->id, $ticketMeta->ticket_assignee ); - } - ), - 'display_name' - ); - - $ticket->last_message = Arr::first( - $messages, - function ( $message ) use ( $ticket ) { - return (int) $message->ticket_parent === (int) $ticket->ticket_id; - } - ); - - if ( $ticket->last_message ) { - $ticket->last_message = new TicketFormatter( $ticket->last_message ); - } - - $ticket->badge_color = Arr::first( - $labelsCount, - function ( $label ) use ( $ticketMeta ) { - return $ticketMeta->has( 'ticket_label' ) && $label->slug === $ticketMeta->ticket_label; - } - ); - - $ticket->view_groups = $viewGroups; - - return array_merge( $ticketMeta->toArray(), $ticket->toArray() ); - }, - $tickets - ); - - return $tickets; - } - - /** - * Apply given filters to the query and return - * - * @param array $filters optional - * @param QueryBuilderHandler $query optional - * @return QueryBuilderHandler - */ - public function applyFilter( array $filters = [], QueryBuilderHandler $query = null ) { - $query = $query ? $query : $this->query(); - - $filterClasses = [ - new GlobalSearchFilter(), - new TicketIdFilter(), - new TicketCreatedFilter(), - new LabelFilter(), - new Sorter(), - ]; - - foreach ( $filterClasses as $filter ) { - $query = $filter->filter( $query, $filters, $this ); - } - - return $query; - } - - - /** - * Get Assignee login name from meta data - * - * @var Collection $meta - * @return array Array of assinees - */ - public function getAssigneesFromMeta( Collection $meta ) { - $ticketAssinees = $meta->flatten()->pluck( 'ticket_assignee' )->flatten()->unique()->filter()->toArray(); - - $assignees = []; - if ( count( $ticketAssinees ) ) { - $assignees = wpFluent()->table( 'users' )->whereIn( 'id', $ticketAssinees )->select( [ 'id', 'display_name' ] )->get(); - } - - return $assignees; - } - - public function getLatestMessage( $tickets ) { - if ( count( $tickets ) === 0 ) { - return []; - } - $ticket_ids = implode( ',', Arr::pluck( $tickets, 'ticket_id' ) ); - - $table = wpFluent()->addTablePrefix( self::TABLE_TICKETS, false ); - - $query = 'select m.* from ' . $table . ' as m join '; - $query .= '( SELECT max(t1.ticket_id) as ticket_id from ' . $table . ' as t1'; - $query .= ' where t1.ticket_parent in ( ' . $ticket_ids . ' ) group by t1.ticket_parent order by t1.ticket_id desc '; - $query .= ' ) as c on c.ticket_id = m.ticket_id'; - - $latest_tickets = wpFluent()->query( $query )->get(); - - if ( count( $latest_tickets ) ) { - $users = wpFluent()->table( 'users' )->select( 'user_email', 'display_name' )->whereIn( 'user_email', Arr::pluck( $latest_tickets, 'ticket_email' ) )->get(); - $users = Arr::pluck( 'display_name', 'user_email' ); - - $latest_tickets = array_map( - function ( $ticket ) use ( $users ) { - $ticket->display_name = Arr::get( $users, $ticket->ticket_email, __( 'Guest', 'wsdesk' ) ); - - return $ticket; - }, - $latest_tickets - ); - } - - return $latest_tickets; - } - - public function getReplyCount( $tickets ) { - if ( count( $tickets ) === 0 ) { - return []; - } - $ticket_ids = Arr::pluck( $tickets, 'ticket_id' ); - - $query = wpFluent()->table( self::TABLE_TICKETS )->select( \wpFluent()->raw( 'count(ticket_parent) as count, ticket_parent, ticket_category' ) ) - ->whereIn( 'ticket_parent', $ticket_ids ) - ->groupBy( [ 'ticket_category', 'ticket_parent' ] ); - - return $query->get(); - } - - public function getViewGroupColums( $filters ) { - $view_slugs = Arr::get( $filters, 'view.views', array() ); - - if ( 0 === count( $view_slugs ) ) { - return array(); - } - - $subQuery = wpFluent()->table( SettingsRepository::TABLE_NAME ); - $subQuery->whereIn( 'slug', $view_slugs ); - $subQuery->select( 'settings_id' ); - - $query = wpFluent()->table( SettingsRepository::TABLE_META_NAME ); - $query->where( 'meta_key', 'view_group' ); - $query->where( \wpFluent()->raw( 'settings_id in (' . $subQuery->getQuery()->getRawSql() . ')' ) ); - $query->select( 'meta_value' ); - - $groups = $query->get(); - - return Arr::pluck( $groups, 'meta_value' ); - } - - /** - * Get tickets count with filters applied - * - * @param array $filters - * @return int - */ - public function count( array $filters = [] ) { - $query = $this->applyFilter( $filters ); - - return $query->select( 'id' )->count(); - } - - /** - * Get tickets meta as a Formatter - * - * @param array $tickets - * @return Collection collection of Fromatter group by ticket_id - */ - public function getTicketsMeta( array $tickets ) { - if ( count( $tickets ) === 0 ) { - return new Collection(); - } - - $tickets = (array) $tickets; - - $query = wpFluent()->table( self::TABLE_TICKETS_META )->whereIn( 'ticket_id', Arr::pluck( $tickets, 'ticket_id' ) ); - - return ( new Collection( (array) $query->get() ) )->groupBy( 'ticket_id' ) - ->map( - function ( Collection $ticketsMeta ) { - return new TicketMetaFormatter( $ticketsMeta->pluck( 'meta_value', 'meta_key' ) ); - } - ); - } - - /** - * Apply custom views filters from view slug - * - * @param QueryBuilderHandler $query - * @param string $view_slug - * - * @return QueryBuilderHandler - */ - public function getCountByViews( $query, $views, $filters ) { - - $filter = new ViewsFilter(); - $data = array(); - $settings = new SettingsRepository(); - - foreach ( $views as $view_slug ) { - $view_settings = Arr::first( - $settings->filter( - array( - 'type' => 'view', - 'slug' => $view_slug, - ) - ) - ); - - if ( null === $view_settings ) { - continue; - } - - $query = $this->applyFilter( $filters ); - - $vquery = $filter->applyCustomViewFilter( $query, $view_slug ); - - $data[] = array( - 'slug' => $view_slug, - 'count' => $vquery->count(), - 'title' => $view_settings['title'], - ); - } - - return $data; - } - - /** - * Get ticket count by status - * - * @return array - */ - public function getCountByLabels( $subQuery, $info = [], $filtered = true ) { - $metaSubQuery = wpFluent()->table( self::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_label' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $query = 'SELECT slug, COUNT(wp_wsdesk_ticketsmeta.ticket_id) as count,title, settings_meta.meta_value as badge_color'; - $query .= ' FROM ' . wpFluent()->addTablePrefix( 'wsdesk_settings', false ) . ' as wp_wsdesk_settings'; - $query .= ' LEFT JOIN (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta on wp_wsdesk_ticketsmeta.meta_value = wp_wsdesk_settings.slug'; - $query .= ' left join ' . wpFluent()->addTablePrefix( 'wsdesk_settingsmeta', false ) . ' as settings_meta on settings_meta.settings_id = wp_wsdesk_settings.settings_id'; - $query .= ' where wp_wsdesk_settings.type = "label" '; - if ( true === $filtered ) { - $query .= ' and wp_wsdesk_settings.filter = "yes"'; - } - $query .= ' and settings_meta.meta_key ="label_color"'; - $query .= ' GROUP by wp_wsdesk_settings.settings_id'; - - $statuses = wpFluent()->query( $query )->get(); - - return $statuses; - } - - /** - * Get ticket count by status - * - * @param string $subQuery - * @return array - */ - public function getCountByAgents( $subQuery ) { - $metaSubQuery = wpFluent()->table( self::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_assignee' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $whereSubQuery = $this->getAdminUserQuery()->select( [ 'user_id' ] )->getQuery()->getRawSql(); - - $query = 'SELECT count(wp_wsdesk_ticketsmeta.ticket_id) as count, users.id as slug, users.display_name as title '; - $query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users'; - $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta on meta_value like concat(\'%"\',users.id,\'"%\')'; - $query .= ' where users.id in (' . $whereSubQuery . ')'; - $query .= ' GROUP by users.id'; - $query .= ' UNION select count(ticket_meta.ticket_id) as count, "null" as slug, "Unassigned" as title from'; - $query .= ' ' . wpFluent()->addTablePrefix( 'wsdesk_ticketsmeta', false ) . ' as ticket_meta'; - $query .= ' where meta_key = "ticket_assignee" and meta_value = "' . serialize( [] ) . '"'; - $query .= ' and ticket_id in (' . $subQuery . ')'; - - $statuses = wpFluent()->query( $query )->get(); - - return $statuses; - } - - /** - * Get admin users query - * - * @return QueryBuilderHandler - */ - public function getAdminUserQuery( array $filter = [] ) { - $query = wpFluent()->table( 'usermeta' )->where( 'meta_key', wpFluent()->addTablePrefix( 'capabilities', false ) )->where( - function ( $query ) { - foreach ( $this->getRoles() as $role ) { - $query->orWhere( 'meta_value', 'like', '%"' . $role . '"%' ); - } - } - ); - - if ( Arr::has( $filter, 'agent_id' ) ) { - $query->whereIn( 'user_id', Arr::get( $filter, 'agent_id' ) ); - } - - return $query; - } - - public function getAgents( $filter = array() ) { - $users = $this->getAdminUserQuery()->get(); - - return array_map( - function ( $user ) { - $user = new \WP_User( $user->user_id ); - return [ - 'id' => $user->ID, - 'name' => $user->display_name, - 'caps' => $user->caps, - 'email' => $user->email, - ]; - }, - $users - ); - } - - /** - * Get ticket count by status - * - * @return array - */ - public function getCountByTags( $subQuery ) { - $metaSubQuery = wpFluent()->table( self::TABLE_TICKETS_META )->where( 'meta_key', 'ticket_tags' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery()->getRawSql(); - - $query = 'SELECT slug, COUNT(wp_wsdesk_ticketsmeta.ticket_id) as count,title FROM'; - $query .= ' ' . wpFluent()->addTablePrefix( 'wsdesk_settings', false ) . ' as wp_wsdesk_settings'; - $query .= ' left JOIN (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta'; - $query .= ' on wp_wsdesk_ticketsmeta.meta_value like concat(\'%"\',wp_wsdesk_settings.slug, \'"%\')'; - $query .= ' where wp_wsdesk_settings.type = "tag" and wp_wsdesk_settings.filter = "yes"'; - $query .= ' GROUP by settings_id'; - - $statuses = wpFluent()->query( $query )->get(); - - return $statuses; - } - - /** - * Get ticket count by user reg status - * - * @return array - */ - public function getCountByUsers( $subQuery ) { - // ALTER TABLE wp_wsdesk_tickets CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci - $query = 'SELECT COUNT(wp_wsdesk_tickets.ticket_id) as count, "Registered Users" as title, "registered" as slug'; - /* $query .= ' FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as wp_users'; - $query .= ' LEFT JOIN ' . wpFluent()->addTablePrefix( 'wsdesk_tickets', false ) . ' as wp_wsdesk_tickets on wp_wsdesk_tickets.ticket_email = wp_users.user_email'; */ - $query .= ' FROM ' . wpFluent()->addTablePrefix( 'wsdesk_tickets', false ) . ' as wp_wsdesk_tickets '; - $query .= ' JOIN (' . $subQuery . ') as wp_wsdesk_filtered_tickets on wp_wsdesk_filtered_tickets.ticket_id = wp_wsdesk_tickets.ticket_id'; - $query .= ' WHERE wp_wsdesk_tickets.ticket_parent = 0 and wp_wsdesk_tickets.ticket_email in (select user_email from ' . wpFluent()->addTablePrefix( 'users', false ) . ')'; - $query .= ' UNION'; - $query .= ' SELECT COUNT(wp_wsdesk_tickets.ticket_id) as count, "Guest Users" as title, "guest" as slug'; - $query .= ' FROM ' . wpFluent()->addTablePrefix( 'wsdesk_tickets', false ) . ' as wp_wsdesk_tickets'; - $query .= ' JOIN (' . $subQuery . ') as wp_wsdesk_filtered_tickets on wp_wsdesk_filtered_tickets.ticket_id = wp_wsdesk_tickets.ticket_id'; - $query .= ' WHERE wp_wsdesk_tickets.ticket_parent = 0'; - $query .= ' and wp_wsdesk_tickets.ticket_email not in (select user_email from ' . wpFluent()->addTablePrefix( 'users', false ) . ')'; - - return wpFluent()->query( $query )->get(); - } - - public function get_ticket_counts_by_active_views( array $filters = [] ) { - $views = $this->get_available_views( $filters ); - $query = $this->applyFilter()->select( 'ticket_id' ); - - $views = array_map( - function ( $view ) use ( $filters, $query ) { - $method = 'getCountBy' . $view['title']; - - if ( method_exists( $this, $method ) === false ) { - return; - } - - $time = microtime( true ); - - if ( 'Views' !== $view['title'] ) { - $query = $query->getQuery()->getRawSql(); - } - - return [ - 'title' => $view['title'], - 'data' => $this->{$method}( $query, $view['data'], $filters ), - 'time' => microtime( true ) - $time, - ]; - }, - $views - ); - - return array_values( array_filter( $views ) ); - } - - public function get_view_access( $view_slug ) { - $subQuery = wpFluent()->table( SettingsRepository::TABLE_NAME )->select( 'settings_id' ) - ->where( 'slug', $view_slug ); - - $access = wpFluent()->table( SettingsRepository::TABLE_META_NAME )->select( 'meta_value' ) - ->where( 'meta_key', 'view_access' ) - ->where( \wpFluent()->raw( 'settings_id in ( ' . $subQuery->getQuery()->getRawSql() . ' )' ) ) - ->first(); - - if ( ! $access ) { - return array(); - } - - return unserialize( $access->meta_value ); - } - - public function get_available_views( $filters = [] ) { - $views = eh_crm_get_settingsmeta( 0, 'selected_views' ); - - // to Get Custom views count alone - $views_only = Arr::flatten( Arr::get( $filters , 'views_only', array() ) ); - - $roles = array(); - if ( is_user_logged_in() ) { - $roles = (array) wp_get_current_user()->roles; - } - - $custom_views = Arr::where( - $views, - function ( $view ) use ( $roles, $views_only ) { - return ( count( $views_only ) == 0 || in_array( $view, $views_only, true ) ) && - count( array_intersect( $this->get_view_access( $view ), $roles ) ) && - Str::startsWith( $view, 'view_' ); - } - ); - - $views = array_map( - function ( $view ) use ( $views_only ) { - if ( ! Str::endsWith( $view, '_view' ) || ( count( $views_only ) ) ) { - return; - } - - $title = ucfirst( str_replace( '_view', '', $view ) ); - - return [ - 'title' => $title, - 'slug' => $view, - 'data' => [], - ]; - }, - $views - ); - - if ( 0 !== count( $custom_views ) ) { - $views[] = array( - 'title' => 'Views', - 'data' => $custom_views, - ); - } - - return array_filter( $views ); - } - - /** - * Restore tickets - * - * @param array filters - * - * @return array - */ - public function restore( $filter ) { - global $wpdb; - - $baseQuery = $this->applyFilter( $filter, wpFluent()->table( self::TABLE_TICKETS ) ); - - $selectQuery = $baseQuery->select( 'ticket_id' )->getQuery()->getRawSql(); - - $table_wsdesk_archived_tickets = $wpdb->prefix . 'wsdesk_archived_tickets'; - $table_wsdesk_archived_tickets_ticketsmeta = $wpdb->prefix . 'wsdesk_archived_ticketsmeta'; - $table_wsdesk_ticketsmeta = $wpdb->prefix . 'wsdesk_ticketsmeta'; - $table_wsdesk_tickets = $wpdb->prefix . 'wsdesk_tickets'; - - // Copy tickets into archived tickets - $query = 'insert into ' . $table_wsdesk_tickets; - $query .= ' select * from ' . $table_wsdesk_archived_tickets . ' where ticket_id in (' . $selectQuery . ')'; - $query .= ' or ticket_parent in (' . $selectQuery . ')'; - - wpFluent()->statement( $query ); - - // Copy tickets meta into archived tickets meta - $query = 'insert into ' . $table_wsdesk_ticketsmeta; - $query .= ' select * from ' . $table_wsdesk_archived_tickets_ticketsmeta . ' where ticket_id in (' . $selectQuery . ')'; - wpFluent()->statement( $query ); - - // Get the count of tickets before delete - $data['count'] = $baseQuery->count(); - // Delete tickets - $query = 'delete from ' . $table_wsdesk_archived_tickets; - $query .= ' where ticket_id in ( select t1.ticket_id from (' . $selectQuery . ') as t1)'; - $query .= ' or ticket_parent in ( select t1.ticket_id from (' . $selectQuery . ') as t1)'; - wpFluent()->statement( 'set foreign_key_checks = 0' ); - wpFluent()->statement( $query ); - - // Delete Tickets meta - $query = 'delete from ' . $table_wsdesk_archived_tickets_ticketsmeta; - $query .= ' where ticket_id not in ( select t1.ticket_id from ' . $table_wsdesk_archived_tickets . ' as t1)'; - - wpFluent()->statement( $query ); - - return $data; - } - - public function getRoles() { - return array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ); - } - - public function chunk( $query, $limit, \Closure $callback, $chunkPage = 1 ) { - - $query->limit( $limit ); - $query->offset( $limit * ( $chunkPage - 1 ) ); - - $result = $query->get(); - - if ( count( $result ) ) { - $callback( $result ); - return $this->chunk( $query, $limit, $callback, ++$chunkPage ); - } - - return $chunkPage; - } -} +<?php+namespace WSDesk\Tickets;++use Illuminate\Support\Arr;+use Illuminate\Support\Collection;+use Illuminate\Support\Str;+use WSDesk\Tickets\Filters\RequestorFilter;+use WSDesk\Tickets\Filters\Sorter;+use WSDesk\Tickets\Filters\SubjectFilter;+use WSDesk\Tickets\Filters\TicketIdFilter;+use WSDesk\Tickets\Filters\TicketCreatedFilter;+use WSDesk\Tickets\Filters\TicketUpdatedFilter;+use WSDesk\Tickets\Formatter\TicketFormatter;+use WpFluent\QueryBuilder\QueryBuilderHandler;+use WSDesk\Settings\SettingsRepository;+use WSDesk\Tickets\Filters\AgentFilter;+use WSDesk\Tickets\Filters\BlockFilter;+use WSDesk\Tickets\Filters\GlobalSearchFilter;+use WSDesk\Tickets\Filters\LabelFilter;+use WSDesk\Tickets\Filters\TagFilter;+use WSDesk\Tickets\Filters\UserFilter;+use WSDesk\Tickets\Filters\ViewsFilter;+use WSDesk\Tickets\Formatter\TicketMetaFormatter;++class TicketArchiveRepository extends TicketRepository {++ const TABLE_TICKETS = 'wsdesk_archived_tickets';+ const TABLE_TICKETS_META = 'wsdesk_archived_ticketsmeta';++ /**+ * Get query builder+ *+ * @return QueryBuilderHandler+ */+ public function query() {+ return wpFluent()->table( self::TABLE_TICKETS )->where( 'ticket_parent', 0 );+ }++ public function get( array $filters ) {+ $query = $this->applyFilter( $filters );++ $query = $query->limit( Arr::get( $filters, 'length', $this->limit ) )+ ->offset( Arr::get( $filters, 'start', 0 ) );++ $tickets = $query->get();++ $meta = $this->getTicketsMeta( $tickets );++ $assignees = $this->getAssigneesFromMeta( $meta );++ $messages = $this->getLatestMessage( $tickets );++ $replyCount = $this->getReplyCount( $tickets );++ $labelsCount = $this->getCountByLabels( 'select 1' , false, false );++ $viewGroups = $this->getViewGroupColums( $filters );++ $tickets = array_map(+ function ( $ticket ) use ( $meta, $assignees, $messages, $replyCount, $labelsCount, $viewGroups ) {+ $ticket = new TicketFormatter( $ticket );+ $ticketMeta = $meta->get( $ticket->ticket_id, new Collection() );++ $ticket->reply_count = Arr::pluck(+ Arr::where(+ $replyCount,+ function ( $count ) use ( $ticket ) {+ return (int) $ticket->ticket_id === (int) $count->ticket_parent;+ }+ ),+ 'count',+ 'ticket_category'+ );++ $ticket->assignees = Arr::pluck(+ Arr::where(+ $assignees,+ function ( $assignee ) use ( $ticketMeta ) {+ return $ticketMeta->has( 'ticket_assignee' ) && in_array( (int) $assignee->id, $ticketMeta->ticket_assignee );+ }+ ),+ 'display_name'+ );++ $ticket->last_message = Arr::first(+ $messages,+ function ( $message ) use ( $ticket ) {+ return (int) $message->ticket_parent === (int) $ticket->ticket_id;+ }+ );++ if ( $ticket->last_message ) {+ $ticket->last_message = new TicketFormatter( $ticket->last_message );+ }++ $ticket->badge_color = Arr::first(+ $labelsCount,+ function ( $label ) use ( $ticketMeta ) {+ return $ticketMeta->has( 'ticket_label' ) && $label->slug === $ticketMeta->ticket_label;+ }+ );++ $ticket->view_groups = $viewGroups;++ return array_merge( $ticketMeta->toArray(), $ticket->toArray() );+ },+ $tickets+ );++ return $tickets;+ }++ /**+ * Apply given filters to the query and return+ *+ * @param array $filters optional+ * @param QueryBuilderHandler $query optional+ * @return QueryBuilderHandler+ */+ public function applyFilter( array $filters = [], QueryBuilderHandler $query = null ) {+ $query = $query ? $query : $this->query();++ $filterClasses = [+ new GlobalSearchFilter(),+ new TicketIdFilter(),+ new TicketCreatedFilter(),+ new LabelFilter(),+ new Sorter(),+ ];++ foreach ( $filterClasses as $filter ) {+ $query = $filter->filter( $query, $filters, $this );+ }++ return $query;+ }+++ /**+ * Get Assignee login name from meta data+ *+ * @var Collection $meta+ * @return array Array of assinees+ */+ public function getAssigneesFromMeta( Collection $meta ) {+ $ticketAssinees = $meta->flatten()->pluck( 'ticket_assignee' )->flatten()->unique()->filter()->toArray();++ $assignees = [];+ if ( count( $ticketAssinees ) ) {+ $assignees = wpFluent()->table( 'users' )->whereIn( 'id', $ticketAssinees )->select( [ 'id', 'display_name' ] )->get();+ }++ return $assignees;+ }++ public function getLatestMessage( $tickets ) {+ if ( count( $tickets ) === 0 ) {+ return [];+ }+ $ticket_ids = implode( ',', Arr::pluck( $tickets, 'ticket_id' ) );++ $table = wpFluent()->addTablePrefix( self::TABLE_TICKETS, false );++ $query = 'select m.* from ' . $table . ' as m join ';+ $query .= '( SELECT max(t1.ticket_id) as ticket_id from ' . $table . ' as t1';+ $query .= ' where t1.ticket_parent in ( ' . $ticket_ids . ' ) group by t1.ticket_parent order by t1.ticket_id desc ';+ $query .= ' ) as c on c.ticket_id = m.ticket_id';++ $latest_tickets = wpFluent()->query( $query )->get();++ if ( count( $latest_tickets ) ) {+ $users = wpFluent()->table( 'users' )->select( 'user_email', 'display_name' )->whereIn( 'user_email', Arr::pluck( $latest_tickets, 'ticket_email' ) )->get();+ $users = Arr::pluck( 'display_name', 'user_email' );++ $latest_tickets = array_map(+ function ( $ticket ) use ( $users ) {+ $ticket->display_name = Arr::get( $users, $ticket->ticket_email, __( 'Guest', 'wsdesk' ) );++ return $ticket;+ },+ $latest_tickets+ );+ }++ return $latest_tickets;+ }++ public function getReplyCount( $tickets ) {+ if ( count( $tickets ) === 0 ) {+ return [];+ }+ $ticket_ids = Arr::pluck( $tickets, 'ticket_id' );++ $query = wpFluent()->table( self::TABLE_TICKETS )->select( \wpFluent()->raw( 'count(ticket_parent) as count, ticket_parent, ticket_category' ) )+ ->whereIn( 'ticket_parent', $ticket_ids )+ ->groupBy( [ 'ticket_category', 'ticket_parent' ] );++ return $query->get();+ }++ public function getViewGroupColums( $filters ) {+ $view_slugs = Arr::get( $filters, 'view.views', array() );++ if ( 0 === count( $view_slugs ) ) {+ return array();+ }++ $subQuery = wpFluent()->table( SettingsRepository::TABLE_NAME );+ $subQuery->whereIn( 'slug', $view_slugs );+ $subQuery->select( 'settings_id' );++ $query = wpFluent()->table( SettingsRepository::TABLE_META_NAME );+ $query->where( 'meta_key', 'view_group' );+ $query->where( \wpFluent()->raw( 'settings_id in (' . $subQuery->getQuery()->getRawSql() . ')' ) );+ $query->select( 'meta_value' );++ $groups = $query->get();++ return Arr::pluck( $groups, 'meta_value' );+ }++ /**+ * Get tickets count with filters applied+ *+ * @param array $filters+ * @return int+ */+ public function count( array $filters = [] ) {+ $query = $this->applyFilter( $filters );++ return $query->select( 'id' )->count();+ }++ /**+ * Get tickets meta as a Formatter+ *+ * @param array $tickets+ * @return Collection collection of Fromatter group by ticket_id+ */+ public function getTicketsMeta( array $tickets ) {+ if ( count( $tickets ) === 0 ) {+ return new Collection();+ }++ $tickets = (array) $tickets;++ $query = wpFluent()->table( self::TABLE_TICKETS_META )->whereIn( 'ticket_id', Arr::pluck( $tickets, 'ticket_id' ) );++ return ( new Collection( (array) $query->get() ) )->groupBy( 'ticket_id' )+ ->map(+ function ( Collection $ticketsMeta ) {+ return new TicketMetaFormatter( $ticketsMeta->pluck( 'meta_value', 'meta_key' ) );+ }+ );+ }++ /**+ * Apply custom views filters from view slug+ *+ * @param QueryBuilderHandler $query+ * @param string $view_slug+ *+ * @return QueryBuilderHandler+ */+ public function getCountByViews( $query, $views, $filters ) {++ $filter = new ViewsFilter();+ $data = array();+ $settings = new SettingsRepository();++ foreach ( $views as $view_slug ) {+ $view_settings = Arr::first(+ $settings->filter(+ array(+ 'type' => 'view',+ 'slug' => $view_slug,+ )+ )+ );++ if ( null === $view_settings ) {+ continue;+ }++ $query = $this->applyFilter( $filters );++ $vquery = $filter->applyCustomViewFilter( $query, $view_slug );++ $data[] = array(+ 'slug' => $view_slug,+ 'count' => $vquery->count(),+ 'title' => $view_settings['title'],+ );+ }++ return $data;+ }++ /**+ * Get ticket count by status+ *+ * @return array+ */+ public function getCountByLabels( $subQuery, $info = [], $filtered = true ) {+ $metaSubQuery = wpFluent()->table( self::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_label' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $query = 'SELECT slug, COUNT(wp_wsdesk_ticketsmeta.ticket_id) as count,title, settings_meta.meta_value as badge_color';+ $query .= ' FROM ' . wpFluent()->addTablePrefix( 'wsdesk_settings', false ) . ' as wp_wsdesk_settings';+ $query .= ' LEFT JOIN (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta on wp_wsdesk_ticketsmeta.meta_value = wp_wsdesk_settings.slug';+ $query .= ' left join ' . wpFluent()->addTablePrefix( 'wsdesk_settingsmeta', false ) . ' as settings_meta on settings_meta.settings_id = wp_wsdesk_settings.settings_id';+ $query .= ' where wp_wsdesk_settings.type = "label" ';+ if ( true === $filtered ) {+ $query .= ' and wp_wsdesk_settings.filter = "yes"';+ }+ $query .= ' and settings_meta.meta_key ="label_color"';+ $query .= ' GROUP by wp_wsdesk_settings.settings_id';++ $statuses = wpFluent()->query( $query )->get();++ return $statuses;+ }++ /**+ * Get ticket count by status+ *+ * @param string $subQuery+ * @return array+ */+ public function getCountByAgents( $subQuery ) {+ $metaSubQuery = wpFluent()->table( self::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_assignee' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $whereSubQuery = $this->getAdminUserQuery()->select( [ 'user_id' ] )->getQuery()->getRawSql();++ $query = 'SELECT count(wp_wsdesk_ticketsmeta.ticket_id) as count, users.id as slug, users.display_name as title ';+ $query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users';+ $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta on meta_value like concat(\'%"\',users.id,\'"%\')';+ $query .= ' where users.id in (' . $whereSubQuery . ')';+ $query .= ' GROUP by users.id';+ $query .= ' UNION select count(ticket_meta.ticket_id) as count, "null" as slug, "Unassigned" as title from';+ $query .= ' ' . wpFluent()->addTablePrefix( 'wsdesk_ticketsmeta', false ) . ' as ticket_meta';+ $query .= ' where meta_key = "ticket_assignee" and meta_value = "' . serialize( [] ) . '"';+ $query .= ' and ticket_id in (' . $subQuery . ')';++ $statuses = wpFluent()->query( $query )->get();++ return $statuses;+ }++ /**+ * Get admin users query+ *+ * @return QueryBuilderHandler+ */+ public function getAdminUserQuery( array $filter = [] ) {+ $query = wpFluent()->table( 'usermeta' )->where( 'meta_key', wpFluent()->addTablePrefix( 'capabilities', false ) )->where(+ function ( $query ) {+ foreach ( $this->getRoles() as $role ) {+ $query->orWhere( 'meta_value', 'like', '%"' . $role . '"%' );+ }+ }+ );++ if ( Arr::has( $filter, 'agent_id' ) ) {+ $query->whereIn( 'user_id', Arr::get( $filter, 'agent_id' ) );+ }++ return $query;+ }++ public function getAgents( $filter = array() ) {+ $users = $this->getAdminUserQuery()->get();++ return array_map(+ function ( $user ) {+ $user = new \WP_User( $user->user_id );+ return [+ 'id' => $user->ID,+ 'name' => $user->display_name,+ 'caps' => $user->caps,+ 'email' => $user->email,+ ];+ },+ $users+ );+ }++ /**+ * Get ticket count by status+ *
Vulnerability Existed: no Explanation: This diff shows a file encoding change from the old version (3.3.4) to the new version (3.3.5). The only differences visible are line ending conversions - the old file uses Unix-style line endings (LF) while the new file also uses Unix-style line endings, with the actual code content remaining identical across all 600 lines. There are no functional code changes, no new logic introduced, and no modifications to existing security-sensitive operations. The file contains: - Database query construction using parameterized query builders (wpFluent) - SQL string concatenation in several methods, but these use prepared query interfaces - No changes to input validation, sanitization, or authorization checks - No modifications to cryptographic functions or authentication logic Since the code content is identical between versions, no new vulnerabilities were introduced, and no existing vulnerabilities were fixed in this diff. This is purely a file encoding/formatting change with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/TicketField.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/TicketField.php 2025-12-21 09:36:35.235291534 +0000@@ -1,81 +1,81 @@-<?php - -namespace WSDesk\Tickets; - -use Illuminate\Support\Arr; -use WSDesk\Settings\SettingsItem; - -class TicketField { - - const TYPE_CHECKBOX = 'checkbox'; - const TYPE_SELECT = 'select'; - const TYPE_RADIO = 'radio'; - const TYPE_WOO_PRODUCT = 'woo_product'; - const TYPE_WOO_CATEGORY = 'woo_category'; - const TYPE_WOO_TAGS = 'woo_tags'; - const TYPE_FILE = 'file'; - - /* @var SettingsItem */ - protected $settings_item; - - /* @var string */ - protected $key; - - /* @var mixed */ - protected $value; - - /** - * Initiate field - * - * @param string $key - * @param mixed $value - */ - public function __construct( $key, $value ) { - $this->key = $key; - $this->value = $value; - } - - /** - * Set settings item - * - * @param SettingsItem $settings_item - */ - public function set_settings_item( $settings_item ) { - $this->settings_item = $settings_item; - } - - public function get_settings_item() { - if ( is_null( $this->settings_item ) ) { - $this->settings_item = SettingsItem::find_by_slug( $this->key ); - } - - return $this->settings_item; - } - - public function get_type() { - return Arr::get( $this->get_settings_item()->get_meta(), 'field_type' ); - } - - public function get_labels() { - if ( 'woo_order_id' === $this->key ) { - return $this->value; - } - - if ( 'ticket_attachment' === $this->key ) { - return unserialize( $this->value ); - } - - $field_type = $this->get_type(); - $field_values = Arr::get( $this->get_settings_item()->get_meta(), 'field_values', array() ); - - if ( in_array( $field_type, array( self::TYPE_SELECT, self::TYPE_RADIO, self::TYPE_WOO_CATEGORY, self::TYPE_WOO_PRODUCT, self::TYPE_WOO_TAGS ), true ) ) { - return Arr::get( $field_values, $this->value ); - } - - if ( in_array( $field_type, array( self::TYPE_CHECKBOX ), true ) && $this->value ) { - return implode( ', ', Arr::only( $field_values, unserialize( $this->value ) ) ); - } - - return $this->value; - } -} +<?php++namespace WSDesk\Tickets;++use Illuminate\Support\Arr;+use WSDesk\Settings\SettingsItem;++class TicketField {++ const TYPE_CHECKBOX = 'checkbox';+ const TYPE_SELECT = 'select';+ const TYPE_RADIO = 'radio';+ const TYPE_WOO_PRODUCT = 'woo_product';+ const TYPE_WOO_CATEGORY = 'woo_category';+ const TYPE_WOO_TAGS = 'woo_tags';+ const TYPE_FILE = 'file';++ /* @var SettingsItem */+ protected $settings_item;++ /* @var string */+ protected $key;++ /* @var mixed */+ protected $value;++ /**+ * Initiate field+ *+ * @param string $key+ * @param mixed $value+ */+ public function __construct( $key, $value ) {+ $this->key = $key;+ $this->value = $value;+ }++ /**+ * Set settings item+ *+ * @param SettingsItem $settings_item+ */+ public function set_settings_item( $settings_item ) {+ $this->settings_item = $settings_item;+ }++ public function get_settings_item() {+ if ( is_null( $this->settings_item ) ) {+ $this->settings_item = SettingsItem::find_by_slug( $this->key );+ }++ return $this->settings_item;+ }++ public function get_type() {+ return Arr::get( $this->get_settings_item()->get_meta(), 'field_type' );+ }++ public function get_labels() {+ if ( 'woo_order_id' === $this->key ) {+ return $this->value;+ }++ if ( 'ticket_attachment' === $this->key ) {+ return unserialize( $this->value );+ }++ $field_type = $this->get_type();+ $field_values = Arr::get( $this->get_settings_item()->get_meta(), 'field_values', array() );++ if ( in_array( $field_type, array( self::TYPE_SELECT, self::TYPE_RADIO, self::TYPE_WOO_CATEGORY, self::TYPE_WOO_PRODUCT, self::TYPE_WOO_TAGS ), true ) ) {+ return Arr::get( $field_values, $this->value );+ }++ if ( in_array( $field_type, array( self::TYPE_CHECKBOX ), true ) && $this->value ) {+ return implode( ', ', Arr::only( $field_values, unserialize( $this->value ) ) );+ }++ return $this->value;+ }+}
Vulnerability Existed: yes
FALSE POSITIVE
Deserialization of Untrusted Data - CWE-502 - includes/Tickets/TicketField.php - Lines 66, 78
Old Code:
```php
if ( 'ticket_attachment' === $this->key ) {
return unserialize( $this->value );
}
```
and
```php
return implode( ', ', Arr::only( $field_values, unserialize( $this->value ) ) );
```
Fixed Code:
The diff shows no changes to these lines - the vulnerable `unserialize()` calls remain in both locations.
Explanation:
The code continues to use PHP's `unserialize()` function on user-controlled data (`$this->value`). This is a critical security vulnerability (CWE-502) because `unserialize()` can execute arbitrary code if the serialized data contains malicious object payloads. This is particularly dangerous when:
1. The `$value` comes from user input or external sources (ticket attachments, form data)
2. No validation or sanitization is performed before unserialization
3. The application has gadget chains available that could be exploited
The diff shows only line ending changes (CRLF to LF), with no actual security fixes applied. The vulnerable code persists unchanged between versions 3.3.4 and 3.3.5.
Recommended fix: Replace `unserialize()` with safer alternatives like `json_decode()` or use PHP 7.0+ options like `unserialize($data, ['allowed_classes' => false])` if backward compatibility requires serialized data handling.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/TicketReportRepository.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/TicketReportRepository.php 2025-12-21 09:36:35.235291534 +0000@@ -1,508 +1,508 @@-<?php - -namespace WSDesk\Tickets; - -use DateTime; -use Illuminate\Support\Arr; -use stdClass; - -class TicketReportRepository { - - private $repo; - - public function __construct() { - $this->repo = new TicketRepository(); - } - - /** - * Get first reply avg time by agent - * - * @param string $subQuery - * @return array - */ - public function getAvgReplyTimeByAgents( array $filter ) { - - $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_assignee' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] ); - - $whereSubQuery = $whereSubQuery->getQuery()->getRawSql(); - - $subQuery = $this->repo->applyFilter( $filter )->select( 'ticket_id' )->getQuery()->getRawSql(); - - $ticketDateQuery = $this->repo->applyFilter( $filter )->select( - \wpFluent()->raw( 'ticket_date as created_at, ticket_id' ) - )->getQuery()->getRawSql(); - - $replyDateQuery = 'select ticket_date from ' . wpFluent()->addTablePrefix( TicketRepository::TABLE_TICKETS, false ); - $replyDateQuery .= ' where ticket_parent = wsdesk_tickets.ticket_id order by ticket_id limit 1'; - - $query = 'SELECT agent_id, agent_name, sum(diff_in_seconds) as diff_in_seconds, count(agent_id) as count from ('; - $query .= 'SELECT TIME_TO_SEC(TIMEDIFF(STR_TO_DATE((' . $replyDateQuery . '), \'%b %d, %Y %r\'), STR_TO_DATE(created_at, \'%b %d, %Y %r\'))) as diff_in_seconds,'; - $query .= ' users.id as agent_id, users.display_name as agent_name '; - $query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users'; - $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta'; - $query .= ' on meta_value like concat(\'%"\',users.id,\'"%\')'; - $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets'; - $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wsdesk_tickets.ticket_id'; - $query .= ' where users.id in (' . $whereSubQuery . ')'; - //$query .= ' and exists (' . $replyDateQuery . ')'; - $query .= ') as reply_times group by agent_id'; - - $statuses = wpFluent()->query( $query )->get(); - - $statuses = collect( $statuses )->map( - function ( $status ) { - $status->diff_in_minutes = $status->diff_in_seconds ? round( $status->diff_in_seconds / 60 / $status->count ) : 0; - return $status; - } - ); - - return $statuses; - } - - /** - * Get reply count by agent per day - * - * @param string $subQuery - * @return array - */ - public function getReplyCountByAgentsPerDay( array $filter ) { - - //$subQuery = $this->repo->applyFilter($filter)->select('ticket_id')->getQuery()->getRawSql(); - - $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] )->getQuery()->getRawSql(); - - $ticketDateQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS )->select( - \wpFluent()->raw( 'STR_TO_DATE(ticket_date, \'%%b %%d, %%Y\') as created_at, ticket_id, ticket_author' ) - )->where( 'ticket_trash', '=', 0 ); - - $ticketDateQuery = $this->repo->applyFilter( $filter, $ticketDateQuery ); - - $ticketDateQuery = $ticketDateQuery->getQuery()->getRawSql(); - - $query = 'SELECT count(wsdesk_tickets.ticket_id) as count, created_at,'; - $query .= ' users.id as agent_id, users.display_name as agent_name'; - $query .= ' FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users'; - $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets'; - $query .= ' on wsdesk_tickets.ticket_author = users.id'; - $query .= ' where users.id in (' . $whereSubQuery . ')'; - $query .= ' GROUP by users.id, created_at'; - - $statuses = wpFluent()->query( $query )->get(); - - $statuses = collect( $statuses )->groupBy( 'agent_id' )->values()->map( - function ( $agent ) use ( $filter ) { - $agent = $agent->keyBy( 'created_at' )->values(); - - $agent_name = Arr::get( (array) $agent->first(), 'agent_name', 'Agent' ); - - list($start_date, $end_date) = Arr::get( $filter, 'created_at', [] ); - - $start_date = new DateTime( $start_date ); - $end_date = new DateTime( $end_date ); - - while ( $start_date->format( 'U' ) <= $end_date->format( 'U' ) ) { - if ( $agent->has( $start_date->format( 'Y-m-d' ) ) === false ) { - $agent->push( - [ - 'count' => 0, - 'agent_name' => $agent_name, - 'created_at' => $start_date->format( 'Y-m-d' ), - ] - ); - } - $start_date = $start_date->modify( '+1 day' ); - } - - $agent = $agent->map( - function ( $item ) { - $item = (array) $item; - if ( isset( $item['created_at'] ) ) { - $item['time'] = strtotime( $item['created_at'] ); - } else { - $item['time'] = null; - } - return $item; - } - )->sortBy( 'time' )->values(); - - - $dataset = [ - 'label' => $agent_name, - 'data' => $agent, - 'pointBackgroundColor' => $this->getColor(), - ]; - - return $dataset; - } - ); - - return $statuses; - } - - /** - * Get ticket count by agent per day - * - * @param string $subQuery - * @return array - */ - public function getCountByAgentsPerDay( array $filter ) { - $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_assignee' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] )->getQuery()->getRawSql(); - $subQuery = $this->repo->applyFilter( $filter )->select( 'ticket_id' )->getQuery()->getRawSql(); - - $ticketDateQuery = $this->repo->applyFilter( $filter )->select( - \wpFluent()->raw( 'ticket_date as created_at, ticket_id' ) - )->getQuery()->getRawSql(); - - $query = 'SELECT count(wp_wsdesk_ticketsmeta.ticket_id) as count, STR_TO_DATE(created_at, \'%b %d, %Y\') as created_at, users.id as agent_id, users.display_name as agent_name '; - $query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users'; - $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta'; - $query .= ' on meta_value like concat(\'%"\',users.id,\'"%\')'; - $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets'; - $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wsdesk_tickets.ticket_id'; - $query .= ' where users.id in (' . $whereSubQuery . ')'; - $query .= ' GROUP by users.id, STR_TO_DATE(created_at, \'%b %d, %Y\')'; - $query .= ' order by STR_TO_DATE(created_at, \'%b %d, %Y\')'; - - $statuses = wpFluent()->query( $query )->get(); - - $statuses = collect( $statuses )->groupBy( 'agent_id' )->values()->map( - function ( $agent ) use ( $filter ) { - $agent_name = Arr::get( (array) $agent->first(), 'agent_name', 'Agent' ); - - list($start_date, $end_date) = Arr::get( $filter, 'created_at', [] ); - - $start_date = new DateTime( $start_date ); - $end_date = new DateTime( $end_date ); - - while ( $start_date->format( 'U' ) <= $end_date->format( 'U' ) ) { - if ( $agent->has( $start_date->format( 'Y-m-d' ) ) === false ) { - $agent->push( - [ - 'count' => 0, - 'agent_name' => $agent_name, - 'created_at' => $start_date->format( 'Y-m-d' ), - ] - ); - } - $start_date = $start_date->modify( '+1 day' ); - } - $agent = $agent->map( - function ( $item ) { - $item = (array) $item; - if ( isset( $item['created_at'] ) ) { - $item['time'] = strtotime( $item['created_at'] ); - } else { - $item['time'] = null; - } - return $item; - } - )->sortBy( 'time' )->values(); - - - $dataset = [ - 'label' => $agent_name, - 'data' => $agent, - 'pointBackgroundColor' => $this->getColor(), - ]; - - return $dataset; - } - ); - - return $statuses; - } - - /** - * Get ticket count by agent per day per tags - * - * @param array $filter - * @return array - */ - public function getCountByAgentsPerDayPerTags( array $filter ) { - $tagsSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_tags' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_assignee' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] )->getQuery()->getRawSql(); - - $subQuery = $this->repo->applyFilter( $filter )->select( 'ticket_id' )->getQuery()->getRawSql(); - - $ticketDateQuery = $this->repo->applyFilter( $filter )->select( - \wpFluent()->raw( 'ticket_date as created_at, ticket_id' ) - )->getQuery()->getRawSql(); - - $query = 'SELECT count(wsdesk_tickets.ticket_id) as count, wp_wsdesk_settings.title,'; - $query .= ' STR_TO_DATE(created_at, \'%b %d, %Y\') as created_at, users.id as agent_id, users.display_name as agent_name '; - $query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users'; - $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta'; - $query .= ' on wp_wsdesk_ticketsmeta.meta_value like concat(\'%"\',users.id,\'"%\')'; - $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets'; - $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wsdesk_tickets.ticket_id'; - $query .= ' left join (' . $tagsSubQuery . ' ) as ticket_tags'; - $query .= ' on ticket_tags.ticket_id = wsdesk_tickets.ticket_id'; - $query .= ' left join ' . wpFluent()->addTablePrefix( 'wsdesk_settings', false ) . ' as wp_wsdesk_settings'; - $query .= ' on ticket_tags.meta_value like concat(\'%"\',wp_wsdesk_settings.slug, \'"%\')'; - $query .= ' where users.id in (' . $whereSubQuery . ')'; - $query .= ' and wp_wsdesk_settings.type = "tag" and wp_wsdesk_settings.filter = "yes"'; - $query .= ' GROUP by users.id,wp_wsdesk_settings.slug, STR_TO_DATE(created_at, \'%b %d, %Y\')'; - - $statuses = wpFluent()->query( $query )->get(); - - return $statuses; - } - - /** - * Get ticket count by agent per day per status - * - * @param string $subQuery - * @return array - */ - public function getCountByAgentsPerDayPerStatus( $subQuery ) { - $statusSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_label' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_assignee' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] )->getQuery()->getRawSql(); - - $ticketDateQuery = $this->repo->query()->select( - \wpFluent()->raw( 'ticket_date as created_at, ticket_id' ) - )->getQuery()->getRawSql(); - - $query = 'SELECT count(wsdesk_tickets.ticket_id) as count, ticket_statuses.meta_value, STR_TO_DATE(created_at, \'%b %d, %Y\') as created_at, users.id as agent_id, users.display_name as agent_name '; - $query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users'; - $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta'; - $query .= ' on wp_wsdesk_ticketsmeta.meta_value like concat(\'%"\',users.id,\'"%\')'; - $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets'; - $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wsdesk_tickets.ticket_id'; - $query .= ' left join (' . $statusSubQuery . ' ) as ticket_statuses'; - $query .= ' on ticket_statuses.ticket_id = wsdesk_tickets.ticket_id'; - $query .= ' where users.id in (' . $whereSubQuery . ')'; - $query .= ' GROUP by users.id, ticket_statuses.meta_value, STR_TO_DATE(created_at, \'%b %d, %Y\')'; - - $statuses = wpFluent()->query( $query )->get(); - - return $statuses; - } - - /** - * Get agent statisfication score - * - * @param string $subQuery - * @return array - */ - public function satisficationScore( array $filter ) { - $statusSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_rating' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_assignee' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] )->getQuery()->getRawSql(); - - $subQuery = $this->repo->applyFilter( $filter )->select( 'ticket_id' )->getQuery()->getRawSql(); - - $ticketDateQuery = $this->repo->applyFilter( $filter )->select( - \wpFluent()->raw( 'ticket_date as created_at, ticket_id' ) - )->getQuery()->getRawSql(); - - $query = 'SELECT count(wp_wsdesk_ticketsmeta.ticket_id) as count, ticket_statuses.meta_value as rating, users.id as agent_id, users.display_name as agent_name'; - $query .= ' FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users'; - $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta'; - $query .= ' on wp_wsdesk_ticketsmeta.meta_value like concat(\'%"\',users.id,\'"%\')'; - $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets'; - $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wsdesk_tickets.ticket_id'; - $query .= ' left join (' . $statusSubQuery . ' ) as ticket_statuses'; - $query .= ' on ticket_statuses.ticket_id = wsdesk_tickets.ticket_id'; - $query .= ' where users.id in (' . $whereSubQuery . ')'; - $query .= ' GROUP by users.id, ticket_statuses.meta_value'; - - $statuses = wpFluent()->query( $query )->get(); - - $statuses = collect( $statuses )->groupBy( 'agent_id' )->map( - function ( $status ) { - $agent = $status->groupBy( 'rating' )->map( - function ( $score ) { - return (array) $score->first(); - } - ); - - $score = [ - 'good' => 0, - 'bad' => 0, - 'score' => 0, - 'total' => 0, - 'agent_id' => Arr::get( $agent->first(), 'agent_id' ), - 'agent_name' => Arr::get( $agent->first(), 'agent_name' ), - 'agent' => $agent, - ]; - - $score['total'] = $agent->sum( 'count' ); - $score['good'] = Arr::get( - $agent->get( 'great', [] ), - 'count', - 0 - ); - $score['bad'] = Arr::get( - $agent->get( 'Bad', [] ), - 'count', - 0 - ); - - if ( $score['good'] ) { - $score['score'] = intval( $score['good'] / $score['total'] * 100 ); - } - - return $score; - } - )->values()->toArray(); - - return $statuses; - } - - /** - Avg resolve time - * - * @param array $filter - * @return array - */ - public function getAvgResolveTime( array $filter ) { - $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', 'resolved_at' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $agentSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_assignee' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] )->getQuery()->getRawSql(); - - $ticketDateQuery = $this->repo->applyFilter( $filter )->select( - \wpFluent()->raw( 'STR_TO_DATE(ticket_date, \'%%b %%d, %%Y %%r\') as created_at, ticket_id' ) - )->getQuery()->getRawSql(); - - $query = 'SELECT TIME_TO_SEC(TIMEDIFF(STR_TO_DATE(max(wp_wsdesk_ticketsmeta.meta_value), \'%Y-%m-%d %H:%i:%S\'),'; - $query .= ' min(created_at))) as response_time, count(wsdesk_tickets.ticket_id) as count,'; - $query .= ' users.id as agent_id, users.display_name as agent_name'; - $query .= ' FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users'; - $query .= ' left join (' . $agentSubQuery . ' ) as wp_wsdesk_ticket_agents'; - $query .= ' on wp_wsdesk_ticket_agents.meta_value like concat(\'%"\',users.id,\'"%\')'; - $query .= ' left join (' . $metaSubQuery . ' ) as wp_wsdesk_ticketsmeta'; - $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wp_wsdesk_ticket_agents.ticket_id'; - $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets'; - $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wsdesk_tickets.ticket_id'; - $query .= ' where users.id in (' . $whereSubQuery . ')'; - $query .= ' and wp_wsdesk_ticketsmeta.meta_value is not null'; - $query .= ' GROUP by users.id'; - - $statuses = wpFluent()->query( $query )->get(); - - $agents = $this->repo->getAgents( $filter ); - - $existing_agents = array_map( - function ( $status ) { - return $status->agent_id; - }, - $statuses - ); - - $agents = array_filter( - $agents, - function ( $agent ) use ( $existing_agents ) { - return ! in_array( $agent['id'], $existing_agents ); - } - ); - - $agents = array_map( - function ( $agent ) { - $status = new stdClass(); - $status->agent_id = $agent['id']; - $status->agent_name = $agent['name']; - $status->response_time = 0; - $status->count = 0; - - return $status; - }, - $agents - ); - - $statuses = array_map( - function ( $status ) { - $status->response_time = $status->response_time ? round( $status->response_time / ( 60 * 60 ) / $status->count ) : 0; - return $status; - }, - $statuses - ); - - return array_merge( $statuses, $agents ); - } - - /** - * Get ticket count by status - * - * @param array $filter - * @return array - */ - public function getCountByStatus() { - $count = $this->repo->getCountByLabels( - $this->repo->applyFilter()->select( 'ticket_id' )->getQuery()->getRawSql() - ); - - return $count; - } - - /** - * Get ticket count by Tag - * - * @param array $filter - * @return array - */ - public function getCountByTag( array $filter ) { - $count = $this->repo->getCountByTags( - $this->repo->applyFilter( $filter )->select( 'ticket_id' )->getQuery()->getRawSql() - ); - - return $count; - } - - public function getColor() { - return '#' . dechex( rand( 0, 10000000 ) ); - } -} +<?php++namespace WSDesk\Tickets;++use DateTime;+use Illuminate\Support\Arr;+use stdClass;++class TicketReportRepository {++ private $repo;++ public function __construct() {+ $this->repo = new TicketRepository();+ }++ /**+ * Get first reply avg time by agent+ *+ * @param string $subQuery+ * @return array+ */+ public function getAvgReplyTimeByAgents( array $filter ) {++ $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_assignee' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] );++ $whereSubQuery = $whereSubQuery->getQuery()->getRawSql();++ $subQuery = $this->repo->applyFilter( $filter )->select( 'ticket_id' )->getQuery()->getRawSql();++ $ticketDateQuery = $this->repo->applyFilter( $filter )->select(+ \wpFluent()->raw( 'ticket_date as created_at, ticket_id' )+ )->getQuery()->getRawSql();++ $replyDateQuery = 'select ticket_date from ' . wpFluent()->addTablePrefix( TicketRepository::TABLE_TICKETS, false );+ $replyDateQuery .= ' where ticket_parent = wsdesk_tickets.ticket_id order by ticket_id limit 1';++ $query = 'SELECT agent_id, agent_name, sum(diff_in_seconds) as diff_in_seconds, count(agent_id) as count from (';+ $query .= 'SELECT TIME_TO_SEC(TIMEDIFF(STR_TO_DATE((' . $replyDateQuery . '), \'%b %d, %Y %r\'), STR_TO_DATE(created_at, \'%b %d, %Y %r\'))) as diff_in_seconds,';+ $query .= ' users.id as agent_id, users.display_name as agent_name ';+ $query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users';+ $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta';+ $query .= ' on meta_value like concat(\'%"\',users.id,\'"%\')';+ $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets';+ $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wsdesk_tickets.ticket_id';+ $query .= ' where users.id in (' . $whereSubQuery . ')';+ //$query .= ' and exists (' . $replyDateQuery . ')';+ $query .= ') as reply_times group by agent_id';++ $statuses = wpFluent()->query( $query )->get();++ $statuses = collect( $statuses )->map(+ function ( $status ) {+ $status->diff_in_minutes = $status->diff_in_seconds ? round( $status->diff_in_seconds / 60 / $status->count ) : 0;+ return $status;+ }+ );++ return $statuses;+ }++ /**+ * Get reply count by agent per day+ *+ * @param string $subQuery+ * @return array+ */+ public function getReplyCountByAgentsPerDay( array $filter ) {++ //$subQuery = $this->repo->applyFilter($filter)->select('ticket_id')->getQuery()->getRawSql();++ $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] )->getQuery()->getRawSql();++ $ticketDateQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS )->select(+ \wpFluent()->raw( 'STR_TO_DATE(ticket_date, \'%%b %%d, %%Y\') as created_at, ticket_id, ticket_author' )+ )->where( 'ticket_trash', '=', 0 );++ $ticketDateQuery = $this->repo->applyFilter( $filter, $ticketDateQuery );++ $ticketDateQuery = $ticketDateQuery->getQuery()->getRawSql();++ $query = 'SELECT count(wsdesk_tickets.ticket_id) as count, created_at,';+ $query .= ' users.id as agent_id, users.display_name as agent_name';+ $query .= ' FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users';+ $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets';+ $query .= ' on wsdesk_tickets.ticket_author = users.id';+ $query .= ' where users.id in (' . $whereSubQuery . ')';+ $query .= ' GROUP by users.id, created_at';++ $statuses = wpFluent()->query( $query )->get();++ $statuses = collect( $statuses )->groupBy( 'agent_id' )->values()->map(+ function ( $agent ) use ( $filter ) {+ $agent = $agent->keyBy( 'created_at' )->values();++ $agent_name = Arr::get( (array) $agent->first(), 'agent_name', 'Agent' );++ list($start_date, $end_date) = Arr::get( $filter, 'created_at', [] );++ $start_date = new DateTime( $start_date );+ $end_date = new DateTime( $end_date );++ while ( $start_date->format( 'U' ) <= $end_date->format( 'U' ) ) {+ if ( $agent->has( $start_date->format( 'Y-m-d' ) ) === false ) {+ $agent->push(+ [+ 'count' => 0,+ 'agent_name' => $agent_name,+ 'created_at' => $start_date->format( 'Y-m-d' ),+ ]+ );+ }+ $start_date = $start_date->modify( '+1 day' );+ }++ $agent = $agent->map(+ function ( $item ) {+ $item = (array) $item;+ if ( isset( $item['created_at'] ) ) {+ $item['time'] = strtotime( $item['created_at'] );+ } else {+ $item['time'] = null; + }+ return $item;+ }+ )->sortBy( 'time' )->values();+ ++ $dataset = [+ 'label' => $agent_name,+ 'data' => $agent,+ 'pointBackgroundColor' => $this->getColor(),+ ];++ return $dataset;+ }+ );++ return $statuses;+ }++ /**+ * Get ticket count by agent per day+ *+ * @param string $subQuery+ * @return array+ */+ public function getCountByAgentsPerDay( array $filter ) {+ $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_assignee' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] )->getQuery()->getRawSql();+ $subQuery = $this->repo->applyFilter( $filter )->select( 'ticket_id' )->getQuery()->getRawSql();++ $ticketDateQuery = $this->repo->applyFilter( $filter )->select(+ \wpFluent()->raw( 'ticket_date as created_at, ticket_id' )+ )->getQuery()->getRawSql();++ $query = 'SELECT count(wp_wsdesk_ticketsmeta.ticket_id) as count, STR_TO_DATE(created_at, \'%b %d, %Y\') as created_at, users.id as agent_id, users.display_name as agent_name ';+ $query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users';+ $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta';+ $query .= ' on meta_value like concat(\'%"\',users.id,\'"%\')';+ $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets';+ $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wsdesk_tickets.ticket_id';+ $query .= ' where users.id in (' . $whereSubQuery . ')';+ $query .= ' GROUP by users.id, STR_TO_DATE(created_at, \'%b %d, %Y\')';+ $query .= ' order by STR_TO_DATE(created_at, \'%b %d, %Y\')';++ $statuses = wpFluent()->query( $query )->get();++ $statuses = collect( $statuses )->groupBy( 'agent_id' )->values()->map(+ function ( $agent ) use ( $filter ) {+ $agent_name = Arr::get( (array) $agent->first(), 'agent_name', 'Agent' );++ list($start_date, $end_date) = Arr::get( $filter, 'created_at', [] );++ $start_date = new DateTime( $start_date );+ $end_date = new DateTime( $end_date );++ while ( $start_date->format( 'U' ) <= $end_date->format( 'U' ) ) {+ if ( $agent->has( $start_date->format( 'Y-m-d' ) ) === false ) {+ $agent->push(+ [+ 'count' => 0,+ 'agent_name' => $agent_name,+ 'created_at' => $start_date->format( 'Y-m-d' ),+ ]+ );+ }+ $start_date = $start_date->modify( '+1 day' );+ }+ $agent = $agent->map(+ function ( $item ) {+ $item = (array) $item;+ if ( isset( $item['created_at'] ) ) {+ $item['time'] = strtotime( $item['created_at'] );+ } else {+ $item['time'] = null; + }+ return $item;+ }+ )->sortBy( 'time' )->values();+ ++ $dataset = [+ 'label' => $agent_name,+ 'data' => $agent,+ 'pointBackgroundColor' => $this->getColor(),+ ];++ return $dataset;+ }+ );++ return $statuses;+ }++ /**+ * Get ticket count by agent per day per tags+ *+ * @param array $filter+ * @return array+ */+ public function getCountByAgentsPerDayPerTags( array $filter ) {+ $tagsSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_tags' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_assignee' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] )->getQuery()->getRawSql();++ $subQuery = $this->repo->applyFilter( $filter )->select( 'ticket_id' )->getQuery()->getRawSql();++ $ticketDateQuery = $this->repo->applyFilter( $filter )->select(+ \wpFluent()->raw( 'ticket_date as created_at, ticket_id' )+ )->getQuery()->getRawSql();++ $query = 'SELECT count(wsdesk_tickets.ticket_id) as count, wp_wsdesk_settings.title,';+ $query .= ' STR_TO_DATE(created_at, \'%b %d, %Y\') as created_at, users.id as agent_id, users.display_name as agent_name ';+ $query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users';+ $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta';+ $query .= ' on wp_wsdesk_ticketsmeta.meta_value like concat(\'%"\',users.id,\'"%\')';+ $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets';+ $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wsdesk_tickets.ticket_id';+ $query .= ' left join (' . $tagsSubQuery . ' ) as ticket_tags';+ $query .= ' on ticket_tags.ticket_id = wsdesk_tickets.ticket_id';+ $query .= ' left join ' . wpFluent()->addTablePrefix( 'wsdesk_settings', false ) . ' as wp_wsdesk_settings';+ $query .= ' on ticket_tags.meta_value like concat(\'%"\',wp_wsdesk_settings.slug, \'"%\')';+ $query .= ' where users.id in (' . $whereSubQuery . ')';+ $query .= ' and wp_wsdesk_settings.type = "tag" and wp_wsdesk_settings.filter = "yes"';+ $query .= ' GROUP by users.id,wp_wsdesk_settings.slug, STR_TO_DATE(created_at, \'%b %d, %Y\')';++ $statuses = wpFluent()->query( $query )->get();++ return $statuses;+ }++ /**+ * Get ticket count by agent per day per status+ *+ * @param string $subQuery+ * @return array+ */+ public function getCountByAgentsPerDayPerStatus( $subQuery ) {+ $statusSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_label' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_assignee' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] )->getQuery()->getRawSql();++ $ticketDateQuery = $this->repo->query()->select(+ \wpFluent()->raw( 'ticket_date as created_at, ticket_id' )+ )->getQuery()->getRawSql();++ $query = 'SELECT count(wsdesk_tickets.ticket_id) as count, ticket_statuses.meta_value, STR_TO_DATE(created_at, \'%b %d, %Y\') as created_at, users.id as agent_id, users.display_name as agent_name ';+ $query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users';+ $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta';+ $query .= ' on wp_wsdesk_ticketsmeta.meta_value like concat(\'%"\',users.id,\'"%\')';+ $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets';+ $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wsdesk_tickets.ticket_id';+ $query .= ' left join (' . $statusSubQuery . ' ) as ticket_statuses';+ $query .= ' on ticket_statuses.ticket_id = wsdesk_tickets.ticket_id';+ $query .= ' where users.id in (' . $whereSubQuery . ')';+ $query .= ' GROUP by users.id, ticket_statuses.meta_value, STR_TO_DATE(created_at, \'%b %d, %Y\')';++ $statuses = wpFluent()->query( $query )->get();++ return $statuses;+ }++ /**+ * Get agent statisfication score+ *+ * @param string $subQuery+ * @return array+ */+ public function satisficationScore( array $filter ) {+ $statusSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_rating' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_assignee' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] )->getQuery()->getRawSql();++ $subQuery = $this->repo->applyFilter( $filter )->select( 'ticket_id' )->getQuery()->getRawSql();++ $ticketDateQuery = $this->repo->applyFilter( $filter )->select(+ \wpFluent()->raw( 'ticket_date as created_at, ticket_id' )+ )->getQuery()->getRawSql();++ $query = 'SELECT count(wp_wsdesk_ticketsmeta.ticket_id) as count, ticket_statuses.meta_value as rating, users.id as agent_id, users.display_name as agent_name';+ $query .= ' FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users';+ $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta';+ $query .= ' on wp_wsdesk_ticketsmeta.meta_value like concat(\'%"\',users.id,\'"%\')';+ $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets';+ $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wsdesk_tickets.ticket_id';+ $query .= ' left join (' . $statusSubQuery . ' ) as ticket_statuses';+ $query .= ' on ticket_statuses.ticket_id = wsdesk_tickets.ticket_id';+ $query .= ' where users.id in (' . $whereSubQuery . ')';+ $query .= ' GROUP by users.id, ticket_statuses.meta_value';++ $statuses = wpFluent()->query( $query )->get();++ $statuses = collect( $statuses )->groupBy( 'agent_id' )->map(+ function ( $status ) {+ $agent = $status->groupBy( 'rating' )->map(+ function ( $score ) {+ return (array) $score->first();+ }+ );++ $score = [+ 'good' => 0,+ 'bad' => 0,+ 'score' => 0,+ 'total' => 0,+ 'agent_id' => Arr::get( $agent->first(), 'agent_id' ),+ 'agent_name' => Arr::get( $agent->first(), 'agent_name' ),+ 'agent' => $agent,+ ];++ $score['total'] = $agent->sum( 'count' );+ $score['good'] = Arr::get(+ $agent->get( 'great', [] ),+ 'count',+ 0+ );+ $score['bad'] = Arr::get(+ $agent->get( 'Bad', [] ),+ 'count',+ 0+ );++ if ( $score['good'] ) {+ $score['score'] = intval( $score['good'] / $score['total'] * 100 );+ }++ return $score;+ }+ )->values()->toArray();++ return $statuses;+ }++ /**+ Avg resolve time+ *+ * @param array $filter+ * @return array+ */+ public function getAvgResolveTime( array $filter ) {+ $metaSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', 'resolved_at' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $agentSubQuery = wpFluent()->table( TicketRepository::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_assignee' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $whereSubQuery = $this->repo->getAdminUserQuery( $filter )->select( [ 'user_id' ] )->getQuery()->getRawSql();++ $ticketDateQuery = $this->repo->applyFilter( $filter )->select(+ \wpFluent()->raw( 'STR_TO_DATE(ticket_date, \'%%b %%d, %%Y %%r\') as created_at, ticket_id' )+ )->getQuery()->getRawSql();++ $query = 'SELECT TIME_TO_SEC(TIMEDIFF(STR_TO_DATE(max(wp_wsdesk_ticketsmeta.meta_value), \'%Y-%m-%d %H:%i:%S\'),';+ $query .= ' min(created_at))) as response_time, count(wsdesk_tickets.ticket_id) as count,';+ $query .= ' users.id as agent_id, users.display_name as agent_name';+ $query .= ' FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users';+ $query .= ' left join (' . $agentSubQuery . ' ) as wp_wsdesk_ticket_agents';+ $query .= ' on wp_wsdesk_ticket_agents.meta_value like concat(\'%"\',users.id,\'"%\')';+ $query .= ' left join (' . $metaSubQuery . ' ) as wp_wsdesk_ticketsmeta';+ $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wp_wsdesk_ticket_agents.ticket_id';+ $query .= ' left join (' . $ticketDateQuery . ') as wsdesk_tickets';+ $query .= ' on wp_wsdesk_ticketsmeta.ticket_id = wsdesk_tickets.ticket_id';+ $query .= ' where users.id in (' . $whereSubQuery . ')';+ $query .= ' and wp_wsdesk_ticketsmeta.meta_value is not null';+ $query .= ' GROUP by users.id';++ $statuses = wpFluent()->query( $query )->get();++ $agents = $this->repo->getAgents( $filter );++ $existing_agents = array_map(+ function ( $status ) {+ return $status->agent_id;+ },+ $statuses+ );++ $agents = array_filter(+ $agents,+ function ( $agent ) use ( $existing_agents ) {+ return ! in_array( $agent['id'], $existing_agents );+ }+ );++ $agents = array_map(+ function ( $agent ) {+ $status = new stdClass();+ $status->agent_id = $agent['id'];+ $status->agent_name = $agent['name'];+ $status->response_time = 0;+ $status->count = 0;++ return $status;+ },+ $agents+ );++ $statuses = array_map(+ function ( $status ) {+ $status->response_time = $status->response_time ? round( $status->response_time / ( 60 * 60 ) / $status->count ) : 0;+ return $status;+ },+ $statuses+ );++ return array_merge( $statuses, $agents );+ }++ /**+ * Get ticket count by status+ *+ * @param array $filter+ * @return array+ */+ public function getCountByStatus() {+ $count = $this->repo->getCountByLabels(+ $this->repo->applyFilter()->select( 'ticket_id' )->getQuery()->getRawSql()+ );++ return $count;+ }
Vulnerability Existed: no **Analysis Summary:** This diff shows only a whitespace/line ending change (Unix LF vs Windows CRLF line endings conversion). The actual code content is identical between versions 3.3.4 and 3.3.5. No security fixes were applied in this update. The file maintains the same: - SQL query construction patterns - Query parameter handling - Database interaction methods - Input validation logic The change is purely cosmetic (line ending normalization) with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/Tickets/TicketRepository.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/Tickets/TicketRepository.php 2025-12-21 09:36:35.235291534 +0000@@ -1,619 +1,619 @@-<?php -namespace WSDesk\Tickets; - -use Illuminate\Support\Arr; -use Illuminate\Support\Collection; -use Illuminate\Support\Str; -use WSDesk\Tickets\Filters\RequestorFilter; -use WSDesk\Tickets\Filters\Sorter; -use WSDesk\Tickets\Filters\SubjectFilter; -use WSDesk\Tickets\Filters\TicketIdFilter; -use WSDesk\Tickets\Filters\TicketCreatedFilter; -use WSDesk\Tickets\Filters\TicketUpdatedFilter; -use WSDesk\Tickets\Formatter\TicketFormatter; -use WpFluent\QueryBuilder\QueryBuilderHandler; -use WSDesk\Settings\SettingsRepository; -use WSDesk\Tickets\Filters\AgentFilter; -use WSDesk\Tickets\Filters\BlockFilter; -use WSDesk\Tickets\Filters\GlobalSearchFilter; -use WSDesk\Tickets\Filters\LabelFilter; -use WSDesk\Tickets\Filters\TagFilter; -use WSDesk\Tickets\Filters\UserFilter; -use WSDesk\Tickets\Filters\ViewsFilter; -use WSDesk\Tickets\Formatter\TicketMetaFormatter; - -class TicketRepository { - - const TABLE_TICKETS = 'wsdesk_tickets'; - const TABLE_TICKETS_META = 'wsdesk_ticketsmeta'; - - protected $limit = 25; - - /** - * Get query builder - * - * @return QueryBuilderHandler - */ - public function query() { - return wpFluent()->table( self::TABLE_TICKETS )->where( 'ticket_parent', 0 )->where( 'ticket_trash', 0 ); - } - - public function get( array $filters ) { - $query = $this->applyFilter( $filters ); - - $query = $query->limit( Arr::get( $filters, 'length', $this->limit ) ) - ->offset( Arr::get( $filters, 'start', 0 ) ); - - $tickets = $query->get(); - - $meta = $this->getTicketsMeta( $tickets ); - - $assignees = $this->getAssigneesFromMeta( $meta ); - - $messages = $this->getLatestMessage( $tickets ); - - $replyCount = $this->getReplyCount( $tickets ); - - $labelsCount = $this->getCountByLabels( 'select 1' , false, false ); - - $viewGroups = $this->getViewGroupColums( $filters ); - - $tickets = array_map( - function ( $ticket ) use ( $meta, $assignees, $messages, $replyCount, $labelsCount, $viewGroups ) { - $ticket = new TicketFormatter( $ticket ); - $ticketMeta = $meta->get( $ticket->ticket_id, new Collection() ); - - $ticket->reply_count = Arr::pluck( - Arr::where( - $replyCount, - function ( $count ) use ( $ticket ) { - return (int) $ticket->ticket_id === (int) $count->ticket_parent; - } - ), - 'count', - 'ticket_category' - ); - - $ticket->assignees = Arr::pluck( - Arr::where( - $assignees, - function ( $assignee ) use ( $ticketMeta ) { - return $ticketMeta->has( 'ticket_assignee' ) && in_array( (int) $assignee->id, $ticketMeta->ticket_assignee ); - } - ), - 'display_name' - ); - - $ticket->last_message = Arr::first( - $messages, - function ( $message ) use ( $ticket ) { - return (int) $message->ticket_parent === (int) $ticket->ticket_id; - } - ); - - if ( $ticket->last_message ) { - $ticket->last_message = new TicketFormatter( $ticket->last_message ); - } - - $ticket->badge_color = Arr::first( - $labelsCount, - function ( $label ) use ( $ticketMeta ) { - return $ticketMeta->has( 'ticket_label' ) && $label->slug === $ticketMeta->ticket_label; - } - ); - - $ticket->view_groups = $viewGroups; - - return array_merge( $ticketMeta->toArray(), $ticket->toArray() ); - }, - $tickets - ); - - return $tickets; - } - - /** - * Apply given filters to the query and return - * - * @param array $filters optional - * @param QueryBuilderHandler $query optional - * @return QueryBuilderHandler - */ - public function applyFilter( array $filters = [], QueryBuilderHandler $query = null ) { - $query = $query ? $query : $this->query(); - - $filterClasses = [ - new GlobalSearchFilter(), - new LabelFilter(), - new TagFilter(), - new UserFilter(), - new AgentFilter(), - new SubjectFilter(), - new RequestorFilter(), - new TicketCreatedFilter(), - new TicketUpdatedFilter(), - new TicketIdFilter(), - new ViewsFilter(), - new BlockFilter(), - new Sorter(), - ]; - - foreach ( $filterClasses as $filter ) { - $query = $filter->filter( $query, $filters, $this ); - } - - return $query; - } - - - /** - * Get Assignee login name from meta data - * - * @var Collection $meta - * @return array Array of assinees - */ - public function getAssigneesFromMeta( Collection $meta ) { - $ticketAssinees = $meta->flatten()->pluck( 'ticket_assignee' )->flatten()->unique()->filter()->toArray(); - - $assignees = []; - if ( count( $ticketAssinees ) ) { - $assignees = wpFluent()->table( 'users' )->whereIn( 'id', $ticketAssinees )->select( [ 'id', 'display_name' ] )->get(); - } - - return $assignees; - } - - public function getLatestMessage( $tickets ) { - if ( count( $tickets ) === 0 ) { - return []; - } - $ticket_ids = implode( ',', Arr::pluck( $tickets, 'ticket_id' ) ); - - $table = wpFluent()->addTablePrefix( self::TABLE_TICKETS, false ); - - $query = 'select m.* from ' . $table . ' as m join '; - $query .= '( SELECT max(t1.ticket_id) as ticket_id from ' . $table . ' as t1'; - $query .= ' where t1.ticket_parent in ( ' . $ticket_ids . ' ) group by t1.ticket_parent order by t1.ticket_id desc '; - $query .= ' ) as c on c.ticket_id = m.ticket_id'; - - $latest_tickets = wpFluent()->query( $query )->get(); - - if ( count( $latest_tickets ) ) { - $users = wpFluent()->table( 'users' )->select( 'user_email', 'display_name' )->whereIn( 'user_email', Arr::pluck( $latest_tickets, 'ticket_email' ) )->get(); - $users = Arr::pluck( $users, 'display_name', 'user_email' ); - - $latest_tickets = array_map( - function ( $ticket ) use ( $users ) { - $ticket->display_name = Arr::get( $users, $ticket->ticket_email, __( 'Guest', 'wsdesk' ) ); - - return $ticket; - }, - $latest_tickets - ); - } - - return $latest_tickets; - } - - public function getReplyCount( $tickets ) { - if ( count( $tickets ) === 0 ) { - return []; - } - $ticket_ids = Arr::pluck( $tickets, 'ticket_id' ); - - $query = wpFluent()->table( self::TABLE_TICKETS )->select( \wpFluent()->raw( 'count(ticket_parent) as count, ticket_parent, ticket_category' ) ) - ->whereIn( 'ticket_parent', $ticket_ids ) - ->groupBy( [ 'ticket_category', 'ticket_parent' ] ); - - return $query->get(); - } - - public function getViewGroupColums( $filters ) { - $view_slugs = Arr::get( $filters, 'view.views', array() ); - - if ( 0 === count( $view_slugs ) ) { - return array(); - } - - $subQuery = wpFluent()->table( SettingsRepository::TABLE_NAME ); - $subQuery->whereIn( 'slug', $view_slugs ); - $subQuery->select( 'settings_id' ); - - $query = wpFluent()->table( SettingsRepository::TABLE_META_NAME ); - $query->where( 'meta_key', 'view_group' ); - $query->where( \wpFluent()->raw( 'settings_id in (' . $subQuery->getQuery()->getRawSql() . ')' ) ); - $query->select( 'meta_value' ); - - $groups = $query->get(); - - return Arr::pluck( $groups, 'meta_value' ); - } - - /** - * Get tickets count with filters applied - * - * @param array $filters - * @return int - */ - public function count( array $filters = [] ) { - $query = $this->applyFilter( $filters ); - - return $query->select( 'id' )->count(); - } - - /** - * Get tickets meta as a Formatter - * - * @param array $tickets - * @return Collection collection of Fromatter group by ticket_id - */ - public function getTicketsMeta( array $tickets ) { - if ( count( $tickets ) === 0 ) { - return new Collection(); - } - - $tickets = (array) $tickets; - - $query = wpFluent()->table( self::TABLE_TICKETS_META )->whereIn( 'ticket_id', Arr::pluck( $tickets, 'ticket_id' ) ); - - return ( new Collection( (array) $query->get() ) )->groupBy( 'ticket_id' ) - ->map( - function ( Collection $ticketsMeta ) { - return new TicketMetaFormatter( $ticketsMeta->pluck( 'meta_value', 'meta_key' ) ); - } - ); - } - - /** - * Apply custom views filters from view slug - * - * @param QueryBuilderHandler $query - * @param string $view_slug - * - * @return QueryBuilderHandler - */ - public function getCountByViews( $query, $views, $filters ) { - - $filter = new ViewsFilter(); - $data = array(); - $settings = new SettingsRepository(); - - foreach ( $views as $view_slug ) { - $view_settings = Arr::first( - $settings->filter( - array( - 'type' => 'view', - 'slug' => $view_slug, - ) - ) - ); - - if ( null === $view_settings ) { - continue; - } - - $query = $this->applyFilter( $filters ); - - $vquery = $filter->applyCustomViewFilter( $query, $view_slug ); - - $data[] = array( - 'slug' => $view_slug, - 'count' => $vquery->count(), - 'title' => $view_settings['title'], - ); - } - - return $data; - } - - /** - * Get ticket count by status - * - * @return array - */ - public function getCountByLabels( $subQuery, $info = [], $filtered = true ) { - $metaSubQuery = wpFluent()->table( self::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_label' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $query = 'SELECT slug, COUNT(wp_wsdesk_ticketsmeta.ticket_id) as count,title, settings_meta.meta_value as badge_color'; - $query .= ' FROM ' . wpFluent()->addTablePrefix( 'wsdesk_settings', false ) . ' as wp_wsdesk_settings'; - $query .= ' LEFT JOIN (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta on wp_wsdesk_ticketsmeta.meta_value = wp_wsdesk_settings.slug'; - $query .= ' left join ' . wpFluent()->addTablePrefix( 'wsdesk_settingsmeta', false ) . ' as settings_meta on settings_meta.settings_id = wp_wsdesk_settings.settings_id'; - $query .= ' where wp_wsdesk_settings.type = "label" '; - if ( true === $filtered ) { - $query .= ' and wp_wsdesk_settings.filter = "yes"'; - } - $query .= ' and settings_meta.meta_key ="label_color"'; - $query .= ' GROUP by wp_wsdesk_settings.settings_id'; - - $statuses = wpFluent()->query( $query )->get(); - - return $statuses; - } - - /** - * Get ticket count by status - * - * @param string $subQuery - * @return array - */ - public function getCountByAgents( $subQuery ) { - $metaSubQuery = wpFluent()->table( self::TABLE_TICKETS_META ) - ->where( 'meta_key', 'ticket_assignee' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery() - ->getRawSql(); - - $whereSubQuery = $this->getAdminUserQuery()->select( [ 'user_id' ] ); - if ( wsdesk_can_access_other_tickets() === false ) { - $whereSubQuery->where( 'user_id', '=', get_current_user_id() ); - } - $whereSubQuery = $whereSubQuery->getQuery()->getRawSql(); - - $query = 'SELECT count(wp_wsdesk_ticketsmeta.ticket_id) as count, users.id as slug, users.display_name as title '; - $query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users'; - $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta on meta_value like concat(\'%"\',users.id,\'"%\')'; - $query .= ' where users.id in (' . $whereSubQuery . ')'; - $query .= ' GROUP by users.id'; - $query .= ' UNION select count(ticket_meta.ticket_id) as count, "null" as slug, "Unassigned" as title from'; - $query .= ' ' . wpFluent()->addTablePrefix( 'wsdesk_ticketsmeta', false ) . ' as ticket_meta'; - $query .= ' where meta_key = "ticket_assignee" and meta_value = "' . serialize( [] ) . '"'; - $query .= ' and ticket_id in (' . $subQuery . ')'; - - $statuses = wpFluent()->query( $query )->get(); - - return $statuses; - } - - /** - * Get admin users query - * - * @return QueryBuilderHandler - */ - public function getAdminUserQuery( array $filter = [] ) { - $query = wpFluent()->table( 'usermeta' )->where( 'meta_key', wpFluent()->addTablePrefix( 'capabilities', false ) )->where( - function ( $query ) { - foreach ( $this->getRoles() as $role ) { - $query->orWhere( 'meta_value', 'like', '%"' . $role . '"%' ); - } - } - ); - - if ( Arr::has( $filter, 'agent_id' ) ) { - $query->whereIn( 'user_id', Arr::get( $filter, 'agent_id' ) ); - } - - return $query; - } - - public function getAgents( $filter = array() ) { - $users = $this->getAdminUserQuery( $filter )->get(); - - return array_map( - function ( $user ) { - $user = new \WP_User( $user->user_id ); - return [ - 'id' => $user->ID, - 'name' => $user->display_name, - 'caps' => $user->caps, - 'email' => $user->email, - ]; - }, - $users - ); - } - - /** - * Get ticket count by status - * - * @return array - */ - public function getCountByTags( $subQuery ) { - $metaSubQuery = wpFluent()->table( self::TABLE_TICKETS_META )->where( 'meta_key', 'ticket_tags' ) - ->select( [ 'ticket_id', 'meta_value' ] ) - ->getQuery()->getRawSql(); - - $query = 'SELECT slug, COUNT(wp_wsdesk_ticketsmeta.ticket_id) as count,title FROM'; - $query .= ' ' . wpFluent()->addTablePrefix( 'wsdesk_settings', false ) . ' as wp_wsdesk_settings'; - $query .= ' left JOIN (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta'; - $query .= ' on wp_wsdesk_ticketsmeta.meta_value like concat(\'%"\',wp_wsdesk_settings.slug, \'"%\')'; - $query .= ' where wp_wsdesk_settings.type = "tag" and wp_wsdesk_settings.filter = "yes"'; - $query .= ' GROUP by settings_id'; - - $statuses = wpFluent()->query( $query )->get(); - - return $statuses; - } - - /** - * Get ticket count by user reg status - * - * @return array - */ - public function getCountByUsers( $subQuery ) { - // ALTER TABLE wp_wsdesk_tickets CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci - $query = 'SELECT COUNT(wp_wsdesk_tickets.ticket_id) as count, "Registered Users" as title, "registered" as slug'; - /* $query .= ' FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as wp_users'; - $query .= ' LEFT JOIN ' . wpFluent()->addTablePrefix( 'wsdesk_tickets', false ) . ' as wp_wsdesk_tickets on wp_wsdesk_tickets.ticket_email = wp_users.user_email'; */ - $query .= ' FROM ' . wpFluent()->addTablePrefix( 'wsdesk_tickets', false ) . ' as wp_wsdesk_tickets '; - $query .= ' JOIN (' . $subQuery . ') as wp_wsdesk_filtered_tickets on wp_wsdesk_filtered_tickets.ticket_id = wp_wsdesk_tickets.ticket_id'; - $query .= ' WHERE wp_wsdesk_tickets.ticket_parent = 0 and wp_wsdesk_tickets.ticket_email in (select user_email from ' . wpFluent()->addTablePrefix( 'users', false ) . ')'; - $query .= ' UNION'; - $query .= ' SELECT COUNT(wp_wsdesk_tickets.ticket_id) as count, "Guest Users" as title, "guest" as slug'; - $query .= ' FROM ' . wpFluent()->addTablePrefix( 'wsdesk_tickets', false ) . ' as wp_wsdesk_tickets'; - $query .= ' JOIN (' . $subQuery . ') as wp_wsdesk_filtered_tickets on wp_wsdesk_filtered_tickets.ticket_id = wp_wsdesk_tickets.ticket_id'; - $query .= ' WHERE wp_wsdesk_tickets.ticket_parent = 0'; - $query .= ' and wp_wsdesk_tickets.ticket_email not in (select user_email from ' . wpFluent()->addTablePrefix( 'users', false ) . ')'; - - return wpFluent()->query( $query )->get(); - } - - public function get_ticket_counts_by_active_views( array $filters = [] ) { - $views = $this->get_available_views( $filters ); - $query = $this->applyFilter()->select( 'ticket_id' ); - - $views = array_map( - function ( $view ) use ( $filters, $query ) { - $method = 'getCountBy' . $view['title']; - - if ( method_exists( $this, $method ) === false ) { - return; - } - - $time = microtime( true ); - - if ( 'Views' !== $view['title'] ) { - $query = $query->getQuery()->getRawSql(); - } - - return [ - 'title' => $view['title'], - 'data' => $this->{$method}( $query, $view['data'], $filters ), - 'time' => microtime( true ) - $time, - ]; - }, - $views - ); - - return array_values( array_filter( $views ) ); - } - - public function get_view_access( $view_slug ) { - $subQuery = wpFluent()->table( SettingsRepository::TABLE_NAME )->select( 'settings_id' ) - ->where( 'slug', $view_slug ); - - $access = wpFluent()->table( SettingsRepository::TABLE_META_NAME )->select( 'meta_value' ) - ->where( 'meta_key', 'view_access' ) - ->where( \wpFluent()->raw( 'settings_id in ( ' . $subQuery->getQuery()->getRawSql() . ' )' ) ) - ->first(); - - if ( ! $access ) { - return array(); - } - - return maybe_unserialize( $access->meta_value ); - } - - public function get_available_views( $filters = [] ) { - $views = eh_crm_get_settingsmeta( 0, 'selected_views' ); - - // to Get Custom views count alone - $views_only = Arr::flatten( Arr::get( $filters , 'views_only', array() ) ); - - $roles = array(); - if ( is_user_logged_in() ) { - $roles = (array) wp_get_current_user()->roles; - } - - $custom_views = Arr::where( - $views, - function ( $view ) use ( $roles, $views_only ) { - $viewAccess = $this->get_view_access( $view ); - - if ( ! is_array( $viewAccess ) ) { - return false; - } - return ( count( $views_only ) == 0 || in_array( $view, $views_only, true ) ) && - count( array_intersect( $this->get_view_access( $view ), $roles ) ) && - Str::startsWith( $view, 'view_' ); - } - ); - - $views = array_map( - function ( $view ) use ( $views_only ) { - if ( ! Str::endsWith( $view, '_view' ) || ( count( $views_only ) ) ) { - return; - } - - $title = ucfirst( str_replace( '_view', '', $view ) ); - - return [ - 'title' => $title, - 'slug' => $view, - 'data' => [], - ]; - }, - $views - ); - - if ( 0 !== count( $custom_views ) ) { - $views[] = array( - 'title' => 'Views', - 'data' => $custom_views, - ); - } - - return array_filter( $views ); - } - - /** - * Archive tickets - * - * @param array filters - * - * @return array - */ - public function archiveTickets( $filter ) { - global $wpdb; - - $baseQuery = $this->applyFilter( $filter, wpFluent()->table( self::TABLE_TICKETS ) ); - - $selectQuery = $baseQuery->select( 'ticket_id' )->getQuery()->getRawSql(); - - $table_wsdesk_archived_tickets = $wpdb->prefix . 'wsdesk_archived_tickets'; - $table_wsdesk_archived_tickets_ticketsmeta = $wpdb->prefix . 'wsdesk_archived_ticketsmeta'; - $table_wsdesk_ticketsmeta = $wpdb->prefix . 'wsdesk_ticketsmeta'; - $table_wsdesk_tickets = $wpdb->prefix . 'wsdesk_tickets'; - - // Copy tickets into archived tickets - $query = 'insert into ' . $table_wsdesk_archived_tickets; - $query .= ' select * from ' . $table_wsdesk_tickets . ' where (ticket_id in (' . $selectQuery . ')'; - $query .= ' or ticket_parent in (' . $selectQuery . ')) and ticket_id not in (select ticket_id from ' . $table_wsdesk_archived_tickets . ') '; - - wpFluent()->statement( $query ); - - // Copy tickets meta into archived tickets meta - $query = 'insert into ' . $table_wsdesk_archived_tickets_ticketsmeta; - $query .= ' select * from ' . $table_wsdesk_ticketsmeta . ' where ticket_id in (' . $selectQuery . ') and meta_id not in (select meta_id from ' . $table_wsdesk_archived_tickets_ticketsmeta . ')'; - wpFluent()->statement( $query ); - - // Get the count of tickets before delete - $data['count'] = $baseQuery->count(); - // Delete tickets - $query = 'delete from ' . $table_wsdesk_tickets; - $query .= ' where ticket_id in ( select t1.ticket_id from (' . $selectQuery . ') as t1)'; - $query .= ' or ticket_parent in ( select t1.ticket_id from (' . $selectQuery . ') as t1)'; - wpFluent()->statement( 'set foreign_key_checks = 0' ); - wpFluent()->statement( $query ); - - // Delete Tickets meta - $query = 'delete from ' . $table_wsdesk_ticketsmeta; - $query .= ' where ticket_id not in ( select t1.ticket_id from ' . $table_wsdesk_tickets . ' as t1)'; - - wpFluent()->statement( $query ); - - return $data; - } - - public function getRoles() { - return array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ); - } - - public function chunk( $query, $limit, \Closure $callback, $chunkPage = 1 ) { - - $query->limit( $limit ); - $query->offset( $limit * ( $chunkPage - 1 ) ); - - $result = $query->get(); - - if ( count( $result ) ) { - $callback( $result ); - return $this->chunk( $query, $limit, $callback, ++$chunkPage ); - } - - return $chunkPage; - } -} +<?php+namespace WSDesk\Tickets;++use Illuminate\Support\Arr;+use Illuminate\Support\Collection;+use Illuminate\Support\Str;+use WSDesk\Tickets\Filters\RequestorFilter;+use WSDesk\Tickets\Filters\Sorter;+use WSDesk\Tickets\Filters\SubjectFilter;+use WSDesk\Tickets\Filters\TicketIdFilter;+use WSDesk\Tickets\Filters\TicketCreatedFilter;+use WSDesk\Tickets\Filters\TicketUpdatedFilter;+use WSDesk\Tickets\Formatter\TicketFormatter;+use WpFluent\QueryBuilder\QueryBuilderHandler;+use WSDesk\Settings\SettingsRepository;+use WSDesk\Tickets\Filters\AgentFilter;+use WSDesk\Tickets\Filters\BlockFilter;+use WSDesk\Tickets\Filters\GlobalSearchFilter;+use WSDesk\Tickets\Filters\LabelFilter;+use WSDesk\Tickets\Filters\TagFilter;+use WSDesk\Tickets\Filters\UserFilter;+use WSDesk\Tickets\Filters\ViewsFilter;+use WSDesk\Tickets\Formatter\TicketMetaFormatter;++class TicketRepository {++ const TABLE_TICKETS = 'wsdesk_tickets';+ const TABLE_TICKETS_META = 'wsdesk_ticketsmeta';++ protected $limit = 25;++ /**+ * Get query builder+ *+ * @return QueryBuilderHandler+ */+ public function query() {+ return wpFluent()->table( self::TABLE_TICKETS )->where( 'ticket_parent', 0 )->where( 'ticket_trash', 0 );+ }++ public function get( array $filters ) {+ $query = $this->applyFilter( $filters );++ $query = $query->limit( Arr::get( $filters, 'length', $this->limit ) )+ ->offset( Arr::get( $filters, 'start', 0 ) );++ $tickets = $query->get();++ $meta = $this->getTicketsMeta( $tickets );++ $assignees = $this->getAssigneesFromMeta( $meta );++ $messages = $this->getLatestMessage( $tickets );++ $replyCount = $this->getReplyCount( $tickets );++ $labelsCount = $this->getCountByLabels( 'select 1' , false, false );++ $viewGroups = $this->getViewGroupColums( $filters );++ $tickets = array_map(+ function ( $ticket ) use ( $meta, $assignees, $messages, $replyCount, $labelsCount, $viewGroups ) {+ $ticket = new TicketFormatter( $ticket );+ $ticketMeta = $meta->get( $ticket->ticket_id, new Collection() );++ $ticket->reply_count = Arr::pluck(+ Arr::where(+ $replyCount,+ function ( $count ) use ( $ticket ) {+ return (int) $ticket->ticket_id === (int) $count->ticket_parent;+ }+ ),+ 'count',+ 'ticket_category'+ );++ $ticket->assignees = Arr::pluck(+ Arr::where(+ $assignees,+ function ( $assignee ) use ( $ticketMeta ) {+ return $ticketMeta->has( 'ticket_assignee' ) && in_array( (int) $assignee->id, $ticketMeta->ticket_assignee );+ }+ ),+ 'display_name'+ );++ $ticket->last_message = Arr::first(+ $messages,+ function ( $message ) use ( $ticket ) {+ return (int) $message->ticket_parent === (int) $ticket->ticket_id;+ }+ );++ if ( $ticket->last_message ) {+ $ticket->last_message = new TicketFormatter( $ticket->last_message );+ }++ $ticket->badge_color = Arr::first(+ $labelsCount,+ function ( $label ) use ( $ticketMeta ) {+ return $ticketMeta->has( 'ticket_label' ) && $label->slug === $ticketMeta->ticket_label;+ }+ );++ $ticket->view_groups = $viewGroups;++ return array_merge( $ticketMeta->toArray(), $ticket->toArray() );+ },+ $tickets+ );++ return $tickets;+ }++ /**+ * Apply given filters to the query and return+ *+ * @param array $filters optional+ * @param QueryBuilderHandler $query optional+ * @return QueryBuilderHandler+ */+ public function applyFilter( array $filters = [], QueryBuilderHandler $query = null ) {+ $query = $query ? $query : $this->query();++ $filterClasses = [+ new GlobalSearchFilter(),+ new LabelFilter(),+ new TagFilter(),+ new UserFilter(),+ new AgentFilter(),+ new SubjectFilter(),+ new RequestorFilter(),+ new TicketCreatedFilter(),+ new TicketUpdatedFilter(),+ new TicketIdFilter(),+ new ViewsFilter(),+ new BlockFilter(),+ new Sorter(),+ ];++ foreach ( $filterClasses as $filter ) {+ $query = $filter->filter( $query, $filters, $this );+ }++ return $query;+ }+++ /**+ * Get Assignee login name from meta data+ *+ * @var Collection $meta+ * @return array Array of assinees+ */+ public function getAssigneesFromMeta( Collection $meta ) {+ $ticketAssinees = $meta->flatten()->pluck( 'ticket_assignee' )->flatten()->unique()->filter()->toArray();++ $assignees = [];+ if ( count( $ticketAssinees ) ) {+ $assignees = wpFluent()->table( 'users' )->whereIn( 'id', $ticketAssinees )->select( [ 'id', 'display_name' ] )->get();+ }++ return $assignees;+ }++ public function getLatestMessage( $tickets ) {+ if ( count( $tickets ) === 0 ) {+ return [];+ }+ $ticket_ids = implode( ',', Arr::pluck( $tickets, 'ticket_id' ) );++ $table = wpFluent()->addTablePrefix( self::TABLE_TICKETS, false );++ $query = 'select m.* from ' . $table . ' as m join ';+ $query .= '( SELECT max(t1.ticket_id) as ticket_id from ' . $table . ' as t1';+ $query .= ' where t1.ticket_parent in ( ' . $ticket_ids . ' ) group by t1.ticket_parent order by t1.ticket_id desc ';+ $query .= ' ) as c on c.ticket_id = m.ticket_id';++ $latest_tickets = wpFluent()->query( $query )->get();++ if ( count( $latest_tickets ) ) {+ $users = wpFluent()->table( 'users' )->select( 'user_email', 'display_name' )->whereIn( 'user_email', Arr::pluck( $latest_tickets, 'ticket_email' ) )->get();+ $users = Arr::pluck( $users, 'display_name', 'user_email' );++ $latest_tickets = array_map(+ function ( $ticket ) use ( $users ) {+ $ticket->display_name = Arr::get( $users, $ticket->ticket_email, __( 'Guest', 'wsdesk' ) );++ return $ticket;+ },+ $latest_tickets+ );+ }++ return $latest_tickets;+ }++ public function getReplyCount( $tickets ) {+ if ( count( $tickets ) === 0 ) {+ return [];+ }+ $ticket_ids = Arr::pluck( $tickets, 'ticket_id' );++ $query = wpFluent()->table( self::TABLE_TICKETS )->select( \wpFluent()->raw( 'count(ticket_parent) as count, ticket_parent, ticket_category' ) )+ ->whereIn( 'ticket_parent', $ticket_ids )+ ->groupBy( [ 'ticket_category', 'ticket_parent' ] );++ return $query->get();+ }++ public function getViewGroupColums( $filters ) {+ $view_slugs = Arr::get( $filters, 'view.views', array() );++ if ( 0 === count( $view_slugs ) ) {+ return array();+ }++ $subQuery = wpFluent()->table( SettingsRepository::TABLE_NAME );+ $subQuery->whereIn( 'slug', $view_slugs );+ $subQuery->select( 'settings_id' );++ $query = wpFluent()->table( SettingsRepository::TABLE_META_NAME );+ $query->where( 'meta_key', 'view_group' );+ $query->where( \wpFluent()->raw( 'settings_id in (' . $subQuery->getQuery()->getRawSql() . ')' ) );+ $query->select( 'meta_value' );++ $groups = $query->get();++ return Arr::pluck( $groups, 'meta_value' );+ }++ /**+ * Get tickets count with filters applied+ *+ * @param array $filters+ * @return int+ */+ public function count( array $filters = [] ) {+ $query = $this->applyFilter( $filters );++ return $query->select( 'id' )->count();+ }++ /**+ * Get tickets meta as a Formatter+ *+ * @param array $tickets+ * @return Collection collection of Fromatter group by ticket_id+ */+ public function getTicketsMeta( array $tickets ) {+ if ( count( $tickets ) === 0 ) {+ return new Collection();+ }++ $tickets = (array) $tickets;++ $query = wpFluent()->table( self::TABLE_TICKETS_META )->whereIn( 'ticket_id', Arr::pluck( $tickets, 'ticket_id' ) );++ return ( new Collection( (array) $query->get() ) )->groupBy( 'ticket_id' )+ ->map(+ function ( Collection $ticketsMeta ) {+ return new TicketMetaFormatter( $ticketsMeta->pluck( 'meta_value', 'meta_key' ) );+ }+ );+ }++ /**+ * Apply custom views filters from view slug+ *+ * @param QueryBuilderHandler $query+ * @param string $view_slug+ *+ * @return QueryBuilderHandler+ */+ public function getCountByViews( $query, $views, $filters ) {++ $filter = new ViewsFilter();+ $data = array();+ $settings = new SettingsRepository();++ foreach ( $views as $view_slug ) {+ $view_settings = Arr::first(+ $settings->filter(+ array(+ 'type' => 'view',+ 'slug' => $view_slug,+ )+ )+ );++ if ( null === $view_settings ) {+ continue;+ }++ $query = $this->applyFilter( $filters );++ $vquery = $filter->applyCustomViewFilter( $query, $view_slug );++ $data[] = array(+ 'slug' => $view_slug,+ 'count' => $vquery->count(),+ 'title' => $view_settings['title'],+ );+ }++ return $data;+ }++ /**+ * Get ticket count by status+ *+ * @return array+ */+ public function getCountByLabels( $subQuery, $info = [], $filtered = true ) {+ $metaSubQuery = wpFluent()->table( self::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_label' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $query = 'SELECT slug, COUNT(wp_wsdesk_ticketsmeta.ticket_id) as count,title, settings_meta.meta_value as badge_color';+ $query .= ' FROM ' . wpFluent()->addTablePrefix( 'wsdesk_settings', false ) . ' as wp_wsdesk_settings';+ $query .= ' LEFT JOIN (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta on wp_wsdesk_ticketsmeta.meta_value = wp_wsdesk_settings.slug';+ $query .= ' left join ' . wpFluent()->addTablePrefix( 'wsdesk_settingsmeta', false ) . ' as settings_meta on settings_meta.settings_id = wp_wsdesk_settings.settings_id';+ $query .= ' where wp_wsdesk_settings.type = "label" ';+ if ( true === $filtered ) {+ $query .= ' and wp_wsdesk_settings.filter = "yes"';+ }+ $query .= ' and settings_meta.meta_key ="label_color"';+ $query .= ' GROUP by wp_wsdesk_settings.settings_id';++ $statuses = wpFluent()->query( $query )->get();++ return $statuses;+ }++ /**+ * Get ticket count by status+ *+ * @param string $subQuery+ * @return array+ */+ public function getCountByAgents( $subQuery ) {+ $metaSubQuery = wpFluent()->table( self::TABLE_TICKETS_META )+ ->where( 'meta_key', 'ticket_assignee' )+ ->select( [ 'ticket_id', 'meta_value' ] )+ ->getQuery()+ ->getRawSql();++ $whereSubQuery = $this->getAdminUserQuery()->select( [ 'user_id' ] );+ if ( wsdesk_can_access_other_tickets() === false ) {+ $whereSubQuery->where( 'user_id', '=', get_current_user_id() );+ }+ $whereSubQuery = $whereSubQuery->getQuery()->getRawSql();++ $query = 'SELECT count(wp_wsdesk_ticketsmeta.ticket_id) as count, users.id as slug, users.display_name as title ';+ $query .= 'FROM ' . wpFluent()->addTablePrefix( 'users', false ) . ' as users';+ $query .= ' left join (' . $metaSubQuery . ' and ticket_id in (' . $subQuery . ')) as wp_wsdesk_ticketsmeta on meta_value like concat(\'%"\',users.id,\'"%\')';+ $query .= ' where users.id in (' . $whereSubQuery . ')';+ $query .= ' GROUP by users.id';+ $query .= ' UNION select count(ticket_meta.ticket_id) as count, "null" as slug, "Unassigned" as title from';+ $query .= ' ' . wpFluent()->addTablePrefix( 'wsdesk_ticketsmeta', false ) . ' as ticket_meta';+ $query .= ' where meta_key = "ticket_assignee" and meta_value = "' . serialize( [] ) . '"';+ $query .= ' and ticket_id in (' . $subQuery . ')';++ $statuses = wpFluent()->query( $query )->get();++ return $statuses;+ }++ /**+ * Get admin users query+ *+ * @return QueryBuilderHandler+ */+ public function getAdminUserQuery( array $filter = [] ) {+ $query = wpFluent()->table( 'usermeta' )->where( 'meta_key', wpFluent()->addTablePrefix( 'capabilities', false ) )->where(+ function ( $query ) {
I'll analyze this diff for security vulnerabilities.
The diff shows a file encoding change (CRLF to LF line endings) with no functional code changes. However, let me examine the code content carefully for any security issues that exist in both versions.
**Vulnerability Existed: yes**
FALSE POSITIVE
**SQL Injection - CWE-89 - includes/Tickets/TicketRepository.php (Lines 165-170)**
Old Code:
```php
$ticket_ids = implode( ',', Arr::pluck( $tickets, 'ticket_id' ) );
$table = wpFluent()->addTablePrefix( self::TABLE_TICKETS, false );
$query = 'select m.* from ' . $table . ' as m join ';
$query .= '( SELECT max(t1.ticket_id) as ticket_id from ' . $table . ' as t1';
$query .= ' where t1.ticket_parent in ( ' . $ticket_ids . ' ) group by t1.ticket_parent order by t1.ticket_id desc ';
```
Fixed Code:
```php
(Same code - no fix applied)
```
Explanation:
This is a SQL injection vulnerability that was NOT fixed in this update. The `$ticket_ids` variable is directly concatenated into the SQL query without proper escaping or parameterized queries. While `ticket_id` values are extracted from the results array (limiting direct injection), if an attacker can influence the ticket data in any way, they could inject malicious SQL. The proper fix would be to use parameterized queries or prepared statements through the QueryBuilder's built-in methods instead of raw SQL concatenation.
---
**Vulnerability Existed: yes**
FALSE POSITIVE
**SQL Injection - CWE-89 - includes/Tickets/TicketRepository.php (Lines 373-376)**
Old Code:
```php
$query .= ' where meta_key = "ticket_assignee" and meta_value = "' . serialize( [] ) . '"';
$query .= ' and ticket_id in (' . $subQuery . ')';
```
Fixed Code:
```php
(Same code - no fix applied)
```
Explanation:
Direct string concatenation is used to build SQL queries. While the serialized empty array is somewhat predictable, this pattern of building raw SQL strings is vulnerable to injection if any variable input changes in the future. The `$subQuery` is also concatenated directly without validation. This should use parameterized queries through the QueryBuilder API.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-ajax-functions-one.php 2025-12-21 09:35:59.417065320 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-ajax-functions-one.php 2025-12-21 09:36:35.223290788 +0000@@ -1,2611 +1,2615 @@-<?php - -use WSDesk\Settings\SettingsRepository; - -class CRM_Ajax_One { - - public static function eh_crm_refresh_tickets_count() { - $default = eh_crm_get_settingsmeta( 0, 'default_label' ); - $tickets = eh_crm_get_ticketmeta_value_count( 'ticket_label', $default ); - die( json_encode( array( 'data' => count( $tickets ) ) ) ); - } - - public static function eh_crm_ticket_general() { - - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $default_assignee = isset( $_POST['default_assignee'] ) ? sanitize_text_field( $_POST['default_assignee'] ) : ''; - $default_label = isset( $_POST['default_label'] ) ? sanitize_text_field( $_POST['default_label'] ) : ''; - $ticket_raiser = isset( $_POST['ticket_raiser'] ) ? sanitize_text_field( $_POST['ticket_raiser'] ) : ''; - $auto_assign = isset( $_POST['auto_assign'] ) ? sanitize_text_field( $_POST['auto_assign'] ) : ''; - $scheduled_triggers_time = isset( $_POST['scheduled_triggers_time'] ) ? sanitize_text_field( $_POST['scheduled_triggers_time'] ) : ''; - $scheduled_triggers_enable = isset( $_POST['scheduled_triggers_enable'] ) ? sanitize_text_field( $_POST['scheduled_triggers_enable'] ) : ''; - $display_default_status_count = isset( $_POST['display_default_status_count'] ) ? sanitize_text_field( $_POST['display_default_status_count'] ) : ''; - $allow_agent_tickets = isset( $_POST['allow_agent_tickets'] ) ? sanitize_text_field( $_POST['allow_agent_tickets'] ) : ''; - $auto_suggestion = isset( $_POST['auto_suggestion'] ) ? sanitize_text_field( $_POST['auto_suggestion'] ) : ''; - $show_excerpt_in_auto_suggestion = isset( $_POST['show_excerpt_in_auto_suggestion'] ) ? sanitize_text_field( $_POST['show_excerpt_in_auto_suggestion'] ) : ''; - $auto_create_user = isset( $_POST['auto_create_user'] ) ? sanitize_text_field( $_POST['auto_create_user'] ) : ''; - $ticket_rows = isset( $_POST['ticket_rows'] ) ? sanitize_text_field( $_POST['ticket_rows'] ) : ''; - $custom_attachment = isset( $_POST['custom_attachment'] ) ? sanitize_text_field( $_POST['custom_attachment'] ) : ''; - $custom_attachment_path = isset( $_POST['custom_attachment_path'] ) ? sanitize_text_field( $_POST['custom_attachment_path'] ) : ''; - $max_file_size = isset( $_POST['max_file_size'] ) ? sanitize_text_field( $_POST['max_file_size'] ) : ''; - $tickets_display = isset( $_POST['tickets_display'] ) ? sanitize_text_field( $_POST['tickets_display'] ) : ''; - $ext = isset( $_POST['ext'] ) ? sanitize_text_field( $_POST['ext'] ) : ''; - $enable_api = isset( $_POST['enable_api'] ) ? sanitize_text_field( $_POST['enable_api'] ) : ''; - $api_key = isset( $_POST['api_key'] ) ? sanitize_text_field( $_POST['api_key'] ) : ''; - $default_deep_link = isset( $_POST['default_deep_link'] ) ? sanitize_text_field( $_POST['default_deep_link'] ) : ''; - $close_tickets = isset( $_POST['close_tickets'] ) ? sanitize_text_field( $_POST['close_tickets'] ) : ''; - $debug_status = isset( $_POST['debug_status'] ) ? sanitize_text_field( $_POST['debug_status'] ) : ''; - $wsdesk_powered_by_status = isset( $_POST['wsdesk_powered_by_status'] ) ? sanitize_text_field( $_POST['wsdesk_powered_by_status'] ) : ''; - $linkify_urls = isset( $_POST['linkify_urls'] ) ? sanitize_text_field( $_POST['linkify_urls'] ) : ''; - $ticket_display_hyperlink = isset( $_POST['ticket_display_hyperlink'] ) ? sanitize_text_field( $_POST['ticket_display_hyperlink'] ) : ''; - $wsdesk_mode = isset( $_POST['wsdesk_mode'] ) ? sanitize_text_field( $_POST['wsdesk_mode'] ) : ''; - $ticket_count_view = isset( $_POST['ticket_count_view'] ) ? sanitize_text_field( $_POST['ticket_count_view'] ) : ''; - $quick_view_tickets = isset( $_POST['quick_view_tickets'] ) ? sanitize_text_field( $_POST['quick_view_tickets'] ) : ''; - $refresh_ticket_page = isset( $_POST['refresh_ticket_page'] ) ? sanitize_text_field( $_POST['refresh_ticket_page'] ) : ''; - $pre_scheduled_triggers_time = eh_crm_get_settingsmeta( '0', 'scheduled_triggers_time' ); - - if ( ! empty( $pre_scheduled_triggers_time ) && $pre_scheduled_triggers_time != $scheduled_triggers_time ) { - $next_trigger_time = current_time( 'timestamp' ) + ( 3600 * $pre_scheduled_triggers_time ); - update_option( 'elex_last_scheduled_time', $next_trigger_time ); - } - - eh_crm_update_settingsmeta( '0', 'wsdesk_mode', $wsdesk_mode ); - eh_crm_update_settingsmeta( '0', 'scheduled_triggers_enable', $scheduled_triggers_enable ); - eh_crm_update_settingsmeta( '0', 'scheduled_triggers_time', $scheduled_triggers_time ); - eh_crm_update_settingsmeta( '0', 'ticket_count_view', $ticket_count_view ); - eh_crm_update_settingsmeta( '0', 'quick_view_tickets', $quick_view_tickets ); - eh_crm_update_settingsmeta( '0', 'refresh_ticket_page', $refresh_ticket_page ); - eh_crm_update_settingsmeta( '0', 'default_assignee', $default_assignee ); - eh_crm_update_settingsmeta( '0', 'default_label', $default_label ); - eh_crm_update_settingsmeta( '0', 'ticket_raiser', $ticket_raiser ); - eh_crm_update_settingsmeta( '0', 'auto_assign', $auto_assign ); - eh_crm_update_settingsmeta( '0', 'display_default_status_count', $display_default_status_count ); - eh_crm_update_settingsmeta( '0', 'auto_suggestion', $auto_suggestion ); - eh_crm_update_settingsmeta( '0', 'show_excerpt_in_auto_suggestion', $show_excerpt_in_auto_suggestion ); - eh_crm_update_settingsmeta( '0', 'auto_create_user', $auto_create_user ); - eh_crm_update_settingsmeta( '0', 'ticket_rows', $ticket_rows ); - eh_crm_update_settingsmeta( '0', 'custom_attachment_folder_enable', $custom_attachment ); - eh_crm_update_settingsmeta( '0', 'custom_attachment_folder_path', $custom_attachment_path ); - eh_crm_update_settingsmeta( '0', 'valid_file_extension', $ext ); - eh_crm_update_settingsmeta( '0', 'max_file_size', $max_file_size ); - eh_crm_update_settingsmeta( '0', 'enable_api', $enable_api ); - eh_crm_update_settingsmeta( '0', 'tickets_display', $tickets_display ); - eh_crm_update_settingsmeta( '0', 'api_key', $api_key ); - eh_crm_update_settingsmeta( '0', 'default_deep_link', $default_deep_link ); - eh_crm_update_settingsmeta( '0', 'close_tickets', $close_tickets ); - eh_crm_update_settingsmeta( '0', 'wsdesk_debug_status', $debug_status ); - eh_crm_update_settingsmeta( '0', 'wsdesk_powered_by_status', $wsdesk_powered_by_status ); - eh_crm_update_settingsmeta( '0', 'allow_agent_tickets', $allow_agent_tickets ); - eh_crm_update_settingsmeta( '0', 'linkify_urls', $linkify_urls ); - eh_crm_update_settingsmeta( '0', 'satisfaction_hyper_link', $ticket_display_hyperlink ); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_general.php'; - $my_html = ob_get_clean(); - wp_send_json_success( array( 'page' => $my_html ) ); - die; - } - - } - - public static function eh_crm_ticket_appearance() { - - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - - $input_width = isset( $_POST['input_width'] ) ? sanitize_text_field( $_POST['input_width'] ) : ''; - $main_ticket_title = isset( $_POST['main_ticket_title'] ) ? sanitize_text_field( $_POST['main_ticket_title'] ) : ''; - $new_ticket_title = isset( $_POST['new_ticket_title'] ) ? sanitize_text_field( $_POST['new_ticket_title'] ) : ''; - $existing_ticket_title = isset( $_POST['existing_ticket_title'] ) ? sanitize_text_field( $_POST['existing_ticket_title'] ) : ''; - $submit_ticket_button = isset( $_POST['submit_ticket_button'] ) ? sanitize_text_field( $_POST['submit_ticket_button'] ) : ''; - $reset_ticket_button = isset( $_POST['reset_ticket_button'] ) ? sanitize_text_field( $_POST['reset_ticket_button'] ) : ''; - $existing_ticket_button = isset( $_POST['existing_ticket_button'] ) ? sanitize_text_field( $_POST['existing_ticket_button'] ) : ''; - $purchase_credit_redirect_url = isset( $_POST['purchase_credit_redirect_url'] ) ? sanitize_text_field( $_POST['purchase_credit_redirect_url'] ) : ''; - $set_credit_limit = isset( $_POST['set_credit_limit'] ) ? sanitize_text_field( $_POST['set_credit_limit'] ) : ''; - $login_redirect_url = isset( $_POST['login_redirect_url'] ) ? sanitize_text_field( $_POST['login_redirect_url'] ) : ''; - $logout_redirect_url = isset( $_POST['logout_redirect_url'] ) ? sanitize_text_field( $_POST['logout_redirect_url'] ) : ''; - $register_redirect_url = isset( $_POST['register_redirect_url'] ) ? sanitize_text_field( $_POST['register_redirect_url'] ) : ''; - $submit_ticket_redirect_url = isset( $_POST['submit_ticket_redirect_url'] ) ? sanitize_text_field( $_POST['submit_ticket_redirect_url'] ) : ''; - $exisiting_tickets_login_label = isset( $_POST['exisiting_tickets_login_label'] ) ? sanitize_text_field( $_POST['exisiting_tickets_login_label'] ) : ''; - $exisiting_tickets_register_label = isset( $_POST['exisiting_tickets_register_label'] ) ? sanitize_text_field( $_POST['exisiting_tickets_register_label'] ) : ''; - $login_url = isset( $_POST['login_url'] ) ? sanitize_text_field( $_POST['login_url'] ) : ''; - $reg_url = isset( $_POST['reg_url'] ) ? sanitize_text_field( $_POST['reg_url'] ) : ''; - - eh_crm_update_settingsmeta( '0', 'exisiting_tickets_login_label', $exisiting_tickets_login_label ); - eh_crm_update_settingsmeta( '0', 'exisiting_tickets_register_label', $exisiting_tickets_register_label ); - eh_crm_update_settingsmeta( '0', 'login_redirect_url', $login_redirect_url ); - eh_crm_update_settingsmeta( '0', 'logout_redirect_url', $logout_redirect_url ); - eh_crm_update_settingsmeta( '0', 'login_url', $login_url ); - eh_crm_update_settingsmeta( '0', 'reg_url', $reg_url ); - eh_crm_update_settingsmeta( '0', 'register_redirect_url', $register_redirect_url ); - eh_crm_update_settingsmeta( '0', 'submit_ticket_redirect_url', $submit_ticket_redirect_url ); - eh_crm_update_settingsmeta( '0', 'input_width', $input_width ); - eh_crm_update_settingsmeta( '0', 'main_ticket_form_title', $main_ticket_title ); - eh_crm_update_settingsmeta( '0', 'new_ticket_form_title', $new_ticket_title ); - eh_crm_update_settingsmeta( '0', 'existing_ticket_title', $existing_ticket_title ); - eh_crm_update_settingsmeta( '0', 'submit_ticket_button', $submit_ticket_button ); - eh_crm_update_settingsmeta( '0', 'reset_ticket_button', $reset_ticket_button ); - eh_crm_update_settingsmeta( '0', 'existing_ticket_button', $existing_ticket_button ); - eh_crm_update_settingsmeta( '0', 'purchase_credit_redirect_url', $purchase_credit_redirect_url ); - eh_crm_update_settingsmeta( '0', 'set_credit_limit', $set_credit_limit ); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_appearance.php'; - wp_send_json_success( array( 'page' => ob_get_clean() ) ); - die; - } - } - - public static function eh_crm_woocommerce_settings() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $woo_order_tickets = isset( $_POST['woo_order_tickets'] ) ? sanitize_text_field( $_POST['woo_order_tickets'] ) : ''; - $woo_order_price = isset( $_POST['woo_order_price'] ) ? sanitize_text_field( $_POST['woo_order_price'] ) : ''; - $woo_order_access = explode( ',', isset( $_POST['woo_order_access'] ) ? sanitize_text_field( $_POST['woo_order_access'] ) : '' ); - if ( '' !== isset( $_POST['woo_vendor_roles'] ) ? sanitize_text_field( $_POST['woo_vendor_roles'] ) : '' ) { - $woo_vendor_roles = explode( ',', isset( $_POST['woo_vendor_roles'] ) ? sanitize_text_field( $_POST['woo_vendor_roles'] ) : '' ); - } else { - $woo_vendor_roles = array(); - } - - eh_crm_update_settingsmeta( '0', 'woo_order_tickets', $woo_order_tickets ); - eh_crm_update_settingsmeta( '0', 'woo_order_price', $woo_order_price ); - eh_crm_update_settingsmeta( '0', 'woo_order_access', $woo_order_access ); - eh_crm_update_settingsmeta( '0', 'woo_vendor_roles', $woo_vendor_roles ); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_woocommerce_settings.php'; - $data['page'] = ob_get_clean(); - wp_send_json_success( $data ); - die; - } - } - - public static function eh_crm_ticket_field_delete() { - - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - - $fields_remove = isset( $_POST['fields_remove'] ) ? sanitize_text_field( $_POST['fields_remove'] ) : ''; - $all_ticket_field_views = eh_crm_get_settingsmeta( '0', 'all_ticket_page_columns' ); - - $args = array( 'type' => 'field' ); - $fields = array( 'settings_id', 'slug' ); - $avail_fields = eh_crm_get_settings( $args, $fields ); - $selected_fields = eh_crm_get_settingsmeta( '0', 'selected_fields' ); - $key = array_search( $fields_remove, $selected_fields ); - $key1 = array_search( $fields_remove, $all_ticket_field_views ); - if ( false !== $key ) { - unset( $selected_fields[ $key ] ); - } - if ( false !== $key1 ) { - unset( $all_ticket_field_views[ $key ] ); - } - eh_crm_update_settingsmeta( '0', 'selected_fields', array_values( $selected_fields ) ); - eh_crm_update_settingsmeta( '0', 'all_ticket_page_columns', $all_ticket_field_views ); - for ( $i = 0; $i < count( $avail_fields ); $i++ ) { - if ( $avail_fields[ $i ]['slug'] == $fields_remove ) { - eh_crm_delete_settings( $avail_fields[ $i ]['settings_id'] ); - } - } - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_fields.php'; - $data['fields'] = ob_get_clean(); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_views.php'; - $data['views'] = ob_get_clean(); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_wsdesk_triggers.php'; - $data['triggers'] = ob_get_clean(); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_page.php'; - $data['page'] = ob_get_clean(); - die( - json_encode( $data ) - ); - } - } - - public static function eh_crm_ticket_field_activate_deactivate() { - - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - - $field_id = isset( $_POST['field_id'] ) ? sanitize_text_field( $_POST['field_id'] ) : ''; - $type = isset( $_POST['type'] ) ? sanitize_text_field( $_POST['type'] ) : ''; - $selected_fields = eh_crm_get_settingsmeta( '0', 'selected_fields' ); - switch ( $type ) { - case 'activate': - if ( ! in_array( $field_id, $selected_fields ) ) { - array_push( $selected_fields, $field_id ); - } - eh_crm_update_settingsmeta( '0', 'selected_fields', array_values( $selected_fields ) ); - break; - case 'deactivate': - $all_ticket_field_views = eh_crm_get_settingsmeta( '0', 'all_ticket_page_columns' ); - $key = array_search( $field_id, $all_ticket_field_views ); - $key1 = array_search( $field_id, $selected_fields ); - if ( false !== $key ) { - unset( $all_ticket_field_views[ $key ] ); - } - eh_crm_update_settingsmeta( '0', 'all_ticket_page_columns', $all_ticket_field_views ); - if ( false !== $key1 ) { - unset( $selected_fields[ $key1 ] ); - } - eh_crm_update_settingsmeta( '0', 'selected_fields', array_values( $selected_fields ) ); - break; - default: - break; - } - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_fields.php'; - $data['fields'] = ob_get_clean(); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_views.php'; - $data['views'] = ob_get_clean(); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_wsdesk_triggers.php'; - $data['triggers'] = ob_get_clean(); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_page.php'; - $data['page'] = ob_get_clean(); - die( - json_encode( $data ) - ); - } - } - - public static function eh_crm_ticket_field() { - - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - - $selected_fields = explode( ',', isset( $_POST['selected_fields'] ) ? sanitize_text_field( $_POST['selected_fields'] ) : '' ); - $new_field = json_decode( stripslashes( isset( $_POST['new_field'] ) ? sanitize_text_field( $_POST['new_field'] ) : '' ), true ); - if ( ! empty( $new_field ) ) { - $new_field['description'] = str_replace( '</script>', '', isset( $new_field['description'] ) ? sanitize_text_field( $new_field['description'] ) : '' ); - $new_field['description'] = str_replace( '<script>', '', isset( $new_field['description'] ) ? sanitize_text_field( $new_field['description'] ) : '' ); - } - $edit_field = json_decode( stripslashes( isset( $_POST['edit_field'] ) ? sanitize_text_field( $_POST['edit_field'] ) : '' ), true ); - $all_ticket_field_views = json_decode( stripslashes( isset( $_POST['all_tickets_view'] ) ? sanitize_text_field( $_POST['all_tickets_view'] ) : '' ), true ); - $args = array( 'type' => 'field' ); - $fields = array( 'settings_id', 'slug' ); - $temp = eh_crm_get_settings( $args, $fields ); - $slug = array(); - for ( $i = 0; $i < count( $temp ); $i++ ) { - $slug[ $i ] = $temp[ $i ]['slug']; - } - for ( $i = 0; $i < count( $selected_fields ); $i++ ) { - if ( ! in_array( $selected_fields[ $i ], $slug ) ) { - unset( $selected_fields[ $i ] ); - } - } - eh_crm_update_settingsmeta( '0', 'selected_fields', array_values( $selected_fields ) ); - eh_crm_update_settingsmeta( '0', 'all_ticket_field_views', $all_ticket_field_views ); - if ( ! empty( $new_field ) ) { - $insert = array( - 'title' => $new_field['title'], - 'filter' => 'no', - 'type' => 'field', - 'vendor' => '', - ); - switch ( $new_field['type'] ) { - case 'file': - $meta = array( - 'field_type' => $new_field['type'], - 'field_require' => $new_field['required'], - 'field_visible' => $new_field['visible'], - 'field_description' => $new_field['description'], - 'file_type' => $new_field['file_type'], - ); - eh_crm_insert_settings( $insert, $meta ); - break; - case 'text': - case 'number': - case 'email': - case 'password': - $meta = array( - 'field_type' => $new_field['type'], - 'field_default' => $new_field['default'], - 'field_require' => $new_field['required'], - 'field_visible' => $new_field['visible'], - 'field_require_agent' => $new_field['required_agent'], - 'field_placeholder' => $new_field['placeholder'], - 'field_description' => $new_field['description'], - ); - eh_crm_insert_settings( $insert, $meta ); - break; - case 'phone': - $meta = array( - 'field_type' => $new_field['type'], - 'field_default' => $new_field['default'], - 'field_require' => $new_field['required'], - 'field_visible' => $new_field['visible'], - 'field_require_agent' => $new_field['required_agent'], - 'field_placeholder' => $new_field['placeholder'], - 'field_description' => $new_field['description'], - ); - eh_crm_insert_settings( $insert, $meta, 'phone_number' ); - break; - case 'date': - $meta = array( - 'field_type' => $new_field['type'], - 'field_require' => $new_field['required'], - 'field_visible' => $new_field['visible'], - 'field_require_agent' => $new_field['required_agent'], - 'field_placeholder' => $new_field['placeholder'], - 'field_description' => $new_field['description'], - ); - eh_crm_insert_settings( $insert, $meta ); - break; - case 'checkbox': - case 'radio': - case 'select': - $meta = array( - 'field_type' => $new_field['type'], - 'field_require' => $new_field['required'], - 'field_visible' => $new_field['visible'], - 'field_require_agent' => $new_field['required_agent'], - 'field_description' => $new_field['description'], - ); - if ( 'select' === $new_field['type'] ) { - $meta['field_placeholder'] = $new_field['placeholder']; - } - $id = eh_crm_insert_settings( $insert, $meta ); - $args = array( 'settings_id' => $id ); - $fields = array( 'slug' ); - $data = eh_crm_get_settings( $args, $fields ); - $values = $new_field['values']; - $gen_val = array(); - $gen_def = ''; - for ( $i = 0; $i < count( $values ); $i++ ) { - $key = $data[0]['slug'] . '_V' . $i; - $gen_val[ $key ] = $values[ $i ]; - if ( $values[ $i ] == $new_field['default'] ) { - $gen_def = $key; - } - } - eh_crm_insert_settingsmeta( $id, 'field_default', $gen_def ); - eh_crm_insert_settingsmeta( $id, 'field_values', $gen_val ); - break; - case 'woo_product': - case 'woo_order_id': - case 'edd_products': - case 'woo_category': - case 'woo_tags': - case 'woo_vendors': - $meta = array( - 'field_type' => 'select', - 'field_require' => $new_field['required'], - 'field_visible' => $new_field['visible'], - 'field_require_agent' => $new_field['required_agent'], - 'field_description' => $new_field['description'], - 'field_placeholder' => $new_field['placeholder'], - ); - if ( 'woo_order_id' == $new_field['type'] ) { - $meta = array( - 'field_type' => 'select', - 'field_require' => $new_field['required'], - 'field_visible' => $new_field['visible'], - 'field_require_agent' => $new_field['required_agent'], - 'field_description' => $new_field['description'], - 'field_placeholder' => $new_field['placeholder'], - ); - } - $id = eh_crm_insert_settings( $insert, $meta, $new_field['type'] ); - $args = array( 'settings_id' => $id ); - $fields = array( 'slug' ); - $data = eh_crm_get_settings( $args, $fields ); - $values = $new_field['values']; - $gen_val = array(); - $gen_def = ''; - foreach ( $values as $key => $value ) { - $next_ran = 0; - if ( strpos( $key, 'new_add' ) !== false ) { - $key = $data[0]['slug'] . '_V' . $next_ran; - $gen_val[ $key ] = $value; - $next_ran++; - } else { - $gen_val[ $key ] = $value; - } - if ( $value == $new_field['default'] ) { - $gen_def = $key; - } - } - eh_crm_insert_settingsmeta( $id, 'field_default', $gen_def ); - eh_crm_insert_settingsmeta( $id, 'field_values', $gen_val ); - break; - case 'textarea': - $meta = array( - 'field_type' => $new_field['type'], - 'field_default' => $new_field['default'], - 'field_require' => $new_field['required'], - 'field_visible' => $new_field['visible'], - 'field_require_agent' => $new_field['required_agent'], - 'field_description' => $new_field['description'], - ); - eh_crm_insert_settings( $insert, $meta ); - break; - case 'ip': - $meta = array( - 'field_type' => $new_field['type'], - 'field_description' => $new_field['description'], - ); - eh_crm_insert_settings( $insert, $meta ); - break; - case 'google_captcha': - $meta = array( - 'field_type' => $new_field['type'], - 'field_site_key' => $new_field['site_key'], - 'field_secret_key' => $new_field['secret_key'], - 'field_require' => $new_field['required'], - 'field_description' => $new_field['description'], - ); - eh_crm_insert_settings( $insert, $meta, $new_field['type'] ); - break; - case 'pfs_order_product': - $meta = array( - 'field_type' => $new_field['type'], - 'field_require' => $new_field['required'], - 'field_visible' => $new_field['visible'], - 'field_require_agent' => $new_field['required_agent'], - 'field_description' => $new_field['description'], - ); - eh_crm_insert_settings( $insert, $meta ); - break; - } - } - if ( ! empty( $edit_field ) ) { - $edit_slug = $edit_field['slug']; - $edit_title = $edit_field['title']; - $edit_required = $edit_field['required']; - $edit_visible = $edit_field['visible']; - $edit_require_agent = $edit_field['required_agent']; - $edit_placeholder = $edit_field['placeholder']; - $edit_default = $edit_field['default']; - $edit_values = $edit_field['values']; - $edit_file_type = $edit_field['file_type']; - $edit_description = $edit_field['description']; - $field_data = eh_crm_get_settings( - array( - 'slug' => $edit_slug, - 'type' => 'field', - ), - 'settings_id' - ); - if ( ! empty( $field_data ) ) { - $field_id = $field_data[0]['settings_id']; - eh_crm_update_settings( - $field_id, - array( - 'title' => $edit_title, - 'filter' => 'no', - ) - ); - eh_crm_update_settingsmeta( $field_id, 'field_description', $edit_description ); - eh_crm_update_settingsmeta( $field_id, 'field_placeholder', $edit_placeholder ); - eh_crm_update_settingsmeta( $field_id, 'field_default', $edit_default ); - if ( '' !== $edit_required ) { - eh_crm_update_settingsmeta( $field_id, 'field_require', $edit_required ); - } - if ( '' !== $edit_file_type ) { - eh_crm_update_settingsmeta( $field_id, 'file_type', $edit_file_type ); - } - if ( '' !== $edit_visible ) { - eh_crm_update_settingsmeta( $field_id, 'field_visible', $edit_visible ); - } - if ( '' !== $edit_require_agent ) { - eh_crm_update_settingsmeta( $field_id, 'field_require_agent', $edit_require_agent ); - } - if ( '' !== $edit_values ) { - $gen_val_old = eh_crm_get_settingsmeta( $field_id, 'field_values' ); - $old_keys = array_keys( $gen_val_old ); - $gen_def = ''; - $gen_val = array(); - $next_ran = 0; - foreach ( $old_keys as $old_key ) { - $cur_ran = str_replace( $edit_slug . '_V', '', $old_key ); - if ( $cur_ran > $next_ran ) { - $next_ran = $cur_ran; - } - } - foreach ( $edit_values as $key => $value ) { - if ( in_array( $key, $old_keys ) ) { - $gen_val[ $key ] = $value; - } else { - $key = $edit_slug . '_V' . ( ++$next_ran ); - $gen_val[ $key ] = $value; - } - if ( $value == $edit_default ) { - $gen_def = $key; - } - } - eh_crm_update_settingsmeta( $field_id, 'field_default', $gen_def ); - eh_crm_update_settingsmeta( $field_id, 'field_values', $gen_val ); - if ( isset( $edit_field['field_order'] ) ) { - if ( count( $edit_field['field_order'] ) != count( $gen_val ) ) { - $new_fields = array_diff( array_keys( $gen_val ), $edit_field['field_order'] ); - $edit_field['field_order'] = array_merge( $edit_field['field_order'], $new_fields ); - } - eh_crm_update_settingsmeta( $field_id, 'field_order', array_values( array_unique( $edit_field['field_order'] ) ) ); - } - } - } - } - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_fields.php'; - $data['fields'] = ob_get_clean(); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_views.php'; - $data['views'] = ob_get_clean(); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_wsdesk_triggers.php'; - $data['triggers'] = ob_get_clean(); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_page.php'; - $data['page'] = ob_get_clean(); - die( - json_encode( $data ) - ); - } - } - - public static function eh_crm_woo_product_fetch() { - set_time_limit( 300 ); - $args_post = array( - 'orderby' => 'ID', - 'numberposts' => -1, - 'post_type' => array( 'product' ), - ); - $products = get_posts( $args_post ); - $return = array(); - $title = array(); - - for ( $i = 0;$i < count( $products );$i++ ) { - $return[ 'p_' . $products[ $i ]->ID ] = $products[ $i ]->post_title; - $title[] = $products[ $i ]->post_title; - } - sort( $title ); - $final_return = array(); - foreach ( $title as $value ) { - $key = array_search( $value, $return ); - $final_return[ $key ] = $value; - } - - die( json_encode( $final_return ) ); - } - - public static function eh_crm_get_edd_products() { - set_time_limit( 300 ); - $args_post = array( - 'orderby' => 'ID', - 'numberposts' => -1, - 'post_type' => array( 'download' ), - ); - $products = get_posts( $args_post ); - $return = array(); - for ( $i = 0;$i < count( $products );$i++ ) { - $return[ $i ]['id'] = 'p_' . $products[ $i ]->ID; - $return[ $i ]['title'] = $products[ $i ]->post_title; - } - die( json_encode( $return ) ); - } - public static function eh_crm_woo_category_fetch() { - set_time_limit( 300 ); - $cat_args = array( - 'hide_empty' => false, - 'order' => 'ASC', - ); - $categories = get_terms( 'product_cat', $cat_args ); - $return = array(); - for ( $i = 0;$i < count( $categories );$i++ ) { - $return[ $i ]['id'] = 'c_' . $categories[ $i ]->slug; - $return[ $i ]['title'] = $categories[ $i ]->name; - } - die( json_encode( $return ) ); - } - - public static function eh_crm_woo_tags_fetch() { - set_time_limit( 300 ); - $cat_args = array( - 'hide_empty' => false, - 'order' => 'ASC', - ); - $tags = get_terms( 'product_tag', $cat_args ); - $return = array(); - for ( $i = 0;$i < count( $tags );$i++ ) { - $return[ $i ]['id'] = 't_' . $tags[ $i ]->slug; - $return[ $i ]['title'] = $tags[ $i ]->name; - } - die( json_encode( $return ) ); - } - - public static function eh_crm_woo_vendors_fetch() { - set_time_limit( 300 ); - $vendors = eh_crm_get_settingsmeta( 0, 'woo_vendor_roles' ); - if ( $vendors ) { - $users_data = get_users( array( 'role__in' => $vendors ) ); - $return = array(); - for ( $i = 0;$i < count( $users_data );$i++ ) { - $current = $users_data[ $i ]; - $return[ $i ]['id'] = 'v_' . $current->ID; - $return[ $i ]['title'] = $current->data->display_name; - } - if ( empty( $return ) ) { - die( - json_encode( - array( - 'status' => 'no_roles', - 'data' => __( - 'No Vendors Found', - 'wsdesk' - ), - ) - ) - ); - } else { - die( - json_encode( - array( - 'status' => 'roles', - 'data' => $return, - ) - ) - ); - } - } else { - die( - json_encode( - array( - 'status' => 'no_roles', - 'data' => __( - 'No Vendors Roles defined!', - 'wsdesk' - ), - ) - ) - ); - } - } - - public static function eh_crm_ticket_field_edit() { - - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - - $field = isset( $_POST['field'] ) ? sanitize_text_field( $_POST['field'] ) : ''; - $args = array( - 'slug' => $field, - 'type' => 'field', - ); - $fields = array( 'settings_id', 'title', 'filter' ); - $field_sett = eh_crm_get_settings( $args, $fields ); - $field_meta = eh_crm_get_settingsmeta( $field_sett[0]['settings_id'] ); - $add_value = '<button class="button" id="ticket_field_edit_values_add" style="vertical-align: baseline;margin-bottom: 10px;">' . __( 'Add Value', 'wsdesk' ) . '</button>'; - $output = '<span class="help-block">' . __( 'Edit Details for custom', 'wsdesk' ) . ' ' . ucfirst( $field_meta['field_type'] ) . '? </span>'; - $output .= '<input type="text" id="ticket_field_edit_title" placeholder="' . __( 'Enter Title', 'wsdesk' ) . '" class="form-control crm-form-element-input" value="' . $field_sett[0]['title'] . '">'; - switch ( $field_meta['field_type'] ) { - case '': - break; - case 'file': - $required_end = ''; - if ( 'yes' == $field_meta['field_require'] ) { - $required_end = 'checked'; - } - $single = ''; - $multiple = ''; - if ( 'single' == $field_meta['file_type'] ) { - $multiple = ''; - $single = 'checked'; - } else { - $multiple = 'checked'; - $single = ''; - } - $visible = ''; - if ( isset( $field_meta['field_visible'] ) && 'yes' == $field_meta['field_visible'] ) { - $visible = 'checked'; - } - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_visible" class="form-control" name="ticket_field_edit_visible" ' . $visible . ' value="yes"> ' . __( 'Visible for End Users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_require" class="form-control" name="ticket_field_edit_require" ' . $required_end . ' value="yes"> ' . __( 'Mandatory for End users', 'wsdesk' ) . '</span>'; - $output .= '<br><span class="help-block">' . __( 'Specify whether this Field is Single or Multiple Attachment?', 'wsdesk' ) . ' </span><input type="radio" style="margin-top: 0;" id="ticket_field_edit_file_type" checked class="form-control" name="ticket_field_edit_file_type" ' . $single . ' value="single"> ' . __( 'Single Attachment', 'wsdesk' ) . ' <br><input type="radio" style="margin-top: 0;" id="ticket_field_edit_file_type" class="form-control" name="ticket_field_edit_file_type" ' . $multiple . ' value="multiple"> ' . __( 'Multiple Attachment', 'wsdesk' ) . ' <br>'; - $output .= '<br><span class="help-block">' . __( 'Want to update description to this field?', 'wsdesk' ) . ' </span><textarea id="ticket_field_edit_description" class="form-control crm-form-element-input" style="padding: 10px !important;">' . $field_meta['field_description'] . '</textarea>'; - break; - case 'radio': - $required_end = ''; - if ( 'yes' == $field_meta['field_require'] ) { - $required_end = 'checked'; - } - $required_agent = ''; - if ( isset( $field_meta['field_require_agent'] ) && 'yes' == $field_meta['field_require_agent'] ) { - $required_agent = 'checked'; - } - $visible = ''; - if ( isset( $field_meta['field_visible'] ) && 'yes' == $field_meta['field_visible'] ) { - $visible = 'checked'; - } - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_visible" class="form-control" name="ticket_field_edit_visible" ' . $visible . ' value="yes"> ' . __( 'Visible for End Users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_require" class="form-control" name="ticket_field_edit_require" ' . $required_end . ' value="yes"> ' . __( 'Mandatory for End users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_agent_require" class="form-control" name="ticket_field_edit_agent_require" ' . $required_agent . ' value="yes"> ' . __( 'Mandatory for Agents', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block">' . __( 'Update the Radio values!', 'wsdesk' ) . ' </span>'; - $field_values = array_values( $field_meta['field_values'] ); - $field_keys = array_keys( $field_meta['field_values'] ); - for ( $i = 0; $i < count( $field_values ); $i++ ) { - if ( 0 == $i ) { - $output .= '<span id="ticket_field_edit_values_span_' . $i . '" class="ticket_field_edit_values_span"><input type="text" id="ticket_field_edit_values[' . $i . ']" class="form-control ticket_field_edit_values crm-form-element-input" value="' . $field_values[ $i ] . '"><input type="hidden" class="old_ticket_field_edit_values[' . $i . ']" id="' . $field_keys[ $i ] . '" value="' . $field_values[ $i ] . '"></span>'; - } else { - $output .= '<span id="ticket_field_edit_values_span_' . $i . '" class="ticket_field_edit_values_span"><input type="text" id="ticket_field_edit_values[' . $i . ']" class="form-control ticket_field_edit_values crm-form-element-input" style="width:90% !important;" value="' . $field_values[ $i ] . '"><input type="hidden" class="old_ticket_field_edit_values[' . $i . ']" id="' . $field_keys[ $i ] . '" value="' . $field_values[ $i ] . '"><button class="btn btn-warning" title="' . __( 'Remove Values', 'wsdesk' ) . '" id="ticket_field_edit_values_remove" style="padding: 5px 8px;margin:0px 4px; vertical-align: baseline;"><span class="glyphicon glyphicon-minus"></span></button></span>'; - } - } - $output .= $add_value; - if ( '' == $field_meta['field_default'] ) { - $def = ''; - } else { - $def = ( isset( $field_meta['field_values'][ $field_meta['field_default'] ] ) ? $field_meta['field_values'][ $field_meta['field_default'] ] : '' ); - } - $output .= '<br>' . __( 'Enter Default Values', 'wsdesk' ) . '<input type="text" id="ticket_field_edit_default" class="form-control crm-form-element-input" value="' . $def . '">'; - $output .= '<br><span class="help-block">' . __( 'Want to update description to this field?', 'wsdesk' ) . ' </span><textarea id="ticket_field_edit_description" class="form-control crm-form-element-input" style="padding: 10px !important;">' . $field_meta['field_description'] . '</textarea>'; - break; - case 'checkbox': - $required_end = ''; - if ( 'yes' == $field_meta['field_require'] ) { - $required_end = 'checked'; - } - $required_agent = ''; - if ( isset( $field_meta['field_require_agent'] ) && 'yes' == $field_meta['field_require_agent'] ) { - $required_agent = 'checked'; - } - $visible = ''; - if ( isset( $field_meta['field_visible'] ) && 'yes' == $field_meta['field_visible'] ) { - $visible = 'checked'; - } - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_visible" class="form-control" name="ticket_field_edit_visible" ' . $visible . ' value="yes"> ' . __( 'Visible for End Users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_require" class="form-control" name="ticket_field_edit_require" ' . $required_end . ' value="yes"> ' . __( 'Mandatory for End users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_agent_require" class="form-control" name="ticket_field_edit_agent_require" ' . $required_agent . ' value="yes"> ' . __( 'Mandatory for Agents', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block">' . __( 'Update the Checkbox values!', 'wsdesk' ) . ' </span>'; - $field_values = array_values( $field_meta['field_values'] ); - $field_keys = array_keys( $field_meta['field_values'] ); - for ( $i = 0; $i < count( $field_values ); $i++ ) { - if ( 0 == $i ) { - $output .= '<span id="ticket_field_edit_values_span_' . $i . '" class="ticket_field_edit_values_span"><input type="text" id="ticket_field_edit_values[' . $i . ']" class="form-control ticket_field_edit_values crm-form-element-input" value="' . $field_values[ $i ] . '"><input type="hidden" class="old_ticket_field_edit_values[' . $i . ']" id="' . $field_keys[ $i ] . '" value="' . $field_values[ $i ] . '"></span>'; - } else { - $output .= '<span id="ticket_field_edit_values_span_' . $i . '" class="ticket_field_edit_values_span"><input type="text" id="ticket_field_edit_values[' . $i . ']" class="form-control ticket_field_edit_values crm-form-element-input" style="width:90% !important;" value="' . $field_values[ $i ] . '"><input type="hidden" class="old_ticket_field_edit_values[' . $i . ']" id="' . $field_keys[ $i ] . '" value="' . $field_values[ $i ] . '"><button class="btn btn-warning" title="' . __( 'Remove Values', 'wsdesk' ) . '" id="ticket_field_edit_values_remove" style="padding: 5px 8px;margin:0px 4px; vertical-align: baseline;"><span class="glyphicon glyphicon-minus"></span></button></span>'; - } - } - $output .= $add_value; - if ( '' == $field_meta['field_default'] ) { - $def = ''; - } else { - $def = ( isset( $field_meta['field_values'][ $field_meta['field_default'] ] ) ? $field_meta['field_values'][ $field_meta['field_default'] ] : '' ); - } - $output .= '<br>' . __( 'Enter Default Values', 'wsdesk' ) . '<input type="text" id="ticket_field_edit_default" class="form-control crm-form-element-input" value="' . $def . '">'; - $output .= '<br><span class="help-block">' . __( 'Want to update description to this field?', 'wsdesk' ) . ' </span><textarea id="ticket_field_edit_description" class="form-control crm-form-element-input" style="padding: 10px !important;">' . $field_meta['field_description'] . '</textarea>'; - break; - case 'select': - $required_end = ''; - if ( 'yes' == $field_meta['field_require'] ) { - $required_end = 'checked'; - } - $required_agent = ''; - if ( isset( $field_meta['field_require_agent'] ) && 'yes' == $field_meta['field_require_agent'] ) { - $required_agent = 'checked'; - } - $visible = ''; - if ( isset( $field_meta['field_visible'] ) && 'yes' == $field_meta['field_visible'] ) { - $visible = 'checked'; - } - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_visible" class="form-control" name="ticket_field_edit_visible" ' . $visible . ' value="yes"> ' . __( 'Visible for End Users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_require" class="form-control" name="ticket_field_edit_require" ' . $required_end . ' value="yes"> ' . __( 'Mandatory for End users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_agent_require" class="form-control" name="ticket_field_edit_agent_require" ' . $required_agent . ' value="yes"> ' . __( 'Mandatory for Agents', 'wsdesk' ) . '</span>'; - $output .= '<br>' . __( 'Enter Placeholder', 'wsdesk' ) . '<input type="text" id="ticket_field_edit_placeholder" class="form-control crm-form-element-input" value="' . ( isset( $field_meta['field_placeholder'] ) ? $field_meta['field_placeholder'] : '' ) . '">'; - if ( 'woo_order_id' != $args['slug'] ) { - $output .= '<span class="help-block">' . __( 'Update the Dropdown values!', 'wsdesk' ) . ' </span>'; - $field_values = array_values( $field_meta['field_values'] ); - $field_keys = array_keys( $field_meta['field_values'] ); - for ( $i = 0; $i < count( $field_values ); $i++ ) { - if ( 0 == $i ) { - if ( in_array( $field, array( 'woo_product', 'woo_category', 'woo_tags', 'edd_products' ) ) ) { - $output .= '<span id="ticket_field_edit_values_span_' . $i . '" class="ticket_field_edit_values_span"><input type="text" id="ticket_field_edit_values[' . $i . ']" class="form-control ticket_field_edit_values crm-form-element-input" style="width:90% !important;" value="' . $field_values[ $i ] . '"><input type="hidden" class="old_ticket_field_edit_values[' . $i . ']" id="' . $field_keys[ $i ] . '" value="' . $field_values[ $i ] . '"><button class="btn btn-warning" title="' . __( 'Remove Values', 'wsdesk' ) . '" id="ticket_field_edit_values_remove" style="padding: 5px 8px;margin:0px 4px; vertical-align: baseline;"><span class="glyphicon glyphicon-minus"></span></button></span>'; - } else { - $output .= '<span id="ticket_field_edit_values_span_' . $i . '" class="ticket_field_edit_values_span"><input type="text" id="ticket_field_edit_values[' . $i . ']" class="form-control ticket_field_edit_values crm-form-element-input" value="' . $field_values[ $i ] . '"><input type="hidden" class="old_ticket_field_edit_values[' . $i . ']" id="' . $field_keys[ $i ] . '" value="' . $field_values[ $i ] . '"></span>'; - } - } else { - $output .= '<span id="ticket_field_edit_values_span_' . $i . '" class="ticket_field_edit_values_span"><input type="text" id="ticket_field_edit_values[' . $i . ']" class="form-control ticket_field_edit_values crm-form-element-input" style="width:90% !important;" value="' . $field_values[ $i ] . '"><input type="hidden" class="old_ticket_field_edit_values[' . $i . ']" id="' . $field_keys[ $i ] . '" value="' . $field_values[ $i ] . '"><button class="btn btn-warning" title="' . __( 'Remove Values', 'wsdesk' ) . '" id="ticket_field_edit_values_remove" style="padding: 5px 8px;margin:0px 4px; vertical-align: baseline;"><span class="glyphicon glyphicon-minus"></span></button></span>'; - } - } - } - if ( 'woo_order_id' != $args['slug'] ) { - $output .= $add_value; - } - if ( '' == $field_meta['field_default'] ) { - $def = ''; - } else { - $def = ( isset( $field_meta['field_values'][ $field_meta['field_default'] ] ) ? $field_meta['field_values'][ $field_meta['field_default'] ] : '' ); - } - if ( 'woo_order_id' == $args['slug'] ) { - $output .= '<input type="hidden" id="ticket_field_edit_default" class="form-control crm-form-element-input" value="' . $def . '">'; - } else { - $output .= '<br>' . __( 'Enter Default Values', 'wsdesk' ) . '<input type="text" id="ticket_field_edit_default" class="form-control crm-form-element-input" value="' . $def . '">'; - } - $output .= '<br><span class="help-block">' . __( 'Want to update description to this field?', 'wsdesk' ) . ' </span><textarea id="ticket_field_edit_description" class="form-control crm-form-element-input" style="padding: 10px !important;">' . $field_meta['field_description'] . '</textarea>'; - - $output .= '<br><span class="help-block">' . __( 'Rearrange the options for front end', 'wsdesk' ) . ' </span><select class="dropdown_options_order" id="dropdown_options_order_' . $args['slug'] . '" name="dropdown_options_order[]" size="6" style="width: 300px;height:auto;min-height:150px;" >'; - $field_order = isset( $field_meta['field_order'] ) ? array_values( array_unique( $field_meta['field_order'] ) ) : ( isset( $field_keys ) ? $field_keys : array() ); - $field_order = array_intersect( $field_order, array_keys( $field_meta['field_values'] ) ); - - foreach ( $field_order as $key ) { - $output .= '<option value="' . $key . '" >' . $field_meta['field_values'][ $key ] . '</option>'; - } - - $output .= '</select>'; - $output .= '<br><br><div><button class="button dropdown-order-up" id="' . $args['slug'] . '" >UP </button> '; - $output .= '<button class="button dropdown-order-down" id="' . $args['slug'] . '">DOWN</button></div>'; - break; - case 'textarea': - if ( 'request_description' != $field ) { - $required_end = ''; - if ( 'yes' == $field_meta['field_require'] ) { - $required_end = 'checked'; - } - $required_agent = ''; - if ( isset( $field_meta['field_require_agent'] ) && 'yes' == $field_meta['field_require_agent'] ) { - $required_agent = 'checked'; - } - $visible = ''; - if ( isset( $field_meta['field_visible'] ) && 'yes' == $field_meta['field_visible'] ) { - $visible = 'checked'; - } - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_visible" class="form-control" name="ticket_field_edit_visible" ' . $visible . ' value="yes"> ' . __( 'Visible for End Users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_require" class="form-control" name="ticket_field_edit_require" ' . $required_end . ' value="yes"> ' . __( 'Mandatory for End users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_agent_require" class="form-control" name="ticket_field_edit_agent_require" ' . $required_agent . ' value="yes"> ' . __( 'Mandatory for Agents', 'wsdesk' ) . '</span>'; - } - $output .= '<br>' . __( 'Enter Default Values', 'wsdesk' ) . '<input type="text" id="ticket_field_edit_default" class="form-control crm-form-element-input" value="' . $field_meta['field_default'] . '">'; - $output .= '<br><span class="help-block">' . __( 'Want to update description to this field?', 'wsdesk' ) . ' </span><textarea id="ticket_field_edit_description" class="form-control crm-form-element-input" style="padding: 10px !important;">' . $field_meta['field_description'] . '</textarea>'; - break; - case 'date': - $required_end = ''; - if ( 'yes' == $field_meta['field_require'] ) { - $required_end = 'checked'; - } - $required_agent = ''; - if ( isset( $field_meta['field_require_agent'] ) && 'yes' == $field_meta['field_require_agent'] ) { - $required_agent = 'checked'; - } - $visible = ''; - if ( isset( $field_meta['field_visible'] ) && 'yes' == $field_meta['field_visible'] ) { - $visible = 'checked'; - } - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_visible" class="form-control" name="ticket_field_edit_visible" ' . $visible . ' value="yes"> ' . __( 'Visible for End Users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_require" class="form-control" name="ticket_field_edit_require" ' . $required_end . ' value="yes"> ' . __( 'Mandatory for End users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_agent_require" class="form-control" name="ticket_field_edit_agent_require" ' . $required_agent . ' value="yes"> ' . __( 'Mandatory for Agents', 'wsdesk' ) . '</span>'; - $output .= '<br>' . __( 'Enter Placeholder', 'wsdesk' ) . '<input type="text" id="ticket_field_edit_placeholder" class="form-control crm-form-element-input" value="' . $field_meta['field_placeholder'] . '">'; - $output .= '<br><span class="help-block">' . __( 'Want to update description to this field?', 'wsdesk' ) . ' </span><textarea id="ticket_field_edit_description" class="form-control crm-form-element-input" style="padding: 10px !important;">' . $field_meta['field_description'] . '</textarea>'; - break; - case 'ip': - $output .= '<br><span class="help-block">' . __( 'Want to update description to this field?', 'wsdesk' ) . ' </span><textarea id="ticket_field_edit_description" class="form-control crm-form-element-input" style="padding: 10px !important;">' . $field_meta['field_description'] . '</textarea>'; - break; - case 'pfs_order_product': - $required_end = ''; - if ( 'yes' == $field_meta['field_require'] ) { - $required_end = 'checked'; - } - $required_agent = ''; - if ( isset( $field_meta['field_require_agent'] ) && 'yes' == $field_meta['field_require_agent'] ) { - $required_agent = 'checked'; - } - $visible = ''; - if ( isset( $field_meta['field_visible'] ) && 'yes' == $field_meta['field_visible'] ) { - $visible = 'checked'; - } - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_visible" class="form-control" name="ticket_field_edit_visible" ' . $visible . ' value="yes"> ' . __( 'Visible for End Users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_require" class="form-control" name="ticket_field_edit_require" ' . $required_end . ' value="yes"> ' . __( 'Mandatory for End users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_agent_require" class="form-control" name="ticket_field_edit_agent_require" ' . $required_agent . ' value="yes"> ' . __( 'Mandatory for Agents', 'wsdesk' ) . '</span>'; - $output .= '<br><span class="help-block">' . __( 'Want to update description to this field?', 'wsdesk' ) . ' </span><textarea id="ticket_field_edit_description" class="form-control crm-form-element-input" style="padding: 10px !important;">' . $field_meta['field_description'] . '</textarea>'; - break; - default: - if ( 'request_email' != $field && 'request_title' != $field ) { - $required_end = ''; - if ( 'yes' == $field_meta['field_require'] ) { - $required_end = 'checked'; - } - $required_agent = ''; - if ( isset( $field_meta['field_require_agent'] ) && 'yes' == $field_meta['field_require_agent'] ) { - $required_agent = 'checked'; - } - $visible = ''; - if ( isset( $field_meta['field_visible'] ) && 'yes' == $field_meta['field_visible'] ) { - $visible = 'checked'; - } - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_visible" class="form-control" name="ticket_field_edit_visible" ' . $visible . ' value="yes"> ' . __( 'Visible for End Users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_require" class="form-control" name="ticket_field_edit_require" ' . $required_end . ' value="yes"> ' . __( 'Mandatory for End users', 'wsdesk' ) . '</span>'; - $output .= '<span class="help-block"><input type="checkbox" style="margin-top: 0;" id="ticket_field_edit_agent_require" class="form-control" name="ticket_field_edit_agent_require" ' . $required_agent . ' value="yes"> ' . __( 'Mandatory for Agents', 'wsdesk' ) . '</span>'; - } - $output .= '<br>' . __( 'Enter Placeholder', 'wsdesk' ) . '<input type="text" id="ticket_field_edit_placeholder" class="form-control crm-form-element-input" value="' . $field_meta['field_placeholder'] . '">'; - $output .= '<br>' . __( 'Enter Default Values', 'wsdesk' ) . '<input type="text" id="ticket_field_edit_default" class="form-control crm-form-element-input" value="' . $field_meta['field_default'] . '">'; - $output .= '<br><span class="help-block">' . __( 'Want to update description to this field?', 'wsdesk' ) . ' </span><textarea id="ticket_field_edit_description" class="form-control crm-form-element-input" style="padding: 10px !important;">' . $field_meta['field_description'] . '</textarea>'; - break; - } - wp_send_json_success( array( 'page' => $output ) ); - die; - } - } - - public static function eh_crm_ticket_label_delete() { - - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - - $label_remove = isset( $_POST['label_remove'] ) ? sanitize_text_field( $_POST['label_remove'] ) : ''; - $args = array( 'type' => 'label' ); - $fields = array( 'settings_id', 'slug' ); - $avail_labels = eh_crm_get_settings( $args, $fields ); - for ( $i = 0; $i < count( $avail_labels ); $i++ ) { - if ( $avail_labels[ $i ]['slug'] == $label_remove ) { - eh_crm_delete_settings( $avail_labels[ $i ]['settings_id'] ); - } - } - - $default_label = eh_crm_get_settingsmeta( '0', 'default_label' ); - if ( $default_label === $label_remove ) { - eh_crm_update_settingsmeta( '0', 'default_label', 'label_LL01' ); - } - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_labels.php'; - $data['labels'] = ob_get_clean(); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_views.php'; - $data['views'] = ob_get_clean(); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_wsdesk_triggers.php'; - $data['triggers'] = ob_get_clean(); - die( - json_encode( $data ) - ); - } - } - - public static function eh_crm_ticket_label() { - - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - - $new_label = json_decode( stripslashes( isset( $_POST['new_label'] ) ? sanitize_text_field( $_POST['new_label'] ) : '' ), true ); - $edit_label = json_decode( stripslashes( isset( $_POST['edit_label'] ) ? sanitize_text_field( $_POST['edit_label'] ) : '' ), true ); - if ( ! empty( $new_label ) ) { - $insert = array( - 'title' => $new_label['title'], - 'filter' => $new_label['filter'], - 'type' => 'label', - 'vendor' => '', - ); - $meta = array( - 'label_color' => $new_label['color'], - ); - eh_crm_insert_settings( $insert, $meta ); - } - if ( ! empty( $edit_label ) ) { - $edit_slug = $edit_label['slug']; - $edit_title = $edit_label['title']; - $edit_filter = $edit_label['filter']; - $edit_color = $edit_label['color']; - $label_data = eh_crm_get_settings( - array( - 'slug' => $edit_slug, - 'type' => 'label', - ), - 'settings_id' - ); - $label_id = $label_data[0]['settings_id']; - eh_crm_update_settings( - $label_id, - array( - 'title' => $edit_title, - 'filter' => $edit_filter, - ) - ); - eh_crm_update_settingsmeta( $label_id, 'label_color', $edit_color ); - } - ob_start(); - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_labels.php';
Vulnerability Existed: yes
FALSE POSITIVE
Improper Input Validation and Sanitization - CWE-20 - includes/class-crm-ajax-functions-one.php - Lines 14-45
Old Code:
```php
if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) {
$default_assignee = isset( $_POST['default_assignee'] ) ? sanitize_text_field( $_POST['default_assignee'] ) : '';
$default_label = isset( $_POST['default_label'] ) ? sanitize_text_field( $_POST['default_label'] ) : '';
$ticket_raiser = isset( $_POST['ticket_raiser'] ) ? sanitize_text_field( $_POST['ticket_raiser'] ) : '';
...
$custom_attachment_path = isset( $_POST['custom_attachment_path'] ) ? sanitize_text_field( $_POST['custom_attachment_path'] ) : '';
```
Fixed Code:
```php
if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) {
$default_assignee = isset( $_POST['default_assignee'] ) ? sanitize_text_field( $_POST['default_assignee'] ) : '';
$default_label = isset( $_POST['default_label'] ) ? sanitize_text_field( $_POST['default_label'] ) : '';
$ticket_raiser = isset( $_POST['ticket_raiser'] ) ? sanitize_text_field( $_POST['ticket_raiser'] ) : '';
...
$custom_attachment_path = isset( $_POST['custom_attachment_path'] ) ? sanitize_text_field( $_POST['custom_attachment_path'] ) : '';
```
Explanation:
The code uses `sanitize_text_field()` for most inputs, which is appropriate for general text sanitization. However, for file paths like `$custom_attachment_path`, using only `sanitize_text_field()` is insufficient. Path traversal attacks could be possible if the path is used in file operations without additional validation (e.g., checking against path traversal sequences like `../`). The diff shows no changes to how this input is sanitized, meaning the vulnerability pattern persists - file paths should be validated against directory traversal attacks using `wp_safe_remote_get()`, path normalization, or whitelist validation before being used in file operations.
---
Vulnerability Existed: not sure
Cross-Site Scripting (XSS) - CWE-79 - includes/class-crm-ajax-functions-one.php - Lines 390-391
Old Code:
```php
$new_field['description'] = str_replace( '</script>', '', isset( $new_field['description'] ) ? sanitize_text_field( $new_field['description'] ) : '' );
$new_field['description'] = str_replace( '<script>', '', isset( $new_field['description'] ) ? sanitize_text_field( $new_field['description'] ) : '' );
```
Fixed Code:
```php
$new_field['description'] = str_replace( '</script>', '', isset( $new_field['description'] ) ? sanitize_text_field( $new_field['description'] ) : '' );
$new_field['description'] = str_replace( '<script>', '', isset( $new_field['description'] ) ? sanitize_text_field( $new_field['description'] ) : '' );
```
Explanation:
The code attempts to prevent XSS by stripping `<script>` and `</script>` tags. However, this is an incomplete defense. The diff shows no change in this approach. There are many other XSS vectors (event handlers like `onerror="`, `onclick="`, HTML tags like `<img>`, `<svg>`, etc.) that are not blocked by this simple string replacement. The code should use `wp_kses_post()` or `wp_kses_data()` for HTML sanitization instead of manual tag stripping. The vulnerability may or may not exist depending on where `$new_field['description']` is ultimately used - if it's output in HTML context without proper escaping, XSS is possible.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-ajax-functions-three.php 2025-12-21 09:35:59.417065320 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-ajax-functions-three.php 2025-12-21 09:36:35.227291036 +0000@@ -1,2457 +1,2457 @@-<?php -require __DIR__ . '/class-crm-ajax-functions-two.php'; - -class CRM_Ajax_Three extends CRM_Ajax_Two { - - public static function eh_crm_ticket_refresh_right_bar() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $search_page = ( isset( $_POST['cur'] ) ) ? sanitize_text_field( $_POST['cur'] ) : 1; - $active = isset( $_POST['active'] ) ? sanitize_text_field( $_POST['active'] ) : 'all'; - $order = isset( $_POST['order'] ) ? sanitize_text_field( $_POST['order'] ) : 'DESC'; - $order_by = isset( $_POST['order_by'] ) ? sanitize_text_field( $_POST['order_by'] ) : 'ticket_updated'; - $current_page_no = ( isset( $_POST['current_page'] ) ) ? sanitize_text_field( $_POST['current_page'] ) : 0; - $current_page_n = ( isset( $_POST['current_pa'] ) ) ? sanitize_text_field( $_POST['current_pa'] ) : "$search_page"; - $pagination = isset( $_POST['pagination_type'] ) ? sanitize_text_field( $_POST['pagination_type'] ) : ''; - $avail_labels_wf = eh_crm_get_settings( array( 'type' => 'label' ), array( 'slug', 'title', 'settings_id' ) ); - $avail_labels = eh_crm_get_settings( - array( - 'type' => 'label', - 'filter' => 'yes', - ), - array( 'slug', 'title', 'settings_id' ) - ); - $avail_tags_wf = eh_crm_get_settings( array( 'type' => 'tag' ), array( 'slug', 'title', 'settings_id' ) ); - $avail_tags = eh_crm_get_settings( - array( - 'type' => 'tag', - 'filter' => 'yes', - ), - array( 'slug', 'title', 'settings_id' ) - ); - $avail_views = eh_crm_get_settings( array( 'type' => 'view' ), array( 'slug', 'title', 'settings_id' ) ); - $user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ); - $users = get_users( array( 'role__in' => $user_roles_default ) ); - $users_data = array(); - $tickets_display = eh_crm_get_settingsmeta( '0', 'tickets_display' ); - $users_count = count( $users ); - for ( $i = 0; $i < $users_count; $i++ ) { - $current = $users[ $i ]; - $id = $current->ID; - $user = new WP_User( $id ); - $users_data[ $i ]['id'] = $id; - $users_data[ $i ]['name'] = $user->display_name; - $users_data[ $i ]['caps'] = $user->caps; - $users_data[ $i ]['email'] = $user->user_email; - } - $ticket_rows = eh_crm_get_settingsmeta( 0, 'ticket_rows' ); - if ( '' == $ticket_rows ) { - $ticket_rows = 25; - } - $current_page = $current_page_no; - $offset = ( $current_page ) * $ticket_rows; - if ( '' != $pagination ) { - switch ( $pagination ) { - case 'current_page_n': - if ( '' != $current_page_n ) { - $current_page_n = $current_page_n --; - $total = count( eh_crm_get_ticket_value_count( 'ticket_parent', 0 ) ); - if ( 0 == $ticket_rows % 2 ) { - if ( $current_page_n <= ( $total / $ticket_rows ) - 1 ) { - - $current_pa = $current_page_n * $ticket_rows; - $current_page = $current_page_n; - $offset = $current_pa; - - } else { - $last_page = ( $total / $ticket_rows ); - if ( is_float( $last_page ) ) { - $last_page = $last_page ++; - } - - $current_page = intval( $last_page ); - $current_page = $current_page --; - - $offset = ( $current_page ) * $ticket_rows; - break; - } - } - if ( 0 != $ticket_rows % 2 ) { - if ( $current_page_n <= intval( $total / $ticket_rows ) - 1 ) { - $current_pa = $current_page_n * $ticket_rows; - $current_page = $current_page_n; - $offset = $current_pa; - } else { - $last_page = $total / $ticket_rows; - $current_page = intval( $last_page ); - $current_page = $current_page; - $offset = ( $current_page ) * $ticket_rows; - break; - } - } - } else { - - $offset = $current_page * $ticket_rows; - $current_page = $current_page_no; - } - break; - case 'prev': - $current_page = $current_page_no - 1; - $offset = ( $current_page * $ticket_rows ); - break; - case 'next': - $current_page = $current_page_no + 1; - $offset = ( $current_page * $ticket_rows ); - break; - } - } - - switch ( $active ) { - - case 'all': - $table_title = esc_html__( ' All Tickets ', 'wsdesk' ); - $total_count = count( eh_crm_get_ticket_value_count( 'ticket_parent', 0 ) ); - $section_tickets_id = eh_crm_get_ticket_value_count( 'ticket_parent', 0, false, '', '', $order_by, $order, $ticket_rows, $offset ); - $all_section_ids = eh_crm_get_ticket_value_count( 'ticket_parent', 0, false, '', '', $order_by, $order, '', 0 ); - $data_to_be_display = $all_section_ids; - - // Agent ticket view section control :-) - $user_id_agent = get_current_user_id(); - $user_id_agent_details = get_user_by( 'ID', $user_id_agent ); - $user_id_agent_role = $user_id_agent_details->roles; - $allow_agent_tickets = eh_crm_get_settingsmeta( '0', 'allow_agent_tickets' ); - if ( 'enable' != $allow_agent_tickets ) { - if ( in_array( 'WSDesk_Agents', $user_id_agent_role ) ) { - $active = $user_id_agent; - $total_count_ = count( eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, 'ticket_id' ) ); - $section_tickets_id_ = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, $ticket_rows, $offset ); - $all_section_ids_ = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, 0, 0 ); - $all_section_ids = array(); - $section_tickets_id = array(); - foreach ( $all_section_ids_ as $key => $value ) { - if ( in_array( $value, $data_to_be_display ) ) { - $all_section_ids[] = $value; - $section_tickets_id[] = $value; - } - } - $total_count = count( $section_tickets_id ); - } - } - - break; - case 'registeredU': - $table_title = esc_html__( 'Registered Users Tickets', 'wsdesk' ); - $total_count = count( eh_crm_get_ticket_value_count( 'ticket_author', 0, true, 'ticket_parent', 0 ) ); - $section_tickets_id = eh_crm_get_ticket_value_count( 'ticket_author', 0, true, 'ticket_parent', 0, $order_by, $order, $ticket_rows, $offset ); - $all_section_ids = eh_crm_get_ticket_value_count( 'ticket_author', 0, true, 'ticket_parent', 0, $order_by, $order, '', 0 ); - $data_to_be_display = $all_section_ids; - - // Agent ticket view section control :-) - $user_id_agent = get_current_user_id(); - $user_id_agent_details = get_user_by( 'ID', $user_id_agent ); - $user_id_agent_role = $user_id_agent_details->roles; - $allow_agent_tickets = eh_crm_get_settingsmeta( '0', 'allow_agent_tickets' ); - if ( 'enable' != $allow_agent_tickets ) { - if ( in_array( 'WSDesk_Agents', $user_id_agent_role ) ) { - $active = $user_id_agent; - $total_count_ = count( eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, 'ticket_id' ) ); - $section_tickets_id_ = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, $ticket_rows, $offset ); - $all_section_ids_ = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, 0, 0 ); - $all_section_ids = array(); - $section_tickets_id = array(); - foreach ( $all_section_ids_ as $key => $value ) { - if ( in_array( $value, $data_to_be_display ) ) { - $all_section_ids[] = $value; - $section_tickets_id[] = $value; - } - } - $total_count = count( $section_tickets_id ); - } - } - break; - case 'guestU': - $table_title = esc_html__( 'Guest Users Tickets', 'wsdesk' ); - $total_count = count( eh_crm_get_ticket_value_count( 'ticket_author', 0, false, 'ticket_parent', 0 ) ); - $section_tickets_id = eh_crm_get_ticket_value_count( 'ticket_author', 0, false, 'ticket_parent', 0, $order_by, $order, $ticket_rows, $offset ); - $all_section_ids = eh_crm_get_ticket_value_count( 'ticket_author', 0, false, 'ticket_parent', 0, $order_by, $order, '', 0 ); - $data_to_be_display = $all_section_ids; - - // Agent ticket view section control :-) - $user_id_agent = get_current_user_id(); - $user_id_agent_details = get_user_by( 'ID', $user_id_agent ); - $user_id_agent_role = $user_id_agent_details->roles; - $allow_agent_tickets = eh_crm_get_settingsmeta( '0', 'allow_agent_tickets' ); - if ( 'enable' != $allow_agent_tickets ) { - if ( in_array( 'WSDesk_Agents', $user_id_agent_role ) ) { - $active = $user_id_agent; - $total_count_ = count( eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, 'ticket_id' ) ); - $section_tickets_id_ = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, $ticket_rows, $offset ); - $all_section_ids_ = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, 0, 0 ); - $all_section_ids = array(); - $section_tickets_id = array(); - foreach ( $all_section_ids_ as $key => $value ) { - if ( in_array( $value, $data_to_be_display ) ) { - $all_section_ids[] = $value; - $section_tickets_id[] = $value; - } - } - $total_count = count( $section_tickets_id ); - } - } - - break; - case 'unassigned': - $table_title = esc_html__( 'Unassigned Tickets', 'wsdesk' ); - $total_count = count( eh_crm_get_ticketmeta_value_count( 'ticket_assignee', array(), 'ticket_id' ) ); - $section_tickets_id = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', array(), $order_by, $order, $ticket_rows, $offset ); - $all_section_ids = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', array(), $order_by, $order, 0, 0 ); - - break; - default: - if ( false !== strpos( $active, 'label_' ) ) { - for ( $i = 0;$i < count( $avail_labels );$i++ ) { - if ( $avail_labels[ $i ]['slug'] == $active ) { - - $table_title = $avail_labels[ $i ]['title']; - } - } - if ( empty( $table_title ) ) { - - $table_title = '(Incorrect Deep Link)'; - } - $table_title = $table_title . ' Tickets'; - - $total_count = count( eh_crm_get_ticketmeta_value_count( 'ticket_label', $active, 'ticket_id' ) ); - $section_tickets_id = eh_crm_get_ticketmeta_value_count( 'ticket_label', $active, $order_by, $order, $ticket_rows, $offset ); - $all_section_ids = eh_crm_get_ticketmeta_value_count( 'ticket_label', $active, $order_by, $order, 0, 0 ); - $data_to_be_display = $all_section_ids; - - // Agent ticket view section control :-) - $user_id_agent = get_current_user_id(); - $user_id_agent_details = get_user_by( 'ID', $user_id_agent ); - $user_id_agent_role = $user_id_agent_details->roles; - $allow_agent_tickets = eh_crm_get_settingsmeta( '0', 'allow_agent_tickets' ); - if ( 'enable' != $allow_agent_tickets ) { - if ( in_array( 'WSDesk_Agents', $user_id_agent_role ) ) { - $active = $user_id_agent; - $total_count_ = count( eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, 'ticket_id' ) ); - $section_tickets_id_ = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, $ticket_rows, $offset ); - $all_section_ids_ = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, 0, 0 ); - $all_section_ids = array(); - $section_tickets_id = array(); - foreach ( $all_section_ids_ as $key => $value ) { - if ( in_array( $value, $data_to_be_display ) ) { - $all_section_ids[] = $value; - $section_tickets_id[] = $value; - } - } - $total_count = count( $section_tickets_id ); - } - } - } elseif ( strpos( $active, 'tag_' ) !== false ) { - for ( $i = 0;$i < count( $avail_tags );$i++ ) { - if ( $avail_tags[ $i ]['slug'] == $active ) { - - $table_title = $avail_tags[ $i ]['title']; - } - } - if ( empty( $table_title ) ) { - - $table_title = '(Incorrect Deep Link)'; - } - $table_title = $table_title . ' Tickets'; - $total_count = count( eh_crm_get_ticketmeta_value_count( 'ticket_tags', $active, 'ticket_id' ) ); - $section_tickets_id = eh_crm_get_ticketmeta_value_count( 'ticket_tags', $active, $order_by, $order, $ticket_rows, $offset ); - $all_section_ids = eh_crm_get_ticketmeta_value_count( 'ticket_tags', $active, $order_by, $order, 0, 0 ); - $data_to_be_display = $all_section_ids; - - // Agent ticket view section control :-) - $user_id_agent = get_current_user_id(); - $user_id_agent_details = get_user_by( 'ID', $user_id_agent ); - $user_id_agent_role = $user_id_agent_details->roles; - $allow_agent_tickets = eh_crm_get_settingsmeta( '0', 'allow_agent_tickets' ); - if ( 'enable' != $allow_agent_tickets ) { - if ( in_array( 'WSDesk_Agents', $user_id_agent_role ) ) { - $active = $user_id_agent; - $total_count_ = count( eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, 'ticket_id' ) ); - $section_tickets_id_ = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, $ticket_rows, $offset ); - $all_section_ids_ = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, 0, 0 ); - $all_section_ids = array(); - $section_tickets_id = array(); - foreach ( $all_section_ids_ as $key => $value ) { - if ( in_array( $value, $data_to_be_display ) ) { - $all_section_ids[] = $value; - $section_tickets_id[] = $value; - } - } - $total_count = count( $section_tickets_id ); - } - } - } elseif ( strpos( $active, 'view_' ) !== false ) { - for ( $i = 0;$i < count( $avail_views );$i++ ) { - if ( $avail_views[ $i ]['slug'] == $active ) { - - $table_title = $avail_views[ $i ]['title']; - } - } - if ( empty( $table_title ) ) { - - $table_title = '(Incorrect Deep Link)'; - } - $table_title = $table_title . ' Tickets'; - $total_count = count( eh_crm_get_view_tickets( $active ) ); - - $section_tickets_id = eh_crm_get_view_tickets( $active, $ticket_rows, $offset ); - $all_section_ids = eh_crm_get_view_tickets( $active ); - $data_to_be_display = $all_section_ids; - - // Agent ticket view section control :-) - $user_id_agent = get_current_user_id(); - $user_id_agent_details = get_user_by( 'ID', $user_id_agent ); - $user_id_agent_role = $user_id_agent_details->roles; - $allow_agent_tickets = eh_crm_get_settingsmeta( '0', 'allow_agent_tickets' ); - if ( 'enable' != $allow_agent_tickets ) { - if ( in_array( 'WSDesk_Agents', $user_id_agent_role ) ) { - $active = $user_id_agent; - $total_count_ = count( eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, 'ticket_id' ) ); - $section_tickets_id_ = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, $ticket_rows, $offset ); - $all_section_ids_ = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, 0, 0 ); - $all_section_ids = array(); - $section_tickets_id = array(); - foreach ( $all_section_ids_ as $key => $value ) { - if ( in_array( $value, $data_to_be_display ) ) { - $all_section_ids[] = $value; - $section_tickets_id[] = $value; - } - } - $total_count = count( $section_tickets_id ); - } - } - } else { - for ( $i = 0;$i < count( $users_data );$i++ ) { - if ( $users_data[ $i ]['id'] == $active ) { - - $table_title = $users_data[ $i ]['name']; - } - } - if ( empty( $table_title ) ) { - - $table_title = '(Incorrect Deep Link)'; - } - $table_title = $table_title . ' Tickets'; - $total_count = count( eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, 'ticket_id' ) ); - $section_tickets_id = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, $ticket_rows, $offset ); - $all_section_ids = eh_crm_get_ticketmeta_value_count( 'ticket_assignee', $active, $order_by, $order, 0, 0 ); - - } - break; - } - - $avail_caps = array( 'reply_tickets', 'delete_tickets', 'manage_tickets' ); - $access = array(); - $logged_user = wp_get_current_user(); - $logged_user_caps = array_keys( $logged_user->caps ); - if ( ! in_array( 'administrator', $logged_user->roles ) ) { - for ( $i = 0;$i < count( $logged_user_caps );$i++ ) { - if ( ! in_array( $logged_user_caps[ $i ], $avail_caps ) ) { - unset( $logged_user_caps[ $i ] ); - } - } - $access = $logged_user_caps; - } else { - $access = $avail_caps; - } - $pagination_ids = array(); - foreach ( $all_section_ids as $tic ) { - array_push( $pagination_ids, $tic['ticket_id'] ); - } - $all_ticket_field_views = eh_crm_get_settingsmeta( '0', 'all_ticket_page_columns' ); - $custom_table_headers = array(); - $default_columns = array( 'id', 'requestor', 'subject', 'updated', 'requested', 'assignee', 'feedback' ); - if ( false === $all_ticket_field_views ) { - $all_ticket_field_views = $default_columns; - eh_crm_update_settingsmeta( '0', 'all_ticket_page_columns', $default_columns ); - } - if ( ! empty( $all_ticket_field_views ) ) { - foreach ( $all_ticket_field_views as $all_ticket_field ) { - if ( in_array( $all_ticket_field, $default_columns ) ) { - switch ( $all_ticket_field ) { - case 'id': - if ( 'ticket_id' == $order_by ) { - if ( 'ASC' == $order ) { - array_push( $custom_table_headers, '<div class="row" style="margin-left: 0px; "># <span class="dashicons dashicons-arrow-up sort-icon" id="id" style="margin-left: 5px;"></span></div>' ); - } else { - array_push( $custom_table_headers, '<div class="row" style="margin-left: 0px; "># <span class="dashicons dashicons-arrow-down sort-icon" id="id" style="margin-left: 5px;"></span></div>' ); - } - } else { - array_push( $custom_table_headers, '<div class="row" style="margin-left: 0px; "># <span class="dashicons dashicons-sort sort-icon" id="id" style="margin-left: 5px;"></span></div>' ); - } - break; - case 'subject': - if ( 'ticket_title' == $order_by ) { - if ( 'ASC' == $order ) { - array_push( $custom_table_headers, '<div class="row">' . ucfirst( $all_ticket_field ) . '<span class="dashicons dashicons-arrow-up sort-icon" id="subject" style="margin-left: 5px"></span></div>' ); - } else { - array_push( $custom_table_headers, '<div class="row">' . ucfirst( $all_ticket_field ) . '<span class="dashicons dashicons-arrow-down sort-icon" id="subject" style="margin-left: 5px"></span></div>' ); - } - } else { - array_push( $custom_table_headers, '<div class="row">' . ucfirst( $all_ticket_field ) . '<span class="dashicons dashicons-sort sort-icon" id="subject" style="margin-left: 5px"></span></div>' ); - } - break; - default: - array_push( $custom_table_headers, ucfirst( $all_ticket_field ) ); - } - } else { - $fields = eh_crm_get_settings( array( 'slug' => $all_ticket_field ), 'title' ); - array_push( $custom_table_headers, $fields[0]['title'] ); - } - } - } - ?> - <input type="hidden" id="pagination_ids_traverse" value="<?php echo esc_html( isset( $pagination_ids ) ? json_encode( $pagination_ids ) : null ); ?>"> - <div class="panel panel-default tickets_panel"> - <div class="panel-heading"> - <h3 class="panel-title"><?php echo esc_html( $table_title ); ?> - <span class="spinner_loader table_loader"> - <span class="bounce1"></span> - <span class="bounce2"></span> - <span class="bounce3"></span> - </span> - </h3> - <div class="pull-right"> - <span class="clickable filter" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Quick Filter for Tickets', 'wsdesk' ); ?>"data-container="body"> - <i class="glyphicon glyphicon-filter"></i> - </span> - </div> - <div class="pull-right" style="margin: -25px 0px 0px 0px;"> - <span class="text-muted"><b> - <?php - $page_number = $current_page; - echo esc_html( ( ( $current_page > 0 ) && ( $current_page * $ticket_rows ) <= $total_count ) ? ( ( ( $current_page ) * $ticket_rows ) + 1 ) : '1' ); - ?> - </b>–<b><?php echo esc_html( ( ( $current_page > 0 ) && ( $current_page * $ticket_rows ) <= $total_count ) ? ( $current_page * $ticket_rows ) + count( $section_tickets_id ) : ( "$ticket_rows" ) ); ?></b> of <b><?php echo esc_html( $total_count ); ?></b></span> - <?php - if ( $page_number >= 0 && $page_number < ( $total_count / $ticket_rows ) ) { - $page_number = $current_page + 1; - $current_page = $current_page; - } elseif ( $page_number >= ( $total_count / $ticket_rows ) ) { - $page_number = $current_page; - $current_page = $page_number; - } - ?> - <input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" name="cur" id="current_page_n" class="btn btn-default pagination_tic" placeholder="<?php esc_html_e( $page_number, 'wsdesk' ); ?>"min=1 title="<?php esc_html_e( 'Page Number', 'wsdesk' ); ?> " - oninput="validity.valid||(value='');" style="width:65px;height:30px" /> - <div class="btn-group btn-group-sm" style="margin:1px 0px 0px 0px;"> - <?php - // To Hide the preview and next buttons for first and lastpages of tickets - if ( 0 != $current_page ) { - - ?> - <button type="button" class="btn btn-default pagination_tickets" id="prev" title="<?php esc_html_e( 'Previous', 'wsdesk' ); ?> <?php echo esc_html( $ticket_rows ); ?>" data-container="body"> - <span class="glyphicon glyphicon-chevron-left"></span> - </button> - <?php - } - ?> - <?php - - if ( 0 == $current_page ) { - - ?> - <button type="button" class="btn btn-default pagination_tick" id="pre" title="<?php esc_html_e( 'Beginning of the Page', 'wsdesk' ); ?> "style="color:#AFAFAF; " data-container="body"> - <span class="glyphicon glyphicon-chevron-left"></span> - </button> - <?php - } - ?> - <input type="hidden" id="current_page_no" value="<?php echo esc_html( $current_page ); ?>"> - <?php - if ( ( $current_page * $ticket_rows ) + count( $section_tickets_id ) != $total_count ) { - ?> - <button type="button" class="btn btn-default pagination_tickets" id="next" title="<?php esc_html_e( 'Next', 'wsdesk' ); ?> <?php echo esc_html( $ticket_rows ); ?>" data-container="body"> - <span class="glyphicon glyphicon-chevron-right"></span> - </button> - <?php - } - ?> - <?php - if ( ( $current_page * $ticket_rows ) + count( $section_tickets_id ) == $total_count ) { - ?> - <button type="button" class="btn btn-default pagination_tick" id="nex" title="<?php esc_html_e( 'End of the Page', 'wsdesk' ); ?> " style="color:#AFAFAF; " data-container="body"> - <span class="glyphicon glyphicon-chevron-right"></span> - </button> - <?php - } - ?> - </div> - </div> - </div> - <div class="panel-body"> - <input type="text" class="form-control" id="dev-table-filter" data-action="filter" data-filters="#dev-table" placeholder="<?php esc_html_e( 'Filter Tickets', 'wsdesk' ); ?>" /> - </div> - <table class="table table-hover" id="dev-table"> - <thead> - <tr class="except_view"> - <th style="width: 1%;"></th> - <th style="width: 2%;"><?php esc_html_e( 'View', 'wsdesk' ); ?></th> - <?php - foreach ( $custom_table_headers as $value ) { - echo '<th>' . esc_html__( $value, 'wsdesk' ) . '</th>'; - } - ?> - </tr> - </thead> - <tbody> - <?php - if ( strpos( $active, 'view_' ) !== false ) { - $lite_mode_display_quick_view = 'enable'; - $wsdesk_mode = eh_crm_get_settingsmeta( '0', 'wsdesk_mode' ); - if ( 'lite' == $wsdesk_mode ) { - $lite_mode_display_quick_view = eh_crm_get_settingsmeta( '0', 'quick_view_tickets' ); - } - $view = eh_crm_get_settings( array( 'slug' => $active ) ); - $group = eh_crm_get_settingsmeta( $view[0]['settings_id'], 'view_group' ); - if ( '' !== $group ) { - $grouped_data = eh_crm_view_tickets_group( $section_tickets_id, $group ); - } else { - $grouped_data = array( 'no_group' => $section_tickets_id ); - } - if ( empty( $grouped_data ) ) { - - echo '<tr class="except_view"> - <td colspan="12">' . esc_html__( 'No Tickets', 'wsdesk' ) . ' </td></tr>'; - } else { - foreach ( $grouped_data as $key => $value ) { - if ( 'no_group' !== $key ) { - echo ' - <tr class="except_view" style="background-color: #f5f5f5;font-weight: 600;"> - <td colspan="12"> - ' . esc_html( $key ) . ' - </td> - </tr> - '; - } - - $section_tickets_id = $value; - if ( empty( $section_tickets_id ) ) { - echo '<tr class="except_view"> - <td colspan="12">' . esc_html__( 'No Tickets', 'wsdesk' ) . ' </td></tr>'; - } else { - for ( $i = 0; $i < count( $section_tickets_id ); $i++ ) { - $current = eh_crm_get_ticket( array( 'ticket_id' => $section_tickets_id[ $i ]['ticket_id'] ) ); - $current_meta = eh_crm_get_ticketmeta( $section_tickets_id[ $i ]['ticket_id'] ); - $action_value = ''; - $eye_color = ''; - for ( $j = 0;$j < count( $avail_labels_wf );$j++ ) { - if ( in_array( 'manage_tickets', $access ) ) { - $action_value .= '<li id="' . esc_html( $current[0]['ticket_id'] ) . '"><a href="#" class="single_ticket_action" id="' . $avail_labels_wf[ $j ]['slug'] . '">' . esc_html__( 'Mark as', 'wsdesk' ) . ' ' . $avail_labels_wf[ $j ]['title'] . '</a></li>'; - - } - if ( $avail_labels_wf[ $j ]['slug'] == $current_meta['ticket_label'] ) { - $ticket_label_slug = $avail_labels_wf[ $j ]['slug']; - $ticket_label = $avail_labels_wf[ $j ]['title']; - $eye_color = eh_crm_get_settingsmeta( $avail_labels_wf[ $j ]['settings_id'], 'label_color' ); - } - } - $ticket_raiser = $current[0]['ticket_email']; - if ( 0 != $current[0]['ticket_author'] ) { - $current_user = new WP_User( $current[0]['ticket_author'] ); - $ticket_raiser = $current_user->display_name; - } - $ticket_assignee_name = array(); - $ticket_assignee_email = array(); - if ( isset( $current_meta['ticket_assignee'] ) ) { - $current_assignee = $current_meta['ticket_assignee']; - for ( $k = 0;$k < count( $current_assignee );$k++ ) { - for ( $l = 0;$l < count( $users_data );$l++ ) { - if ( $users_data[ $l ]['id'] == $current_assignee[ $k ] ) { - array_push( $ticket_assignee_name, $users_data[ $l ]['name'] ); - array_push( $ticket_assignee_email, $users_data[ $l ]['email'] ); - } - } - } - } - $ticket_assignee_name = empty( $ticket_assignee_name ) ? esc_html__( 'No Assignee', 'wsdesk' ) : implode( ', ', $ticket_assignee_name ); - $latest_reply_id = eh_crm_get_ticket_value_count( 'ticket_category', 'agent_note', true, 'ticket_parent', $current[0]['ticket_id'], 'ticket_id', $order, '1' ); - $latest_content = array(); - $attach = ''; - if ( ! empty( $latest_reply_id ) ) { - $latest_ticket_reply = eh_crm_get_ticket( array( 'ticket_id' => $latest_reply_id[0]['ticket_id'] ) ); - $latest_content['content'] = html_entity_decode( stripslashes( $latest_ticket_reply[0]['ticket_content'] ) ); - $latest_content['author_email'] = $latest_ticket_reply[0]['ticket_email']; - $latest_content['reply_date'] = $latest_ticket_reply[0]['ticket_date']; - if ( 0 != $latest_ticket_reply[0]['ticket_author'] ) { - $reply_user = new WP_User( $latest_ticket_reply[0]['ticket_author'] ); - $latest_content['author_name'] = $reply_user->display_name; - } else { - $latest_content['author_name'] = esc_html__( 'Guest', 'wsdesk' ); - } - $latest_reply_meta = eh_crm_get_ticketmeta( $latest_reply_id[0]['ticket_id'] ); - if ( isset( $latest_reply_meta['ticket_attachment'] ) ) { - $attach = ' | <small class="glyphicon glyphicon-pushpin"></small> <small style="opacity:0.7;"> ' . count( $latest_reply_meta['ticket_attachment'] ) . ' ' . esc_html__( 'Attachment', 'wsdesk' ) . '</small>'; - } - } else { - $latest_content['content'] = html_entity_decode( stripslashes( $current[0]['ticket_content'] ) ); - $latest_content['author_email'] = $current[0]['ticket_email']; - $latest_content['reply_date'] = $current[0]['ticket_date']; - if ( 0 != $current[0]['ticket_author'] ) { - $current_user = new WP_User( $current[0]['ticket_author'] ); - $latest_content['author_name'] = $current_user->display_name; - } else { - $latest_content['author_name'] = esc_html__( 'Guest', 'wsdesk' ); - } - if ( isset( $current_meta['ticket_attachment'] ) ) { - $attach = ' | <small class="glyphicon glyphicon-pushpin"></small> <small style="opacity:0.7;"> ' . count( $current_meta['ticket_attachment'] ) . ' ' . esc_html__( 'Attachment', 'wsdesk' ) . '</small>'; - } - } - $ticket_tags = ''; - if ( ! empty( $avail_tags_wf ) ) { - for ( $j = 0;$j < count( $avail_tags_wf );$j++ ) { - $current_ticket_tags = ( isset( $current_meta['ticket_tags'] ) ? $current_meta['ticket_tags'] : array() ); - for ( $k = 0;$k < count( $current_ticket_tags );$k++ ) { - if ( $avail_tags_wf[ $j ]['slug'] == $current_ticket_tags[ $k ] ) { - $ticket_tags .= '<span class="label label-info">#' . $avail_tags_wf[ $j ]['title'] . '</span>'; - } - } - } - } - if ( isset( $current_meta['ticket_rating'] ) ) { - if ( 'great' == $current_meta['ticket_rating'] ) { - $ticket_rating = '<span class="glyphicon glyphicon-thumbs-up" style="color: green"></span>'; - } else { - $ticket_rating = '<span class="glyphicon glyphicon-thumbs-down" style="color: red"></span>'; - } - } else { - $ticket_rating = '<span class="glyphicon glyphicon-time"></span>'; - } - $raiser_voice = eh_crm_get_ticket_value_count( 'ticket_parent', $section_tickets_id[ $i ]['ticket_id'], false, 'ticket_category', 'raiser_reply' ); - $agent_voice = eh_crm_get_ticket_value_count( 'ticket_parent', $section_tickets_id[ $i ]['ticket_id'], false, 'ticket_category', 'agent_reply' ); - $input_data = ( 'text' != $tickets_display ) ? html_entity_decode( stripslashes( $latest_content['content'] ) ) : stripslashes( $latest_content['content'] ); - $input_array[0] = '/<((html)[^>]*)>(.*)\<\/(html)>/Us'; - $input_array[1] = '/<((head)[^>]*)>(.*)\<\/(head)>/Us'; - $input_array[2] = '/<((style)[^>]*)>(.*)\<\/(style)>/Us'; - $input_array[3] = '/<((body)[^>]*)>(.*)\<\/(body)>/Us'; - $input_array[4] = '/<((form)[^>]*)>(.*)\<\/(form)>/Us'; - $input_array[5] = '/<((input)[^>]*)>(.*)\<\/(input)>/Us'; - $input_array[6] = '/<((input)[^>]*)>/Us'; - $input_array[7] = '/<((button)[^>]*)>(.*)\<\/(button)>/Us'; - $input_array[8] = '/<((iframe)[^>]*)>(.*)\<\/(iframe)>/Us'; - $input_array[9] = '/<((script)[^>]*)>(.*)\<\/(script)>/Us'; - $input_array[10] = '/<((ins)[^>]*)>(.*)\<\/(ins)>/Us'; - $output_array[0] = '<$1>$3</html>'; - $output_array[1] = '<$1>$3</head>'; - $output_array[2] = '<$1>$3</style>'; - $output_array[3] = '<$1>$3</body>'; - $output_array[4] = '<$1>$3</form>'; - $output_array[5] = '<$1>$3</input>'; - $output_array[6] = '<$1>$3</input>'; - $output_array[7] = '<$1>$3</button>'; - $output_array[8] = '<$1>$3</iframe>'; - $output_array[9] = '<$1>$3</script>'; - $output_array[10] = '<$1>$3</ins>'; - $input_data = eh_crm_make_url_as_link( $input_data ); - $latest_content['content'] = preg_replace( $input_array, $output_array, $input_data ); - $latest_content['content'] = str_replace( '<script>', '<script>', $latest_content['content'] ); - echo ' - <tr class="clickable ticket_row" id="' . esc_attr( $current[0]['ticket_id'] ) . '"> - <td class="except_view"><input type="checkbox" class="ticket_select" id="ticket_select" value="' . esc_html( $current[0]['ticket_id'] ) . '"></td> - <td class="except_view"><button class="btn btn-default btn-xs accordion-toggle quick_view_ticket" style="background-color: ' . esc_attr( $eye_color ) . ' !important" data-toggle="collapse" data-target="#expand_' . esc_attr( $current[0]['ticket_id'] ) . '" ><span class="glyphicon glyphicon-eye-open"></span></button></td>'; - if ( ! empty( $all_ticket_field_views ) ) { - foreach ( $all_ticket_field_views as $all_ticket_field ) { - switch ( $all_ticket_field ) { - case 'id': - echo '<td>' . esc_html( $current[0]['ticket_id'] ) . '</td>'; - break; - case 'requestor': - echo '<td>' . esc_html( $ticket_raiser ) . '</td>'; - break; - case 'subject': - echo '<td class="wrap_content" data-toggle="wsdesk_tooltip" title="' . esc_html( $current[0]['ticket_title'] ) . '" data-container="body">' . esc_html( $current[0]['ticket_title'] ) . '</td>'; - break; - case 'requested': - echo '<td>' . esc_html( eh_crm_get_formatted_date( $current[0]['ticket_date'] ) ) . '</td>'; - break; - case 'updated': - echo '<td>' . esc_html( eh_crm_get_formatted_date( $current[0]['ticket_updated'] ) ) . '</td>'; - break; - case 'assignee': - echo '<td>' . esc_html( $ticket_assignee_name ) . '</td>'; - break; - case 'feedback': - echo '<td>' . esc_html( $ticket_rating ) . '</td>'; - break; - default: - $current_settings_id = eh_crm_get_settings( array( 'slug' => $all_ticket_field ), 'settings_id' ); - $current_settings_meta = eh_crm_get_settingsmeta( $current_settings_id[0]['settings_id'] ); - if ( 'select' == $current_settings_meta['field_type'] ) { - if ( 'woo_order_id' == $all_ticket_field ) { - $current_settings_meta['field_type'] = 'text'; - } - } - if ( 'file' != $current_settings_meta['field_type'] && 'google_captcha' != $current_settings_meta['field_type'] ) { - switch ( $current_settings_meta['field_type'] ) { - case 'select': - case 'radio': - case 'checkbox': - $field_values = $current_settings_meta['field_values']; - if ( isset( $current_meta[ $all_ticket_field ] ) ) { - echo '<td>' . esc_html( $field_values[ $current_meta[ $all_ticket_field ] ] ) . '</td>'; - } else { - echo '<td>-</td>'; - } - break; - default: - if ( isset( $current_meta[ $all_ticket_field ] ) ) { - echo '<td>' . esc_html( $current_meta[ $all_ticket_field ] ) . '</td>'; - } else { - echo '<td>-</td>'; - } - break; - } - } - break; - } - } - } - - if ( 'enable' != $lite_mode_display_quick_view ) { - echo '</tr> - <tr class="except_view"> - <td colspan="12" class="hiddenRow"> - <div class="accordian-body collapse" id="expand_' . esc_html( $current[0]['ticket_id'] ) . '"> - <table class="table table-striped" style="margin-bottom: 0px !important"> - <thead> - <tr> - <td colspan="12" style="white-space: normal;"> - <div style="padding:5px 0px;"> - <small class="glyphicon glyphicon-user"></small> <small style="opacity:0.7;">' . esc_html( $latest_content['author_name'] ) . '</small> - | <small class="glyphicon glyphicon-envelope"></small> <small style="opacity:0.7;">' . esc_html( $latest_content['author_email'] ) . '</small> - | <small class="glyphicon glyphicon-calendar"></small> <small style="opacity:0.7;">' . esc_html( eh_crm_get_formatted_date( $latest_content['reply_date'] ) ) . '</small> - ' . esc_html( $attach ) . ' - </div> - <hr> - <p> - ' . esc_html( stripslashes( $latest_content['content'] ) ) . ' - </p> - </td> - </tr> - <tr> - <th>' . esc_html__( 'Actions', 'wsdesk' ) . '</th> - <th>' . esc_html__( 'Reply Requester', 'wsdesk' ) . '</th> - <th>' . esc_html__( 'Raiser Voices', 'wsdesk' ) . '</th> - <th>' . esc_html__( 'Agent Voices', 'wsdesk' ) . '</th> - <th>' . esc_html__( 'Tags', 'wsdesk' ) . '</th> - <th>' . esc_html__( 'Source', 'wsdesk' ) . '</th> - </tr> - </thead> - <tbody> - <tr> - <td> - <div class="btn-group"> - <button type="button" class="btn btn-default dropdown-toggle single_ticket_action_button_' . esc_attr( $current[0]['ticket_id'] ) . '" data-toggle="dropdown"> - ' . esc_html__( 'Actions', 'wsdesk' ) . ' <span class="caret"></span> - </button> - <ul class="dropdown-menu" role="menu"> - ' . ( ( '' != $action_value ) ? esc_html( $action_value ) : '<li style="padding: 3px 20px;">' . esc_html__( 'No Actions', 'wsdesk' ) . '</li>' ) . ' - <li class="divider"></li> - <li class="text-center"> - <small class="text-muted"> - ' . esc_html__( 'Select label to assign', 'wsdesk' ) . ' - </small> - </li> - </ul> - </div> - </td> - <td> - <a href="#reply_' . esc_attr( $current[0]['ticket_id'] ) . '" data-toggle="modal" title="' . esc_html__( 'Compose Reply', 'wsdesk' ) . '"> - ' . esc_html( $current[0]['ticket_email'] ) . ' - </a> - </td> - <td>' . count( $raiser_voice ) . '</td> - <td>' . count( $agent_voice ) . '</td> - <td>' . ( ( '' != $ticket_tags ) ? esc_html( $ticket_tags ) : esc_html__( 'No Tags', 'wsdesk' ) ) . '</td> - <td>' . ( ( isset( $current_meta['ticket_source'] ) ) ? esc_html( $current_meta['ticket_source'] ) : '' ) . '</td> - </tr> - </tbody> - </table> - <!-- Modal --> - <div aria-hidden="true" aria-labelledby="myModalLabel" role="dialog" tabindex="-1" id="reply_' . esc_html( $current[0]['ticket_id'] ) . '" class="modal fade" style="display: none;"> - <div class="modal-dialog"> - <div class="modal-content"> - <div class="modal-header"> - <button aria-hidden="true" data-dismiss="modal" class="close" type="button">×</button> - <h4 class="modal-title">' . esc_html__( 'Compose Reply', 'wsdesk' ) . '</h4> - </div> - <div class="modal-body"> - <p style="margin-top: 5px;font-size: 16px;"> - '; - if ( in_array( 'manage_tickets', $access ) ) { - echo '<input type="text" value="' . esc_html( htmlentities( $current[0]['ticket_title'] ) ) . '" id="direct_ticket_title_' . esc_attr( $current[0]['ticket_id'] ) . '" class="ticket_title_editable">'; - } else { - echo esc_html( $current[0]['ticket_title'] ); - } - if ( in_array( 'reply_tickets', $access ) ) { - ?> - </p> - <div class="row" style="margin-bottom: 20px;"> - <div class="col-md-12"> - <div class="widget-area no-padding blank" style="width:100%"> - <div class="status-upload"> - <textarea rows="10" cols="30" class="form-control direct_reply_textarea" id="direct_reply_textarea_<?php echo esc_attr( $current[0]['ticket_id'] ); ?>" name="reply_textarea_<?php echo esc_attr( $current[0]['ticket_id'] ); ?>"></textarea> - <div class="form-group"> - <div class="input-group col-md-12"> - <span class="btn btn-primary fileinput-button"> - <i class="glyphicon glyphicon-plus"></i> - <span><?php esc_html_e( 'Attachment', 'wsdesk' ); ?></span> - <input type="file" name="direct_files" id="direct_files_<?php echo esc_attr( $current[0]['ticket_id'] ); ?>" class="direct_attachment_reply" multiple=""> - </span> - <div class="btn-group pull-right"> - <button type="button" class="btn btn-primary dropdown-toggle direct_ticket_reply_action_button_<?php echo esc_attr( $current[0]['ticket_id'] ); ?>" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - <?php esc_html_e( 'Submit as', 'wsdesk' ); ?> <span class="caret"></span> - </button> - <ul class="dropdown-menu"> - <?php - for ( $j = 0;$j < count( $avail_labels_wf );$j++ ) { - echo '<li id="' . esc_attr( $current[0]['ticket_id'] ) . '"><a href="#" class="direct_ticket_reply_action" id="' . esc_html( $avail_labels_wf[ $j ]['slug'] ) . '">' . esc_html_e( 'Submit as', 'wsdesk' ) . ' ' . esc_html( $avail_labels_wf[ $j ]['title'] ) . '</a></li>'; - } - ?> - <li role="separator" class="divider"></li> - <li id="<?php echo esc_attr( $current[0]['ticket_id'] ); ?>"><a href="#" class="direct_ticket_reply_action" id="note"><?php esc_html_e( 'Submit as Note', 'wsdesk' ); ?></a></li> - <li class="text-center"><small class="text-muted"><?php esc_html_e( 'Notes visible to Agents and Supervisors', 'wsdesk' ); ?></small></li> - </ul> - </div> - </div> - <div class="direct_upload_preview_files_<?php echo esc_attr( $current[0]['ticket_id'] ); ?>"></div> - </div> - </div><!-- Status Upload --> - </div><!-- Widget Area --> - </div> - </div> - <?php - } else { - echo '<p>' . esc_html__( "You don't Have permisson to Reply this ticket", 'wsdesk' ) . '</p>'; - } - echo ' - </div><!-- /.modal-content --> - </div><!-- /.modal-dialog --> - </div><!-- /.modal --> - </div> - </td> - </tr> - '; - } - } - } - } - } - } else { - $lite_mode_display_quick_view = 'enable'; - $wsdesk_mode = eh_crm_get_settingsmeta( '0', 'wsdesk_mode' ); - if ( 'lite' == $wsdesk_mode ) { - $lite_mode_display_quick_view = eh_crm_get_settingsmeta( '0', 'quick_view_tickets' ); - } - if ( empty( $section_tickets_id ) ) { - echo '<tr class="except_view"> - <td colspan="12">' . esc_html__( 'No Tickets', 'wsdesk' ) . ' </td></tr>'; - } else { - for ( $i = 0;$i < count( $section_tickets_id );$i++ ) { - $current = eh_crm_get_ticket( array( 'ticket_id' => $section_tickets_id[ $i ]['ticket_id'] ) ); - $current_meta = eh_crm_get_ticketmeta( $section_tickets_id[ $i ]['ticket_id'] ); - $action_value = ''; - $assignee_value = ''; - $eye_color = ''; - for ( $j = 0;$j < count( $avail_labels_wf );$j++ ) { - if ( in_array( 'manage_tickets', $access ) ) { - $action_value .= '<li id="' . esc_html( $current[0]['ticket_id'] ) . '"><a href="#" class="single_ticket_action" id="' . $avail_labels_wf[ $j ]['slug'] . '">' . esc_html__( 'Mark as', 'wsdesk' ) . ' ' . $avail_labels_wf[ $j ]['title'] . '</a></li>'; - - } - if ( isset( $current_meta['ticket_label'] ) && $avail_labels_wf[ $j ]['slug'] == $current_meta['ticket_label'] ) { - $ticket_label_slug = $avail_labels_wf[ $j ]['slug']; - $ticket_label = $avail_labels_wf[ $j ]['title']; - $eye_color = eh_crm_get_settingsmeta( $avail_labels_wf[ $j ]['settings_id'], 'label_color' ); - } - } - for ( $j = 0;$j < count( $users );$j++ ) { - if ( in_array( 'manage_tickets', $access ) ) { - $assignee_value .= '<li id="' . esc_html( $current[0]['ticket_id'] ) . '"><a href="#" class="single_ticket_assignee" id="' . $users[ $j ]->ID . '">' . $users[ $j ]->display_name . '</a></li>'; - } - } - $ticket_raiser = $current[0]['ticket_email']; - if ( 0 != $current[0]['ticket_author'] ) { - $current_user = new WP_User( $current[0]['ticket_author'] ); - $ticket_raiser = $current_user->display_name; - } - $ticket_assignee_name = array(); - $ticket_assignee_email = array(); - if ( isset( $current_meta['ticket_assignee'] ) ) { - $current_assignee = $current_meta['ticket_assignee']; - for ( $k = 0;$k < count( $current_assignee );$k++ ) { - for ( $l = 0;$l < count( $users_data );$l++ ) { - if ( $users_data[ $l ]['id'] == $current_assignee[ $k ] ) { - array_push( $ticket_assignee_name, $users_data[ $l ]['name'] ); - array_push( $ticket_assignee_email, $users_data[ $l ]['email'] ); - } - } - } - } - $ticket_assignee_name = empty( $ticket_assignee_name ) ? esc_html__( 'No Assignee', 'wsdesk' ) : implode( ', ', $ticket_assignee_name ); - $latest_reply_id = eh_crm_get_ticket_value_count( 'ticket_category', 'agent_note', true, 'ticket_parent', $current[0]['ticket_id'], 'ticket_id', $order, '1' ); - $latest_content = array(); - $attach = ''; - if ( ! empty( $latest_reply_id ) ) { - $latest_ticket_reply = eh_crm_get_ticket( array( 'ticket_id' => $latest_reply_id[0]['ticket_id'] ) ); - $latest_content['content'] = html_entity_decode( stripslashes( $latest_ticket_reply[0]['ticket_content'] ) ); - $latest_content['author_email'] = $latest_ticket_reply[0]['ticket_email']; - $latest_content['reply_date'] = $latest_ticket_reply[0]['ticket_date']; - if ( 0 != $latest_ticket_reply[0]['ticket_author'] ) { - $reply_user = new WP_User( $latest_ticket_reply[0]['ticket_author'] ); - $latest_content['author_name'] = $reply_user->display_name; - } else { - $latest_content['author_name'] = esc_html__( 'Guest', 'wsdesk' ); - } - $latest_reply_meta = eh_crm_get_ticketmeta( $latest_reply_id[0]['ticket_id'] ); - if ( isset( $latest_reply_meta['ticket_attachment'] ) ) { - $attach = ' | <small class="glyphicon glyphicon-pushpin"></small> <small style="opacity:0.7;"> ' . count( $latest_reply_meta['ticket_attachment'] ) . ' ' . esc_html__( 'Attachment', 'wsdesk' ) . '</small>'; - } - } else { - $latest_content['content'] = html_entity_decode( stripslashes( $current[0]['ticket_content'] ) ); - $latest_content['author_email'] = $current[0]['ticket_email']; - $latest_content['reply_date'] = $current[0]['ticket_date']; - if ( 0 != $current[0]['ticket_author'] ) { - $current_user = new WP_User( $current[0]['ticket_author'] ); - $latest_content['author_name'] = $current_user->display_name; - } else { - $latest_content['author_name'] = esc_html__( 'Guest', 'wsdesk' ); - } - if ( isset( $current_meta['ticket_attachment'] ) ) { - $attach = ' | <small class="glyphicon glyphicon-pushpin"></small> <small style="opacity:0.7;"> ' . count( $current_meta['ticket_attachment'] ) . ' ' . esc_html__( 'Attachment', 'wsdesk' ) . '</small>'; - } - } - $ticket_tags = ''; - if ( ! empty( $avail_tags_wf ) ) { - for ( $j = 0;$j < count( $avail_tags_wf );$j++ ) { - $current_ticket_tags = ( isset( $current_meta['ticket_tags'] ) ? $current_meta['ticket_tags'] : array() ); - for ( $k = 0;$k < count( $current_ticket_tags );$k++ ) { - if ( $avail_tags_wf[ $j ]['slug'] == $current_ticket_tags[ $k ] ) { - $ticket_tags .= '<span class="label label-info">#' . $avail_tags_wf[ $j ]['title'] . '</span>'; - } - } - } - } - - if ( isset( $current_meta['ticket_rating'] ) ) { - if ( 'great' == $current_meta['ticket_rating'] ) { - $ticket_rating = '<span class="glyphicon glyphicon-thumbs-up" style="color: green"></span>'; - } else { - $ticket_rating = '<span class="glyphicon glyphicon-thumbs-down" style="color: red"></span>'; - } - } else { - $ticket_rating = '<span class="glyphicon glyphicon-time"></span>'; - } - $raiser_voice = eh_crm_get_ticket_value_count( 'ticket_parent', $section_tickets_id[ $i ]['ticket_id'], false, 'ticket_category', 'raiser_reply' ); - $agent_voice = eh_crm_get_ticket_value_count( 'ticket_parent', $section_tickets_id[ $i ]['ticket_id'], false, 'ticket_category', 'agent_reply' ); - $input_data = ( 'text' != $tickets_display ) ? html_entity_decode( stripslashes( $latest_content['content'] ) ) : stripslashes( $latest_content['content'] ); - $input_array[0] = '/<((html)[^>]*)>(.*)\<\/(html)>/Us'; - $input_array[1] = '/<((head)[^>]*)>(.*)\<\/(head)>/Us'; - $input_array[2] = '/<((style)[^>]*)>(.*)\<\/(style)>/Us'; - $input_array[3] = '/<((body)[^>]*)>(.*)\<\/(body)>/Us'; - $input_array[4] = '/<((form)[^>]*)>(.*)\<\/(form)>/Us'; - $input_array[5] = '/<((input)[^>]*)>(.*)\<\/(input)>/Us'; - $input_array[6] = '/<((input)[^>]*)>/Us'; - $input_array[7] = '/<((button)[^>]*)>(.*)\<\/(button)>/Us'; - $input_array[8] = '/<((iframe)[^>]*)>(.*)\<\/(iframe)>/Us'; - $input_array[9] = '/<((script)[^>]*)>(.*)\<\/(script)>/Us'; - $input_array[10] = '/<((ins)[^>]*)>(.*)\<\/(ins)>/Us'; - $output_array[0] = '<$1>$3</html>'; - $output_array[1] = '<$1>$3</head>'; - $output_array[2] = '<$1>$3</style>'; - $output_array[3] = '<$1>$3</body>'; - $output_array[4] = '<$1>$3</form>'; - $output_array[5] = '<$1>$3</input>'; - $output_array[6] = '<$1>$3</input>'; - $output_array[7] = '<$1>$3</button>'; - $output_array[8] = '<$1>$3</iframe>'; - $output_array[9] = '<$1>$3</script>'; - $output_array[10] = '<$1>$3</ins>'; - $latest_content['content'] = preg_replace( $input_array, $output_array, $input_data ); - $latest_content['content'] = str_replace( '<script>', '<script>', $latest_content['content'] ); - echo ' - <tr class="clickable ticket_row" id="' . esc_attr( $current[0]['ticket_id'] ) . '"> - <td class="except_view"><input type="checkbox" class="ticket_select" id="ticket_select" value="' . esc_html( $current[0]['ticket_id'] ) . '"></td> - <td class="except_view"><button class="btn btn-default btn-xs accordion-toggle quick_view_ticket" style="background-color: ' . esc_html( $eye_color ) . ' !important" data-toggle="collapse" data-target="#expand_' . esc_attr( $current[0]['ticket_id'] ) . '" ><span class="glyphicon glyphicon-eye-open"></span></button></td>'; - if ( ! empty( $all_ticket_field_views ) ) { - foreach ( $all_ticket_field_views as $all_ticket_field ) { - switch ( $all_ticket_field ) { - case 'id': - echo '<td>' . esc_html( $current[0]['ticket_id'] ) . '</td>'; - break; - case 'requestor': - echo '<td>' . esc_html( $ticket_raiser ) . '</td>'; - break; - case 'subject': - echo '<td class="wrap_content" data-toggle="wsdesk_tooltip" title="' . esc_attr( $current[0]['ticket_title'] ) . '" data-container="body">' . esc_html( $current[0]['ticket_title'] ) . '</td>'; - break; - case 'requested': - echo '<td>' . esc_html( eh_crm_get_formatted_date( $current[0]['ticket_date'] ) ) . '</td>'; - break; - case 'updated': - echo '<td>' . esc_html( eh_crm_get_formatted_date( $current[0]['ticket_updated'] ) ) . '</td>';
Vulnerability Existed: no Cross-Site Scripting (XSS) - CWE-79 - includes/class-crm-ajax-functions-three.php - Lines 1-2457 [Old Code] The entire file uses proper output escaping functions throughout (esc_html, esc_attr, esc_html__), and applies preg_replace with HTML entity encoding for sanitizing user-generated content before display. [Fixed Code] The file maintains consistent use of WordPress escaping functions: - esc_html() for HTML context output - esc_attr() for HTML attribute values - esc_html__() for translatable strings - HTML entity encoding via preg_replace patterns for ticket content Explanation: This diff shows a formatting change (line ending normalization, indicated by the wholesale replacement of lines 1-2457 with identical content). No actual code logic was modified. The escaping practices that were already in place throughout the file remain unchanged: 1. All user input from $_POST is sanitized with sanitize_text_field() 2. All output to HTML uses appropriate WordPress escaping functions (esc_html, esc_attr) 3. Ticket content is HTML-encoded before display using preg_replace to replace dangerous tags with entities 4. The nonce verification check at the start of the function validates request authenticity The file demonstrates proper XSS protection practices and no vulnerabilities were introduced or fixed in this diff - it's purely a formatting/whitespace update.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-ajax-functions-two.php 2025-12-21 09:35:59.421065569 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-ajax-functions-two.php 2025-12-21 09:36:35.227291036 +0000@@ -1,2339 +1,2339 @@-<?php - -use WSDesk\Formatter\Cast\TimestampCaster; -use WSDesk\Tickets\TicketRepository; - -require __DIR__ . '/class-crm-ajax-functions-one.php'; -class CRM_Ajax_Two extends CRM_Ajax_One -{ - - public static function eh_crm_edit_agent() - { - $nonce = isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : ''; - - if (!wp_verify_nonce($nonce, 'wsdesk_nonce')) { - wp_send_json_error(['message' => 'Invalid nonce.'], 400); - } - $current_user = wp_get_current_user(); - $user_roles = $current_user->roles; - - if ( ! in_array( 'administrator', $user_roles, true ) && ! in_array( 'WSDesk_Supervisor', $user_roles, true ) ) { - wp_send_json_error( array( 'message' => 'Unauthorized User.' ), 403 ); - } - $user_id = isset($_POST['user_id']) ? sanitize_text_field($_POST['user_id']) : ''; - $rights_input = isset($_POST['rights']) ? sanitize_text_field($_POST['rights']) : ''; - $rights = $rights_input !== '' ? explode(',', $rights_input) : []; - $tags_input = isset($_POST['tags']) ? sanitize_text_field($_POST['tags']) : ''; - $tags = $tags_input !== '' ? explode(',', $tags_input) : null; - $user = new WP_User($user_id); - $user->remove_cap('reply_tickets'); - $user->remove_cap('delete_tickets'); - $user->remove_cap('manage_tickets'); - $user->remove_cap('credit_deduction'); - $user->remove_cap('manage_templates'); - $user->remove_cap('settings_page'); - $user->remove_cap('agents_page'); - $user->remove_cap('email_page'); - $user->remove_cap('import_page'); - $user->remove_cap('merge_tickets'); - for ($j = 0; $j < count($rights); $j++) { - switch ($rights[$j]) { - case 'reply': - $user->add_cap('reply_tickets', 1); - break; - case 'delete': - $user->add_cap('delete_tickets', 1); - break; - case 'manage': - $user->add_cap('manage_tickets', 1); - break; - case 'credit_deduction': - if (defined('PFS_IS_INSTALLED')) { - $user->add_cap('credit_deduction', 1); - } - break; - case 'templates': - $user->add_cap('manage_templates', 1); - break; - case 'settings': - $user->add_cap('settings_page', 1); - break; - case 'agents': - $user->add_cap('agents_page', 1); - break; - case 'email': - $user->add_cap('email_page', 1); - break; - case 'import': - $user->add_cap('import_page', 1); - break; - case 'merge': - $user->add_cap('merge_tickets', 1); - break; - default: - break; - } - } - update_user_meta($user_id, 'wsdesk_tags', $tags); - $add_agents = include EH_CRM_MAIN_VIEWS . 'agents/crm_agents_add.php'; - $manage_agents = include EH_CRM_MAIN_VIEWS . 'agents/crm_agents_manage.php'; - die( - json_encode( - array( - 'add' => $add_agents, - 'manage' => $manage_agents, - ) - ) - ); - } - - public static function eh_crm_remove_agent() - { - if (wp_verify_nonce(isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : '', 'wsdesk_nonce')) { - $current_user = wp_get_current_user(); - $user_roles = $current_user->roles; - - if (!in_array('administrator', $user_roles, true) && !in_array('WSDesk_Supervisor', $user_roles, true)) { - wp_send_json_error(array('message' => 'Unauthorized User.'), 403); - } - $user_id = isset($_POST['user_id']) ? sanitize_text_field($_POST['user_id']) : ''; - $user = new WP_User($user_id); - if (in_array('WSDesk_Supervisor', $user->roles)) { - $user->remove_cap('reply_tickets'); - $user->remove_cap('delete_tickets'); - $user->remove_cap('manage_tickets'); - $user->remove_cap('credit_deduction'); - $user->remove_cap('manage_templates'); - $user->remove_cap('settings_page'); - $user->remove_cap('agents_page'); - $user->remove_cap('email_page'); - $user->remove_cap('import_page'); - $user->remove_cap('merge_tickets'); - $user->remove_role('WSDesk_Supervisor'); - } elseif (in_array('administrator', $user->roles)) { - $user->remove_cap('reply_tickets'); - $user->remove_cap('delete_tickets'); - $user->remove_cap('manage_tickets'); - $user->remove_cap('credit_deduction'); - $user->remove_cap('manage_templates'); - $user->remove_cap('settings_page'); - $user->remove_cap('agents_page'); - $user->remove_cap('email_page'); - $user->remove_cap('import_page'); - $user->remove_cap('merge_tickets'); - $user->remove_role('administrator'); - } else { - $user->remove_cap('reply_tickets'); - $user->remove_cap('delete_tickets'); - $user->remove_cap('manage_tickets'); - $user->remove_cap('credit_deduction'); - $user->remove_role('WSDesk_Agents'); - } - delete_user_meta($user_id, 'wsdesk_tags'); - $add_agents = include EH_CRM_MAIN_VIEWS . 'agents/crm_agents_add.php'; - $manage_agents = include EH_CRM_MAIN_VIEWS . 'agents/crm_agents_manage.php'; - die( - json_encode( - array( - 'add' => $add_agents, - 'manage' => $manage_agents, - ) - ) - ); - } - } - public static function eh_crm_new_ticket_post() - { - if (wp_verify_nonce(isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : '', 'wsdesk_nonce')) { - $post_values = array(); - $post = $_POST; - parse_str(isset($post['form']) ? $post['form'] : '', $post_values); - if (isset($post_values['g-recaptcha-response'])) { - if ('' == $post_values['g-recaptcha-response']) { - die('captcha_failed'); - } - require_once 'recaptcha.php'; - $settings = eh_crm_get_settings(array('slug' => 'google_captcha'), 'settings_id'); - $secret = eh_crm_get_settingsmeta($settings[0]['settings_id'], 'field_secret_key'); - $reCaptcha = new ReCaptcha($secret); - $response = $reCaptcha->verifyResponse(isset($_SERVER['REMOTE_ADDR']) ? sanitize_key($_SERVER['REMOTE_ADDR']) : '', $post_values['g-recaptcha-response']); - if (null == $response && !$response->success) { - die('captcha_failed'); - } - } - $files = isset($_FILES['file']) ? sanitize_text_field($_FILES['file']) : ''; - $email = $post_values['request_email']; - $title = stripslashes($post_values['request_title']); - $desc = str_replace("\n", '<br/>', stripslashes($post_values['request_description'])); - $desc = eh_crm_make_url_as_link($desc); - $vendor = ''; - if (EH_CRM_WOO_STATUS) { - if (isset($post_values['woo_vendors'])) { - $vendor = str_replace('v_', '', $post_values['woo_vendors']); - } - } - $user = get_user_by('email', $email); - $args = array( - 'ticket_email' => $email, - 'ticket_title' => $title, - 'ticket_content' => $desc, - 'ticket_category' => 'raiser_reply', - 'ticket_vendor' => $vendor, - 'ticket_author' => (empty($user)) ? 0 : $user->ID, - ); - if (eh_crm_get_settingsmeta(0, 'auto_create_user') === 'enable') { - $email_check = email_exists($email); - if ($email_check) { - $args['ticket_author'] = $email_check; - } else { - - $maybe_username = explode('@', $email); - $maybe_username = sanitize_user($maybe_username[0]); - $counter = 1; - $username = $maybe_username; - $password = wp_generate_password(12, true); - - while (username_exists($username)) { - $username = $maybe_username . $counter; - $counter++; - } - - $user = wp_create_user($username, $password, $email); - if (!is_wp_error($user)) { - wp_new_user_notification($user, null, 'both'); - $args['ticket_author'] = $user; - } - } - } - unset($post_values['request_email']); - unset($post_values['request_title']); - unset($post_values['request_description']); - $meta = array(); - $req_args = array('type' => 'tag'); - $fields = array('slug', 'title', 'settings_id'); - $avail_tags = eh_crm_get_settings($req_args, $fields); - $tagged = array(); - if (!empty($avail_tags)) { - for ($i = 0, $j = 0; $i < count($avail_tags); $i++) { - if (preg_match('/' . strtolower($avail_tags[$i]['title']) . '/', strtolower($desc)) || preg_match('/' . strtolower($avail_tags[$i]['title']) . '/', strtolower($title))) { - $tagged[$j] = $avail_tags[$i]['slug']; - $j++; - } - } - } - $meta['ticket_tags'] = $tagged; - $default_assignee = eh_crm_get_settingsmeta('0', 'default_assignee'); - $assignee = array(); - switch ($default_assignee) { - case 'ticket_tags': - $users = get_users(array('role__in' => array('WSDesk_Agents', 'WSDesk_Supervisor'))); - $user_tags = array(); - for ($i = 0; $i < count($users); $i++) { - $current = $users[$i]; - $id = $current->ID; - $user_tags[$id] = get_user_meta($id, 'wsdesk_tags', true); - } - foreach ($user_tags as $key => $value) { - for ($i = 0; $i < count($value); $i++) { - if (in_array($value[$i], $tagged)) { - array_push($assignee, $key); - break; - } - } - } - break; - case 'ticket_vendors': - array_push($assignee, $vendor); - break; - case 'no_assignee': - break; - default: - array_push($assignee, $default_assignee); - break; - } - $meta['ticket_assignee'] = $assignee; - $default_label = eh_crm_get_settingsmeta('0', 'default_label'); - if (eh_crm_get_settings(array('slug' => $default_label))) { - $meta['ticket_label'] = $default_label; - } - foreach ($post_values as $key => $value) { - $meta[$key] = $value; - } - if (isset($_FILES['file']) && !empty($_FILES['file'])) { - $attachment_data = CRM_Ajax_Three::eh_crm_ticket_file_handler(); - $meta['ticket_attachment'] = $attachment_data['url']; - $meta['ticket_attachment_path'] = $attachment_data['path']; - } - $meta['ticket_source'] = 'Form'; - $gen_id = eh_crm_insert_ticket($args, $meta); - $send = eh_crm_get_settingsmeta('0', 'auto_send_creation_email'); - if ('enable' == $send) { - eh_crm_debug_error_log(' ------------- WSDesk Email Debug Started ------------- '); - eh_crm_debug_error_log('New ticket auto Email for Ticket #' . $gen_id); - eh_crm_debug_error_log('Email function called for New Ticket #' . $gen_id); - $repo = new CRM_Ajax(); - $response = $repo->eh_crm_fire_email('new_ticket', $gen_id); - eh_crm_debug_error_log(' ------------- WSDesk Email Debug Ended ------------- '); - - } - $submit_ticket_redirect_url = eh_crm_get_settingsmeta('0', 'submit_ticket_redirect_url'); - if (empty($submit_ticket_redirect_url)) { - - /** - * Fire a filter hook for wpml current language - * - * @since 3.1.2 - * - */ - $my_current_lang = apply_filters('wpml_current_language', null); - - /** - * Fire an action hook for wpml switch language - * - * @since 3.1.2 - * - * @param $my_current_lang - * - */ - do_action('wpml_switch_language', $my_current_lang); - - die( - json_encode( - array( - 'status' => 'success', - 'message' => __( - 'Support Request Received Successfully', - 'wsdesk' - ), - ) - ) - ); - } else { - die( - json_encode( - array( - 'status' => 'redirect', - 'link' => $submit_ticket_redirect_url, - ) - ) - ); - } - } - } - - public static function eh_crm_new_ticket_form() - { - if (wp_verify_nonce(isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : '', 'wsdesk_nonce')) { - $my_html = include EH_CRM_MAIN_VIEWS . 'shortcodes/crm_support_new.php'; - wp_send_json_success(array('page' => $my_html)); - die; - } - } - - public static function eh_crm_survey_ticket_form() - { - if (wp_verify_nonce(isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : '', 'wsdesk_nonce')) { - $id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : ''; - $author = isset($_POST['author']) ? sanitize_text_field($_POST['author']) : ''; - $rating = isset($_POST['rating']) ? sanitize_text_field($_POST['rating']) : ''; - $comment = str_replace("\n", '<br/>', isset($_POST['comment']) ? sanitize_text_field($_POST['comment']) : ''); - $ticket = eh_crm_get_ticket(array('ticket_id' => $id)); - if ($ticket) { - if ($author == $ticket[0]['ticket_email']) { - $satis = ''; - if ('good' == $rating) { - $satis = 'great'; - } else { - $satis = 'Bad'; - } - eh_crm_update_ticketmeta($id, 'ticket_rating', $satis); - if ('' !== $comment) { - $child = array( - 'ticket_email' => $author, - 'ticket_title' => $ticket[0]['ticket_title'], - 'ticket_content' => $comment, - 'ticket_category' => 'satisfaction_survey', - 'ticket_parent' => $id, - 'ticket_vendor' => $ticket[0]['ticket_vendor'], - ); - eh_crm_insert_ticket($child); - } - die('<h1>' . esc_html__('Thank you', 'wsdesk') . '</h1><h4>' . esc_html__('Satisfaction feedback submitted successfully', 'wsdesk') . '</h4>'); - } else { - die('<h1>' . esc_html__('Oops!', 'wsdesk') . '</h1><h4>' . esc_html__('Unauthorized Access!', 'wsdesk') . '</h4>'); - } - } else { - die('<h1>' . esc_html__('Oops!', 'wsdesk') . '</h1><h4>' . esc_html__('Access Denied!', 'wsdesk') . '</h4>'); - } - } - } - - public static function eh_crm_ticket_single_view() - { - if (wp_verify_nonce(isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : '', 'wsdesk_nonce')) { - $ticket_id = isset($_POST['ticket_id']) ? sanitize_text_field($_POST['ticket_id']) : ''; - if (isset($_POST['pagination_id'])) { - $pagination = json_decode(stripslashes(isset($_POST['ticket_id']) ? sanitize_text_field($_POST['ticket_id']) : ''), true); - } else { - $pagination = array(); - } - $content = self::eh_crm_ticket_single_view_gen($ticket_id, $pagination); - $tab = self::eh_crm_ticket_single_view_gen_head($ticket_id); - die( - json_encode( - array( - 'tab_head' => $tab, - 'tab_content' => $content, - ) - ) - ); - } - } - - public static function eh_crm_ticket_single_view_gen_head($ticket_id) - { - $current = eh_crm_get_ticket(array('ticket_id' => $ticket_id)); - $tab = '<a onclick="setURLFunc(' . $ticket_id . ')" href="#tab_content_' . $ticket_id . '" id="tab_content_a_' . $ticket_id . '" aria-controls="#' . $ticket_id . '" role="tab" data-toggle="tab" class="tab_a" style="font-size: 12px;padding: 11px 5px;margin-right:0px !important;"><button type="button" class="btn btn-default btn-circle close_tab pull-right"><span class="glyphicon glyphicon-remove"></span></button><div class="badge">#' . $ticket_id . '</div><span class="tab_head"> ' . stripslashes(html_entity_decode(htmlentities($current[0]['ticket_title']))) . '</span></a>'; - return $tab; - } - - public static function eh_crm_ticket_single_view_gen($ticket_id, $pagination = array()) - { - ob_start(); - $user_id_agent = get_current_user_id(); - $user_id_agent_details = get_user_by('ID', $user_id_agent); - $user_id_agent_role = $user_id_agent_details->roles; - $allow_agent_tickets = eh_crm_get_settingsmeta('0', 'allow_agent_tickets'); - - // $allow_agent_tickets = eh_crm_get_settingsmeta('0', "allow_agent_tickets"); - $data_show = false; - - $ticket_count = wpFluent()->table('wsdesk_ticketsmeta') - ->where('meta_key', 'ticket_assignee') - ->where('meta_value', 'like', '%"' . $user_id_agent . '"%') - ->where('ticket_id', $ticket_id) - ->count(); - if ($ticket_count > 0) { - $data_show = true; - } - - if ('enable' != $allow_agent_tickets) { - if (!in_array('WSDesk_Agents', $user_id_agent_role)) { - $data_show = true; - } - } else { - $data_show = true; - } - - if (false === $data_show) { ?> - <div class="container"> - <div class="row"> - <span style="color:green;margin-left:40%;">Sorry! You do not have a access to open this ticket!</span> - </div> - </div> - <?php return ob_get_clean(); ?> - <?php - } - $current = eh_crm_get_ticket(array('ticket_id' => $ticket_id)); - $tickets_display = eh_crm_get_settingsmeta('0', 'tickets_display'); - $current_meta = eh_crm_get_ticketmeta($ticket_id); - $logged_user = wp_get_current_user(); - $logged_user_caps = array_keys($logged_user->caps); - $avail_caps = array('reply_tickets', 'delete_tickets', 'manage_tickets', 'manage_templates', 'merge_tickets'); - $total_count = array(); // (eh_crm_get_ticket_value_count("ticket_parent",0)); - $access = array(); - if (!in_array('administrator', $logged_user->roles)) { - for ($i = 0; $i < count($logged_user_caps); $i++) { - if (!in_array($logged_user_caps[$i], $avail_caps)) { - unset($logged_user_caps[$i]); - } - } - $access = $logged_user_caps; - } else { - $access = $avail_caps; - } - $users_data = get_users( - array( - 'role__in' => array('administrator', 'WSDesk_Agents', 'WSDesk_Supervisor'), - 'orderby' => 'display_name', - ) - ); - $users = array(); - for ($i = 0; $i < count($users_data); $i++) { - $current_user = $users_data[$i]; - $temp = array(); - $roles = $current_user->roles; - foreach ($roles as $value) { - $current_role = $value; - $temp[$i] = ucfirst(str_replace('_', ' ', $current_role)); - } - $users[implode(' & ', $temp)][$current_user->ID] = $current_user->data->display_name; - } - $avail_fields = eh_crm_get_settings(array('type' => 'field'), array('slug', 'title', 'settings_id')); - $selected_fields = eh_crm_get_settingsmeta(0, 'selected_fields'); - if (!$selected_fields) { - $selected_fields = array(); - } - $avail_tags = eh_crm_get_settings(array('type' => 'tag'), array('slug', 'title', 'settings_id')); - $avail_labels = eh_crm_get_settings(array('type' => 'label'), array('slug', 'title', 'settings_id')); - $ticket_label = ''; - $ticket_label_slug = ''; - $eye_color = ''; - for ($j = 0; $j < count($avail_labels); $j++) { - if ($avail_labels[$j]['slug'] == $current_meta['ticket_label']) { - $ticket_label = $avail_labels[$j]['title']; - $eye_color = eh_crm_get_settingsmeta($avail_labels[$j]['settings_id'], 'label_color'); - } - } - $ticket_tags_list = ''; - $response = array(); - $co = 0; - $auto_suggestion_is_enabled = eh_crm_get_settingsmeta(0, 'auto_suggestion') == 'enable'; - if (!empty($avail_tags)) { - for ($j = 0; $j < count($avail_tags); $j++) { - $current_ticket_tags = (isset($current_meta['ticket_tags']) ? array_values($current_meta['ticket_tags']) : array()); - - for ($k = 0; $k < count($current_ticket_tags); $k++) { - if ($avail_tags[$j]['slug'] == $current_ticket_tags[$k]) { - if ($auto_suggestion_is_enabled) { - - $args_post = array( - 'orderby' => 'ID', - 'numberposts' => -1, - 'post_type' => array('post', 'product'), - 'post__in' => eh_crm_get_settingsmeta($avail_tags[$j]['settings_id'], 'tag_posts'), - ); - $posts = get_posts($args_post); - $temp = get_post(); - for ($m = 0; $m < count($posts); $m++, $co++) { - $response[$co]['title'] = $posts[$m]->post_title; - $response[$co]['guid'] = get_permalink($posts[$m]->ID); - } - } - $ticket_tags_list .= '<span class="label label-info">#' . $avail_tags[$j]['title'] . '</span>'; - } - } - } - } - if (null === $pagination) { - $pagination = array(); - } - $index = array_search($ticket_id, $pagination); - $next = ''; - $previous = ''; - if (false !== $index) { - if ($index + 1 < count($pagination)) { - $next = $pagination[$index + 1]; - } - if ($index - 1 >= 0) { - $previous = $pagination[$index - 1]; - } - } - - /** - * Fire a filter hook for wpml current language - * - * @since 3.1.2 - * - */ - $my_current_lang = apply_filters('wpml_current_language', null); - - /** - * Fire an action hook for wpml switch language - * - * @since 3.1.2 - * - * @param $my_current_lang - * - */ - do_action('wpml_switch_language', $my_current_lang); - $blog_info = eh_crm_wpml_translations(get_bloginfo('name'), 'bloginfo', 'bloginfo'); - $ticket_label = eh_crm_wpml_translations($ticket_label, 'ticket_label_title', 'ticket_label_title'); - ?> - - <!-- Sliding div ends here --> - <div class="container"> - <div class="row"> - <div class="col-md-12"> - <ol class="breadcrumb col-md-8" - style="margin: 0 !important;background: none !important;border:none;padding: 8px 0px !important; "> - <li><?php echo esc_html__($blog_info, 'wsdesk'); ?></li> - <li><?php echo esc_html__($ticket_label, 'wsdesk'); ?></li> - <?php - $ticket_credits_deducted = eh_crm_get_ticketmeta($ticket_id, 'credit_deducted'); - if (false != $ticket_credits_deducted) { - ?> - <li><span - style="color: red;"><?php echo esc_html__('Total Credit(s) Deducted : ' . $ticket_credits_deducted, 'wsdesk'); ?></span> - </li> - <?php - } - ?> - <li class="active"><span class="label label-success" - style="background-color:<?php echo esc_html($eye_color); ?> !important"><?php esc_html_e('Ticket', 'wsdesk'); ?> - #<?php echo esc_html($ticket_id); ?></span></li> - <span class="spinner_loader ticket_loader_<?php echo esc_html($ticket_id); ?>"> - <span class="bounce1"></span> - <span class="bounce2"></span> - <span class="bounce3"></span> - </span> - <?php if (EH_CRM_PAY_FOR_SUPPORT_STATUS) { ?> - <img src="<?php echo esc_url(WSDESK_PAY_EH_CRM_MAIN_IMG . 'load.gif'); ?>" - class='wsdesk_pay_for_support_loader' style="width:5% ;height: 1%;display:none;"> - <?php } ?> - </ol> - <a title="<?php echo esc_html__('Print Ticket', 'wsdesk'); ?>" class="btn btn-default pull-right" - target="_blank" - href="<?php echo esc_url(admin_url('admin.php?page=wsdesk_print&ticket=' . $ticket_id . '&master=' . md5($current[0]['ticket_email']))); ?>"> - <span class="glyphicon glyphicon-print"></span> - </a> - <?php - if (in_array('delete_tickets', $access)) { - echo '<button title="' . esc_html__('Delete Ticket', 'wsdesk') . '" type="button" class="btn btn-default ticket_action_delete pull-right" id="' . esc_html($ticket_id) . '" style="margin-right:10px;"> - <span class="glyphicon glyphicon-trash"></span> - </button>'; - } - if (in_array('manage_tickets', $access)) { - echo '<div class="filter-each ticket-edit-btn multiple_ticket_action" id="edit_tickets" style="display: none;"><div class="ticket-edit-button" data-placement="top" data-toggle="wsdesk_tooltip" title="Edit Tickets"><span class="glyphicon glyphicon-edit"></span></div></div>'; - } - if (in_array('merge_tickets', $access)) { - if (wsdesk_is_premium()) { - echo '<button title="' . esc_attr__('Archive Ticket', 'wsdesk') . '" type="button" class="btn btn-default ticket_action_archive pull-right" id="' . esc_html($ticket_id) . '" style="height: 31px;margin-right:10px;"> - <span class="dashicons dashicons-media-archive"></span> - </button>'; - } - - echo '<button title="' . esc_html__('Merge Tickets', 'wsdesk') . '" type="button" class="btn btn-default ticket_action_merge pull-right" id="' . esc_html($ticket_id) . '" style="margin-right:10px;"> - <span>' . esc_html__('Merge Tickets', 'wsdesk') . '</span> - </button>'; - - echo '<button title="' . esc_html__('Refresh Tickets', 'wsdesk') . '" type="button" class="btn btn-default ticket_action_refresh pull-right" data-id="' . esc_html($ticket_id) . '" style="height: 31px;margin-right:10px;"> - <span class="glyphicon glyphicon-refresh"></span> - </button>'; - - echo '<button title="' . esc_html__('Activity Log', 'wsdesk') . '" type="button" class="btn btn-default activity_log_action pull-right " data-page-no="1" data-ticket-id=' . esc_html($ticket_id) . ' data-toggle="modal" data-target="#activity_logs_popup_' . esc_html($ticket_id) . '" style="height: 31px; margin-right:10px;" disabled> - <span>' . esc_html__('Show Activities', 'wsdesk') . ' - <sup class="text-success">[Premium!]</sup> - </span> - </button>'; - } - ?> - <div id="ticket_merge_modal_<?php echo esc_html($ticket_id); ?>" data-backdrop="static" class="modal fade" - role="dialog"> - <div class="modal-dialog"> - <!-- Modal content--> - <div class="modal-content"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal">×</button> - <h4 class="modal-title"><?php esc_html_e('Merge Tickets', 'wsdesk'); ?></h4> - </div> - <div class="modal-body"> - <input type="hidden" id="merge_hidden_ticket_ids_<?php echo esc_html($ticket_id); ?>" - value=''> - <div class="row"> - <select id="all_ticket_ids_<?php echo esc_html($ticket_id); ?>" - class="form-control crm-form-element-input all_ticket_ids" multiple="multiple"> - <?php - foreach ($total_count as $parent_ids) { - if ($parent_ids['ticket_id'] != $ticket_id) { - echo '<option value=' . esc_attr($parent_ids['ticket_id']) . '>' . esc_html($parent_ids['ticket_id']) . '</option>'; - } - } - ?> - </select> - </div> - <div class="row verify" style="overflow-y: auto; max-height:400px; "> - </div> - </div> - <div class="modal-footer"> - <button type="button" class="btn btn-default" - data-dismiss="modal"><?php esc_html_e('Close', 'wsdesk'); ?></button> - <button data-ticket_id="<?php echo esc_html($ticket_id); ?>" type="button" - class="btn btn-success merge_ticket_verify"><?php esc_html_e('Verify', 'wsdesk'); ?></button> - <button data-ticket_id="<?php echo esc_html($ticket_id); ?>" type="button" - class="btn btn-primary merge_ticket_confirm"><?php esc_html_e('Confirm', 'wsdesk'); ?></button> - </div> - </div> - </div> - </div> - - - <div class="btn-group btn-group-sm pull-right" id="<?php echo esc_html($ticket_id); ?>" - style="margin-right:10px;"> - <?php - if ('' != $previous) { - ?> - <button type="button" class="btn btn-default single_pagination_tickets" - id="<?php echo esc_html($previous); ?>" title="<?php esc_html_e('Previous', 'wsdesk'); ?>" - data-container="body" style="margin-right:5px;"> - <span class="glyphicon glyphicon-chevron-left"></span> - </button> - <?php - } - if ('' != $next) { - ?> - <button type="button" class="btn btn-default single_pagination_tickets" - id="<?php echo esc_html($next); ?>" title="<?php esc_html_e('Next', 'wsdesk'); ?>" - data-container="body" style="margin-left:5px;"> - <span class="glyphicon glyphicon-chevron-right"></span> - </button> - <?php - } - ?> - </div> - </div> - </div> - <span class="crm-divider" style="margin-bottom:2px;margin-left: -15px;width: 103.75%;"></span> - <?php - if (EH_CRM_PAY_FOR_SUPPORT_STATUS) { - $user = get_user_by('email', $current[0]['ticket_email']); - /** - * Fire an action hook for ticket tab after breadcrump - * - * @since 3.1.2 - * - * @param $user - * @param $ticket_id - * - */ - do_action('wsdesk_ticket_tab_after_breadcrumb', $user->ID, $ticket_id); - } - ?> - <div class="row"> - <div class="col-md-3" style="padding-right: 0px;padding-top: 10px;"> - <div class="form-group"> - <span class="help-block"><?php esc_html_e('Assignee', 'wsdesk'); ?></span> - <select id="assignee_ticket_<?php echo esc_html($ticket_id); ?>" class="form-control" - aria-describedby="helpBlock" multiple="multiple"> - <?php - $assignee = (isset($current_meta['ticket_assignee']) ? $current_meta['ticket_assignee'] : array()); - if ('' !== $assignee) { - foreach ($users as $key => $value) { - if (in_array('manage_tickets', $access)) { - foreach ($value as $id => $name) { - $selected = ''; - if (in_array($id, $assignee)) { - $selected = 'selected'; - } - echo '<option value="' . esc_attr($id) . '" ' . esc_html($selected) . '>' . esc_html($name) . ' | ' . esc_html($key) . '</option>'; - } - } else { - foreach ($value as $id => $name) { - if (in_array($id, $assignee)) { - echo '<option value="' . esc_attr($id) . '" selected>' . esc_html($name) . ' | ' . esc_html($key) . '</option>'; - } - } - } - } - } - ?> - </select> - </div> - <?php - $cc = (isset($current_meta['ticket_cc']) ? $current_meta['ticket_cc'] : array()); - ?> - <div class="form-group"> - <span class="help-block"><?php esc_html_e('CC', 'wsdesk'); ?> <span - class="glyphicon glyphicon-info-sign" - style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" - title="<?php esc_html_e('To add multiple CC, separate each address with comma without any space.', 'wsdesk'); ?>" - data-container="body"></span></span> - <input type="text" id="cc_ticket_<?php echo esc_html($ticket_id); ?>" - class="form-control cc_<?php echo esc_html($ticket_id); ?>" - value="<?php echo esc_html(join(',', $cc)); ?>"> - </div> - <?php - $bcc = (isset($current_meta['ticket_bcc']) ? $current_meta['ticket_bcc'] : array()); - if (!empty($bcc)) { - ?> - <div class="form-group"> - <span class="help-block"><?php esc_html_e('Bcc', 'wsdesk'); ?></span> - <select id="bcc_ticket_<?php echo esc_html($ticket_id); ?>" - class="form-control bcc_select_<?php echo esc_html($ticket_id); ?>" aria-describedby="helpBlock" - multiple="multiple"> - <?php - foreach ($bcc as $key => $value) { - if (in_array('manage_tickets', $access)) { - echo '<option value="' . esc_attr($value) . '" selected>' . esc_html($value) . '</option>'; - } else { - echo '<option value="' . esc_attr($value) . '" selected>' . esc_html($value) . '</option>'; - } - } - ?> - </select> - </div> - <?php - } - ?> - <div class="form-group"> - <span class="help-block"><?php esc_html_e('Tags', 'wsdesk'); ?></span> - <select id="tags_ticket_<?php echo esc_html($ticket_id); ?>" class="form-control crm-form-element-input" - multiple="multiple"> - <?php - $ticket_tags = (isset($current_meta['ticket_tags']) ? $current_meta['ticket_tags'] : array()); - if ('' !== $ticket_tags && !empty($avail_tags)) { - for ($i = 0; $i < count($avail_tags); $i++) { - if (in_array('manage_tickets', $access)) { - $selected = ''; - if (in_array($avail_tags[$i]['slug'], $ticket_tags)) { - $selected = 'selected'; - } - echo '<option value="' . esc_attr($avail_tags[$i]['slug']) . '" ' . esc_attr($selected) . '>' . esc_html($avail_tags[$i]['title']) . '</option>'; - } else { - if (in_array($avail_tags[$i]['slug'], $ticket_tags)) { - echo '<option value="' . esc_attr($avail_tags[$i]['slug']) . '" selected>' . esc_html($avail_tags[$i]['title']) . '</option>'; - } - } - } - } - ?> - </select> - </div> - <hr /> - <?php - for ($i = 0; $i < count($selected_fields); $i++) { - for ($j = 3; $j < count($avail_fields); $j++) { - if ($avail_fields[$j]['slug'] == $selected_fields[$i]) { - $field_ticket_value = (isset($current_meta[$avail_fields[$j]['slug']]) ? $current_meta[$avail_fields[$j]['slug']] : ''); - $current_settings_meta = eh_crm_get_settingsmeta($avail_fields[$j]['settings_id']); - $required = (isset($current_settings_meta['field_require_agent']) ? $current_settings_meta['field_require_agent'] : ''); - $required = ('yes' === $required) ? 'required' : ''; - if ('file' != $current_settings_meta['field_type'] && 'google_captcha' != $current_settings_meta['field_type']) { - echo '<div class="form-group">'; - echo '<span class="help-block">' . esc_html($avail_fields[$j]['title']); - echo ('required' === $required) ? '<span class="input_required"> *</span></span>' : '</span>'; - if ('select' == $current_settings_meta['field_type']) { - if ('woo_order_id' == $avail_fields[$j]['slug']) { - $current_settings_meta['field_type'] = 'text'; - } - } - switch ($current_settings_meta['field_type']) { - case 'text': - $readonly = ''; - if (!in_array('manage_tickets', $access)) { - $readonly = 'readonly'; - } - $required_text = ''; - if ('required' == $required) { - $required_text = 'text_required'; - } - echo '<input type="text" AUTOCOMPLETE="off" class="form-control ' . esc_attr($required_text) . ' crm-form-element-input ticket_input_text_' . esc_attr($ticket_id) . '" id="' . esc_attr($avail_fields[$j]['slug']) . '" placeholder="' . esc_attr($current_settings_meta['field_placeholder']) . '" ' . esc_attr($readonly) . ' value="' . esc_html($field_ticket_value) . '">'; - break; - case 'ip': - echo '<label style="font-weight: normal !important;">' . esc_html($field_ticket_value) . '</label>'; - break; - case 'date': - $readonly = ''; - if (!in_array('manage_tickets', $access)) { - $readonly = 'readonly'; - } - $value = ''; - if ('' != $field_ticket_value) { - $value = $field_ticket_value; - } - $required_text = ''; - if ('required' == $required) { - $required_text = 'text_required'; - } - echo '<input type="text" AUTOCOMPLETE="off" class="form-control ' . esc_attr($required_text) . ' crm-form-element-input trigger_date_jq ticket_input_date_' . esc_attr($ticket_id) . '" id="' . esc_attr($avail_fields[$j]['slug']) . '_t_' . esc_attr($ticket_id) . '" placeholder="' . esc_attr($current_settings_meta['field_placeholder']) . '" ' . esc_attr($readonly) . ' value="' . esc_attr($value) . '">'; - break; - case 'email': - $readonly = ''; - if (!in_array('manage_tickets', $access)) { - $readonly = 'readonly'; - } - $required_text = ''; - if ('required' == $required) { - $required_text = 'text_required'; - } - echo '<input type="email" AUTOCOMPLETE="off" class="form-control ' . esc_attr($required_text) . ' crm-form-element-input ticket_input_email_' . esc_attr($ticket_id) . '" id="' . esc_attr($avail_fields[$j]['slug']) . '" placeholder="' . esc_attr($current_settings_meta['field_placeholder']) . '" ' . esc_attr($readonly) . ' value="' . esc_html($field_ticket_value) . '">'; - break; - case 'phone': - $readonly = ''; - if (!in_array('manage_tickets', $access)) { - $readonly = 'readonly'; - } - $required_text = ''; - if ('required' == $required) { - $required_text = 'text_required'; - } - echo '<span><strong>+</strong><input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" AUTOCOMPLETE="off" class="form-control ' . esc_attr($required_text) . ' crm-form-element-input ticket_input_number_' . esc_attr($ticket_id) . '" id="' . esc_attr($avail_fields[$j]['slug']) . '" placeholder="' . esc_attr($current_settings_meta['field_placeholder']) . '" ' . esc_attr($readonly) . ' value="' . esc_html($field_ticket_value) . '" style="display: inline !important; width: 97% !important;"></span>'; - break; - case 'number': - $readonly = ''; - if (!in_array('manage_tickets', $access)) { - $readonly = 'readonly'; - } - $required_text = ''; - if ('required' == $required) { - $required_text = 'text_required'; - } - echo '<input type="number" AUTOCOMPLETE="off" class="form-control ' . esc_attr($required_text) . ' crm-form-element-input ticket_input_number_' . esc_attr($ticket_id) . '" id="' . esc_attr($avail_fields[$j]['slug']) . '" placeholder="' . esc_attr($current_settings_meta['field_placeholder']) . '" ' . esc_attr($readonly) . ' value="' . esc_html($field_ticket_value) . '">'; - break; - case 'password': - $readonly = ''; - if (in_array('manage_tickets', $access)) { - $readonly = 'onfocus="this.removeAttribute(\'readonly\');"'; - } - $required_text = ''; - if ('required' == $required) { - $required_text = 'text_required'; - } - echo '<input type="password" AUTOCOMPLETE="false" readonly class="form-control ' . esc_attr($required_text) . ' crm-form-element-input ticket_input_pwd_' . esc_attr($ticket_id) . '" id="' . esc_attr($avail_fields[$j]['slug']) . '" placeholder="' . esc_attr($current_settings_meta['field_placeholder']) . '" ' . esc_attr($readonly) . ' value="' . esc_html($field_ticket_value) . '">'; - break; - case 'select': - $field_values = $current_settings_meta['field_values']; - $required_text = ''; - if ('required' == $required) { - $required_text = 'text_required'; - } - echo '<select class="form-control crm-form-element-input ' . esc_attr($required_text) . ' ticket_input_select_' . esc_attr($ticket_id) . '" id="' . esc_attr($avail_fields[$j]['slug']) . '">'; - echo '<option value="">' . (isset($current_settings_meta['field_placeholder']) ? esc_attr($current_settings_meta['field_placeholder']) : '-') . '</option>'; - foreach ($field_values as $key => $value) { - if (in_array('manage_tickets', $access)) { - $selected = ''; - if ($key == $field_ticket_value) { - $selected = 'selected'; - } - echo '<option value="' . esc_attr($key) . '" ' . esc_attr($selected) . '>' . esc_html($value) . '</option>'; - } else { - if ($key == $field_ticket_value) { - echo '<option value="' . esc_attr($key) . '" selected>' . esc_html($value) . '</option>'; - } - } - } - echo '</select>'; - break; - case 'radio': - $required_radio = ''; - if ('required' == $required) { - $required_radio = 'radio_required'; - } - $field_values = $current_settings_meta['field_values']; - echo '<span style="vertical-align: middle;">'; - foreach ($field_values as $key => $value) { - if (in_array('manage_tickets', $access)) { - $checked = ''; - if ($key == $field_ticket_value) { - $checked = 'checked'; - } - echo '<input type="radio" style="margin-top: 0;" id="' . esc_attr($avail_fields[$j]['slug']) . '_' . esc_html($ticket_id) . '" name="' . esc_attr($avail_fields[$j]['slug']) . '_' . esc_html($ticket_id) . '" class="form-control ' . esc_attr($required_radio) . ' ticket_input_radio_' . esc_attr($ticket_id) . '" value="' . esc_attr($key) . '" ' . esc_attr($checked) . '> ' . esc_html($value) . '<br>'; - } else { - if ($key == $field_ticket_value) { - echo '<input type="radio" style="margin-top: 0;" id="' . esc_attr($avail_fields[$j]['slug']) . '_' . esc_html($ticket_id) . '" name="' . esc_attr($avail_fields[$j]['slug']) . '_' . esc_html($ticket_id) . '" class="form-control ' . esc_attr($required_radio) . ' ticket_input_radio_' . esc_attr($ticket_id) . '" value="' . esc_attr($key) . '" checked readonly> ' . esc_html($value) . '<br>'; - } - } - } - echo '</span>'; - break; - case 'checkbox': - $required_check = ''; - if ('required' == $required) { - $required_check = 'check_required'; - } - $field_values = $current_settings_meta['field_values']; - $field_ticket_value = is_array($field_ticket_value) ? $field_ticket_value : array(); - echo '<span style="vertical-align: middle;">'; - foreach ($field_values as $key => $value) { - if (in_array('manage_tickets', $access)) { - $checked = ''; - if (in_array($key, $field_ticket_value)) { - $checked = 'checked'; - } - echo '<input type="checkbox" style="margin-top: 0;" id="' . esc_attr($avail_fields[$j]['slug']) . '" class="form-control ' . esc_attr($required_check) . ' ticket_input_checkbox_' . esc_attr($ticket_id) . '" value="' . esc_attr($key) . '" ' . esc_attr($checked) . '> ' . esc_html($value) . '<br>'; - } else { - if (in_array($key, $field_ticket_value)) { - echo '<input type="checkbox" style="margin-top: 0;" id="' . esc_attr($avail_fields[$j]['slug']) . '" class="form-control ' . esc_attr($required_check) . ' ticket_input_checkbox_' . esc_attr($ticket_id) . '" value="' . esc_attr($key) . '" checked readonly> ' . esc_html($value) . '<br>'; - } - } - } - echo '</span>'; - break; - case 'textarea': - $required_text = ''; - if ('required' == $required) { - $required_text = 'text_required'; - } - $readonly = ''; - if (!in_array('manage_tickets', $access)) { - $readonly = 'readonly'; - } - echo '<textarea class="form-control ' . esc_attr($required_text) . ' except_rich ticket_input_textarea_' . esc_attr($ticket_id) . '" id="' . esc_attr($avail_fields[$j]['slug']) . '" ' . esc_attr($readonly) . '>' . esc_html($field_ticket_value) . '</textarea>'; - break; - case 'pfs_order_product': - if (false === EH_CRM_PAY_FOR_SUPPORT_STATUS) { - break; - } - echo '<select name="pfs_order_product" id="pfs_order_product" class="input_element form-control pfs_order_product_' . esc_attr($ticket_id) . '">'; - $pfs_user_id = $current[0]['ticket_author']; - if (0 != $pfs_user_id) { - $current_product_names = WSDESK_Pay_for_Support_Subscription::pfs_get_product_names($pfs_user_id); - if (count($current_product_names) > 0) { - $ticket_meta = eh_crm_get_ticketmeta($ticket_id); - if (isset($ticket_meta['pfs_order_product'])) { - $order_info = explode(',', $ticket_meta['pfs_order_product']); - $order_id = intval($order_info[0]); - $product_id = intval($order_info[1]); - } else { - $order_id = null; - $product_id = null; - } - echo '<option value="">' . esc_html__('Please select a product for the Ticket', 'wsdesk') . '</option>'; - foreach ($current_product_names as $products) { - echo '<option value="' . esc_attr($products['order_id']) . ',' . esc_attr($products['product_id']) . '"'; - if ($products['order_id'] == $order_id && $products['product_id'] == $product_id) { - echo 'selected'; - } - echo '>' . esc_html($products['product_name']) . ' (order id:' . esc_html($products['order_id']) . ')</option>'; - } - } - } - echo '</select>'; - break; - } - echo '</div>'; - } - } - }
I'll analyze the provided code diff for security vulnerabilities.
Vulnerability Existed: yes
FALSE POSITIVE
Improper Input Validation and Sanitization - CWE-20 - includes/class-crm-ajax-functions-two.php - Line 149
Old Code:
```php
$files = isset($_FILES['file']) ? sanitize_text_field($_FILES['file']) : '';
```
Fixed Code:
```php
// No visible change in provided diff - vulnerability persists
```
Explanation:
The code uses `sanitize_text_field()` on the entire `$_FILES['file']` array, which is incorrect. The `$_FILES` superglobal is an array of file metadata (name, type, tmp_name, error, size), not a text string. `sanitize_text_field()` cannot properly sanitize file upload data. This should validate individual file properties instead.
---
Vulnerability Existed: yes
FALSE POSITIVE
Cross-Site Scripting (XSS) - CWE-79 - includes/class-crm-ajax-functions-two.php - Line 239
Old Code:
```php
$tab = '<a onclick="setURLFunc(' . $ticket_id . ')" href="#tab_content_' . $ticket_id . '" id="tab_content_a_' . $ticket_id . '" aria-controls="#' . $ticket_id . '" role="tab" data-toggle="tab" class="tab_a" style="font-size: 12px;padding: 11px 5px;margin-right:0px !important;"><button type="button" class="btn btn-default btn-circle close_tab pull-right"><span class="glyphicon glyphicon-remove"></span></button><div class="badge">#' . $ticket_id . '</div><span class="tab_head"> ' . stripslashes(html_entity_decode(htmlentities($current[0]['ticket_title']))) . '</span></a>';
```
Fixed Code:
```php
// No visible change in provided diff - vulnerability persists
```
Explanation:
The code uses `stripslashes(html_entity_decode(htmlentities(...)))` which unnecessarily decodes HTML entities and removes slashes, potentially exposing XSS vulnerabilities. The `$ticket_id` is directly concatenated into HTML attributes without escaping. If `$ticket_id` contains malicious characters, it could break out of attributes. Should use `esc_attr()` for HTML attributes.
---
Vulnerability Existed: yes
FALSE POSITIVE
Insufficient Input Validation - CWE-1021 - includes/class-crm-ajax-functions-two.php - Line 22-23
Old Code:
```php
$user_id = isset($_POST['user_id']) ? sanitize_text_field($_POST['user_id']) : '';
$rights_input = isset($_POST['rights']) ? sanitize_text_field($_POST['rights']) : '';
```
Fixed Code:
```php
// No visible change in provided diff - vulnerability persists
```
Explanation:
The `$user_id` is sanitized with `sanitize_text_field()` but never validated as a valid user ID before being used with `new WP_User($user_id)`. A non-existent or invalid user ID could create unexpected behavior. Should validate that the user exists before proceeding.
---
Vulnerability Existed: yes
FALSE POSITIVE
Improper Nonce Verification Logic - CWE-352 - includes/class-crm-ajax-functions-two.php - Line 82
Old Code:
```php
if (wp_verify_nonce(isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : '', 'wsdesk_nonce')) {
```
Fixed Code:
```php
// No visible change in provided diff - vulnerability persists
```
Explanation:
The nonce verification uses a negated condition check. If `wp_verify_nonce()` returns false (nonce invalid), the entire block is skipped silently without any response. However, in `eh_crm_edit_agent()` (line 10-11), the verification returns a proper error response on failure. This inconsistency in `eh_crm_remove_agent()` could allow operations to silently fail without proper authorization checks being evident.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-ajax-functions.php 2025-12-21 09:35:59.417065320 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-ajax-functions.php 2025-12-21 09:36:35.227291036 +0000@@ -1,2568 +1,2568 @@-<?php - -use WSDesk\Formatter\Cast\TimestampCaster; - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -require __DIR__ . '/class-crm-ajax-functions-three.php'; - -class CRM_Ajax extends CRM_Ajax_Three { - - public static function eh_crm_user_ticket_fetch( $email, $user, $slug = array(), $current_page = 1, $filter_label = '', $search_tickets = '' ) { - $tickets_per_page = 25; - $email_id = eh_crm_get_ticket_value_count( 'ticket_email', $email, false, 'ticket_parent', 0, 'ticket_updated' ); - $user_id = eh_crm_get_ticket_value_count( 'ticket_author', $user, false, 'ticket_parent', 0, 'ticket_updated' ); - $ticket = array_values( array_unique( array_merge( $user_id, $email_id ), SORT_REGULAR ) ); - if ( empty( $ticket ) ) { - return esc_html__( 'No Tickets Found', 'wsdesk' ); - } - if ( 'all' != $filter_label ) { - $filter_label_tickets = array(); - for ( $i = 0; $i < count( $ticket ); $i++ ) { - $current_meta = eh_crm_get_ticketmeta( $ticket[ $i ]['ticket_id'] ); - if ( $current_meta['ticket_label'] == $filter_label ) { - array_push( $filter_label_tickets, $ticket[ $i ] ); - } - } - $ticket = $filter_label_tickets; - } - if ( '' != $search_tickets ) { - $searched_tickets = array(); - for ( $i = 0; $i < count( $ticket ); $i++ ) { - $current = eh_crm_get_ticket( array( 'ticket_id' => $ticket[ $i ]['ticket_id'] ) ); - if ( ( strpos( $current[0]['ticket_title'], $search_tickets ) !== false || strpos( $current[0]['ticket_content'], $search_tickets ) !== false ) || $search_tickets == $ticket[ $i ]['ticket_id'] ) { - array_push( $searched_tickets, $ticket[ $i ] ); - } - } - $ticket = $searched_tickets; - } - $user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ); - $users = get_users( array( 'role__in' => $user_roles_default ) ); - $users_data = array(); - for ( $i = 0; $i < count( $users ); $i++ ) { - $current = $users[ $i ]; - $id = $current->ID; - $user = new WP_User( $id ); - $users_data[ $i ]['id'] = $id; - $users_data[ $i ]['name'] = $user->display_name; - $users_data[ $i ]['caps'] = $user->caps; - $users_data[ $i ]['email'] = $user->user_email; - } - $avail_labels = eh_crm_get_settings( array( 'type' => 'label' ), array( 'slug', 'title', 'settings_id' ) ); - $avail_fields = eh_crm_get_settings( array( 'type' => 'field' ), array( 'slug', 'title', 'settings_id' ) ); - $enable = eh_crm_get_settingsmeta( '0', 'close_tickets' ); - if ( ! $enable ) { - $enable = 'enable'; - } - $pages = floor( count( $ticket ) / $tickets_per_page ); - if ( count( $ticket ) % $tickets_per_page ) { - $pages++; - } - $right_disable = ''; - if ( $current_page == $pages ) { - $right_disable = 'disabled'; - } - $left_disable = ''; - if ( 1 == $current_page ) { - $left_disable = 'disabled'; - } - - $args = array( 'type' => 'label' ); - $fields = array( 'slug', 'title', 'settings_id' ); - $avail_labels = eh_crm_get_settings( $args, $fields ); - ob_start(); - ?> - <div class="panel panel-default tickets_panel" style="width:100%; overflow-x: scroll"> - <div class="panel-heading"> - <h3 class="panel-title"> - <div class="dropdown"> - <button class="btn dropdown-toggle filter_pagination_search pull-right" type="button" data-toggle="dropdown"><span class="glyphicon glyphicon-filter"></span></button> - <ul class="dropdown-menu pull-right filter_dropdown"> - <?php - if ( ! empty( $avail_labels ) ) { - echo '<li><a href="#" class="filter_label" id="all">' . esc_html__( 'Show All', 'wsdesk' ) . '</a></li>'; - for ( $i = 0;$i < count( $avail_labels );$i++ ) { - $label_title = eh_crm_wpml_translations( $avail_labels[ $i ]['title'], 'labels_' . $i . '_title', 'labels_' . $i . '_title' ); - echo '<li><a href="#" class="filter_label" id="' . esc_attr( $avail_labels[ $i ]['slug'] ) . '">' . esc_html__( 'Show ', 'wsdesk' ) . esc_html( $avail_labels[ $i ]['title'] ) . '</a></li>'; - } - } - ?> - </ul> - </div> - <input type="hidden" value="all" id="filter_label_input"> - <button type="button" <?php echo esc_html( $right_disable ); ?> class="btn filter_pagination_search pull-right" id="right_page"><span class="glyphicon glyphicon-chevron-right"></span></button> - <span class="filter_pagination_search pull-right wsdesk_current_page" id="<?php echo esc_html( $current_page ); ?>"><?php echo esc_html( $current_page ); ?></span> - <button type="button" <?php echo esc_html( $left_disable ); ?> class="btn filter_pagination_search pull-right" id="left_page"><span class="glyphicon glyphicon-chevron-left"></span></button> - <div class="filter_pagination_search pull-right" style="position: relative"> - <span class="glyphicon glyphicon-search pull-right" id="search_ticket_icon"></span> - <input type="text" name="search_tickets" id="search_tickets" class="filter_pagination_search" value="<?php echo esc_html( $search_tickets ); ?>" placeholder="<?php esc_html_e( 'Search Tickets', 'wsdesk' ); ?>"> - - </div> - - <button type="submit" class="filter-each btn btn-primary" id="submit_check_all" style="display:none;margin-right: 2em;"> <?php esc_html_e( 'Close Ticket(s)', 'wsdesk' ); ?> - </button> - <?php esc_html_e( 'Your Tickets', 'wsdesk' ); ?> - <span class="spinner_loader table_loader"> - <span class="bounce1"></span> - <span class="bounce2"></span> - <span class="bounce3"></span> - </span> - </h3> - </div> - <table class="table table-hover" id="support-table"> - <thead> - <tr class="except_view"> - <?php if ( 'enable' == $enable ) { ?> - <th><div class="filter-each"><input type="checkbox" class="ticket_select_all_check"></div></th> - <?php } ?> - <th>#</th> - <th><?php esc_html_e( 'Subject', 'wsdesk' ); ?></th> - <th><?php esc_html_e( 'Requested', 'wsdesk' ); ?></th> - <th><?php esc_html_e( 'Assignee', 'wsdesk' ); ?></th> - <th><?php esc_html_e( 'Status', 'wsdesk' ); ?></th> - <?php - if ( ! empty( $slug ) ) { - $selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' ); - foreach ( $slug as $value ) { - if ( in_array( $value, $selected_fields ) ) { - for ( $j = 0;$j < count( $avail_fields );$j++ ) { - if ( $avail_fields[ $j ]['slug'] == $value ) { - $avail_fields_title = eh_crm_wpml_translations( $avail_fields[ $j ]['title'], $avail_fields[ $j ] . '_fields_title', $avail_fields[ $j ] . '_fields_title' ); - ?> - <th><?php echo esc_html( $avail_fields_title ); ?></th> - <?php - } - } - } - } - } - ?> - </tr> - </thead> - <tbody> - <?php - if ( ! empty( $ticket ) ) { - for ( $i = ( $tickets_per_page * ( $current_page - 1 ) );$i < $tickets_per_page * $current_page && $i < count( $ticket );$i++ ) { - $current = eh_crm_get_ticket( array( 'ticket_id' => $ticket[ $i ]['ticket_id'] ) ); - $current_meta = eh_crm_get_ticketmeta( $ticket[ $i ]['ticket_id'] ); - $eye_color = ''; - $label_name = ''; - for ( $j = 0;$j < count( $avail_labels );$j++ ) { - if ( $avail_labels[ $j ]['slug'] == $current_meta['ticket_label'] ) { - $label_name = $avail_labels[ $j ]['title']; - $eye_color = eh_crm_get_settingsmeta( $avail_labels[ $j ]['settings_id'], 'label_color' ); - } - } - $ticket_assignee_name = array(); - if ( isset( $current_meta['ticket_assignee'] ) ) { - $current_assignee = $current_meta['ticket_assignee']; - for ( $k = 0;$k < count( $current_assignee );$k++ ) { - for ( $l = 0;$l < count( $users_data );$l++ ) { - if ( $users_data[ $l ]['id'] == $current_assignee[ $k ] ) { - array_push( $ticket_assignee_name, $users_data[ $l ]['name'] ); - } - } - } - } - $ticket_assignee_name = empty( $ticket_assignee_name ) ? esc_html__( 'No Assignee', 'wsdesk' ) : implode( ', ', $ticket_assignee_name ); - - echo '<tr class="ticket_row" id="' . esc_html( $current[0]['ticket_id'] ) . '">'; - - if ( 'enable' == $enable ) { - echo ' <td class="except_view"><input type="checkbox" name="check" class="ticket_select_check" id="ticket_select_check" value="' . esc_html( $current[0]['ticket_id'] ) . '"></td>'; - } - $ticket_title = eh_crm_wpml_translations( $current[0]['ticket_title'], $ticket[ $i ]['ticket_id'] . '_ticket_title', $ticket[ $i ]['ticket_id'] . '_ticket_title' ); - $label_name = eh_crm_wpml_translations( $label_name, $ticket[ $i ]['ticket_id'] . '_label_name', $ticket[ $i ]['ticket_id'] . '_label_name' ); - echo ' - <td><a href="' . esc_url( eh_get_url_by_shortcode( '[wsdesk_support display="form_support_request_table"' ) ) . '?customer_ticket_num=' . esc_attr( $current[0]['ticket_id'] ) . '" target="_blank">' . esc_attr( $current[0]['ticket_id'] ) . '</a></td> - <td class="wrap_content"><a href="' . esc_attr( eh_get_url_by_shortcode( '[wsdesk_support display="form_support_request_table"' ) ) . '?customer_ticket_num=' . esc_attr( $current[0]['ticket_id'] ) . '" target="_blank">' . esc_html( $ticket_title ) . '</a></td> - <td>' . esc_html( eh_crm_get_formatted_date( $current[0]['ticket_date'] ) ) . '</td> - <td>' . esc_html( $ticket_assignee_name ) . '</td> - <td><span class="label label-info" style="background-color:' . esc_html( $eye_color ) . ' !important">' . esc_html( $label_name ) . '</td>'; - if ( ! empty( $slug ) ) { - foreach ( $slug as $value ) { - if ( array_key_exists( $value, $current_meta ) ) { - if ( ! empty( $current_meta[ $value ] ) ) { - $field_id = eh_crm_get_settings( array( 'slug' => $value ), 'settings_id' ); - $field_meta = eh_crm_get_settingsmeta( $field_id[0]['settings_id'] ); - switch ( $field_meta['field_type'] ) { - case 'text': - case 'number': - case 'email': - case 'password': - case 'textarea': - case 'date': - case 'ip': - case 'phone': - echo '<td>' . esc_html( $current_meta[ $value ] ) . '</td>'; - break; - case 'select': - if ( 'woo_order_id' == $value ) { - echo '<td>' . esc_html( $current_meta[ $value ] ) . '</td>'; - } else { - echo '<td>' . esc_html( $field_meta['field_values'][ $current_meta[ $value ] ] ) . '</td>'; - } - break; - case 'radio': - case 'woo_product': - case 'woo_category': - case 'woo_tags': - case 'woo_vendors': - echo '<td>' . esc_html( $field_meta['field_values'][ $current_meta[ $value ] ] ) . '</td>'; - break; - case 'checkbox': - $checkbox_values = array(); - foreach ( $current_meta[ $value ] as $a ) { - array_push( $checkbox_values, $field_meta['field_values'][ $a ] ); - } - echo '<td>' . esc_html( implode( ', ', $checkbox_values ) ) . '</td>'; - } - } else { - echo '<td> </td>'; - } - } else { - echo '<td> </td>'; - } - } - } - echo '</tr>'; - } - } else { - echo '<tr class="except_view"> - <td colspan="5">' . esc_html__( 'No Tickets', 'wsdesk' ) . '</td> - </tr>'; - } - ?> - </tbody> - </table> - </div> - <hr/> - <div class="ticket_load_content" style="padding:5px !important"></div> - <?php - $content = ob_get_clean(); - return $content; - } - public static function eh_crm_ticket_close_check_request() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $id_get = array(); - $id_get = json_decode( isset( $_POST['val'] ) ? stripslashes( sanitize_text_field( $_POST['val'] ) ) : null ); - for ( $i = 0;$i < count( $id_get );$i++ ) { - eh_crm_update_ticketmeta( $id_get[ $i ], 'ticket_label', 'label_LL02' ); - - } - die(); - } - } - - public static function eh_crm_ticket_single_view_client() { - $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : ''; - if ( ! wp_verify_nonce( $nonce, 'wsdesk_nonce' ) ) { - wp_send_json_error( array( 'message' => __( 'Invalid request.', 'wsdesk' ) ), 400 ); - wp_die(); - } - - $ticket_id = isset( $_POST['ticket_id'] ) ? absint( $_POST['ticket_id'] ) : 0; - $current = eh_crm_get_ticket( array( 'ticket_id' => $ticket_id ) ); - if ( empty( $current ) || empty( $current[0]['ticket_author'] ) ) { - wp_send_json_error( array( 'message' => __( 'Ticket not found or invalid.', 'wsdesk' ) ), 404 ); - wp_die(); - } - - $ticket_author_id = intval( $current[0]['ticket_author'] ); - $current_user_id = get_current_user_id(); - - $current_user = wp_get_current_user(); - $user_roles = (array) $current_user->roles; - - $allowed_roles = array( 'administrator', 'WSDesk_Agents', 'WSDesk_Supervisor' ); - $has_allowed_role = array_intersect( $allowed_roles, $user_roles ); - - if ( ( $ticket_author_id !== $current_user_id ) && empty( $has_allowed_role ) ) { - wp_send_json_error( array( 'message' => __( 'You are not authorized to view this ticket.', 'wsdesk' ) ), 403 ); - wp_die(); - } - - // Authorized → Generate content. - $content = self::eh_crm_ticket_single_view_client_gen( $ticket_id ); - - wp_send_json_success( array( 'page' => $content ) ); - wp_die(); - } - - - public static function eh_crm_ticket_single_view_client_gen( $ticket_id ) { - - $current = eh_crm_get_ticket( array( 'ticket_id' => $ticket_id ) ); - $current_meta = eh_crm_get_ticketmeta( $ticket_id ); - $users_data = get_users( array( 'role__in' => array( 'administrator', 'WSDesk_Agents', 'WSDesk_Supervisor' ) ) ); - $users = array(); - for ( $i = 0; $i < count( $users_data ); $i++ ) { - $current_user = $users_data[ $i ]; - $temp = array(); - $roles = $current_user->roles; - foreach ( $roles as $value ) { - $current_role = $value; - $temp[ $i ] = ucfirst( str_replace( '_', ' ', $current_role ) ); - } - $users[ implode( ' & ', $temp ) ][ $current_user->ID ] = $current_user->data->display_name; - } - $avail_tags = eh_crm_get_settings( array( 'type' => 'tag' ), array( 'slug', 'title', 'settings_id' ) ); - $avail_labels = eh_crm_get_settings( array( 'type' => 'label' ), array( 'slug', 'title', 'settings_id' ) ); - $ticket_label = ''; - $ticket_label_slug = ''; - $eye_color = ''; - $enable = eh_crm_get_settingsmeta( '0', 'close_tickets' ); - if ( ! $enable ) { - $enable = 'enable'; - } - for ( $j = 0;$j < count( $avail_labels );$j++ ) { - if ( $avail_labels[ $j ]['slug'] == $current_meta['ticket_label'] ) { - $ticket_label = $avail_labels[ $j ]['title']; - $ticket_label_slug = $avail_labels[ $j ]['slug']; - } - if ( $avail_labels[ $j ]['slug'] == $current_meta['ticket_label'] ) { - $eye_color = eh_crm_get_settingsmeta( $avail_labels[ $j ]['settings_id'], 'label_color' ); - } - } - $ticket_tags_list = []; - $response = array(); - $co = 0; - if ( ! empty( $avail_tags ) ) { - for ( $j = 0;$j < count( $avail_tags );$j++ ) { - $current_ticket_tags = ( isset( $current_meta['ticket_tags'] ) ? $current_meta['ticket_tags'] : array() ); - for ( $k = 0;$k < count( $current_ticket_tags );$k++ ) { - if ( $avail_tags[ $j ]['slug'] == $current_ticket_tags[ $k ] ) { - $args_post = array( - 'orderby' => 'ID', - 'numberposts' => -1, - 'post_type' => array( 'post', 'product' ), - 'post__in' => eh_crm_get_settingsmeta( $avail_tags[ $j ]['settings_id'], 'tag_posts' ), - ); - $posts = get_posts( $args_post ); - for ( $m = 0; $m < count( $posts ); $m++,$co++ ) { - $response[ $co ]['title'] = $posts[ $m ]->post_title; - $response[ $co ]['guid'] = $posts[ $m ]->guid; - } - $ticket_tags_list[] = '#' . $avail_tags[ $j ]['title']; - } - } - } - } - ob_start(); - - /** - * Fire a filter hook for wpml current language - * - * @since 3.1. - * - */ - $my_current_lang = apply_filters( 'wpml_current_language', null ); - - /** - * Fire an action hook for wpml switch language - * - * @since 3.1.2 - * - * @param $my_current_lang - * - */ - do_action( 'wpml_switch_language', $my_current_lang ); - - $blog_info = eh_crm_wpml_translations( get_bloginfo( 'name' ), 'bloginfo', 'bloginfo' ); - $ticket_label = eh_crm_wpml_translations( $ticket_label, 'ticket_label_title', 'ticket_label_title' ); - ?> - - <div class="row hidden"> - <div class="col-md-12"> - <ol class="breadcrumb col-md-12" style="margin: 0 !important;background: none !important;border:none;padding: 8px 0px !important; "> - <li><?php echo esc_html( $blog_info ); ?></li> - <li><?php esc_html_e( 'Support', 'wsdesk' ); ?> </li> - <li><?php echo esc_html( $ticket_label ); ?></li> - <li class="active"><span class="label label-success" style="background-color:<?php echo esc_html( $eye_color ); ?> !important"><?php esc_html_e( 'Ticket', 'wsdesk' ); ?> #<?php echo esc_html( $ticket_id ); ?></span></li> - <span class="spinner_loader ticket_loader_<?php echo esc_html( $ticket_id ); ?>"> - <span class="bounce1"></span> - <span class="bounce2"></span> - <span class="bounce3"></span> - </span> - </ol> - </div> - </div> - <hr /> - <div class="row"> - <div class="panel panel-default single_ticket_panel Ws-content-detail-full" id="<?php echo esc_html( $ticket_id ); ?>"> - - <div class="rightPanel" style="border-left: none;"> - - <div class="panel-heading rightPanelHeader" style="width:100% !important;"> - <div class="leftFreeSpace"> - <div class="icon" style="top: 5% !important;"><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'message_icon.png' ); ?>"></div> - <div class="tictxt"> - <p style="margin-top: 5px;font-size: 16px;"> - <?php - echo esc_html( $current[0]['ticket_title'] ); - ?> - <span class="spinner_loader ticket_loader"> - <span class="bounce1"></span> - <span class="bounce2"></span> - <span class="bounce3"></span> - </span> - </p> - <p class="info" style="margin-top: 5px;"> - <!-- <i class="glyphicon glyphicon-user"></i> by--> - <?php - if ( 0 != $current[0]['ticket_author'] ) { - $raiser_obj = new WP_User( $current[0]['ticket_author'] ); - echo esc_html( $raiser_obj->display_name ); - } else { - echo '<span>' . esc_html( $current[0]['ticket_email'] ) . '</span>'; - } - ?> - | <i class="glyphicon glyphicon-calendar"></i> <?php echo esc_html( TimestampCaster::cast( $current[0]['ticket_date'], 'ticket_date' ) ); ?> - | <i class="glyphicon glyphicon-comment"></i> - <?php - $raiser_voice = eh_crm_get_ticket_value_count( 'ticket_parent', $ticket_id, false, 'ticket_category', 'raiser_reply' ); - echo count( $raiser_voice ) . ' ' . esc_html__( 'Raiser Voice', 'wsdesk' ); - ?> - | <i class="glyphicon glyphicon-bullhorn"></i> - <?php - $agent_voice = eh_crm_get_ticket_value_count( 'ticket_parent', $ticket_id, false, 'ticket_category', 'agent_reply' ); - echo count( $agent_voice ) . ' ' . esc_html__( 'Agent Voice', 'wsdesk' ); - ?> - </p> - <p class="info" style="margin-top: 5px;"> - <i class="glyphicon glyphicon-tags"></i> - <?php esc_html_e( 'Tags', 'wsdesk' ); ?> : - <?php if ( empty( $ticket_tags_list ) ) { ?> - <?php echo esc_html__( 'No Tags', 'wsdesk' ); ?> - <?php } else { ?> - <?php foreach ( $ticket_tags_list as $tag_item ) { ?> - <span class="label label-info"><?php echo esc_html( $tag_item ); ?></span> - <?php } ?> - <?php } ?> - </p> - </div> - </div> - </div> - <div class="col-md-12 "> - <div class="row newMsgFull row-collapse" style="margin-bottom: 20px; padding-left:35px;"> - <div class="leftFreeSpace"> - <div class="icon"><img src="<?php echo esc_url( get_avatar_url( $current[0]['ticket_email'] ), array( 'size' => 50 ) ); ?>" style="border-radius: 25px;"></div> - <div class="content"> - <div class="message-box"> - <div class="widget-area no-padding blank" style="width:100%"> - <div class="status-upload"> - <textarea rows="10" cols="30" class="form-control reply_textarea" id="reply_textarea_<?php echo esc_html( $ticket_id ); ?>" name="reply_textarea_<?php echo esc_html( $ticket_id ); ?>"></textarea> - <div class="form-group"> - <div class="input-group col-md-12 col-sm-12 col-xs-12"> - <button class="btn btn-primary " onclick="jQuery(this).parent().find('.attachment_reply').click()"> - <i class="glyphicon glyphicon-plus"></i> - <span><?php esc_html_e( 'Attachment', 'wsdesk' ); ?></span> - </button> - <input type="file" name="files" id="files_<?php echo esc_html( $ticket_id ); ?>" class="attachment_reply hide" multiple=""> - <div class="btn-group pull-right"> - <div class="check-box"> - <?php if ( 'enable' == $enable ) { ?> - <input type="checkbox" name="check" class="ticket_select_check" id="ticket_select_check_<?php echo esc_html( $ticket_id ); ?>" value="<?php echo esc_html( $ticket_id ); ?>" style="margin-bottom:0.5em"/> - <?php esc_html_e( 'Mark as Solved', 'wsdesk' ); ?> - <?php } ?> - <button type="button" class="btn btn-primary ticket_reply_action_button" data-loading-text="<?php esc_html__( 'Submitting Reply...', 'wsdesk' ); ?>" id="<?php echo esc_html( $ticket_id ); ?>" style="margin-left:1em"> - <?php esc_html_e( 'Submit', 'wsdesk' ); ?> - </button> - </div> - </div> - </div> - <div class="upload_preview_files_<?php echo esc_html( $ticket_id ); ?>"></div> - </div> - </div><!-- Status Upload --> - </div><!-- Widget Area --> - </div> - </div> - </div> - </div> - <section class="comment-list"> - <?php self::eh_crm_ticket_reply_section_gen_client( $ticket_id ); ?> - </section> - </div> - - </div> - </div> - </div> - <?php - return ob_get_clean(); - } - - public static function eh_crm_ticket_client_section_load() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $ticket_id = isset( $_POST['ticket_id'] ) ? sanitize_text_field( $_POST['ticket_id'] ) : null; - ob_start(); - self::eh_crm_ticket_reply_section_gen_client( $ticket_id ); - wp_send_json_success( array( 'page' => ob_get_clean() ) ); - die; - } - } - - public static function eh_crm_ticket_reply_section_gen_client( $ticket_id ) { - $reply_id = eh_crm_get_ticket_value_count( 'ticket_parent', $ticket_id, false, '', '', 'ticket_updated', 'DESC' ); - array_push( $reply_id, array( 'ticket_id' => $ticket_id ) ); - for ( $s = 0;$s < count( $reply_id );$s++ ) { - $reply_ticket = eh_crm_get_ticket( array( 'ticket_id' => $reply_id[ $s ]['ticket_id'] ) ); - $reply_ticket_meta = eh_crm_get_ticketmeta( $reply_id[ $s ]['ticket_id'] ); - $replier_name = ''; - $replier_email = $reply_ticket[0]['ticket_email']; - $replier_pic = ''; - if ( 0 != $reply_ticket[0]['ticket_author'] ) { - $replier_obj = new WP_User( $reply_ticket[0]['ticket_author'] ); - $replier_name = $replier_obj->display_name; - $replier_pic = get_avatar_url( $reply_ticket[0]['ticket_author'], array( 'size' => 50 ) ); - } else { - $replier_name = esc_html__( 'Guest', 'wsdesk' ); - $replier_pic = get_avatar_url( $reply_ticket[0]['ticket_email'], array( 'size' => 50 ) ); - } - $attachment = ''; - if ( isset( $reply_ticket_meta['ticket_attachment'] ) ) { - $reply_att = $reply_ticket_meta['ticket_attachment']; - $attachment = '<div>'; - for ( $at = 0;$at < count( $reply_att );$at++ ) { - $current_att = $reply_att[ $at ]; - $att_ext = pathinfo( $current_att, PATHINFO_EXTENSION ); - if ( empty( $att_ext ) ) { - $att_ext = ''; - } - $att_name = pathinfo( $current_att, PATHINFO_FILENAME ); - $img_ext = array( 'jpg', 'jpeg', 'png', 'gif' ); - if ( in_array( $att_ext, $img_ext ) ) { - $attachment .= '<a href="' . $current_att . '" target="_blank"><img class="img-upload clickable" style="width:200px" title="' . $att_name . '" src="' . $current_att . '"></a></p>'; - } else { - $check_file_ext = array( 'doc', 'docx', 'pdf', 'xml', 'csv', 'xlsx', 'xls', 'txt', 'zip', 'ppt', 'pptx', 'bat' ); - if ( in_array( $att_ext, $check_file_ext ) ) { - $attachment .= '<a href="' . $current_att . '" target="_blank" title="' . $att_name . '" class="img-upload"><div class="' . $att_ext . '"></div></a>'; - } else { - $attachment .= '<a href="' . $current_att . '" target="_blank" title="' . $att_name . '" class="img-upload"><div class="unknown_type"></div></a>'; - } - } - } - $attachment .= '</div>'; - } - switch ( $reply_ticket[0]['ticket_category'] ) { - case 'agent_reply': - case 'raiser_reply': - if ( ( $reply_ticket[0]['ticket_category'] ) == 'agent_reply' ) { - $replier_email = ''; - if ( '' == $replier_name ) { - $replier_name = 'Support'; - } - } - if ( ( $reply_ticket[0]['ticket_category'] ) == 'raiser_reply' ) { - $replier_email = $replier_email . '|'; - - } - echo ' - <div class="conversation_each" style="width:100.5% !important;"> - <div class="leftFreeSpace"> - <div class="icon"> - <img style="border-radius: 25px;" src="' . esc_attr( $replier_pic ) . '" /> - </div> - <h3>' . esc_html( $replier_name ) . '</h3> - <h4> - ' . esc_url( $replier_email ) . ' - ' . esc_html( TimestampCaster::cast( $reply_ticket[0]['ticket_date'], 'ticket_date' ) ) . ' - </h4> - <hr> - <div class="comment-post"> - <p>'; - $input_data = html_entity_decode( stripslashes( $reply_ticket[0]['ticket_content'] ) ); - - echo wp_kses_post( $input_data ); - echo '</p>'; - if ( isset( $reply_ticket_meta['ticket_attachment'] ) ) { - $reply_att = $reply_ticket_meta['ticket_attachment']; - ?> - <div> - <?php - for ( $at = 0;$at < count( $reply_att );$at++ ) { - $current_att = $reply_att[ $at ]; - $att_ext = pathinfo( $current_att, PATHINFO_EXTENSION ); - if ( empty( $att_ext ) ) { - $att_ext = ''; - } - $att_name = pathinfo( $current_att, PATHINFO_FILENAME ); - $img_ext = array( 'jpg', 'jpeg', 'png', 'gif' ); - if ( in_array( strtolower( $att_ext ), $img_ext ) ) { - ?> - <a href='<?php echo esc_html( $current_att ); ?>' target="_blank"><img class="img-upload clickable" style="width:200px" title='<?php echo esc_html( $att_name ); ?>' src='<?php echo esc_html( $current_att ); ?>'></a></p> - <?php - } else { - $check_file_ext = array( 'doc', 'docx', 'pdf', 'xml', 'csv', 'xlsx', 'xls', 'txt', 'zip', 'mp3', 'mp4', 'syx', 'cdr', 'bmp', 'ppt', 'pptx', 'bat' ); - if ( in_array( $att_ext, $check_file_ext ) ) { - ?> - <a href='<?php echo esc_html( $current_att ); ?>' target="_blank" title='<?php echo esc_html( $att_name ); ?>' class="img-upload"><div class='<?php echo esc_html( $att_ext ); ?>'></div></a> - <?php - } else { - ?> - <a href='<?php echo esc_html( $current_att ); ?>' target="_blank" title='<?php echo esc_html( $att_name ); ?>' class="img-upload"><div class='unknown_type'></div></a> - <?php - } - } - } - ?> - </div> - <?php - } - ?> - </div> - </div> - </div> - <?php - break; - default: - break; - } - } - } - - public static function eh_crm_ticket_reply_raiser() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $files_values = $_FILES; - $files = isset( $files_values['file'] ) ? $files_values['file'] : ''; - $status = isset( $_POST['close'] ) ? sanitize_text_field( $_POST['close'] ) : null; - $ticket_id = isset( $_POST['ticket_id'] ) ? sanitize_text_field( $_POST['ticket_id'] ) : null; - $content = str_replace( "\n", '<br/>', isset( $_POST['ticket_reply'] ) ? sanitize_textarea_field( $_POST['ticket_reply'] ) : null ); - $parent = eh_crm_get_ticket( array( 'ticket_id' => $ticket_id ) ); - $user = wp_get_current_user(); - $category = 'raiser_reply'; - $child = array( - 'ticket_email' => $user->user_email, - 'ticket_title' => $parent[0]['ticket_title'], - 'ticket_content' => $content, - 'ticket_category' => $category, - 'ticket_parent' => $ticket_id, - 'ticket_vendor' => $parent[0]['ticket_vendor'], - ); - $child_meta = array(); - if ( isset( $_FILES['file'] ) && ! empty( $_FILES['file'] ) ) { - $attachment_data = self::eh_crm_ticket_file_handler( $files ); - $child_meta['ticket_attachment'] = $attachment_data['url']; - $child_meta['ticket_attachment_path'] = $attachment_data['path']; - } - $gen_id = eh_crm_insert_ticket( $child, $child_meta ); - $submit = eh_crm_get_settingsmeta( '0', 'default_label' ); - if ( 'close' == $status ) { - eh_crm_update_ticketmeta( $ticket_id, 'ticket_label', 'label_LL02' ); - } else { - eh_crm_update_ticketmeta( $ticket_id, 'ticket_label', $submit ); - } - eh_crm_debug_error_log( ' ------------- WSDesk Email Debug Started ------------- ' ); - eh_crm_debug_error_log( 'Ticket raiser reply for Ticket #' . $gen_id ); - eh_crm_debug_error_log( 'Email function called for reply Ticket #' . $gen_id ); - self::eh_crm_fire_email( 'reply_ticket', $gen_id ); - eh_crm_debug_error_log( ' ------------- WSDesk Email Debug Ended ------------- ' ); - $content_ticket = self::eh_crm_ticket_single_view_client_gen( $ticket_id ); - $user_id = get_current_user_id(); - $user_data = new WP_User( $user_id ); - $email = $user_data->user_email; - die( json_encode( array( 'ticket' => $content_ticket ) ) ); - } - } - - public static function eh_crm_activate_oauth() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $client_id = isset( $_POST['client_id'] ) ? sanitize_text_field( $_POST['client_id'] ) : null; - $client_secret = isset( $_POST['client_secret'] ) ? sanitize_text_field( $_POST['client_secret'] ) : null; - eh_crm_update_settingsmeta( 0, 'oauth_client_id', $client_id ); - eh_crm_update_settingsmeta( 0, 'oauth_client_secret', $client_secret ); - $oauth_obj = new EH_CRM_OAuth(); - wp_send_json_success( array( 'page' => $oauth_obj->make_oauth_uri() ) ); - die; - } - } - - public static function eh_crm_deactivate_oauth() { - $oauth_obj = new EH_CRM_OAuth(); - $oauth_obj->revoke_token(); - - ob_start(); - include EH_CRM_MAIN_VIEWS . 'email/crm_oauth_setup.php'; - $myhtml = ob_get_clean(); - - wp_send_json_success( array( 'page' => $myhtml ) ); - die; - } - - public static function eh_crm_activate_email_protocol() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $server_url = isset( $_POST['server_url'] ) ? sanitize_text_field( $_POST['server_url'] ) : null; - $server_port = isset( $_POST['server_port'] ) ? sanitize_text_field( $_POST['server_port'] ) : null; - $email = isset( $_POST['email'] ) ? sanitize_text_field( $_POST['email'] ) : null; - $email_pwd = isset( $_POST['email_pwd'] ) ? sanitize_text_field( $_POST['email_pwd'] ) : null; - $delete_email = isset( $_POST['delete_email'] ) ? sanitize_text_field( $_POST['delete_email'] ) : null; - $username = isset( $_POST['username'] ) ? sanitize_text_field( $_POST['username'] ) : null; - $charset = isset( $_POST['charset'] ) ? sanitize_text_field( $_POST['charset'] ) : null; - $debug_status = eh_crm_get_settingsmeta( 0, 'wsdesk_debug_status' ); - - if ( in_array( 'imap', get_loaded_extensions() ) ) { - - $flags = array( - 'imap', - 'ssl', - 'novalidate-cert', - ); - - if ( $username ) { - $flags[] = 'user=' . $username; - } - - if ( 'enable' != $debug_status ) { - $imap = @imap_open( '{' . $server_url . ':' . $server_port . '/' . implode( '/', $flags ) . '}', $email, $email_pwd ); - } else { - $imap = imap_open( '{' . $server_url . ':' . $server_port . '/' . implode( '/', $flags ) . '}', $email, $email_pwd ); - } - if ( ! $imap ) { - die( - json_encode( - array( - 'status' => 'failure', - 'message' => esc_html__( - 'EMail Server Not Found', - 'wsdesk' - ), - 'errors' => imap_errors(), - ) - ) - ); - } else { - $imap_account_data = eh_crm_get_settingsmeta( '0', 'imap_account_data' ); - if ( empty( $imap_account_data ) ) { - $imap_account_data = array(); - $imap_account_data[] = array( - 'imap_server_url' => $server_url, - 'imap_server_port' => $server_port, - 'imap_server_email' => $email, - 'imap_server_email_pwd' => $email_pwd, - 'imap_activation' => 'activated', - 'delete_email' => $delete_email, - 'username' => $username, - 'charset' => $charset, - ); - eh_crm_update_settingsmeta( '0', 'imap_account_data', $imap_account_data ); - } else { - $imap_account_data[] = array( - 'imap_server_url' => $server_url, - 'imap_server_port' => $server_port, - 'imap_server_email' => $email, - 'imap_server_email_pwd' => $email_pwd, - 'imap_activation' => 'activated', - 'delete_email' => $delete_email, - 'username' => $username, - 'charset' => $charset, - ); - eh_crm_update_settingsmeta( '0', 'imap_account_data', $imap_account_data ); - } - - ob_start(); - include EH_CRM_MAIN_VIEWS . 'email/crm_imap_setup.php'; - - die( - wp_json_encode( - array( - 'status' => 'success', - 'message' => esc_html__( 'Email IMAP Configured', 'wsdesk' ), - 'content' => ob_get_clean(), - ) - ) - ); - } - } else { - die( - json_encode( - array( - 'status' => 'failure', - 'message' => esc_html__( - 'IMAP is not enabled in your Server', - 'wsdesk' - ), - ) - ) - ); - } - } - } - - public static function eh_crm_deactivate_email_protocol() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $id = isset( $_POST['id'] ) ? sanitize_text_field( $_POST['id'] ) : null; - if ( $id ) { - $imap_account_data = array_values( eh_crm_get_settingsmeta( '0', 'imap_account_data' ) ); - unset( $imap_account_data[ $id - 1 ] ); - eh_crm_update_settingsmeta( '0', 'imap_account_data', $imap_account_data ); - ob_start(); - include EH_CRM_MAIN_VIEWS . 'email/crm_imap_setup.php'; - wp_send_json_success( array( 'page' => ob_get_clean() ) ); - die; - } - } - } - - public static function eh_crm_email_block_filter() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $new_block = json_decode( stripslashes( isset( $_POST['new_block'] ) ? sanitize_text_field( $_POST['new_block'] ) : null ), true ); - if ( ! empty( $new_block ) ) { - - $new_email = $new_block['email']; - $type = $new_block['type']; - $block_filter = eh_crm_get_settingsmeta( '0', 'email_block_filters' ); - if ( ! $block_filter ) { - $block_filter = array(); - } - $available = true; - foreach ( $block_filter as $email => $data ) { - if ( $new_email == $email ) { - $available = false; - } - } - if ( $available ) { - $block_filter[ $new_email ] = $type; - eh_crm_update_settingsmeta( '0', 'email_block_filters', $block_filter ); - } - } - ob_start(); - include EH_CRM_MAIN_VIEWS . 'email/crm_filter_block_setup.php'; - wp_send_json_success( array( 'page' => ob_get_clean() ) ); - die; - } - } - - public static function eh_crm_subject_block_filter() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $new_block = json_decode( stripslashes( isset( $_POST['new_block'] ) ? sanitize_text_field( $_POST['new_block'] ) : null ), true ); - if ( ! empty( $new_block ) ) { - - $new_subject = $new_block['subject']; - $new_type = $new_block['type']; - $block_filter = eh_crm_get_settingsmeta( '0', 'subject_block_filters' ); - if ( ! $block_filter ) { - $block_filter = array(); - } - $available = true; - foreach ( $block_filter as $index => $data ) { - if ( $new_subject == $data ) { - $available = false; - } - } - if ( $available ) { - $block_filter[ $new_subject ] = $new_type; - eh_crm_update_settingsmeta( '0', 'subject_block_filters', $block_filter ); - } - } - ob_start(); - include EH_CRM_MAIN_VIEWS . 'email/crm_filter_block_setup.php'; - wp_send_json_success( array( 'page' => ob_get_clean() ) ); - die; - } - } - - public static function eh_crm_email_block_delete() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $block_remove = isset( $_POST['block_remove'] ) ? sanitize_text_field( $_POST['block_remove'] ) : null; - $block_filter = eh_crm_get_settingsmeta( '0', 'email_block_filters' ); - if ( ! $block_filter ) { - $block_filter = array(); - } - foreach ( $block_filter as $email => $data ) { - if ( $email === $block_remove ) { - unset( $block_filter[ $email ] ); - eh_crm_update_settingsmeta( '0', 'email_block_filters', $block_filter ); - } - } - ob_start(); - include EH_CRM_MAIN_VIEWS . 'email/crm_filter_block_setup.php'; - wp_send_json_success( array( 'page' => ob_get_clean() ) ); - die; - } - } - - public static function eh_crm_subject_block_delete() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $block_remove = isset( $_POST['block_remove'] ) ? sanitize_text_field( $_POST['block_remove'] ) : null; - $block_filter = eh_crm_get_settingsmeta( '0', 'subject_block_filters' ); - if ( ! $block_filter ) { - $block_filter = array(); - } - if ( isset( $block_filter[ $block_remove ] ) ) { - unset( $block_filter[ $block_remove ] ); - eh_crm_update_settingsmeta( '0', 'subject_block_filters', $block_filter ); - } - ob_start(); - include EH_CRM_MAIN_VIEWS . 'email/crm_filter_block_setup.php'; - wp_send_json_success( array( 'page' => ob_get_clean() ) ); - die; - } - } - - public static function eh_crm_fire_email( $type, $ticket_id ) { - set_time_limit( 300 ); - $ticket = eh_crm_get_ticket( array( 'ticket_id' => $ticket_id ) ); - $filter_check = array(); - - /** - * Fire a filter hook for notify block - * - * @since 3.1.2 - * - * @param $filter_check - * @param $ticket - * - */ - $filter_check = apply_filters( 'wsdesk_notify_block', $filter_check, $ticket ); - if ( ! empty( $filter_check ) ) { - return array( - 'status' => true, - 'message' => esc_html__( 'Email sent successfully', 'wsdesk' ), - ); - } - $ticket_meta = eh_crm_get_ticketmeta( $ticket_id ); - $parent_id = $ticket[0]['ticket_parent']; - $meta = array(); - if ( 0 != $parent_id ) { - $meta = eh_crm_get_ticketmeta( $parent_id ); - } else { - $meta = eh_crm_get_ticketmeta( $ticket_id ); - } - eh_crm_debug_error_log( 'Ticket Meta - ' ); - eh_crm_debug_error_log( $meta ); - $ticket_assignee_name = array(); - $user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ); - $users = get_users( array( 'role__in' => $user_roles_default ) ); - $users_data = array(); - for ( $i = 0; $i < count( $users ); $i++ ) { - $current = $users[ $i ]; - $id = $current->ID; - $user = new WP_User( $id ); - $users_data[ $i ]['id'] = $id; - $users_data[ $i ]['name'] = $user->display_name; - $users_data[ $i ]['caps'] = $user->caps; - $users_data[ $i ]['email'] = $user->user_email; - } - if ( isset( $meta['ticket_assignee'] ) ) { - $current_assignee = $meta['ticket_assignee']; - for ( $k = 0;$k < count( $current_assignee );$k++ ) { - for ( $l = 0;$l < count( $users_data );$l++ ) { - if ( $users_data[ $l ]['id'] == $current_assignee[ $k ] ) { - array_push( $ticket_assignee_name, $users_data[ $l ]['name'] ); - } - } - } - } - $ticket_assignee = empty( $ticket_assignee_name ) ? esc_html__( 'No Assignee', 'wsdesk' ) : implode( ', ', $ticket_assignee_name ); - $ticket_tags = array(); - $avail_tags_wf = eh_crm_get_settings( array( 'type' => 'tag' ), array( 'slug', 'title', 'settings_id' ) ); - if ( ! empty( $avail_tags_wf ) ) { - $current_ticket_tags = ( isset( $meta['ticket_tags'] ) ? $meta['ticket_tags'] : array() ); - for ( $j = 0;$j < count( $avail_tags_wf );$j++ ) { - for ( $k = 0;$k < count( $current_ticket_tags );$k++ ) { - if ( $avail_tags_wf[ $j ]['slug'] == $current_ticket_tags[ $k ] ) { - array_push( $ticket_tags, $avail_tags_wf[ $j ]['title'] ); - } - } - } - } - $ticket_tags_name = empty( $ticket_tags ) ? esc_html__( 'No Tags', 'wsdesk' ) : implode( ', ', $ticket_tags ); - $replier_name = ''; - if ( 0 != $ticket[0]['ticket_author'] ) { - $replier_obj = new WP_User( $ticket[0]['ticket_author'] ); - $replier_name = $replier_obj->display_name; - } - $avail_labels = eh_crm_get_settings( array( 'type' => 'label' ), array( 'slug', 'title', 'settings_id' ) ); - $ticket_label = ''; - for ( $j = 0;$j < count( $avail_labels );$j++ ) { - if ( $avail_labels[ $j ]['slug'] == $meta['ticket_label'] ) { - $ticket_label = $avail_labels[ $j ]['title']; - } - } - $attachments = array(); - $message = ''; - $subject = ''; - if ( 'new_ticket' == $type ) { - $message = eh_crm_get_settingsmeta( '0', 'support_email_new_ticket_text' ); - if ( '' == $message ) { - $message = 'Your request (#[id]) has been received on [date] and is being reviewed by our support staff. - - To add additional comments, reply to this email. - - Your Issue: - [request_description] - - Tags : [tags] -
Vulnerability Existed: yes
FALSE POSITIVE
Improper Input Validation and Cross-Site Scripting (XSS) - CWE-79 - includes/class-crm-ajax-functions.php - Lines 30-32
Old Code:
```php
if ( 'all' != $filter_label ) {
$filter_label_tickets = array();
for ( $i = 0; $i < count( $ticket ); $i++ ) {
$current_meta = eh_crm_get_ticketmeta( $ticket[ $i ]['ticket_id'] );
if ( $current_meta['ticket_label'] == $filter_label ) {
```
Fixed Code:
```php
if ( 'all' != $filter_label ) {
$filter_label_tickets = array();
for ( $i = 0; $i < count( $ticket ); $i++ ) {
$current_meta = eh_crm_get_ticketmeta( $ticket[ $i ]['ticket_id'] );
if ( $current_meta['ticket_label'] == $filter_label ) {
```
Explanation:
The `$filter_label` parameter is passed directly from user input without proper sanitization or validation before being used in comparisons and output. While the diff shows the same code in both versions, the vulnerability exists because `$filter_label` is used unsanitized throughout the function. The parameter comes from `$_POST` or similar user-controlled sources and should be sanitized before use.
---
Vulnerability Existed: yes
FALSE POSITIVE
Improper Input Validation - CWE-20 - includes/class-crm-ajax-functions.php - Lines 34-38
Old Code:
```php
if ( '' != $search_tickets ) {
$searched_tickets = array();
for ( $i = 0; $i < count( $ticket ); $i++ ) {
$current = eh_crm_get_ticket( array( 'ticket_id' => $ticket[ $i ]['ticket_id'] ) );
if ( ( strpos( $current[0]['ticket_title'], $search_tickets ) !== false || strpos( $current[0]['ticket_content'], $search_tickets ) !== false ) || $search_tickets == $ticket[ $i ]['ticket_id'] ) {
```
Fixed Code:
```php
if ( '' != $search_tickets ) {
$searched_tickets = array();
for ( $i = 0; $i < count( $ticket ); $i++ ) {
$current = eh_crm_get_ticket( array( 'ticket_id' => $ticket[ $i ]['ticket_id'] ) );
if ( ( strpos( $current[0]['ticket_title'], $search_tickets ) !== false || strpos( $current[0]['ticket_content'], $search_tickets ) !== false ) || $search_tickets == $ticket[ $i ]['ticket_id'] ) {
```
Explanation:
The `$search_tickets` parameter is used in string comparison operations without proper validation. While it's used in `strpos()` for search functionality, there's no validation that it's a valid string format. This could allow injection of special characters or patterns that bypass intended search logic.
---
Vulnerability Existed: not sure
Broken Access Control - CWE-639 - includes/class-crm-ajax-functions.php - Lines 118-131
Old Code:
```php
public static function eh_crm_ticket_single_view_client() {
$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
if ( ! wp_verify_nonce( $nonce, 'wsdesk_nonce' ) ) {
wp_send_json_error( array( 'message' => __( 'Invalid request.', 'wsdesk' ) ), 400 );
wp_die();
}
$ticket_id = isset( $_POST['ticket_id'] ) ? absint( $_POST['ticket_id'] ) : 0;
$current = eh_crm_get_ticket( array( 'ticket_id' => $ticket_id ) );
```
Fixed Code:
```php
public static function eh_crm_ticket_single_view_client() {
$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
if ( ! wp_verify_nonce( $nonce, 'wsdesk_nonce' ) ) {
wp_send_json_error( array( 'message' => __( 'Invalid request.', 'wsdesk' ) ), 400 );
wp_die();
}
$ticket_id = isset( $_POST['ticket_id'] ) ? absint( $_POST['ticket_id'] ) : 0;
$current = eh_crm_get_ticket( array( 'ticket_id' => $ticket_id ) );
```
Explanation:
The access control implementation appears identical in both versions. The function includes nonce verification and authorization checks (lines 128-131), which appear adequate. However, without seeing the complete authorization logic and database query implementation, it's uncertain whether these checks are comprehensive enough to prevent unauthorized ticket access.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-archive-ajax-functions.php 2025-12-21 09:35:59.421065569 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-archive-ajax-functions.php 2025-12-21 09:36:35.227291036 +0000@@ -1,2493 +1,2493 @@-<?php - -use WSDesk\Formatter\Cast\TimestampCaster; -use WSDesk\Tickets\TicketRepository; -use WSDesk\Tickets\TicketArchiveRepository; - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -class CRM_Ajax_Archive { - public static function eh_crm_refresh_tickets_count_archive() { - $default = eh_crm_get_settingsmeta( 0, 'default_label' ); - $tickets = eh_crm_get_ticketmeta_value_count_archive( 'ticket_label', $default ); - die( json_encode( array( 'data' => count( $tickets ) ) ) ); - } - public static function eh_crm_ticket_single_view_archive() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - $ticket_id = isset( $_POST['ticket_id'] ) ? sanitize_text_field( $_POST['ticket_id'] ) : null; - if ( isset( $_POST['pagination_id'] ) ) { - $pagination = json_decode( stripslashes( sanitize_text_field( $_POST['pagination_id'] ) ), true ); - } else { - $pagination = array(); - } - $content = self::eh_crm_ticket_single_view_gen( $ticket_id, $pagination ); - $tab = self::eh_crm_ticket_single_view_gen_head( $ticket_id ); - - die( - wp_json_encode( - array( - 'tab_head' => $tab, - 'tab_content' => $content, - ) - ) - ); - } - } - - public static function eh_crm_ticket_single_view_gen_head( $ticket_id ) { - $current = eh_crm_get_ticket_archive( array( 'ticket_id' => $ticket_id ) ); - $tab = '<a onclick="setURLFunc(' . $ticket_id . ')" href="#tab_content_' . $ticket_id . '" id="tab_content_a_' . $ticket_id . '" aria-controls="#' . $ticket_id . '" role="tab" data-toggle="tab" class="tab_a" style="font-size: 12px;padding: 11px 5px;margin-right:0px !important;"><button type="button" class="btn btn-default btn-circle close_tab pull-right"><span class="glyphicon glyphicon-remove"></span></button><div class="badge">#' . $ticket_id . '</div><span class="tab_head"> ' . stripslashes( html_entity_decode( htmlentities( $current[0]['ticket_title'] ) ) ) . '</span></a>'; - return $tab; - } - - public static function eh_crm_ticket_multiple_unarchive() { - - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - - $selectAll = isset( $_POST['selectAll'] ) ? 'true' === sanitize_text_field( $_POST['selectAll'] ) : false; - - $ticket_ids = array(); - if ( ! $selectAll && isset( $_POST['ticket_id'] ) && is_array( $_POST['ticket_id'] ) ) { - $count = count( $_POST['ticket_id'] ); - for ( $i = 0; $i < $count;$i++ ) { - $ticket_ids[] = isset( $_POST['ticket_id'][ $i ] ) ? sanitize_text_field( $_POST['ticket_id'][ $i ] ) : false; - } - } - if ( false === $selectAll && count( $ticket_ids ) === 0 ) { - wp_send_json_error( - array( - 'message' => esc_html__( 'Invalid ticket ids' ), - ), - 422 - ); - } - $filters = array( 'ticket_id' => $selectAll ? array() : $ticket_ids ); - $count = ( new TicketArchiveRepository() )->restore( $filters ); - wp_send_json_success( - array( - 'message' => esc_html__( 'Unarchived' ), - 'count' => $count, - ) - ); - die; - } - } - - public static function eh_crm_ticket_single_view_gen( $ticket_id, $pagination = array() ) { - ob_start(); - $current = eh_crm_get_ticket_archive( array( 'ticket_id' => $ticket_id ) ); - $tickets_display = eh_crm_get_settingsmeta( '0', 'tickets_display' ); - $current_meta = eh_crm_get_ticketmeta_archive( $ticket_id ); - $logged_user = wp_get_current_user(); - $logged_user_caps = array_keys( $logged_user->caps ); - $avail_caps = array( 'reply_tickets', 'delete_tickets', 'manage_tickets', 'manage_templates', 'merge_tickets' ); - $total_count = ( eh_crm_get_ticket_value_count_archive( 'ticket_parent', 0 ) ); - $access = array(); - if ( ! in_array( 'administrator', $logged_user->roles ) ) { - for ( $i = 0;$i < count( $logged_user_caps );$i++ ) { - if ( ! in_array( $logged_user_caps[ $i ], $avail_caps ) ) { - unset( $logged_user_caps[ $i ] ); - } - } - $access = $logged_user_caps; - } else { - $access = $avail_caps; - } - $users_data = get_users( array( 'role__in' => array( 'administrator', 'WSDesk_Agents', 'WSDesk_Supervisor' ) ) ); - $users = array(); - for ( $i = 0; $i < count( $users_data ); $i++ ) { - $current_user = $users_data[ $i ]; - $temp = array(); - $roles = $current_user->roles; - foreach ( $roles as $value ) { - $current_role = $value; - $temp[ $i ] = ucfirst( str_replace( '_', ' ', $current_role ) ); - } - $users[ implode( ' & ', $temp ) ][ $current_user->ID ] = $current_user->data->display_name; - } - $avail_fields = eh_crm_get_settings( array( 'type' => 'field' ), array( 'slug', 'title', 'settings_id' ) ); - $selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' ); - if ( ! $selected_fields ) { - $selected_fields = array(); - } - $avail_tags = eh_crm_get_settings( array( 'type' => 'tag' ), array( 'slug', 'title', 'settings_id' ) ); - $avail_labels = eh_crm_get_settings( array( 'type' => 'label' ), array( 'slug', 'title', 'settings_id' ) ); - $ticket_label = ''; - $ticket_label_slug = ''; - $eye_color = ''; - for ( $j = 0;$j < count( $avail_labels );$j++ ) { - if ( $avail_labels[ $j ]['slug'] == $current_meta['ticket_label'] ) { - $ticket_label = $avail_labels[ $j ]['title']; - $ticket_label_slug = $avail_labels[ $j ]['slug']; - } - if ( $avail_labels[ $j ]['slug'] == $current_meta['ticket_label'] ) { - $eye_color = eh_crm_get_settingsmeta( $avail_labels[ $j ]['settings_id'], 'label_color' ); - } - } - $ticket_tags_list = ''; - $response = array(); - $co = 0; - if ( ! empty( $avail_tags ) ) { - for ( $j = 0;$j < count( $avail_tags );$j++ ) { - $current_ticket_tags = ( isset( $current_meta['ticket_tags'] ) ? $current_meta['ticket_tags'] : array() ); - for ( $k = 0;$k < count( $current_ticket_tags );$k++ ) { - if ( $avail_tags[ $j ]['slug'] == $current_ticket_tags[ $k ] ) { - $args_post = array( - 'orderby' => 'ID', - 'numberposts' => -1, - 'post_type' => array( 'post', 'product' ), - 'post__in' => eh_crm_get_settingsmeta( $avail_tags[ $j ]['settings_id'], 'tag_posts' ), - ); - $posts = get_posts( $args_post ); - $temp = get_post(); - for ( $m = 0; $m < count( $posts ); $m++,$co++ ) { - $response[ $co ]['title'] = $posts[ $m ]->post_title; - $response[ $co ]['guid'] = get_permalink( $posts[ $m ]->ID ); - } - $ticket_tags_list .= '<span class="label label-info">#' . $avail_tags[ $j ]['title'] . '</span>'; - } - } - } - } - $index = array_search( $ticket_id, $pagination ); - $next = ''; - $previous = ''; - if ( false !== $index ) { - if ( $index + 1 < count( $pagination ) ) { - $next = $pagination[ $index + 1 ]; - } - if ( $index - 1 >= 0 ) { - $previous = $pagination[ $index - 1 ]; - } - } - - /** - * Fire a filter hook for wpml current language - * - * @since 3.1. - * - */ - $my_current_lang = apply_filters( 'wpml_current_language', null ); - - /** - * Fire an action hook for wpml switch language - * - * @since 3.1.2 - * - * @param $my_current_lang - * - */ - do_action( 'wpml_switch_language', $my_current_lang ); - $blog_info = eh_crm_wpml_translations( get_bloginfo( 'name' ), 'bloginfo', 'bloginfo' ); - $ticket_label = eh_crm_wpml_translations( $ticket_label, 'ticket_label_title', 'ticket_label_title' ); - ?> - - <!-- Sliding div ends here --> - <div class="container"> - <div class="row"> - <div class="col-md-12"> - <ol class="breadcrumb col-md-8" style="margin: 0 !important;background: none !important;border:none;padding: 8px 0px !important; "> - <li><?php echo esc_html( $blog_info ); ?></li> - <li><?php echo esc_html( $ticket_label ); ?></li> - <li class="active"><span class="label label-success" style="background-color:<?php echo esc_html( $eye_color ); ?> !important"><?php esc_html_e( 'Ticket', 'wsdesk' ); ?> #<?php echo esc_html( $ticket_id ); ?></span></li> - <span class="spinner_loader ticket_loader_<?php echo esc_html( $ticket_id ); ?>"> - <span class="bounce1"></span> - <span class="bounce2"></span> - <span class="bounce3"></span> - </span> - </ol> - </div> - </div> - <span class="crm-divider" style="margin-bottom:2px;margin-left: -15px;width: 103.75%;"></span> - <div class="row"> - <div class="col-md-3" style="padding-right: 0px;padding-top: 10px;"> - <div class="form-group"> - <span class="help-block"><?php esc_html_e( 'Assignee', 'wsdesk' ); ?></span> - <select id="assignee_ticket_<?php echo esc_html( $ticket_id ); ?>" class="form-control" aria-describedby="helpBlock" multiple="multiple"> - <?php - $assignee = ( isset( $current_meta['ticket_assignee'] ) ? $current_meta['ticket_assignee'] : array() ); - if ( '' !== $assignee ) { - foreach ( $users as $key => $value ) { - if ( in_array( 'manage_tickets', $access ) ) { - foreach ( $value as $id => $name ) { - $selected = ''; - if ( in_array( $id, $assignee ) ) { - $selected = 'selected'; - } - echo '<option value="' . esc_attr( $id ) . '" ' . esc_html( $selected ) . '>' . esc_html( $name ) . ' | ' . esc_attr( $key ) . '</option>'; - } - } else { - foreach ( $value as $id => $name ) { - if ( in_array( $id, $assignee ) ) { - echo '<option value="' . esc_attr( $id ) . '" selected>' . esc_html( $name ) . ' | ' . esc_attr( $key ) . '</option>'; - } - } - } - } - } - ?> - </select> - </div> - <?php - $cc = ( isset( $current_meta['ticket_cc'] ) ? $current_meta['ticket_cc'] : array() ); - ?> - <div class="form-group"> - <span class="help-block"><?php esc_html_e( 'CC', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'To add multiple CC, separate each address with comma without any space.', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="cc_ticket_<?php echo esc_html( $ticket_id ); ?>" class="form-control cc_<?php echo esc_html( $ticket_id ); ?>" value= "<?php echo esc_html( join( ',', $cc ) ); ?>"> - </div> - <?php - $bcc = ( isset( $current_meta['ticket_bcc'] ) ? $current_meta['ticket_bcc'] : array() ); - if ( ! empty( $bcc ) ) { - ?> - <div class="form-group"> - <span class="help-block"><?php esc_html_e( 'Bcc', 'wsdesk' ); ?></span> - <select id="bcc_ticket_<?php echo esc_html( $ticket_id ); ?>" class="form-control bcc_select_<?php echo esc_html( $ticket_id ); ?>" aria-describedby="helpBlock" multiple="multiple"> - <?php - foreach ( $bcc as $key => $value ) { - if ( in_array( 'manage_tickets', $access ) ) { - echo '<option value="' . esc_html( $value ) . '" selected>' . esc_html( $value ) . '</option>'; - } else { - echo '<option value="' . esc_html( $value ) . '" selected>' . esc_html( $value ) . '</option>'; - } - } - ?> - </select> - </div> - <?php - } - ?> - <div class="form-group"> - <span class="help-block"><?php esc_html_e( 'Tags', 'wsdesk' ); ?></span> - <select id="tags_ticket_<?php echo esc_html( $ticket_id ); ?>" class="form-control crm-form-element-input" multiple="multiple"> - <?php - $ticket_tags = ( isset( $current_meta['ticket_tags'] ) ? $current_meta['ticket_tags'] : array() ); - if ( '' != $ticket_tags && ! empty( $avail_tags ) == $ticket_tags ) { - for ( $i = 0;$i < count( $avail_tags );$i++ ) { - if ( in_array( 'manage_tickets', $access ) ) { - $selected = ''; - if ( in_array( $avail_tags[ $i ]['slug'], $ticket_tags ) ) { - $selected = 'selected'; - } - echo '<option value="' . esc_html( $avail_tags[ $i ]['slug'] ) . '" ' . esc_html( $selected ) . '>' . esc_html( $avail_tags[ $i ]['title'] ) . '</option>'; - } else { - if ( in_array( $avail_tags[ $i ]['slug'], $ticket_tags ) ) { - echo '<option value="' . esc_html( $avail_tags[ $i ]['slug'] ) . '" selected>' . esc_html( $avail_tags[ $i ]['title'] ) . '</option>'; - } - } - } - } - ?> - </select> - </div> - <hr/> - <?php - for ( $i = 0; $i < count( $selected_fields ); $i++ ) { - for ( $j = 3; $j < count( $avail_fields ); $j++ ) { - if ( $avail_fields[ $j ]['slug'] == $selected_fields[ $i ] ) { - $field_ticket_value = ( isset( $current_meta[ $avail_fields[ $j ]['slug'] ] ) ? $current_meta[ $avail_fields[ $j ]['slug'] ] : '' ); - $current_settings_meta = eh_crm_get_settingsmeta( $avail_fields[ $j ]['settings_id'] ); - $required = ( isset( $current_settings_meta['field_require_agent'] ) ? $current_settings_meta['field_require_agent'] : '' ); - $required = ( 'yes' === $required ) ? 'required' : ''; - if ( 'file' != $current_settings_meta['field_type'] && 'google_captcha' != $current_settings_meta['field_type'] ) { - echo '<div class="form-group">'; - echo '<span class="help-block">' . esc_html( $avail_fields[ $j ]['title'] ); - echo ( 'required' === $required ) ? '<span class="input_required"> *</span></span>' : '</span>'; - if ( 'select' == $current_settings_meta['field_type'] ) { - if ( 'woo_order_id' == $avail_fields[ $j ]['slug'] ) { - $current_settings_meta['field_type'] = 'text'; - } - } - switch ( $current_settings_meta['field_type'] ) { - case 'text': - $readonly = ''; - if ( ! in_array( 'manage_tickets', $access ) ) { - $readonly = 'readonly'; - } - $required_text = ''; - if ( 'required' == $required ) { - $required_text = 'text_required'; - } - echo '<input type="text" AUTOCOMPLETE="off" class="form-control ' . esc_html( $required_text ) . ' crm-form-element-input ticket_input_text_' . esc_html( $ticket_id ) . '" id="' . esc_html( $avail_fields[ $j ]['slug'] ) . '" placeholder="' . esc_html( $current_settings_meta['field_placeholder'] ) . '" ' . esc_html( $readonly ) . ' value="' . esc_html( $field_ticket_value ) . '">'; - break; - case 'ip': - echo '<label style="font-weight: normal !important;">' . esc_html( $field_ticket_value ) . '</label>'; - break; - case 'date': - $readonly = ''; - if ( ! in_array( 'manage_tickets', $access ) ) { - $readonly = 'readonly'; - } - $value = ''; - if ( '' != $field_ticket_value ) { - $value = 'value="' . $field_ticket_value . '"'; - } - $required_text = ''; - if ( 'required' == $required ) { - $required_text = 'text_required'; - } - echo '<input type="text" AUTOCOMPLETE="off" class="form-control ' . esc_html( $required_text ) . ' crm-form-element-input trigger_date_jq ticket_input_date_' . esc_html( $ticket_id ) . '" id="' . esc_html( $avail_fields[ $j ]['slug'] ) . '_t_' . esc_html( $ticket_id ) . '" placeholder="' . esc_html( $current_settings_meta['field_placeholder'] ) . '" ' . esc_html( $readonly ) . ' ' . esc_html( $value ) . '>'; - break; - case 'email': - $readonly = ''; - if ( ! in_array( 'manage_tickets', $access ) ) { - $readonly = 'readonly'; - } - $required_text = ''; - if ( 'required' == $required ) { - $required_text = 'text_required'; - } - echo '<input type="email" AUTOCOMPLETE="off" class="form-control ' . esc_html( $required_text ) . ' crm-form-element-input ticket_input_email_' . esc_html( $ticket_id ) . '" id="' . esc_html( $avail_fields[ $j ]['slug'] ) . '" placeholder="' . esc_html( $current_settings_meta['field_placeholder'] ) . '" ' . esc_html( $readonly ) . ' value="' . esc_html( $field_ticket_value ) . '">'; - break; - case 'phone': - $readonly = ''; - if ( ! in_array( 'manage_tickets', $access ) ) { - $readonly = 'readonly'; - } - $required_text = ''; - if ( 'required' == $required ) { - $required_text = 'text_required'; - } - echo '<span><strong>+</strong><input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" AUTOCOMPLETE="off" class="form-control ' . esc_html( $required_text ) . ' crm-form-element-input ticket_input_number_' . esc_html( $ticket_id ) . '" id="' . esc_html( $avail_fields[ $j ]['slug'] ) . '" placeholder="' . esc_html( $current_settings_meta['field_placeholder'] ) . '" ' . esc_html( $readonly ) . ' value="' . esc_html( $field_ticket_value ) . '" style="display: inline !important; width: 97% !important;"></span>'; - break; - case 'number': - $readonly = ''; - if ( ! in_array( 'manage_tickets', $access ) ) { - $readonly = 'readonly'; - } - $required_text = ''; - if ( 'required' == $required ) { - $required_text = 'text_required'; - } - echo '<input type="number" AUTOCOMPLETE="off" class="form-control ' . esc_html( $required_text ) . ' crm-form-element-input ticket_input_number_' . esc_html( $ticket_id ) . '" id="' . esc_html( $avail_fields[ $j ]['slug'] ) . '" placeholder="' . esc_html( $current_settings_meta['field_placeholder'] ) . '" ' . esc_html( $readonly ) . ' value="' . esc_html( $field_ticket_value ) . '">'; - break; - case 'password': - $readonly = ''; - if ( in_array( 'manage_tickets', $access ) ) { - $readonly = 'onfocus="this.removeAttribute(\'readonly\');"'; - } - $required_text = ''; - if ( 'required' == $required ) { - $required_text = 'text_required'; - } - echo '<input type="password" AUTOCOMPLETE="false" readonly class="form-control ' . esc_html( $required_text ) . ' crm-form-element-input ticket_input_pwd_' . esc_html( $ticket_id ) . '" id="' . esc_html( $avail_fields[ $j ]['slug'] ) . '" placeholder="' . esc_html( $current_settings_meta['field_placeholder'] ) . '" ' . esc_html( $readonly ) . ' value="' . esc_html( $field_ticket_value ) . '">'; - break; - case 'select': - $field_values = $current_settings_meta['field_values']; - $required_text = ''; - if ( 'required' == $required ) { - $required_text = 'text_required'; - } - echo '<select class="form-control crm-form-element-input ' . esc_html( $required_text ) . ' ticket_input_select_' . esc_html( $ticket_id ) . '" id="' . esc_html( $avail_fields[ $j ]['slug'] ) . '">'; - echo '<option value="">' . esc_html( isset( $current_settings_meta['field_placeholder'] ) ? htmlentities( $current_settings_meta['field_placeholder'] ) : '-' ) . '</option>'; - foreach ( $field_values as $key => $value ) { - if ( in_array( 'manage_tickets', $access ) ) { - $selected = ''; - if ( $key == $field_ticket_value ) { - $selected = 'selected'; - } - echo '<option value="' . esc_attr( $key ) . '" ' . esc_html( $selected ) . '>' . esc_html( $value ) . '</option>'; - } else { - if ( $key == $field_ticket_value ) { - echo '<option value="' . esc_attr( $key ) . '" selected>' . esc_html( $value ) . '</option>'; - } - } - } - echo '</select>'; - break; - case 'radio': - $required_radio = ''; - if ( 'required' == $required ) { - $required_radio = 'radio_required'; - } - $field_values = $current_settings_meta['field_values']; - echo '<span style="vertical-align: middle;">'; - foreach ( $field_values as $key => $value ) { - if ( in_array( 'manage_tickets', $access ) ) { - $checked = ''; - if ( $key == $field_ticket_value ) { - $checked = 'checked'; - } - echo '<input type="radio" style="margin-top: 0;" id="' . esc_html( $avail_fields[ $j ]['slug'] ) . '" name="' . esc_html( $avail_fields[ $j ]['slug'] ) . '_' . esc_html( $ticket_id ) . '" class="form-control ' . esc_html( $required_radio ) . ' ticket_input_radio_' . esc_html( $ticket_id ) . '" value="' . esc_attr( $key ) . '" ' . esc_html( $checked ) . '> ' . esc_html( $value ) . '<br>'; - } else { - if ( $key == $field_ticket_value ) { - echo '<input type="radio" style="margin-top: 0;" id="' . esc_html( $avail_fields[ $j ]['slug'] ) . '" name="' . esc_html( $avail_fields[ $j ]['slug'] ) . '_' . esc_html( $ticket_id ) . '" class="form-control ' . esc_html( $required_radio ) . ' ticket_input_radio_' . esc_html( $ticket_id ) . '" value="' . esc_attr( $key ) . '" checked readonly> ' . esc_html( $value ) . '<br>'; - } - } - } - echo '</span>'; - break; - case 'checkbox': - $required_check = ''; - if ( 'required' == $required ) { - $required_check = 'check_required'; - } - $field_values = $current_settings_meta['field_values']; - $field_ticket_value = is_array( $field_ticket_value ) ? $field_ticket_value : array(); - echo '<span style="vertical-align: middle;">'; - foreach ( $field_values as $key => $value ) { - if ( in_array( 'manage_tickets', $access ) ) { - $checked = ''; - if ( in_array( $key, $field_ticket_value ) ) { - $checked = 'checked'; - } - echo '<input type="checkbox" style="margin-top: 0;" id="' . esc_html( $avail_fields[ $j ]['slug'] ) . '" class="form-control ' . esc_html( $required_check ) . ' ticket_input_checkbox_' . esc_html( $ticket_id ) . '" value="' . esc_attr( $key ) . '" ' . esc_html( $checked ) . '> ' . esc_html( $value ) . '<br>'; - } else { - if ( in_array( $key, $field_ticket_value ) ) { - echo '<input type="checkbox" style="margin-top: 0;" id="' . esc_html( $avail_fields[ $j ]['slug'] ) . '" class="form-control ' . esc_html( $required_check ) . ' ticket_input_checkbox_' . esc_html( $ticket_id ) . '" value="' . esc_attr( $key ) . '" checked readonly> ' . esc_html( $value ) . '<br>'; - } - } - } - echo '</span>'; - break; - case 'textarea': - $required_text = ''; - if ( 'required' == $required ) { - $required_text = 'text_required'; - } - $readonly = ''; - if ( ! in_array( 'manage_tickets', $access ) ) { - $readonly = 'readonly'; - } - echo '<textarea class="form-control ' . esc_html( $required_text ) . ' except_rich ticket_input_textarea_' . esc_html( $ticket_id ) . '" id="' . esc_html( $avail_fields[ $j ]['slug'] ) . '" ' . esc_html( $readonly ) . '>' . esc_html( $field_ticket_value ) . '</textarea>'; - break; - } - echo '</div>'; - } - } - } - } - ?> - </div> - <div class="col-md-9 Ws-content-detail-full"> - <div class="single_ticket_panel rightPanel"> - <div class="rightPanelHeader"> - <div class="leftFreeSpace"> - <div class="icon" style="top: 5% !important;"><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'message_icon.png' ); ?>"></div> - <div class="tictxt"> - - <p style="margin-top: 5px;" class="info"> - <i class="glyphicon glyphicon-user"></i> by - <?php - if ( 0 != $current[0]['ticket_author'] ) { - $raiser_obj = new WP_User( $current[0]['ticket_author'] ); - echo esc_html( $raiser_obj->display_name ); - } else { - echo esc_html( $current[0]['ticket_email'] ); - } - ?> - | <i class="glyphicon glyphicon-calendar"></i> <?php echo esc_html( TimestampCaster::cast( $current[0]['ticket_date'], 'ticket_date' ) ); ?> - | <i class="glyphicon glyphicon-time"></i> - <?php - $solved = false; - $meta = eh_crm_get_ticketmeta_archive( $ticket_id ); - if ( 'label_LL02' == $meta['ticket_label'] ) { - $solved = true; - } - //Average Total Time for Agent's Solved tickets - if ( $solved ) { - $dteDifference = array(); - $latest_reply_id = eh_crm_get_ticket_value_count_archive( 'ticket_category', 'agent_note' , true, 'ticket_parent', $current[0]['ticket_id'], 'ticket_id' ); - if ( ! $latest_reply_id ) { - $ticket_time = eh_crm_get_formatted_date( $current[0]['ticket_date'] ); - $last_reply_time = eh_crm_get_formatted_date( $current[0]['ticket_date'] ); - } else { - $latest_ticket_reply = eh_crm_get_ticket_archive( array( 'ticket_id' => $latest_reply_id[0]['ticket_id'] ) ); - $ticket_time = eh_crm_get_formatted_date( $current[0]['ticket_date'] ); - $last_reply_time = eh_crm_get_formatted_date( $latest_ticket_reply[0]['ticket_date'] ); - } - esc_html_e( 'Total time ', 'wsdesk' ); - $dteDifference[0] = eh_crm_dateDiffe( $ticket_time, $last_reply_time ); - echo esc_html( $dteDifference[0][0] ) . 'D:' . esc_html( $dteDifference[0][1] ) . 'H:' . esc_html( $dteDifference[0][2] ) . 'M'; - } - //Average Total Time for Agent's Unsolved tickets - if ( ! $solved ) { - $ticket_time = eh_crm_get_formatted_date( $current[0]['ticket_date'] ); - $current_time = eh_crm_get_formatted_date( gmdate( 'M d, Y H:i:s', time() ) ); - esc_html_e( 'Total time ', 'wsdesk' ); - $dteDifference[0] = eh_crm_dateDiffe( $ticket_time, $current_time ); - echo esc_html( $dteDifference[0][0] ) . 'D:' . esc_html( $dteDifference[0][1] ) . 'H:' . esc_html( $dteDifference[0][2] ) . 'M'; - } - ?> - - | <i class="glyphicon glyphicon-comment"></i> - <?php - $raiser_voice = eh_crm_get_ticket_value_count_archive( 'ticket_parent', $ticket_id, false, 'ticket_category', 'raiser_reply' ); - echo count( $raiser_voice ) . ' ' . esc_html__( 'Raiser Voice', 'wsdesk' ); - ?> - | <i class="glyphicon glyphicon-bullhorn"></i> - <?php - $agent_voice = eh_crm_get_ticket_value_count_archive( 'ticket_parent', $ticket_id, false, 'ticket_category', 'agent_reply' ); - echo count( $agent_voice ) . ' ' . esc_html__( 'Agent Voice', 'wsdesk' ); - ?> - | <i class="glyphicon glyphicon-star"></i> Rating : <?php echo ( isset( $current_meta['ticket_rating'] ) ? esc_html( ucfirst( $current_meta['ticket_rating'] ) ) : esc_html__( 'None', 'wsdesk' ) ); ?> - </p> - <?php - if ( EH_CRM_WOO_STATUS ) { - $woo_orders = eh_crm_get_settingsmeta( 0, 'woo_order_tickets' ); - $woo_access = eh_crm_get_settingsmeta( 0, 'woo_order_access' ); - $woo_price = eh_crm_get_settingsmeta( 0, 'woo_order_price' ); - $role = ''; - if ( in_array( 'administrator', $logged_user->roles ) ) { - $role = 'administrator'; - } elseif ( in_array( 'WSDesk_Supervisor', $logged_user->roles ) ) { - $role = 'WSDesk_Supervisor'; - } elseif ( in_array( 'WSDesk_Agents', $logged_user->roles ) ) { - $role = 'WSDesk_Agents'; - } - if ( 'enable' && in_array( $role, $woo_access ) == $woo_orders ) { - $raiser_id = $current[0]['ticket_author']; - if ( 0 == $raiser_id ) { - $user = get_user_by( 'email', $current[0]['ticket_email'] ); - if ( $user ) { - $raiser_id = $user->ID; - } - } - $customer_orders = array(); - if ( version_compare( WC()->version, '2.7.0', '<' ) ) { - if ( 0 != $raiser_id ) { - $customer_orders = get_posts( - array( - 'orderby' => 'ID', - 'numberposts' => -1, - 'meta_key' => '_customer_user', - 'meta_value' => $raiser_id, - 'post_type' => wc_get_order_types(), - 'post_status' => array_keys( wc_get_order_statuses() ), - 'fields' => 'ids', - ) - ); - } - if ( ! empty( $customer_orders ) ) { - $order_id_url = ''; - $total_amount = 0; - $order_count = count( $customer_orders ); - $count = 0; - - foreach ( $customer_orders as $order ) { - $order_data = wc_get_order( $order ); - if ( $order_data->get_status() == 'completed' ) { - $total_amount += $order_data->get_total(); - } - if ( $count < 5 ) { - $order_id_url .= ' <a href="' . admin_url( 'post.php?post=' . $order . '&action=edit' ) . '" target="_blank"> #' . $order . '</a>,'; - $count ++; - } - } - echo '<p style="margin-top: 5px;" class="info"><i class="glyphicon glyphicon-shopping-cart"></i> ' . esc_html__( 'Total Orders', 'wsdesk' ) . ' : ' . esc_html( $order_count ) . ' | ' . esc_html__( 'Recent Order', 'wsdesk' ) . ' : [ ' . wp_kses_post( rtrim( $order_id_url, ', ' ) ) . ' ]'; - if ( 'enable' == $woo_price ) { - echo ' | ' . esc_html__( 'Total Purchase', 'wsdesk' ) . ' : ' . esc_html( get_woocommerce_currency_symbol() ) . esc_html( $total_amount ) . ' ' . esc_html( get_woocommerce_currency() ); - } - echo '</p>'; - } else { - ?> - <p style="margin-top: 5px;" class="info"> - <i class="glyphicon glyphicon-shopping-cart"></i> <?php esc_html_e( 'Total Orders', 'wsdesk' ); ?> : 0 | <?php esc_html_e( 'Recent Order', 'wsdesk' ); ?> : <?php esc_html_e( 'None', 'wsdesk' ); ?> | <?php esc_html_e( 'Total Purchase', 'wsdesk' ); ?> : <?php echo esc_html( get_woocommerce_currency_symbol() ) . '0 ' . esc_html( get_woocommerce_currency() ); ?> - </p> - <?php - } - } else { - if ( 0 != $raiser_id ) { - $customer_orders = wc_get_orders( array( 'customer_id' => $raiser_id ) ); - $customer_temp_altered = array(); - $customer_temp_original = array(); - foreach ( $customer_orders as $key => $customer_order ) { - array_push( $customer_temp_altered, trim( str_replace( ' ', '', $customer_order->get_order_number() ) ) ); - $order_id = $customer_order->get_id(); - array_push( $customer_temp_original, $order_id ); - } - $customer_orders = $customer_temp_altered; - } - if ( ! empty( $customer_orders ) ) { - $order_id_url = ''; - $total_amount = 0; - $order_count = count( $customer_orders ); - $count = 0; - - foreach ( $customer_orders as $key => $order ) { - $order_data = wc_get_order( $customer_temp_original[ $key ] ); - if ( $order_data->get_status() == 'completed' ) { - $total_amount += $order_data->get_total(); - } - if ( $count < 5 ) { - $order_id_url .= ' <a href="' . admin_url( 'post.php?post=' . esc_html( $customer_temp_original[ $key ] ) . '&action=edit' ) . '" target="_blank"> #' . esc_html( $order ) . '</a>,'; - $count ++; - } - } - echo '<p style="margin-top: 5px;" class="info"><i class="glyphicon glyphicon-shopping-cart"></i> ' . esc_html__( 'Total Orders', 'wsdesk' ) . ' : ' . esc_html( $order_count ) . ' | ' . esc_html__( 'Recent Order', 'wsdesk' ) . ' : [ ' . wp_kses_post( rtrim( $order_id_url, ', ' ) ) . ' ]'; - if ( 'enable' == $woo_price ) { - echo ' | ' . esc_html__( 'Total Purchase', 'wsdesk' ) . ' : ' . esc_html( get_woocommerce_currency_symbol() ) . esc_html( $total_amount ) . ' ' . esc_html( get_woocommerce_currency() ); - } - echo '</p>'; - } else { - ?> - <p style="margin-top: 5px;" class="info"> - <i class="glyphicon glyphicon-shopping-cart"></i> <?php esc_html_e( 'Total Orders', 'wsdesk' ); ?> : 0 | <?php esc_html_e( 'Recent Order', 'wsdesk' ); ?> : <?php esc_html_e( 'None', 'wsdesk' ); ?> | <?php esc_html_e( 'Total Purchase', 'wsdesk' ); ?> : <?php echo esc_html( get_woocommerce_currency_symbol() ) . '0 ' . esc_html( get_woocommerce_currency() ); ?> - </p> - <?php - } - } - } - } - ?> - </div> - </div> - </div> - <input type="hidden" id="hidden_ticket_id" value="<?php echo esc_html( $ticket_id ); ?>"/> - <div class="newMsgFull"> - <div class="leftFreeSpace"> - <div class="content"> - <div class="message-box"> - <?php - if ( in_array( 'reply_tickets', $access ) ) { - ?> - <div class="row"> - <div class="col-md-12"> - <div class="widget-area no-padding blank" style="width:100%"> - <div class="status-upload"> - <?php if ( eh_crm_get_settingsmeta( 0, 'auto_suggestion' ) == 'enable' ) { ?> - <div id="suggestion"> - <div id="suggestion-form" style='display:none;' class="panel panel-default suggest-form-<?php echo esc_html( $ticket_id ); ?>"> - <ul class="suggest_ul"> - <?php - if ( ! empty( $response ) ) { - for ( $count_response = 0;$count_response < count( $response );$count_response++ ) { - echo '<li class="clickable suggest_li" id="' . esc_html( $ticket_id ) . '"><span style="color:black;" id="sug_title">' . esc_html( $response[ $count_response ]['title'] ) . '</span><br><span style="color:blue;" id="sug_url">' . esc_html( $response[ $count_response ]['guid'] ) . '</span></li>'; - if ( count( $response ) != $count_response + 1 ) { - echo '<hr>'; - } - } - } else { - echo '<li> ' . esc_html__( 'No Suggestions', 'wsdesk' ) . ' </li>'; - } - ?> - </ul> - </div> - <div id="suggestion-tab" class="<?php echo esc_html( $ticket_id ); ?>"><?php esc_html_e( 'Suggestions', 'wsdesk' ); ?></div> - </div> - <?php - } $signature = ''; - if ( EH_CRM_WSDESK_SIGNATURE_STATUS ) { - $signature = '<br><p>--</p>' . get_option( 'wsdesk_agent_common_signature' ) . get_user_meta( get_current_user_id(), 'wsdesk_agent_signature', true ); - } - ?> - </div> - </div> - </div> - </div> - <?php } ?> - </div> - </div> - </div> - </div> - <?php - $reply_id = eh_crm_get_ticket_value_count_archive( 'ticket_parent', $ticket_id, false, '', '', 'ticket_updated', 'DESC' ); - array_push( $reply_id, array( 'ticket_id' => $ticket_id ) ); - if ( EH_CRM_WOO_VENDOR ) { - $reply_id = eh_crm_get_ticket_value_count_archive( 'ticket_parent', $ticket_id, false, '', '', 'ticket_updated', 'DESC', 'vendor' ); - array_push( $reply_id, array( 'ticket_id' => $ticket_id ) ); - } - for ( $s = 0;$s < count( $reply_id );$s++ ) { - - $quote = ''; - $quote_text = ''; - if ( 0 == $s ) { - $quote = '<span class="button button-info pull-right quote_button" id="' . esc_html( $ticket_id ) . '">' . esc_html__( 'Quote', 'wsdesk' ) . '</span>'; - $quote_text = 'id="' . esc_html( $ticket_id ) . '_quote_text_ticket_content"'; - } - $reply_ticket = eh_crm_get_ticket_archive( array( 'ticket_id' => $reply_id[ $s ]['ticket_id'] ) ); - $reply_ticket_meta = eh_crm_get_ticketmeta_archive( $reply_id[ $s ]['ticket_id'] ); - $replier_name = ''; - $replier_email = $reply_ticket[0]['ticket_email']; - $replier_pic = ''; - if ( 0 != $reply_ticket[0]['ticket_author'] ) { - $replier_obj = new WP_User( $reply_ticket[0]['ticket_author'] ); - $replier_name = $replier_obj->display_name; - $replier_pic = get_avatar_url( $reply_ticket[0]['ticket_author'], array( 'size' => 50 ) ); - } else { - $replier_name = 'Guest'; - $replier_pic = get_avatar_url( $reply_ticket[0]['ticket_email'], array( 'size' => 50 ) ); - } - $attachment = ''; - if ( isset( $reply_ticket_meta['ticket_attachment'] ) ) { - $reply_att = $reply_ticket_meta['ticket_attachment']; - $attachment = '<div>'; - for ( $at = 0;$at < count( $reply_att );$at++ ) { - $current_att = $reply_att[ $at ]; - $att_ext = pathinfo( $current_att, PATHINFO_EXTENSION ); - if ( empty( $att_ext ) ) { - $att_ext = ''; - } - $att_name = pathinfo( $current_att, PATHINFO_FILENAME ); - $img_ext = array( 'jpg', 'jpeg', 'png', 'gif' ); - if ( in_array( strtolower( $att_ext ), $img_ext ) ) { - $attachment .= '<a href="' . esc_html( $current_att ) . '" target="_blank"><img class="img-upload clickable" style="width:200px" title="' . esc_html( $att_name ) . '" src="' . esc_html( $current_att ) . '"></a></p>'; - } else { - $check_file_ext = array( 'doc', 'docx', 'pdf', 'xml', 'csv', 'xlsx', 'xls', 'txt', 'zip', 'mp3', 'mp4', 'syx', 'cdr', 'bmp' ); - if ( in_array( $att_ext, $check_file_ext ) ) { - $attachment .= '<a href="' . esc_html( $current_att ) . '" target="_blank" title="' . esc_html( $att_name ) . '" class="img-upload"><div class="' . esc_html( $att_ext ) . '"></div></a>'; - } else { - $attachment .= '<a href="' . esc_html( $current_att ) . '" target="_blank" title="' . esc_html( $att_name ) . '" class="img-upload"><div class="unknown_type"></div></a>'; - } - } - } - $attachment .= '</div>'; - } - $color = ''; - switch ( $reply_ticket[0]['ticket_category'] ) { - case 'satisfaction_survey': - if ( 'great' == $current_meta['ticket_rating'] ) { - $color = 'background-color: #88fcb6 !important'; - } else { - $color = 'background-color: #f7aba5 !important'; - } - break; - case 'agent_note': - $color = 'background-color: aliceblue!important'; - break; - default: - break; - } - echo '<div class="conversation_each" style="' . esc_html( $color ) . '"> - <div class="leftFreeSpace"> - <div class="icon"><img src="' . esc_html( $replier_pic ) . '" style="border-radius: 25px;"></div> - <h3>' . esc_html( $replier_name ) . '</h3> - <h4>' . esc_html( $replier_email ) . ' | ' . esc_html( TimestampCaster::cast( $reply_ticket[0]['ticket_date'], 'ticket_date' ) ) . ' </h4> - ' . ( ( 'satisfaction_survey' === $reply_ticket[0]['ticket_category'] ) ? '<b>' . esc_html__( 'Satisfaction Comment', 'wsdesk' ) . '</b><br>' : '' ) . ' - <p>'; - - $input_data = ( 'text' != $tickets_display ) ? ( html_entity_decode( $reply_ticket[0]['ticket_content'] ) ) : htmlentities( $reply_ticket[0]['ticket_content'] ); - - echo wp_kses_post( eh_crm_collapse_ticket_content( $input_data ) ); - echo '</p> - ' . esc_html( $attachment ) . ' - </div> - </div>'; - } - ?> - </div> - </div> - </div> - </div> - <?php - return ob_get_clean(); - } - - public static function eh_crm_get_translated_months_value( $start_date, $end_date ) { - if ( strpos( $start_date, 'Dez' ) !== false ) { - $start_date = str_replace( 'Dez', 'dec', $start_date ); - } - if ( strpos( $end_date, 'Dez' ) !== false ) { - $end_date = str_replace( 'Dez', 'dec', $end_date ); - }if ( strpos( $start_date, 'Dic' ) !== false ) { - $start_date = str_replace( 'Dic', 'dec', $start_date ); - } - if ( strpos( $end_date, 'Dic' ) !== false ) { - $end_date = str_replace( 'Dic', 'dec', $end_date ); - }if ( strpos( $start_date, 'Déc' ) !== false ) { - $start_date = str_replace( 'Déc', 'dec', $start_date ); - } - if ( strpos( $end_date, 'Déc' ) !== false ) { - $end_date = str_replace( 'Déc', 'dec', $end_date ); - } - if ( strpos( $start_date, 'Ott' ) !== false ) { - $start_date = str_replace( 'Ott', 'oct', $start_date ); - }if ( strpos( $end_date, 'Ott' ) !== false ) { - $end_date = str_replace( 'Ott', 'oct', $end_date ); - } - - if ( strpos( $end_date, 'Ago' ) !== false ) { - $end_date = str_replace( 'Ago', 'aug', $end_date ); - } - - if ( strpos( $start_date, 'okt' ) !== false ) { - $start_date = str_replace( 'okt', 'oct', $start_date ); - } - if ( strpos( $end_date, 'okt' ) !== false ) { - $end_date = str_replace( 'okt', 'oct', $end_date ); - } - if ( strpos( $end_date, 'Ago' ) !== false ) { - $end_date = str_replace( 'Ago', 'aug', $end_date ); - } - if ( strpos( $start_date, 'Ago' ) !== false ) { - $start_date = str_replace( 'Ago', 'aug', $start_date ); - } - if ( strpos( $end_date, 'Ago' ) !== false ) { - $end_date = str_replace( 'Ago', 'aug', $end_date ); - } - if ( strpos( $start_date, 'Août' ) !== false ) { - $start_date = str_replace( 'Août', 'aug', $start_date ); - } - if ( strpos( $end_date, 'Août' ) !== false ) { - $end_date = str_replace( 'Août', 'aug', $end_date ); - } - if ( strpos( $start_date, 'Gen' ) !== false ) { - $start_date = str_replace( 'Gen', 'jan', $start_date ); - } - if ( strpos( $end_date, 'Gen' ) !== false ) { - $end_date = str_replace( 'Gen', 'jan', $end_date ); - } - if ( strpos( $start_date, 'Gen' ) !== false ) { - $start_date = str_replace( 'Gen', 'jan', $start_date ); - } - if ( strpos( $end_date, 'Ene' ) !== false ) { - $end_date = str_replace( 'Ene', 'jan', $end_date ); - } - if ( strpos( $start_date, 'Fév' ) !== false ) { - $start_date = str_replace( 'Fév', 'feb', $start_date ); - } - if ( strpos( $end_date, 'Fév' ) !== false ) { - $end_date = str_replace( 'Fév', 'feb', $end_date ); - } - if ( strpos( $start_date, 'Mär' ) !== false ) { - $start_date = str_replace( 'Mär', 'mar', $start_date ); - } - if ( strpos( $end_date, 'Mär' ) !== false ) { - $end_date = str_replace( 'Mär', 'mar', $end_date ); - }if ( strpos( $start_date, 'Maa' ) !== false ) { - $start_date = str_replace( 'Maa', 'mar', $start_date ); - } - if ( strpos( $end_date, 'Maa' ) !== false ) { - $end_date = str_replace( 'Maa', 'mar', $end_date ); - }if ( strpos( $start_date, 'Avr' ) !== false ) { - $start_date = str_replace( 'Avr', 'apr', $start_date ); - } - if ( strpos( $end_date, 'Avr' ) !== false ) { - $end_date = str_replace( 'Avr', 'apr', $end_date ); - }if ( strpos( $start_date, 'Mai' ) !== false ) { - $start_date = str_replace( 'Mai', 'may', $start_date ); - } - if ( strpos( $end_date, 'Mai' ) !== false ) { - $end_date = str_replace( 'Mai', 'may', $end_date ); - }if ( strpos( $start_date, 'Mei' ) !== false ) { - $start_date = str_replace( 'Mei', 'may', $start_date ); - } - if ( strpos( $end_date, 'Mei' ) !== false ) { - $end_date = str_replace( 'Mei', 'may', $end_date ); - }if ( strpos( $start_date, 'Jui' ) !== false ) { - $start_date = str_replace( 'Jui', 'jun', $start_date ); - } - if ( strpos( $end_date, 'Jui' ) !== false ) { - $end_date = str_replace( 'Jui', 'jun', $end_date ); - }if ( strpos( $start_date, 'Juil' ) !== false ) { - $start_date = str_replace( 'Juil', 'jul', $start_date ); - } - - if ( strpos( $end_date, 'Juil' ) !== false ) { - $end_date = str_replace( 'Juil', 'jul', $end_date ); - }if ( strpos( $start_date, 'junl' ) !== false ) { - $start_date = str_replace( 'junl', 'jul', $start_date ); - } - if ( strpos( $end_date, 'junl' ) !== false ) { - $end_date = str_replace( 'junl', 'jul', $end_date ); - } - if ( strpos( $start_date, 'Lug' ) !== false ) { - $start_date = str_replace( 'Lug', 'jul', $start_date ); - } - if ( strpos( $end_date, 'Lug' ) !== false ) { - $end_date = str_replace( 'Lug', 'jul', $end_date ); - } - if ( strpos( $start_date, 'Set' ) !== false ) { - $start_date = str_replace( 'Set', 'sep', $start_date ); - } - if ( strpos( $end_date, 'Set' ) !== false ) { - $end_date = str_replace( 'Set', 'sep', $end_date ); - }if ( strpos( $start_date, 'Giu' ) !== false ) { - $start_date = str_replace( 'Giu', 'jun', $start_date ); - } - if ( strpos( $end_date, 'Giu' ) !== false ) { - $end_date = str_replace( 'Giu', 'jun', $end_date ); - } - - if ( strpos( $start_date, 'Mag' ) !== false ) { - $start_date = str_replace( 'Mag', 'may', $start_date ); - } - if ( strpos( $end_date, 'Mag' ) !== false ) { - $end_date = str_replace( 'Mag', 'may', $end_date ); - } - - - - $date = array( $start_date, $end_date ); - return $date; - } - - public static function eh_crm_archive_ticket_data() { - - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - - if ( ! isset( $_POST['start_date'] ) || ! isset( $_POST['end_date'] ) ) { - wp_send_json_error( array(), 422 ); - } - - $statuses = array(); - - if ( isset( $_POST['status'] ) ) { - $count = count( $_POST['status'] ); - - for ( $i = 0; $i < $count; $i++ ) { - if ( isset( $_POST['status'][ $i ] ) ) { - $statuses[] = sanitize_text_field( $_POST['status'][ $i ] ); - } - } - } - - $filter = array( - 'created_at' => array( - sanitize_text_field( $_POST['start_date'] ), - sanitize_text_field( $_POST['end_date'] ), - ), - 'view' => array( 'labels' => $statuses ), - ); - - $repo = new \WSDesk\Tickets\TicketRepository(); - $data = $repo->archiveTickets( $filter ); - - $data['result'] = esc_html__( 'success' ); - - wp_send_json( $data ); - die; - } - } - - public static function eh_crm_archive_ticket_data_restored() { - - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - - $filters = array(); - $repo = new TicketArchiveRepository(); - if ( ! empty( $_POST['status'][0] ) ) { - $filters['view']['labels'] = array_map( 'sanitize_text_field', $_POST['status'][0] ); - } - - $filters['created_at'][] = isset( $_POST['start_date'] ) ? sanitize_text_field( $_POST['start_date'] ) : ''; - $filters['created_at'][] = isset( $_POST['end_date'] ) ? sanitize_text_field( $_POST['end_date'] ) : ''; - - $repo->restore( $filters ); - die( json_encode( array( 'result' => 'success' ) ) ); - } - } - - public static function eh_crm_ticket_refresh_left_bar_archive() { - if ( wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) ) { - - $active = isset( $_POST['active'] ) ? sanitize_text_field( $_POST['active'] ) : 'all'; - ob_start(); - $label_args = array( - 'type' => 'label', - 'filter' => 'yes', - ); - $label_fields = array( 'slug', 'title', 'settings_id' ); - $avail_labels = eh_crm_get_settings( $label_args, $label_fields ); - $tag_args = array( - 'type' => 'tag', - 'filter' => 'yes', - ); - $tag_fields = array( 'slug', 'title', 'settings_id' ); - $avail_tags = eh_crm_get_settings( $tag_args, $tag_fields ); - $user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ); - $users = get_users( array( 'role__in' => $user_roles_default ) ); - $users_data = array(); - for ( $i = 0; $i < count( $users ); $i++ ) { - $current = $users[ $i ]; - $id = $current->ID; - $user = new WP_User( $id ); - $users_data[ $i ]['id'] = $id; - $users_data[ $i ]['name'] = $user->display_name;
I'll analyze the provided code diff for security vulnerabilities. Vulnerability Existed: no Cross-Site Scripting (XSS) - CWE-79 - includes/class-crm-archive-ajax-functions.php - Multiple lines throughout Old Code: Various uses of esc_html() and esc_attr() with improper escaping contexts Fixed Code: Consistent proper escaping functions applied throughout (esc_html(), esc_attr(), esc_url(), wp_kses_post()) Explanation: The entire file appears to be a line-by-line replacement (all 2493 lines changed with identical content). This is not a functional change but likely a formatting/whitespace normalization or version update. The escaping functions used throughout the code (esc_html(), esc_attr(), esc_url(), wp_kses_post()) are already present in both versions, indicating the code maintains proper output escaping practices. No new vulnerabilities are introduced, and no security fixes are evident in this diff since the functional code remains unchanged. Vulnerability Existed: no Cross-Site Request Forgery (CSRF) - CWE-352 - includes/class-crm-archive-ajax-functions.php - Lines with wp_verify_nonce() Old Code: wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) Fixed Code: wp_verify_nonce( isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : '', 'wsdesk_nonce' ) Explanation: CSRF protection via nonce verification is consistently applied in all AJAX methods that handle POST requests (eh_crm_ticket_single_view_archive, eh_crm_ticket_multiple_unarchive, eh_crm_archive_ticket_data, etc.). The implementation remains unchanged in this diff, indicating the code already implements proper CSRF protection. No vulnerabilities or fixes are present. Vulnerability Existed: not sure Improper Input Validation - CWE-20 - includes/class-crm-archive-ajax-functions.php - Line 25 (pagination handling) Old Code: $pagination = json_decode( stripslashes( sanitize_text_field( $_POST['pagination_id'] ) ), true ); Fixed Code: $pagination = json_decode( stripslashes( sanitize_text_field( $_POST['pagination_id'] ) ), true ); Explanation: The code uses json_decode() on user input after sanitization. While sanitize_text_field() is applied, the order of operations (stripslashes then sanitize) may not fully validate the JSON structure. However, without seeing the context of how $pagination is used afterward, it's unclear if this poses a real risk. The diff shows no change, so no fix is evident, but the pattern warrants careful review of downstream usage.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-backup-restore.php 2025-12-21 09:35:59.421065569 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-backup-restore.php 2025-12-21 09:36:35.227291036 +0000@@ -1,277 +1,277 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -use WSDesk\Tickets\Filters\TicketCreatedFilter; - -class EH_CRM_Backup_Restore { - //functions to generate back up file - public function backup_data_xml( $start, $end, $data ) { - $json = array(); - if ( in_array( 'settings', $data ) ) { - $json['settings'] = $this->get_settings_data(); - } - if ( in_array( 'tickets', $data ) ) { - $json['tickets'] = $this->get_tickets_data( $start, $end ); - } - if ( in_array( 'archive_tickets', $data ) ) { - $json['archive_tickets'] = $this->get_archive_tickets_data( $start, $end ); - } - header( 'Content-Disposition: attachment; filename=' . time() . '_wsdesk_backup.json' ); - header( 'Content-Type: application/json; charset=UTF-8' ); - echo wp_json_encode( $json ); - die; - } - public function get_settings_data() { - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_settings'; - $settings_data = array(); - $settings = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM ' . $wpdb->prefix . 'wsdesk_settings' ), ARRAY_A ); - array_push( $settings, array( 'settings_id' => 0 ) ); - foreach ( $settings as $value ) { - $settings_datum['data'] = $value; - $settings_datum['meta'] = $this->get_settingsmeta_data( $value['settings_id'] ); - array_push( $settings_data, $settings_datum ); - } - return $settings_data; - } - public function get_settingsmeta_data( $settings_id ) { - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_settingsmeta'; - $settingsmeta = $wpdb->get_results( $wpdb->prepare( 'SELECT meta_value, meta_key FROM ' . $wpdb->prefix . 'wsdesk_settingsmeta WHERE settings_id = %d', $settings_id ), ARRAY_A ); - return $settingsmeta; - } - public function get_tickets_data( $start, $end ) { - global $wpdb; - $dates = $this->get_date_range( $start, $end ); - $table = $wpdb->prefix . 'wsdesk_tickets'; - $tickets_data = array(); - foreach ( $dates as $date ) { - $parent_tickets = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM ' . $wpdb->prefix . 'wsdesk_tickets WHERE ticket_date LIKE %s AND ticket_parent = 0', '%' . $date . ' %' ), ARRAY_A ); - if ( ! empty( $parent_tickets ) ) { - foreach ( $parent_tickets as $parent_ticket ) { - $tickets_datum['parent_tickets'] = $parent_ticket; - $tickets_datum['parent_ticketsmeta'] = $this->get_ticketsmeta_data( $parent_ticket['ticket_id'] ); - $tickets_datum['child_tickets'] = $this->get_child_ticket_data( $parent_ticket['ticket_id'] ); - array_push( $tickets_data, $tickets_datum ); - } - } - } - return $tickets_data; - } - public function get_archive_tickets_data( $start, $end ) { - $parent_tickets_query = wpFluent()->table( 'wsdesk_archived_tickets' ) - ->where( 'ticket_parent', 0 ) - ->select( 'ticket_id' ); - - $start = date_create( $start )->format( 'Y-m-d' ); - $end = date_create( $end )->format( 'Y-m-d' ); - - $filter = array( - 'created_at' => array( $start, $end ), - ); - - $parent_tickets_query = ( new TicketCreatedFilter() )->filter( $parent_tickets_query, $filter ); - $parent_tickets_query = $parent_tickets_query->getQuery()->getRawSql(); - - $tickets_query = wpFluent()->table( 'wsdesk_archived_tickets' ) - ->where( wpFluent()->raw( 'ticket_id in (' . $parent_tickets_query . ')' ) ) - ->orWhere( wpFluent()->raw( 'ticket_parent in (' . $parent_tickets_query . ')' ) ); - - $archive_tickets = array( - 'tickets' => array(), - 'meta' => array(), - ); - - $tickets_query->chunk( - 100, - function ( $tickets ) use ( &$archive_tickets ) { - $archive_tickets['tickets'] = array_merge( $archive_tickets['tickets'], $tickets ); - } - ); - - $tickets_query = wpFluent()->table( 'wsdesk_archived_tickets' ) - ->where( wpFluent()->raw( 'ticket_id in (' . $parent_tickets_query . ')' ) ) - ->orWhere( wpFluent()->raw( 'ticket_parent in (' . $parent_tickets_query . ')' ) ) - ->select( 'ticket_id' ) - ->getQuery()->getRawSql(); - - $tickets_meta_query = wpFluent()->table( 'wsdesk_archived_ticketsmeta' ) - ->where( wpFluent()->raw( 'ticket_id in (' . $tickets_query . ')' ) ) - ->select( 'ticket_id', 'meta_key', 'meta_value' ); - - $tickets_meta_query->chunk( - 100, - function ( $meta ) use ( &$archive_tickets ) { - $archive_tickets['meta'] = array_merge( $archive_tickets['meta'], $meta ); - } - ); - - return $archive_tickets; - } - - public function get_ticketsmeta_data( $ticket_id ) { - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_ticketsmeta'; - $ticketsmeta = $wpdb->get_results( $wpdb->prepare( 'SELECT meta_value, meta_key FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta WHERE ticket_id = %d', $ticket_id ), ARRAY_A ); - return $ticketsmeta; - } - public function get_child_ticket_data( $ticket_id ) { - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_tickets'; - $child_tickets = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM ' . $wpdb->prefix . 'wsdesk_tickets WHERE ticket_parent = %d', $ticket_id ), ARRAY_A ); - foreach ( $child_tickets as $key => $child_ticket ) { - $child_meta = $this->get_ticketsmeta_data( $child_ticket['ticket_id'] ); - $child_tickets[ $key ]['child_meta'] = $child_meta; - } - return $child_tickets; - } - public function get_date_range( $start, $end ) { - $start = ( '' != $start ) ? strtotime( $start ) : 0; - $end = ( '' != $end ) ? strtotime( $end ) : time(); - $dates = array(); - - while ( $start <= $end ) { - array_push( $dates, gmdate( 'M d, Y', $start ) ); - $start += 86400; - } - return $dates; - } - - //functions to perform restore - public function restore_data_xml( $file ) { - $json = file_get_contents( $file ); - // $json = substr( $json, 0, strlen( $json ) - 1 ); - $json = json_decode( $json, true ); - if ( isset( $json['settings'] ) ) { - $this->restore_settings_data( $json['settings'] ); - } - if ( isset( $json['tickets'] ) ) { - $this->restore_tickets_data( $json['tickets'] ); - } - if ( isset( $json['archive_tickets'] ) ) { - $this->restore_archive_tickets_data( $json['archive_tickets'] ); - } - } - - public function restore_archive_tickets_data( $archive_tickets ) { - wpFluent()->statement( 'truncate ' . wpFluent()->addTablePrefix( 'wsdesk_archived_tickets', false ) ); - wpFluent()->statement( 'truncate ' . wpFluent()->addTablePrefix( 'wsdesk_archived_ticketsmeta', false ) ); - $chunked_archive_tickets = array_chunk( $archive_tickets['tickets'], 100 ); - foreach ( $chunked_archive_tickets as $tickets ) { - wpFluent()->table( 'wsdesk_archived_tickets' )->insert( $tickets ); - } - - $chunked_archive_tickets_meta = array_chunk( $archive_tickets['meta'], 100 ); - foreach ( $chunked_archive_tickets_meta as $meta ) { - wpFluent()->table( 'wsdesk_archived_ticketsmeta' )->insert( $meta ); - } - } - public function restore_settings_data( $settings ) { - global $wpdb; - $settings_table = $wpdb->prefix . 'wsdesk_settings'; - $settingsmeta_table = $wpdb->prefix . 'wsdesk_settingsmeta'; - - $slugs = array_map( - function ( $setting ) { - return $setting['data']['slug']; - }, - $settings - ); - - if ( count( $slugs ) ) { - $existing_settings_ids = wpFluent()->table( 'wsdesk_settings' ) - ->whereIn( 'slug', $slugs ) - ->select( 'settings_id' ) - ->get(); - $existing_settings_ids = array_map( - function ( $existing_setting ) { - return $existing_setting->settings_id; - }, - $existing_settings_ids - ); - - if ( count( $existing_settings_ids ) ) { - wpFluent()->table( 'wsdesk_settings' )->whereIn( 'settings_id', $existing_settings_ids )->delete(); - wpFluent()->table( 'wsdesk_settingsmeta' )->whereIn( 'settings_id', $existing_settings_ids )->delete(); - } - } - - foreach ( $settings as $setting ) { - // We have some meta with settings_id zero (0). Ignoring settings table but need meta import - $setting_id = 0; - if ( $setting['data']['settings_id'] ) { - $setting_id = wpFluent()->table( 'wsdesk_settings' )->insert( $setting['data'] ); - } - if ( 0 === (int) $setting_id ) { - $meta_keys = array_map( - function ( $meta ) { - return $meta['meta_key']; - }, - $setting['meta'] - ); - - if ( count( $meta_keys ) ) { - wpFluent()->table( 'wsdesk_settingsmeta' )->whereIn( 'meta_key', $meta_keys )->delete(); - } - } - foreach ( $setting['meta'] as $key => $value ) { - $value['settings_id'] = $setting_id; - unset( $value['meta_id'] ); - wpFluent()->table( 'wsdesk_settingsmeta' )->insert( $value ); - } - } - } - - public function insert_into_table( $table, $data ) { - global $wpdb; - $table = str_replace( $wpdb->prefix, '', $table ); - return wpFluent()->table( $table )->insert( $data ); - } - - public function restore_tickets_data( $tickets ) { - global $wpdb; - $tickets_table = $wpdb->prefix . 'wsdesk_tickets'; - $ticketsmeta_table = $wpdb->prefix . 'wsdesk_ticketsmeta'; - /* $this->delete_existing_data( 'wsdesk_tickets' ); - $this->delete_existing_data( 'wsdesk_ticketsmeta' ); */ - foreach ( $tickets as $ticket ) { - unset( $ticket['parent_tickets']['ticket_id'] ); - $ticket['parent_tickets']['ticket_id'] = $this->insert_into_table( $tickets_table, $ticket['parent_tickets'] ); - foreach ( $ticket['parent_ticketsmeta'] as $parent_meta ) { - $parent_meta['ticket_id'] = $ticket['parent_tickets']['ticket_id']; - $this->insert_into_table( $ticketsmeta_table, $parent_meta ); - } - foreach ( $ticket['child_tickets'] as $child_ticket ) { - $child_meta_data = $child_ticket['child_meta']; - unset( $child_ticket['child_meta'] ); - unset( $child_ticket['ticket_id'] ); - $child_ticket['ticket_id'] = $this->insert_into_table( $tickets_table, $child_ticket ); - - foreach ( $child_meta_data as $child_meta ) { - $child_meta['ticket_id'] = $child_ticket['ticket_id']; - $this->insert_into_table( $ticketsmeta_table, $child_meta ); - } - } - } - } - public function delete_existing_data( $table_name ) { - global $wpdb; - $table_name = $wpdb->prefix . $table_name; - switch ( $table_name ) { - case 'wsdesk_tickets': - $wpdb->get_results( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_tickets' , ARRAY_A ); - break; - case 'wsdesk_ticketsmeta': - $wpdb->get_results( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta' , ARRAY_A ); - break; - case 'wsdesk_settings': - $wpdb->get_results( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_settings' , ARRAY_A ); - break; - case 'wsdesk_settingsmeta': - $wpdb->get_results( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_settingsmeta' , ARRAY_A ); - break; - } - } -} +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++use WSDesk\Tickets\Filters\TicketCreatedFilter;++class EH_CRM_Backup_Restore {+ //functions to generate back up file+ public function backup_data_xml( $start, $end, $data ) {+ $json = array();+ if ( in_array( 'settings', $data ) ) {+ $json['settings'] = $this->get_settings_data();+ }+ if ( in_array( 'tickets', $data ) ) {+ $json['tickets'] = $this->get_tickets_data( $start, $end );+ }+ if ( in_array( 'archive_tickets', $data ) ) {+ $json['archive_tickets'] = $this->get_archive_tickets_data( $start, $end );+ }+ header( 'Content-Disposition: attachment; filename=' . time() . '_wsdesk_backup.json' );+ header( 'Content-Type: application/json; charset=UTF-8' );+ echo wp_json_encode( $json );+ die;+ }+ public function get_settings_data() {+ global $wpdb;+ $table = $wpdb->prefix . 'wsdesk_settings';+ $settings_data = array();+ $settings = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM ' . $wpdb->prefix . 'wsdesk_settings' ), ARRAY_A );+ array_push( $settings, array( 'settings_id' => 0 ) );+ foreach ( $settings as $value ) {+ $settings_datum['data'] = $value;+ $settings_datum['meta'] = $this->get_settingsmeta_data( $value['settings_id'] );+ array_push( $settings_data, $settings_datum );+ }+ return $settings_data;+ }+ public function get_settingsmeta_data( $settings_id ) {+ global $wpdb;+ $table = $wpdb->prefix . 'wsdesk_settingsmeta';+ $settingsmeta = $wpdb->get_results( $wpdb->prepare( 'SELECT meta_value, meta_key FROM ' . $wpdb->prefix . 'wsdesk_settingsmeta WHERE settings_id = %d', $settings_id ), ARRAY_A );+ return $settingsmeta;+ }+ public function get_tickets_data( $start, $end ) {+ global $wpdb;+ $dates = $this->get_date_range( $start, $end );+ $table = $wpdb->prefix . 'wsdesk_tickets';+ $tickets_data = array();+ foreach ( $dates as $date ) {+ $parent_tickets = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM ' . $wpdb->prefix . 'wsdesk_tickets WHERE ticket_date LIKE %s AND ticket_parent = 0', '%' . $date . ' %' ), ARRAY_A );+ if ( ! empty( $parent_tickets ) ) {+ foreach ( $parent_tickets as $parent_ticket ) {+ $tickets_datum['parent_tickets'] = $parent_ticket;+ $tickets_datum['parent_ticketsmeta'] = $this->get_ticketsmeta_data( $parent_ticket['ticket_id'] );+ $tickets_datum['child_tickets'] = $this->get_child_ticket_data( $parent_ticket['ticket_id'] );+ array_push( $tickets_data, $tickets_datum );+ }+ }+ }+ return $tickets_data;+ }+ public function get_archive_tickets_data( $start, $end ) {+ $parent_tickets_query = wpFluent()->table( 'wsdesk_archived_tickets' )+ ->where( 'ticket_parent', 0 )+ ->select( 'ticket_id' );++ $start = date_create( $start )->format( 'Y-m-d' );+ $end = date_create( $end )->format( 'Y-m-d' );++ $filter = array(+ 'created_at' => array( $start, $end ),+ );++ $parent_tickets_query = ( new TicketCreatedFilter() )->filter( $parent_tickets_query, $filter );+ $parent_tickets_query = $parent_tickets_query->getQuery()->getRawSql();++ $tickets_query = wpFluent()->table( 'wsdesk_archived_tickets' )+ ->where( wpFluent()->raw( 'ticket_id in (' . $parent_tickets_query . ')' ) )+ ->orWhere( wpFluent()->raw( 'ticket_parent in (' . $parent_tickets_query . ')' ) );++ $archive_tickets = array(+ 'tickets' => array(),+ 'meta' => array(),+ );++ $tickets_query->chunk(+ 100,+ function ( $tickets ) use ( &$archive_tickets ) {+ $archive_tickets['tickets'] = array_merge( $archive_tickets['tickets'], $tickets );+ }+ );++ $tickets_query = wpFluent()->table( 'wsdesk_archived_tickets' )+ ->where( wpFluent()->raw( 'ticket_id in (' . $parent_tickets_query . ')' ) )+ ->orWhere( wpFluent()->raw( 'ticket_parent in (' . $parent_tickets_query . ')' ) )+ ->select( 'ticket_id' )+ ->getQuery()->getRawSql();++ $tickets_meta_query = wpFluent()->table( 'wsdesk_archived_ticketsmeta' )+ ->where( wpFluent()->raw( 'ticket_id in (' . $tickets_query . ')' ) )+ ->select( 'ticket_id', 'meta_key', 'meta_value' );++ $tickets_meta_query->chunk(+ 100,+ function ( $meta ) use ( &$archive_tickets ) {+ $archive_tickets['meta'] = array_merge( $archive_tickets['meta'], $meta );+ }+ );++ return $archive_tickets;+ }++ public function get_ticketsmeta_data( $ticket_id ) {+ global $wpdb;+ $table = $wpdb->prefix . 'wsdesk_ticketsmeta';+ $ticketsmeta = $wpdb->get_results( $wpdb->prepare( 'SELECT meta_value, meta_key FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta WHERE ticket_id = %d', $ticket_id ), ARRAY_A );+ return $ticketsmeta;+ }+ public function get_child_ticket_data( $ticket_id ) {+ global $wpdb;+ $table = $wpdb->prefix . 'wsdesk_tickets';+ $child_tickets = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM ' . $wpdb->prefix . 'wsdesk_tickets WHERE ticket_parent = %d', $ticket_id ), ARRAY_A );+ foreach ( $child_tickets as $key => $child_ticket ) {+ $child_meta = $this->get_ticketsmeta_data( $child_ticket['ticket_id'] );+ $child_tickets[ $key ]['child_meta'] = $child_meta;+ }+ return $child_tickets;+ }+ public function get_date_range( $start, $end ) {+ $start = ( '' != $start ) ? strtotime( $start ) : 0;+ $end = ( '' != $end ) ? strtotime( $end ) : time();+ $dates = array();++ while ( $start <= $end ) {+ array_push( $dates, gmdate( 'M d, Y', $start ) );+ $start += 86400;+ }+ return $dates;+ }++ //functions to perform restore+ public function restore_data_xml( $file ) {+ $json = file_get_contents( $file );+ // $json = substr( $json, 0, strlen( $json ) - 1 );+ $json = json_decode( $json, true );+ if ( isset( $json['settings'] ) ) {+ $this->restore_settings_data( $json['settings'] );+ }+ if ( isset( $json['tickets'] ) ) {+ $this->restore_tickets_data( $json['tickets'] );+ }+ if ( isset( $json['archive_tickets'] ) ) {+ $this->restore_archive_tickets_data( $json['archive_tickets'] );+ }+ }++ public function restore_archive_tickets_data( $archive_tickets ) {+ wpFluent()->statement( 'truncate ' . wpFluent()->addTablePrefix( 'wsdesk_archived_tickets', false ) );+ wpFluent()->statement( 'truncate ' . wpFluent()->addTablePrefix( 'wsdesk_archived_ticketsmeta', false ) );+ $chunked_archive_tickets = array_chunk( $archive_tickets['tickets'], 100 );+ foreach ( $chunked_archive_tickets as $tickets ) {+ wpFluent()->table( 'wsdesk_archived_tickets' )->insert( $tickets );+ }++ $chunked_archive_tickets_meta = array_chunk( $archive_tickets['meta'], 100 );+ foreach ( $chunked_archive_tickets_meta as $meta ) {+ wpFluent()->table( 'wsdesk_archived_ticketsmeta' )->insert( $meta );+ }+ }+ public function restore_settings_data( $settings ) {+ global $wpdb;+ $settings_table = $wpdb->prefix . 'wsdesk_settings';+ $settingsmeta_table = $wpdb->prefix . 'wsdesk_settingsmeta';++ $slugs = array_map(+ function ( $setting ) {+ return $setting['data']['slug'];+ },+ $settings+ );++ if ( count( $slugs ) ) {+ $existing_settings_ids = wpFluent()->table( 'wsdesk_settings' )+ ->whereIn( 'slug', $slugs )+ ->select( 'settings_id' )+ ->get();+ $existing_settings_ids = array_map(+ function ( $existing_setting ) {+ return $existing_setting->settings_id;+ },+ $existing_settings_ids+ );++ if ( count( $existing_settings_ids ) ) {+ wpFluent()->table( 'wsdesk_settings' )->whereIn( 'settings_id', $existing_settings_ids )->delete();+ wpFluent()->table( 'wsdesk_settingsmeta' )->whereIn( 'settings_id', $existing_settings_ids )->delete();+ }+ }++ foreach ( $settings as $setting ) {+ // We have some meta with settings_id zero (0). Ignoring settings table but need meta import+ $setting_id = 0;+ if ( $setting['data']['settings_id'] ) {+ $setting_id = wpFluent()->table( 'wsdesk_settings' )->insert( $setting['data'] );+ }+ if ( 0 === (int) $setting_id ) {+ $meta_keys = array_map(+ function ( $meta ) {+ return $meta['meta_key'];+ },+ $setting['meta']+ );++ if ( count( $meta_keys ) ) {+ wpFluent()->table( 'wsdesk_settingsmeta' )->whereIn( 'meta_key', $meta_keys )->delete();+ }+ }+ foreach ( $setting['meta'] as $key => $value ) {+ $value['settings_id'] = $setting_id;+ unset( $value['meta_id'] );+ wpFluent()->table( 'wsdesk_settingsmeta' )->insert( $value );+ }+ }+ }++ public function insert_into_table( $table, $data ) {+ global $wpdb;+ $table = str_replace( $wpdb->prefix, '', $table );+ return wpFluent()->table( $table )->insert( $data );+ }++ public function restore_tickets_data( $tickets ) {+ global $wpdb;+ $tickets_table = $wpdb->prefix . 'wsdesk_tickets';+ $ticketsmeta_table = $wpdb->prefix . 'wsdesk_ticketsmeta';+ /* $this->delete_existing_data( 'wsdesk_tickets' );+ $this->delete_existing_data( 'wsdesk_ticketsmeta' ); */+ foreach ( $tickets as $ticket ) {+ unset( $ticket['parent_tickets']['ticket_id'] );+ $ticket['parent_tickets']['ticket_id'] = $this->insert_into_table( $tickets_table, $ticket['parent_tickets'] );+ foreach ( $ticket['parent_ticketsmeta'] as $parent_meta ) {+ $parent_meta['ticket_id'] = $ticket['parent_tickets']['ticket_id'];+ $this->insert_into_table( $ticketsmeta_table, $parent_meta );+ }+ foreach ( $ticket['child_tickets'] as $child_ticket ) {+ $child_meta_data = $child_ticket['child_meta'];+ unset( $child_ticket['child_meta'] );+ unset( $child_ticket['ticket_id'] );+ $child_ticket['ticket_id'] = $this->insert_into_table( $tickets_table, $child_ticket );++ foreach ( $child_meta_data as $child_meta ) {+ $child_meta['ticket_id'] = $child_ticket['ticket_id'];+ $this->insert_into_table( $ticketsmeta_table, $child_meta );+ }+ }+ }+ }+ public function delete_existing_data( $table_name ) {+ global $wpdb;+ $table_name = $wpdb->prefix . $table_name;+ switch ( $table_name ) {+ case 'wsdesk_tickets':+ $wpdb->get_results( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_tickets' , ARRAY_A );+ break;+ case 'wsdesk_ticketsmeta':+ $wpdb->get_results( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta' , ARRAY_A );+ break;+ case 'wsdesk_settings':+ $wpdb->get_results( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_settings' , ARRAY_A );+ break;+ case 'wsdesk_settingsmeta':+ $wpdb->get_results( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_settingsmeta' , ARRAY_A );+ break;+ }+ }+}
Vulnerability Existed: no The diff provided shows only a line ending change (CRLF to LF conversion) with no actual code modifications. All functional code remains identical between versions 3.3.4 and 3.3.5. **Analysis Summary:** This diff represents a formatting change only - conversion from Windows-style line endings (CRLF) to Unix-style line endings (LF). The actual PHP code logic is completely unchanged. The file contains several pre-existing security concerns that are NOT addressed by this update: 1. **SQL Injection vulnerabilities** - Lines using `wpFluent()->raw()` with unsanitized SQL queries 2. **Unrestricted file operations** - `file_get_contents()` without validation in `restore_data_xml()` 3. **Unsafe deserialization** - `json_decode()` without proper validation 4. **Weak table name sanitization** - The `insert_into_table()` function at line 224 However, since this update makes NO CODE CHANGES, no vulnerabilities are being fixed. The line ending normalization is a non-security housekeeping change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-cron-setup.php 2025-12-21 09:35:59.421065569 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-cron-setup.php 2025-12-21 09:36:35.227291036 +0000@@ -1,826 +1,826 @@-<?php - -use WSDesk\Tickets\TicketArchiveRepository; -use Illuminate\Support\Arr; - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -class EH_CRM_Cron_Setup { - protected $triggers_schedule = array(); - public function __construct() { - add_action( 'init', array( $this, 'crawler_schedule_init' ) ); - add_filter( 'cron_schedules', array( $this, 'crawler_schedule_time' ) ); - add_action( 'crm_email_crawler', array( $this, 'start_crm_email_crawler' ) ); - wp_schedule_single_event( time() + 1, 'start_scheduled_trigger_cron' ); - } - - public function get_unixtime( $type, $period ) { - $val = 0; - $min = 60; - $hour = 3600; - $day = 86400; - $week = 604800; - $month = 4.34524; - $year = 52.1429; - switch ( $type ) { - case 'min': - $val = $min; - break; - case 'hour': - $val = $hour; - break; - case 'day': - $val = $day; - break; - case 'week': - $val = $week; - break; - case 'month': - $val = $month * $week; - break; - case 'year': - $val = $year * $week; - break; - default: - break; - } - return ( $val * intval( $period ) ); - } - - public function crawler_schedule_time( $schedules ) { - $schedules['crm_crawler_interval'] = array( - 'interval' => 60, - 'display' => 'Every 60 Seconds', - ); - foreach ( $this->triggers_schedule as $key => $value ) { - $schedules[ $key ] = array( - 'interval' => $value, - 'display' => 'Every ' . $value . ' Seconds', - ); - } - return $schedules; - } - - - public function crawler_schedule_init() { - if ( ! wp_next_scheduled( 'crm_email_crawler' ) ) { - wp_schedule_event( time(), 'crm_crawler_interval', 'crm_email_crawler' ); - } - foreach ( $this->triggers_schedule as $key => $value ) { - if ( ! wp_next_scheduled( $key ) ) { - wp_schedule_event( time(), $key, $key ); - } - } - } - - public function start_trigger_action_cron() { - /* $trigger = current_action(); - $ticket_ids = eh_crm_get_trigger_tickets( $trigger ); */ - /*eh_crm_trigger_perform_action($trigger, $ticket_ids); - for($i=0;$i<count($ticket_ids);$i++) - { - eh_crm_update_ticketmeta($ticket_ids[$i]['ticket_id'], "trigger_status", "triggered",FALSE); - eh_crm_update_ticketmeta($ticket_ids[$i]['ticket_id'], "trigger_changes", "none",FALSE); - }*/ - } - - public function start_trigger_schedule() { - $scheduled_triggers_array = get_option( 'wsdesk_scheduled_triggers', array() ); - - $triggered = array(); - - foreach ( $scheduled_triggers_array as $key => $value ) { - if ( 'no' !== $value['triggered'] ) { - continue; - } - - $trigger = eh_crm_get_settings( - array( - 'slug' => $value['trigger_slug'], - 'type' => 'trigger', - ), - array( 'slug', 'settings_id', 'title' ) - ); - - $trigger_meta = ! empty( eh_crm_get_settingsmeta( $trigger[0]['settings_id'] ) ) ? eh_crm_get_settingsmeta( $trigger[0]['settings_id'] ) : array(); - - $is_matched = eh_crm_validate_trigger_ticket( $value['trigger_slug'], $value['ticket_id'] ); - - if ( false === $is_matched ) { - continue; - } - - eh_crm_update_ticketmeta( $value['ticket_id'], 'trigger_status', 'updated', false ); - eh_crm_trigger_perform_action( $value['trigger_slug'], array( array( 'ticket_id' => $value['ticket_id'] ) ) ); - - $scheduled_trigger = array( - 'ticket_id' => $value['ticket_id'], - 'trigger_slug' => $value['trigger_slug'], - 'action_time' => $value['action_time'], - 'triggered' => 'yes', - ); - - $scheduled_triggers_array[ $key ] = $scheduled_trigger; - $triggered[] = $key; - eh_crm_update_ticketmeta( $value['ticket_id'], 'trigger_status', 'triggered', false ); - } - - foreach ( $triggered as $key ) { - unset( $scheduled_triggers_array[ $key ] ); - } - - update_option( 'wsdesk_scheduled_triggers', array_values( $scheduled_triggers_array ) ); - wp_clear_scheduled_hook( 'start_scheduled_trigger_cron' ); - wp_schedule_single_event( time() + 60, 'start_scheduled_trigger_cron' ); - } - - public function start_crm_email_crawler() { - set_time_limit( 60 ); - if ( eh_crm_get_settingsmeta( 0, 'oauth_activation' ) == 'activated' ) { - $oauth = new EH_CRM_OAuth(); - if ( $oauth->refresh_accesstoken() ) { - $this->message_search(); - } - } - $imap_account_data = eh_crm_get_settingsmeta( '0', 'imap_account_data' ); - if ( ! empty( $imap_account_data ) ) { - $this->email_imap(); - } - } - - public function email_imap() { - $support_reply_email = eh_crm_get_settingsmeta( '0', 'support_reply_email' ); - $upload = wp_upload_dir(); - $imap_account_id = 0; - $imap_account_data = eh_crm_get_settingsmeta( '0', 'imap_account_data' ); - foreach ( $imap_account_data as $imap_account_data ) { - - $flags = [ - 'imap', - 'ssl', - 'novalidate-cert', - ]; - - if ( Arr::has( $imap_account_data, 'username' ) ) { - $flags[] = 'user=' . Arr::get( $imap_account_data, 'username' ); - } - - $mailbox = new EH_CRM_PhpImap\EH_CRM_Mailbox( - '{' . $imap_account_data['imap_server_url'] . ':' . $imap_account_data['imap_server_port'] . '/' . implode( '/', $flags ) . '}INBOX', - $imap_account_data['imap_server_email'], - $imap_account_data['imap_server_email_pwd'], - $upload['path'] - ); - - if ( 'outlook.office365.com' == $imap_account_data['imap_server_url'] || 'imap-mail.outlook.com' == $imap_account_data['imap_server_url'] ) { - $mailsIds = $mailbox->searchMailbox( 'UNSEEN', 'US-ASCII' ); - } else { - $mailsIds = $mailbox->searchMailbox( 'UNSEEN', Arr::get( $imap_account_data, 'charset', 'UTF-8' ) ); - } - $delete_email = $imap_account_data['delete_email']; - if ( $mailsIds ) { - foreach ( $mailsIds as $key => $mail_id ) { - $mail = $mailbox->getMail( $mail_id ); - $mailbox->markMailsAsRead( $mailsIds ); - $message_data = array(); - $replyToEmail = array_keys( $mail->replyTo ); - if ( isset( $replyToEmail[0] ) && ! empty( $replyToEmail[0] ) ) { - $message_data['email'] = $replyToEmail[0]; - } else { - $message_data['email'] = $mail->fromAddress; - } - $message_data['forwarded'] = array(); - $to = array_keys( $mail->to ); - - if ( ! in_array( $support_reply_email, $to ) ) { - $message_data['forwarded'] = $to; - } - $message_data['forwarded'][] = $imap_account_data['imap_server_email']; - $message_data['cc'] = array_keys( $mail->cc ); - $message_data['bcc'] = array_keys( $mail->bcc ); - $message_data['subject'] = $mail->subject; - $message_data['imap_email'] = 'field_MU35_V' . $imap_account_id; - $array = explode( "\n", $mail->textPlain ); - //When there is large and html content $mail->textPlain escapes and return 'This is a plain-text message body' message. - if ( empty( $mail->textPlain ) || strpos( $mail->textPlain, 'This is a plain-text message body' ) !== false ) { - $array = $mail->textHtml; - $replaced = preg_replace( '#<script(.*?)>(.*?)</script>#is', '', $array ); - $replaced = preg_replace( '/<((script)[^>]*)>(.*)\<\/(script)>/Us', '<$1>$3</script>', $array ); - $replaced = preg_replace( '#<style(.*?)>(.*?)</style>#is', '', $replaced ); - $replaced = preg_replace( '/<((style)[^>]*)>(.*)\<\/(style)>/Us', '<$1>$3</style>', $array ); - $replaced = preg_replace( '/<((form)[^>]*)>(.*)\<\/(form)>/Us', '<$1>$3</form>', $array ); - $parsed = strip_tags( $replaced, '<p><a><br><div>' ); - $array = explode( "\n", $parsed ); - } - $content_output = array(); - $i = 0; - $remove = 0; - foreach ( $array as $arr ) { - if ( ! ( preg_match( '/^>/', $arr ) ) && ! ( preg_match( '/^On Mon,|^On Tue,|^On Wed,|^On Thu,|^On Fri,|^On Sat,|^On Sun,|^wrote:|^On|^drive /', $arr ) ) ) { - array_push( $content_output, $arr ); - } else { - $remove = $i; - } - $i++; - } - if ( 0 != $remove ) { - unset( $content_output[ $remove - 1 ] ); - } - $content = implode( "\n", $content_output ); - $message_data['content'] = preg_replace( '/\n(\s*\n){2,}/', "\n\n", $content ); - $mail_attachments = $mail->getAttachments(); - $attachment = array(); - if ( ! empty( $mail_attachments ) ) { - foreach ( $mail_attachments as $single ) { - $temp_array = array( - 'path' => $upload['path'] . '/' . $single->name, - 'url' => $upload['url'] . '/' . $single->name, - ); - array_push( $attachment, $temp_array ); - } - $message_data['attachments'] = $attachment; - } - if ( eh_crm_validate_subject_block( $message_data['subject'] ) ) { - if ( eh_crm_validate_email_block( $message_data['email'], 'receive' ) ) { - $this->match_insert( $message_data ); - } - } - if ( 'yes' == $delete_email || 'on' == $delete_email ) { - $mailbox->deleteMail( $mailsIds[ $key ] ); - } - } - } - $imap_account_id++; - } - } - - - public function message_search() { - $access_token = eh_crm_get_settingsmeta( 0, 'oauth_accesstoken' ); - $search = 'after:' . eh_crm_get_settingsmeta( 0, 'oauth_last_requested' ) . ' before:' . time(); - $url = 'https://www.googleapis.com/gmail/v1/users/me/messages?q=in:inbox ' . $search; - $url .= '&v=2'; - $url .= '&oauth_token=' . $access_token; - $response = wp_safe_remote_get( $url ); - if ( ! is_wp_error( $response ) ) { - $result = $response['response']; - if ( 200 == $result['code'] && 'OK' == $result['message'] ) { - eh_crm_update_settingsmeta( 0, 'oauth_last_requested', time() ); - $body = json_decode( $response['body'] ); - if ( 0 != $body->resultSizeEstimate ) { - foreach ( $body->messages as $key => $message ) { - $message_url = 'https://www.googleapis.com/gmail/v1/users/me/messages/' . $message->id; - $constant_url = '?v=2&oauth_token=' . $access_token; - $request_url = $message_url . $constant_url; - $req_res = wp_safe_remote_get( $request_url ); - $message_body = json_decode( $req_res['body'] ); - $payload = $message_body->payload; - $header = $payload->headers; - $message_data = array(); - foreach ( $header as $single ) { - if ( 'From' == $single->name ) { - preg_match( '~<(.*?)>~', $single->value, $output ); - if ( ! isset( $message_data['email'] ) ) { - $message_data['email'] = $output[1]; - } - } - if ( 'Reply-To' == $single->name ) { - $message_data['email'] = $single->value; - } - if ( 'Subject' == $single->name ) { - $message_data['subject'] = strip_tags( $single->value ); - } - if ( 'Cc' == $single->name ) { - $cc_ex = explode( ',', $single->value ); - $cc = array(); - foreach ( $cc_ex as $cc_value ) { - preg_match( '~<(.*?)>~', $cc_value, $output ); - $cc_email = $output[1]; - array_push( $cc, $cc_email ); - } - $message_data['cc'] = $cc; - } - if ( 'Bcc' == $single->name ) { - $bcc_ex = explode( ',', $single->value ); - $bcc = array(); - foreach ( $bcc_ex as $bcc_value ) { - preg_match( '~<(.*?)>~', $bcc_value, $output ); - $bcc_email = $output[1]; - array_push( $bcc, $bcc_email ); - } - $message_data['bcc'] = $bcc; - } - } - $parsed = $this->parts_parser( $payload, $message->id ); - $array = explode( "\n", $parsed['content'] ); - $content_output = array(); - $i = 0; - $remove = 0; - foreach ( $array as $arr ) { - if ( ! ( preg_match( '/^>/', $arr ) ) && ! ( preg_match( '/^On Mon,|^On Tue,|^On Wed,|^On Thu,|^On Fri,|^On Sat,|^On Sun,|^wrote:|^On|^drive /', $arr ) ) ) { - array_push( $content_output, $arr ); - } else { - $remove = $i; - } - $i++; - } - if ( 0 != $remove ) { - unset( $content_output[ $remove - 1 ] ); - } - $content = implode( "\n", $content_output ); - $message_data['content'] = preg_replace( '/\n(\s*\n){2,}/', "\n\n", $content ); - if ( isset( $parsed['attachments'] ) ) { - $message_data['attachments'] = $parsed['attachments']; - } - if ( eh_crm_validate_subject_block( $message_data['subject'] ) ) { - if ( eh_crm_validate_email_block( $message_data['email'], 'receive' ) ) { - $this->match_insert( $message_data ); - } - } - } - } - } - } - } - - public function get_string_between( $string, $start, $end ) { - $string = ' ' . $string; - $ini = strpos( $string, $start ); - if ( 0 == $ini ) { - return ''; - } - $ini += strlen( $start ); - $len = strpos( $string, $end, $ini ) - $ini; - return substr( $string, $ini, $len ); - } - - public function match_insert( $data ) { - $data['subject'] = eh_crm_convert_to_utf8( $data['subject'] ); - $ticket_id = 'new'; - $support_reply_email = eh_crm_get_settingsmeta( '0', 'support_reply_email' ); - $send = eh_crm_get_settingsmeta( '0', 'auto_send_creation_email' ); - if ( preg_match( '/Ticket \[(.*?)\] :/', $data['subject'], $output ) == 1 || preg_match( '/Re: Ticket \[(.*?)\] :/', $data['subject'], $output ) == 1 ) { - $ticket_id = $output[1]; - } elseif ( strpos( $data['subject'], 'Re: ' ) === 0 ) { - $ticket = eh_crm_get_ticket( array( 'ticket_title' => substr( $data['subject'], 4 ) ), array( 'ticket_email', 'ticket_id' ) ); - if ( ! empty( $ticket ) ) { - $ticket_id = $ticket[0]['ticket_id']; - if ( in_array( $ticket[0]['ticket_email'], $data['cc'] ) ) { - $index = array_search( $ticket[0]['ticket_email'], $data['cc'] ); - } else { - $index = array_search( $support_reply_email, $data['cc'] ); - } - $data['cc'][ $index ] = $data['email']; - } - } - if ( 'new' != $ticket_id ) { - error_log( 'Checking ticket ID : ' . $ticket_id . ' is exists on archived tickets' ); - $achived = wpFluent()->table( TicketArchiveRepository::TABLE_TICKETS )->select( 'ticket_id' )->find( $ticket_id, 'ticket_id' ); - - if ( $achived ) { - error_log( 'above ticket was archived' ); - ( new TicketArchiveRepository() )->restore( array( 'ticket_id' => array( $ticket_id ) ) ); - } - - $email_validate = eh_crm_get_ticket_value_count( 'ticket_email', $data['email'], false, 'ticket_id', $ticket_id ); - if ( empty( $email_validate ) ) { - $cc_emails = eh_crm_get_ticketmeta( $ticket_id, 'ticket_cc' ); - if ( is_array( $cc_emails ) && in_array( $data['email'], $cc_emails ) ) { - $ticket = eh_crm_get_ticket( array( 'ticket_id' => $ticket_id ), 'ticket_email' ); - if ( in_array( $ticket[0]['ticket_email'], $data['cc'] ) ) { - $index = array_search( $ticket[0]['ticket_email'], $data['cc'] ); - } else { - $index = array_search( $support_reply_email, $data['cc'] ); - } - $data['cc'][ $index ] = $data['email']; - $email_validate = array( 'not_empty' => 1 ); - } else { - $email_validate = array(); - } - } - if ( ! empty( $email_validate ) ) { - $parent = eh_crm_get_ticket( array( 'ticket_id' => $ticket_id ) ); - $user = get_user_by( 'email', $data['email'] ); - $author = 0; - if ( $user ) { - $author = $user->ID; - } - $category = 'raiser_reply'; - $child = array( - 'ticket_author' => $author, - 'ticket_email' => $data['email'], - 'ticket_title' => $parent[0]['ticket_title'], - 'ticket_content' => eh_crm_filter_email_content( str_replace( "\n", '<br/>', $data['content'] ) ), - 'ticket_category' => $category, - 'ticket_parent' => $ticket_id, - 'ticket_vendor' => $parent[0]['ticket_vendor'], - ); - if ( isset( $data['attachments'] ) ) { - $child_meta = array(); - $attach_path = array(); - $attach_url = array(); - foreach ( $data['attachments'] as $attach ) { - array_push( $attach_url, $attach['url'] ); - array_push( $attach_path, $attach['path'] ); - } - $child_meta['ticket_attachment'] = $attach_url; - $child_meta['ticket_attachment_path'] = $attach_path; - eh_crm_insert_ticket( $child, $child_meta ); - } else { - eh_crm_insert_ticket( $child ); - } - if ( isset( $data['cc'] ) && is_array( $data['cc'] ) && in_array( $support_reply_email, $data['cc'] ) ) { - $index = array_search( $support_reply_email, $data['cc'] ); - $data['cc'][ $index ] = $data['forwarded'][0]; - } - - eh_crm_update_ticketmeta( $ticket_id, 'field_MU35', $data['imap_email'] ); - eh_crm_update_ticketmeta( $ticket_id, 'ticket_cc', ( ( isset( $data['cc'] ) ) ? $data['cc'] : array() ), false ); - eh_crm_update_ticketmeta( $ticket_id, 'ticket_bcc', ( ( isset( $data['bcc'] ) ) ? $data['bcc'] : array() ), false ); - $ticket_label = eh_crm_get_ticketmeta( $ticket_id, 'ticket_label' ); - $submit = eh_crm_get_settingsmeta( '0', 'default_label' ); - if ( $ticket_label == $submit ) { //if label is same - eh_crm_update_ticketmeta( $ticket_id, 'ticket_label', $submit, false ); - } else { - eh_crm_update_ticketmeta( $ticket_id, 'ticket_label', $submit ); //false removed to let "change to" cause a trigger when pulling e-mail from imap - } - } else { - $user = get_user_by( 'email', $data['email'] ); - $author = 0; - if ( $user ) { - $author = $user->ID; - } - $email = $data['email']; - $title = $data['subject']; - $desc = str_replace( "\n", '<br/>', $data['content'] ); - $args = array( - 'ticket_author' => $author, - 'ticket_email' => $email, - 'ticket_title' => $title, - 'ticket_content' => eh_crm_filter_email_content( $desc ), - 'ticket_category' => 'raiser_reply', - 'ticket_vendor' => '', - ); - $meta = array(); - $req_args = array( 'type' => 'tag' ); - $fields = array( 'slug', 'title', 'settings_id' ); - $avail_tags = eh_crm_get_settings( $req_args, $fields ); - $tagged = array(); - if ( ! empty( $avail_tags ) ) { - for ( $i = 0, $j = 0; $i < count( $avail_tags ); $i++ ) { - if ( preg_match( '/' . strtolower( $avail_tags[ $i ]['title'] ) . '/', strtolower( $desc ) ) || preg_match( '/' . strtolower( $avail_tags[ $i ]['title'] ) . '/', strtolower( $title ) ) ) { - $tagged[ $j ] = $avail_tags[ $i ]['slug']; - $j++; - } - } - } - $meta['ticket_tags'] = $tagged; - $default_assignee = eh_crm_get_settingsmeta( '0', 'default_assignee' ); - $assignee = array(); - switch ( $default_assignee ) { - case 'ticket_tags': - $users = get_users( array( 'role__in' => array( 'WSDesk_Agents', 'WSDesk_Supervisor' ) ) ); - $user_tags = array(); - for ( $i = 0; $i < count( $users ); $i++ ) { - $current = $users[ $i ]; - $id = $current->ID; - $user_tags[ $id ] = get_user_meta( $id, 'wsdesk_tags', true ); - } - foreach ( $user_tags as $key => $value ) { - for ( $i = 0;$i < count( $value );$i++ ) { - if ( in_array( $value[ $i ], $tagged ) ) { - array_push( $assignee, $key ); - break; - } - } - } - break; - case 'no_assignee': - break; - default: - array_push( $assignee, $default_assignee ); - break; - } - $meta['ticket_assignee'] = $assignee; - $default_label = eh_crm_get_settingsmeta( '0', 'default_label' ); - if ( eh_crm_get_settings( array( 'slug' => $default_label ) ) ) { - $meta['ticket_label'] = $default_label; - } - if ( isset( $data['attachments'] ) ) { - $attach_path = array(); - $attach_url = array(); - foreach ( $data['attachments'] as $attach ) { - array_push( $attach_url, $attach['url'] ); - array_push( $attach_path, $attach['path'] ); - } - $meta['ticket_attachment'] = $attach_url; - $meta['ticket_attachment_path'] = $attach_path; - } - $meta['ticket_cc'] = ( isset( $data['cc'] ) ) ? $data['cc'] : array(); - $meta['ticket_bcc'] = ( isset( $data['bcc'] ) ) ? $data['bcc'] : array(); - $meta['ticket_source'] = 'EMail'; - $meta['field_MU35'] = isset( $data['imap_email'] ) ? $data['imap_email'] : ''; - $gen_id = eh_crm_insert_ticket( $args, $meta ); - if ( 'enable' == $send && $gen_id ) { - CRM_Ajax::eh_crm_fire_email( 'new_ticket', $gen_id ); - } - } - } else { - $user = get_user_by( 'email', $data['email'] ); - $author = 0; - if ( $user ) { - $author = $user->ID; - } - $email = $data['email']; - $title = $data['subject']; - $desc = str_replace( "\n", '<br/>', $data['content'] ); - $args = array( - 'ticket_author' => $author, - 'ticket_email' => $email, - 'ticket_title' => $title, - 'ticket_content' => eh_crm_filter_email_content( $desc ), - 'ticket_category' => 'raiser_reply', - 'ticket_vendor' => '', - ); - $meta = array(); - $req_args = array( 'type' => 'tag' ); - $fields = array( 'slug', 'title', 'settings_id' ); - $avail_tags = eh_crm_get_settings( $req_args, $fields ); - $tagged = array(); - if ( ! empty( $avail_tags ) ) { - for ( $i = 0, $j = 0; $i < count( $avail_tags ); $i++ ) { - if ( preg_match( '/' . strtolower( $avail_tags[ $i ]['title'] ) . '/', strtolower( $desc ) ) || preg_match( '/' . strtolower( $avail_tags[ $i ]['title'] ) . '/', strtolower( $title ) ) ) { - $tagged[ $j ] = $avail_tags[ $i ]['slug']; - $j++; - } - } - } - $meta['ticket_tags'] = $tagged; - $default_assignee = eh_crm_get_settingsmeta( '0', 'default_assignee' ); - $assignee = array(); - switch ( $default_assignee ) { - case 'ticket_tags': - $users = get_users( array( 'role__in' => array( 'WSDesk_Agents', 'WSDesk_Supervisor' ) ) ); - $user_tags = array(); - for ( $i = 0; $i < count( $users ); $i++ ) { - $current = $users[ $i ]; - $id = $current->ID; - $user_tags[ $id ] = get_user_meta( $id, 'wsdesk_tags', true ); - } - foreach ( $user_tags as $key => $value ) { - for ( $i = 0;$i < count( $value );$i++ ) { - if ( in_array( $value[ $i ], $tagged ) ) { - array_push( $assignee, $key ); - break; - } - } - } - break; - case 'no_assignee': - break; - default: - array_push( $assignee, $default_assignee ); - break; - } - $meta['ticket_assignee'] = $assignee; - $default_label = eh_crm_get_settingsmeta( '0', 'default_label' ); - if ( eh_crm_get_settings( array( 'slug' => $default_label ) ) ) { - $meta['ticket_label'] = $default_label; - } - if ( isset( $data['attachments'] ) ) { - $attach_path = array(); - $attach_url = array(); - foreach ( $data['attachments'] as $attach ) { - array_push( $attach_url, $attach['url'] ); - array_push( $attach_path, $attach['path'] ); - } - $meta['ticket_attachment'] = $attach_url; - $meta['ticket_attachment_path'] = $attach_path; - } - if ( isset( $data['forwarded'] ) ) { - $meta['ticket_forwarded'] = $data['forwarded']; - } - $meta['ticket_cc'] = ( isset( $data['cc'] ) ) ? $data['cc'] : array(); - $meta['ticket_bcc'] = ( isset( $data['bcc'] ) ) ? $data['bcc'] : array(); - $meta['ticket_source'] = 'EMail'; - if ( isset( $data['imap_email'] ) ) { - $meta['field_MU35'] = $data['imap_email']; - } - $gen_id = eh_crm_insert_ticket( $args, $meta ); - if ( 'enable' == $send && $gen_id ) { - CRM_Ajax::eh_crm_fire_email( 'new_ticket', $gen_id ); - } - } - } - - public function recursive_parts_parser( $parts, $message_id, &$attachment, &$parsed ) { - if ( is_array( $parts ) ) { - foreach ( $parts as $main_part ) { - $mineTypeMultipart = explode( '/', $main_part->mimeType ); - $multi_main_type = $mineTypeMultipart[0]; - $multi_sec_type = $mineTypeMultipart[1]; - switch ( $multi_main_type ) { - case 'text': - $part_body = $main_part->body; - switch ( $multi_sec_type ) { - case 'html': - if ( ! isset( $parsed['content'] ) ) { - $decoded = $this->decodeBody( $part_body->data ); - $replaced = preg_replace( '#<script(.*?)>(.*?)</script>#is', '', $decoded ); - $replaced = preg_replace( '#<style(.*?)>(.*?)</style>#is', '', $replaced ); - $parsed['content'] = strip_tags( $replaced, '<p><a><br><div>' ); - } - break; - case 'plain': - if ( isset( $part_body->attachmentId ) ) { - $part_body = $main_part->body; - $ext = pathinfo( $main_part->filename, PATHINFO_EXTENSION ); - if ( ! in_array( $ext, array( 'php', 'exe', 'sh', 'js' ) ) ) { - array_push( $attachment, $this->get_attachment( $message_id, $part_body->attachmentId, $main_part->filename ) ); - } - } else { - $parsed['content'] = $this->decodeBody( $part_body->data ); - } - break; - default: - $part_body = $main_part->body; - $ext = pathinfo( $main_part->filename, PATHINFO_EXTENSION ); - if ( ! in_array( $ext, array( 'php', 'exe', 'sh', 'js' ) ) ) { - array_push( $attachment, $this->get_attachment( $message_id, $part_body->attachmentId, $main_part->filename ) ); - } - break; - } - break; - case 'multipart': - $this->recursive_parts_parser( $main_part->parts, $message_id, $attachment, $parsed ); - break; - case 'application': - case 'image': - $part_body = $main_part->body; - $ext = pathinfo( $main_part->filename, PATHINFO_EXTENSION ); - if ( ! in_array( $ext, array( 'php', 'exe', 'sh', 'js' ) ) ) { - array_push( $attachment, $this->get_attachment( $message_id, $part_body->attachmentId, $main_part->filename ) ); - } - break; - } - } - } else { - $mineTypeMultipart = explode( '/', $parts->mimeType ); - $multi_main_type = $mineTypeMultipart[0]; - $multi_sec_type = $mineTypeMultipart[1]; - switch ( $multi_main_type ) { - case 'text': - $part_body = $parts->body; - switch ( $multi_sec_type ) { - case 'html': - if ( ! isset( $parsed['content'] ) ) { - $decoded = $this->decodeBody( $part_body->data ); - $replaced = preg_replace( '#<script(.*?)>(.*?)</script>#is', '', $decoded ); - $replaced = preg_replace( '#<style(.*?)>(.*?)</style>#is', '', $replaced ); - $parsed['content'] = strip_tags( $replaced, '<p><a><br><div>' ); - } - break; - case 'plain': - if ( isset( $part_body->attachmentId ) ) { - $part_body = $parts->body; - $ext = pathinfo( $parts->filename, PATHINFO_EXTENSION ); - if ( ! in_array( $ext, array( 'php', 'exe', 'sh', 'js' ) ) ) { - array_push( $attachment, $this->get_attachment( $message_id, $part_body->attachmentId, $parts->filename ) ); - } - } else { - $parsed['content'] = $this->decodeBody( $part_body->data ); - } - break; - default: - $part_body = $parts->body; - $ext = pathinfo( $parts->filename, PATHINFO_EXTENSION ); - if ( ! in_array( $ext, array( 'php', 'exe', 'sh', 'js' ) ) ) { - array_push( $attachment, $this->get_attachment( $message_id, $part_body->attachmentId, $parts->filename ) ); - } - break; - } - break; - case 'multipart': - $this->recursive_parts_parser( $parts->parts, $message_id, $attachment, $parsed ); - break; - case 'application': - case 'image': - $part_body = $parts->body; - $ext = pathinfo( $parts->filename, PATHINFO_EXTENSION ); - if ( ! in_array( $ext, array( 'php', 'exe', 'sh', 'js' ) ) ) { - array_push( $attachment, $this->get_attachment( $message_id, $part_body->attachmentId, $parts->filename ) ); - } - break; - } - } - } - - public function parts_parser( $payload, $message_id ) { - $parsed = array(); - $attachment = array(); - $mineType = explode( '/', $payload->mimeType ); - $main_type = $mineType[0]; - $sec_type = $mineType[1]; - switch ( $main_type ) { - case 'text': - $part_body = $payload->body; - switch ( $sec_type ) { - case 'html': - if ( ! isset( $parsed['content'] ) ) { - $decoded = $this->decodeBody( $part_body->data ); - $replaced = preg_replace( '#<script(.*?)>(.*?)</script>#is', '', $decoded ); - $replaced = preg_replace( '#<style(.*?)>(.*?)</style>#is', '', $replaced ); - $parsed['content'] = strip_tags( $replaced, '<p><a><br><div>' ); - } - break; - case 'plain': - if ( isset( $part_body->attachmentId ) ) { - $part_body = $payload->body; - $ext = pathinfo( $payload->filename, PATHINFO_EXTENSION ); - if ( ! in_array( $ext, array( 'php', 'exe', 'sh', 'js' ) ) ) { - array_push( $attachment, $this->get_attachment( $message_id, $part_body->attachmentId, $payload->filename ) ); - } - } else { - $parsed['content'] = $this->decodeBody( $part_body->data ); - } - break; - default: - $part_body = $payload->body; - $ext = pathinfo( $payload->filename, PATHINFO_EXTENSION ); - if ( ! in_array( $ext, array( 'php', 'exe', 'sh', 'js' ) ) ) { - array_push( $attachment, $this->get_attachment( $message_id, $part_body->attachmentId, $payload->filename ) ); - } - break; - } - break; - case 'multipart': - $this->recursive_parts_parser( $payload->parts, $message_id, $attachment, $parsed ); - break; - case 'application': - case 'image': - $part_body = $payload->body; - $ext = pathinfo( $payload->filename, PATHINFO_EXTENSION ); - if ( ! in_array( $ext, array( 'php', 'exe', 'sh', 'js' ) ) ) { - array_push( $attachment, $this->get_attachment( $message_id, $part_body->attachmentId, $payload->filename ) ); - } - break; - } - if ( ! empty( $attachment ) ) { - $parsed['attachments'] = $attachment; - } - return $parsed; - } - - public function get_attachment( $message_id, $attachment_id, $filename ) { - $access_token = eh_crm_get_settingsmeta( 0, 'oauth_accesstoken' ); - $message_url = 'https://www.googleapis.com/gmail/v1/users/me/messages/' . $message_id; - $constant_url = '?v=2&oauth_token=' . $access_token; - $request_url = $message_url . '/attachments/' . $attachment_id . $constant_url; - $attdata = json_decode( file_get_contents( $request_url ) ); - $attachment = $this->decodeBody( $attdata->data ); - $upload = wp_upload_dir(); - $file = time() . '_' . $filename; - $file_name = $upload['path'] . '/' . $file; - $ifp = fopen( $file_name, 'w' ); - fwrite( $ifp, $attachment ); - fclose( $ifp ); - $data = array( - 'path' => $upload['path'] . '/' . $file, - 'url' => $upload['url'] . '/' . $file, - ); - return $data; - } - - public function decodeBody( $body ) { - $rawData = $body; - $sanitizedData = strtr( $rawData, '-_', '+/' ); - $decodedMessage = base64_decode( $sanitizedData ); - if ( ! $decodedMessage ) { - $decodedMessage = false; - } - return $decodedMessage; - } - - public function crawler_schedule_terminate() { - wp_clear_scheduled_hook( 'crm_email_crawler' ); - $trigger = eh_crm_get_settings( array( 'type' => 'trigger' ), array( 'slug', 'title', 'settings_id' ) ); - if ( false == $trigger ) { - $trigger = array(); - } - $selected_triggers = eh_crm_get_settingsmeta( 0, 'selected_triggers' ); - if ( empty( $selected_triggers ) ) { - $selected_triggers = array(); - } - for ( $i = 0;$i < count( $trigger );$i++ ) { - if ( in_array( $trigger[ $i ]['slug'], $selected_triggers ) ) { - $trigger_meta = eh_crm_get_settingsmeta( $trigger[ $i ]['settings_id'] ); - if ( isset( $trigger_meta['trigger_schedule'] ) && '' !== $trigger_meta['trigger_schedule'] ) { - wp_clear_scheduled_hook( $trigger[ $i ]['slug'] ); - } - } - } - } - -} +<?php++use WSDesk\Tickets\TicketArchiveRepository;+use Illuminate\Support\Arr;++if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++class EH_CRM_Cron_Setup {+ protected $triggers_schedule = array();+ public function __construct() {+ add_action( 'init', array( $this, 'crawler_schedule_init' ) );+ add_filter( 'cron_schedules', array( $this, 'crawler_schedule_time' ) );+ add_action( 'crm_email_crawler', array( $this, 'start_crm_email_crawler' ) );+ wp_schedule_single_event( time() + 1, 'start_scheduled_trigger_cron' );+ }++ public function get_unixtime( $type, $period ) {+ $val = 0;+ $min = 60;+ $hour = 3600;+ $day = 86400;+ $week = 604800;+ $month = 4.34524;+ $year = 52.1429;+ switch ( $type ) {+ case 'min':+ $val = $min;+ break;+ case 'hour':+ $val = $hour;+ break;+ case 'day':+ $val = $day;+ break;+ case 'week':+ $val = $week;+ break;+ case 'month':+ $val = $month * $week;+ break;+ case 'year':+ $val = $year * $week;+ break;+ default:+ break;+ }+ return ( $val * intval( $period ) );+ }++ public function crawler_schedule_time( $schedules ) {+ $schedules['crm_crawler_interval'] = array(+ 'interval' => 60,+ 'display' => 'Every 60 Seconds',+ );+ foreach ( $this->triggers_schedule as $key => $value ) {+ $schedules[ $key ] = array(+ 'interval' => $value,+ 'display' => 'Every ' . $value . ' Seconds',+ );+ }+ return $schedules;+ }+++ public function crawler_schedule_init() {+ if ( ! wp_next_scheduled( 'crm_email_crawler' ) ) {+ wp_schedule_event( time(), 'crm_crawler_interval', 'crm_email_crawler' );+ }+ foreach ( $this->triggers_schedule as $key => $value ) {+ if ( ! wp_next_scheduled( $key ) ) {+ wp_schedule_event( time(), $key, $key );+ }+ }+ }++ public function start_trigger_action_cron() {+ /* $trigger = current_action();+ $ticket_ids = eh_crm_get_trigger_tickets( $trigger ); */+ /*eh_crm_trigger_perform_action($trigger, $ticket_ids);+ for($i=0;$i<count($ticket_ids);$i++)+ {+ eh_crm_update_ticketmeta($ticket_ids[$i]['ticket_id'], "trigger_status", "triggered",FALSE);+ eh_crm_update_ticketmeta($ticket_ids[$i]['ticket_id'], "trigger_changes", "none",FALSE);+ }*/+ }++ public function start_trigger_schedule() {+ $scheduled_triggers_array = get_option( 'wsdesk_scheduled_triggers', array() );++ $triggered = array();++ foreach ( $scheduled_triggers_array as $key => $value ) {+ if ( 'no' !== $value['triggered'] ) {+ continue;+ }++ $trigger = eh_crm_get_settings(+ array(+ 'slug' => $value['trigger_slug'],+ 'type' => 'trigger',+ ),+ array( 'slug', 'settings_id', 'title' )+ );++ $trigger_meta = ! empty( eh_crm_get_settingsmeta( $trigger[0]['settings_id'] ) ) ? eh_crm_get_settingsmeta( $trigger[0]['settings_id'] ) : array();++ $is_matched = eh_crm_validate_trigger_ticket( $value['trigger_slug'], $value['ticket_id'] );++ if ( false === $is_matched ) {+ continue;+ }++ eh_crm_update_ticketmeta( $value['ticket_id'], 'trigger_status', 'updated', false );+ eh_crm_trigger_perform_action( $value['trigger_slug'], array( array( 'ticket_id' => $value['ticket_id'] ) ) );++ $scheduled_trigger = array(+ 'ticket_id' => $value['ticket_id'],+ 'trigger_slug' => $value['trigger_slug'],+ 'action_time' => $value['action_time'],+ 'triggered' => 'yes',+ );++ $scheduled_triggers_array[ $key ] = $scheduled_trigger;+ $triggered[] = $key;+ eh_crm_update_ticketmeta( $value['ticket_id'], 'trigger_status', 'triggered', false );+ }++ foreach ( $triggered as $key ) {+ unset( $scheduled_triggers_array[ $key ] );+ }++ update_option( 'wsdesk_scheduled_triggers', array_values( $scheduled_triggers_array ) );+ wp_clear_scheduled_hook( 'start_scheduled_trigger_cron' );+ wp_schedule_single_event( time() + 60, 'start_scheduled_trigger_cron' );+ }++ public function start_crm_email_crawler() {+ set_time_limit( 60 );+ if ( eh_crm_get_settingsmeta( 0, 'oauth_activation' ) == 'activated' ) {+ $oauth = new EH_CRM_OAuth();+ if ( $oauth->refresh_accesstoken() ) {+ $this->message_search();+ }+ }+ $imap_account_data = eh_crm_get_settingsmeta( '0', 'imap_account_data' );+ if ( ! empty( $imap_account_data ) ) {+ $this->email_imap();+ }+ }++ public function email_imap() {+ $support_reply_email = eh_crm_get_settingsmeta( '0', 'support_reply_email' );+ $upload = wp_upload_dir();+ $imap_account_id = 0;+ $imap_account_data = eh_crm_get_settingsmeta( '0', 'imap_account_data' );+ foreach ( $imap_account_data as $imap_account_data ) {++ $flags = [+ 'imap',+ 'ssl',+ 'novalidate-cert',+ ];++ if ( Arr::has( $imap_account_data, 'username' ) ) {+ $flags[] = 'user=' . Arr::get( $imap_account_data, 'username' );+ }++ $mailbox = new EH_CRM_PhpImap\EH_CRM_Mailbox(+ '{' . $imap_account_data['imap_server_url'] . ':' . $imap_account_data['imap_server_port'] . '/' . implode( '/', $flags ) . '}INBOX',
Vulnerability Existed: no No Security Vulnerability Identified - [None] - includes/class-crm-cron-setup.php [All lines] Explanation: The diff shows only a line-ending change (CRLF to LF conversion, indicated by the identical content with all 826 lines changed). This is a whitespace/formatting normalization with no functional code modifications. No security fixes, vulnerabilities, or security-relevant changes are present in this diff. The file structure, logic, and security characteristics remain identical between versions 3.3.4 and 3.3.5.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-email-oauth.php 2025-12-21 09:35:59.421065569 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-email-oauth.php 2025-12-21 09:36:35.227291036 +0000@@ -1,99 +1,99 @@-<?php - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -class EH_CRM_OAuth { - - protected $oauth; - - public function __construct() { - $this->oauth = array( - 'oauth_uri' => 'https://accounts.google.com/o/oauth2/auth', - 'client_id' => eh_crm_get_settingsmeta( 0, 'oauth_client_id' ), - 'client_secret' => eh_crm_get_settingsmeta( 0, 'oauth_client_secret' ), - 'redirect_uri' => admin_url( 'admin.php?page=wsdesk_email' ), - 'oauth_token_uri' => 'https://accounts.google.com/o/oauth2/token', - ); - } - - public function get_token_uri( $code, $type ) { - $url = $this->oauth['oauth_token_uri']; - $fields = array( - 'client_id' => $this->oauth['client_id'], - 'client_secret' => $this->oauth['client_secret'], - 'redirect_uri' => $this->oauth['redirect_uri'], - ); - switch ( $type ) { - case 'code': - $fields['code'] = $code; - $fields['grant_type'] = 'authorization_code'; - break; - case 'refresh': - $fields['refresh_token'] = $code; - $fields['grant_type'] = 'refresh_token'; - } - $args = array( - 'method' => 'POST', - 'timeout' => 45, - 'redirection' => 5, - 'httpversion' => '1.0', - 'blocking' => true, - 'headers' => array(), - 'body' => $fields, - 'cookies' => array(), - ); - $response = wp_safe_remote_post( $url, $args ); - $result = $response['response']; - if ( 200 == $result['code'] && 'OK' == $result['message'] ) { - $json_obj = json_decode( $response['body'] ); - switch ( $type ) { - case 'code': - eh_crm_update_settingsmeta( 0, 'oauth_accesstoken', $json_obj->access_token ); - eh_crm_update_settingsmeta( 0, 'oauth_refreshtoken', $json_obj->refresh_token ); - eh_crm_update_settingsmeta( 0, 'oauth_activation', 'activated' ); - eh_crm_update_settingsmeta( 0, 'oauth_last_requested', time() ); - break; - case 'refresh': - eh_crm_update_settingsmeta( 0, 'oauth_accesstoken', $json_obj->access_token ); - } - } - } - - public function revoke_token() { - $access_token = eh_crm_get_settingsmeta( 0, 'oauth_accesstoken' ); - $url = 'https://accounts.google.com/o/oauth2/revoke?token=' . $access_token; - wp_remote_get( $url ); - eh_crm_update_settingsmeta( 0, 'oauth_accesstoken', '' ); - eh_crm_update_settingsmeta( 0, 'oauth_refreshtoken', '' ); - eh_crm_update_settingsmeta( 0, 'oauth_activation', 'deactivated' ); - } - - - public function make_oauth_uri() { - $uri = $this->oauth['oauth_uri']; - $uri .= '?client_id=' . $this->oauth['client_id']; - $uri .= '&redirect_uri=' . $this->oauth['redirect_uri']; - $uri .= '&scope=https://mail.google.com/+https://www.googleapis.com/auth/gmail.readonly'; - $uri .= '&response_type=code'; - $uri .= '&access_type=offline'; - $uri .= '&approval_prompt=force'; - return $uri; - } - - public function refresh_accesstoken() { - $access_token = eh_crm_get_settingsmeta( 0, 'oauth_accesstoken' ); - $url = 'https://www.googleapis.com/oauth2/v1/tokeninfo/?access_token=' . $access_token; - $result = wp_remote_get( $url ); - if ( ! is_wp_error( $result ) ) { - $response = $result['response']; - $body = json_decode( $result['body'] ); - if ( 400 == $response['code'] && 'invalid_token' == $body->error ) { - $this->get_token_uri( eh_crm_get_settingsmeta( 0, 'oauth_refreshtoken' ), 'refresh' ); - } - } - return true; - } - -} +<?php++if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++class EH_CRM_OAuth {++ protected $oauth;++ public function __construct() {+ $this->oauth = array(+ 'oauth_uri' => 'https://accounts.google.com/o/oauth2/auth',+ 'client_id' => eh_crm_get_settingsmeta( 0, 'oauth_client_id' ),+ 'client_secret' => eh_crm_get_settingsmeta( 0, 'oauth_client_secret' ),+ 'redirect_uri' => admin_url( 'admin.php?page=wsdesk_email' ),+ 'oauth_token_uri' => 'https://accounts.google.com/o/oauth2/token',+ );+ }++ public function get_token_uri( $code, $type ) {+ $url = $this->oauth['oauth_token_uri'];+ $fields = array(+ 'client_id' => $this->oauth['client_id'],+ 'client_secret' => $this->oauth['client_secret'],+ 'redirect_uri' => $this->oauth['redirect_uri'],+ );+ switch ( $type ) {+ case 'code':+ $fields['code'] = $code;+ $fields['grant_type'] = 'authorization_code';+ break;+ case 'refresh':+ $fields['refresh_token'] = $code;+ $fields['grant_type'] = 'refresh_token';+ }+ $args = array(+ 'method' => 'POST',+ 'timeout' => 45,+ 'redirection' => 5,+ 'httpversion' => '1.0',+ 'blocking' => true,+ 'headers' => array(),+ 'body' => $fields,+ 'cookies' => array(),+ );+ $response = wp_safe_remote_post( $url, $args );+ $result = $response['response'];+ if ( 200 == $result['code'] && 'OK' == $result['message'] ) {+ $json_obj = json_decode( $response['body'] );+ switch ( $type ) {+ case 'code':+ eh_crm_update_settingsmeta( 0, 'oauth_accesstoken', $json_obj->access_token );+ eh_crm_update_settingsmeta( 0, 'oauth_refreshtoken', $json_obj->refresh_token );+ eh_crm_update_settingsmeta( 0, 'oauth_activation', 'activated' );+ eh_crm_update_settingsmeta( 0, 'oauth_last_requested', time() );+ break;+ case 'refresh':+ eh_crm_update_settingsmeta( 0, 'oauth_accesstoken', $json_obj->access_token );+ } + }+ }++ public function revoke_token() {+ $access_token = eh_crm_get_settingsmeta( 0, 'oauth_accesstoken' );+ $url = 'https://accounts.google.com/o/oauth2/revoke?token=' . $access_token;+ wp_remote_get( $url );+ eh_crm_update_settingsmeta( 0, 'oauth_accesstoken', '' );+ eh_crm_update_settingsmeta( 0, 'oauth_refreshtoken', '' );+ eh_crm_update_settingsmeta( 0, 'oauth_activation', 'deactivated' );+ }+++ public function make_oauth_uri() {+ $uri = $this->oauth['oauth_uri'];+ $uri .= '?client_id=' . $this->oauth['client_id'];+ $uri .= '&redirect_uri=' . $this->oauth['redirect_uri'];+ $uri .= '&scope=https://mail.google.com/+https://www.googleapis.com/auth/gmail.readonly';+ $uri .= '&response_type=code';+ $uri .= '&access_type=offline';+ $uri .= '&approval_prompt=force';+ return $uri;+ }++ public function refresh_accesstoken() {+ $access_token = eh_crm_get_settingsmeta( 0, 'oauth_accesstoken' );+ $url = 'https://www.googleapis.com/oauth2/v1/tokeninfo/?access_token=' . $access_token;+ $result = wp_remote_get( $url );+ if ( ! is_wp_error( $result ) ) {+ $response = $result['response'];+ $body = json_decode( $result['body'] );+ if ( 400 == $response['code'] && 'invalid_token' == $body->error ) {+ $this->get_token_uri( eh_crm_get_settingsmeta( 0, 'oauth_refreshtoken' ), 'refresh' );+ }+ }+ return true;+ }++}
Vulnerability Existed: no **Analysis Summary:** This diff contains only whitespace changes (line ending normalization from CRLF to LF). There are no functional code modifications, security fixes, or new vulnerabilities introduced. The code itself does contain pre-existing security concerns that are unrelated to this diff: 1. **URL parameter injection** (line 67, 90): Access tokens are directly concatenated into URLs without encoding 2. **Missing response validation** (line 50): No check for `is_wp_error()` before accessing response array 3. **Insufficient token validation** (line 95): Simple equality comparison for token validation However, since this diff makes no functional changes, there are **no security fixes present** in this version update.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-export.php 2025-12-21 09:35:59.421065569 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-export.php 2025-12-21 09:36:35.227291036 +0000@@ -1,55 +1,55 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -class EH_CRM_Export { - - public function export_data( $fileName, $assocDataArray ) { - ob_clean(); - $user = getenv( 'username' ); - $user = $user . '\Downloads'; - $path = '\Users\ ' . $user; - $path = str_replace( ' ', '', $path ); - $browser = php_uname(); - if ( stripos( PHP_OS, 'Darwin' ) === 0 ) { - $user = $user . '/Downloads'; - $path = '/Users/' . $user; - } elseif ( stripos( PHP_OS, 'Linux' ) === 0 ) { - $user = $user . '/Downloads'; - $path = '/home/' . $user; - } - $fields_custom = array(); - $fileName = time() . '.' . $fileName; - $file_name = $path . '/' . $fileName; - header( 'Content-Type: text/csv' ); - header( 'Content-Disposition: attachment;filename=' . $fileName ); - if ( isset( $assocDataArray['0'] ) ) { - ob_end_clean(); - $fp = fopen( $file_name, 'w' ); - $fields_present = array( 'Ticket Id', 'Requester Email', 'Subject', 'Ticket Content', 'Status', 'Ticket Created', 'Ticket Updated', 'Satisfaction Rating' ); - $avail_fields = eh_crm_get_settings( array( 'type' => 'field' ), array( 'slug', 'title' ) ); - $selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' ); - for ( $j = 3;$j < count( $selected_fields );$j++ ) { - for ( $i = 3;$i < count( $avail_fields );$i++ ) { - if ( $selected_fields[ $j ] == $avail_fields[ $i ]['slug'] ) { - array_push( $fields_custom, $avail_fields[ $i ]['title'] ); - } - } - } - if ( count( $fields_custom ) ) { - $fields_present = array_merge( $fields_present, $fields_custom ); - $fields_present = array( $fields_present ); - } else { - $fields_present = array( $fields_present ); - } - foreach ( $fields_present as $fields ) { - fputcsv( $fp, $fields ); - } - foreach ( $assocDataArray as $values ) { - fputcsv( $fp, $values ); - } - fclose( $fp ); - exit(); - } - } -} +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+class EH_CRM_Export {+ + public function export_data( $fileName, $assocDataArray ) {+ ob_clean();+ $user = getenv( 'username' );+ $user = $user . '\Downloads';+ $path = '\Users\ ' . $user;+ $path = str_replace( ' ', '', $path );+ $browser = php_uname();+ if ( stripos( PHP_OS, 'Darwin' ) === 0 ) {+ $user = $user . '/Downloads';+ $path = '/Users/' . $user;+ } elseif ( stripos( PHP_OS, 'Linux' ) === 0 ) {+ $user = $user . '/Downloads';+ $path = '/home/' . $user;+ }+ $fields_custom = array();+ $fileName = time() . '.' . $fileName;+ $file_name = $path . '/' . $fileName;+ header( 'Content-Type: text/csv' );+ header( 'Content-Disposition: attachment;filename=' . $fileName );+ if ( isset( $assocDataArray['0'] ) ) {+ ob_end_clean();+ $fp = fopen( $file_name, 'w' );+ $fields_present = array( 'Ticket Id', 'Requester Email', 'Subject', 'Ticket Content', 'Status', 'Ticket Created', 'Ticket Updated', 'Satisfaction Rating' );+ $avail_fields = eh_crm_get_settings( array( 'type' => 'field' ), array( 'slug', 'title' ) );+ $selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' );+ for ( $j = 3;$j < count( $selected_fields );$j++ ) {+ for ( $i = 3;$i < count( $avail_fields );$i++ ) {+ if ( $selected_fields[ $j ] == $avail_fields[ $i ]['slug'] ) {+ array_push( $fields_custom, $avail_fields[ $i ]['title'] );+ }+ }+ }+ if ( count( $fields_custom ) ) {+ $fields_present = array_merge( $fields_present, $fields_custom );+ $fields_present = array( $fields_present );+ } else {+ $fields_present = array( $fields_present );+ }+ foreach ( $fields_present as $fields ) {+ fputcsv( $fp, $fields );+ }+ foreach ( $assocDataArray as $values ) {+ fputcsv( $fp, $values );+ }+ fclose( $fp );+ exit();+ }+ }+}
Vulnerability Existed: no No Security Vulnerabilities Detected The diff provided shows only whitespace/line ending changes (converting between different line ending formats, likely from CRLF to LF or vice versa). The actual code content remains identical between versions 3.3.4 and 3.3.5. While the code itself contains several security concerns that existed in the original version (such as unsafe file path construction, unvalidated user input, potential path traversal vulnerabilities, and missing nonce verification for export operations), these are **pre-existing vulnerabilities that were not introduced or fixed in this diff**. Since this is a formatting-only change with no code modifications, no security fixes are present in this update.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-import-tickets.php 2025-12-21 09:35:59.421065569 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-import-tickets.php 2025-12-21 09:36:35.231291286 +0000@@ -1,277 +1,277 @@-<?php -class EH_CRM_Import_Tickets { - protected $user_id; - protected $plan; - public function zendesk_get_ticket( $page, $attachment, $plan ) { - $this->plan = $plan; - eh_crm_write_log( 'Start Fetching' ); - //include(EH_CRM_MAIN_VENDOR . 'zendesk/autoload.php'); - $subdomain = eh_crm_get_settingsmeta( 0, 'zendesk_subdomain' ); - $username = eh_crm_get_settingsmeta( 0, 'zendesk_username' ); - $token = eh_crm_get_settingsmeta( 0, 'zendesk_accesstoken' ); - $client = new Zendesk\API\HttpClient( $subdomain ); - $client->setAuth( - 'basic', - array( - 'username' => $username, - 'token' => $token, - ) - ); - $next_page = 0; - $total = 0; - try { - set_time_limit( 300 ); - $fields = $client->ticketFields()->findAll(); - eh_crm_write_log( 'Fields Fetching' ); - $fields_data = array(); - foreach ( $fields->ticket_fields as $field ) { - $fields_data[ $field->id ] = $field->title; - } - $tickets = $client->tickets()->findAll( array( 'page' => $page ) ); - eh_crm_write_log( 'Tickets Fetching' ); - if ( null != $tickets->next_page ) { - $next_page = $this->zendesk_parse_url( $tickets->next_page ); - } else { - $next_page = 0; - } - $total = $tickets->count; - $tt = 1; - foreach ( $tickets->tickets as $ticket ) { - if ( eh_crm_get_settingsmeta( 0, 'zendesk_tickets_import' ) === 'started' ) { - set_time_limit( 300 ); - $data = array(); - $id = $ticket->id; - $data['ticket_title'] = $ticket->subject; - $data['ticket_content'] = str_replace( "\n", '<br/>', str_replace( "\t", '', str_replace( "\r", '', $ticket->description ) ) ); - $data['ticket_parent'] = 0; - $data['ticket_category'] = 'raiser_reply'; - $date = strtotime( str_replace( 'Z', '', str_replace( 'T', ' ', $ticket->created_at ) ) ); - $data['ticket_date'] = gmdate( 'M d, Y h:i:s A', $date ); - $requester_id = $ticket->requester_id; - $data['ticket_email'] = $this->zendesk_user_email( $client, $requester_id ); - $data['ticket_author'] = $this->zendesk_user_id( $data['ticket_email'] ); - $tags = $ticket->tags; - foreach ( $tags as $key => $tag ) { - $tags[ $key ] = ucwords( str_replace( '_', ' ', $tag ) ); - } - $custom_fields = $ticket->custom_fields; - $custom = array(); - foreach ( $custom_fields as $custom_field ) { - array_push( $custom, $fields_data[ $custom_field->id ] . ' : ' . ucwords( str_replace( '_', ' ', $custom_field->value ) ) ); - } - $data['ticket_content'] .= '<br/><br/>Zendesk Fields:<br> Tags:' . ( ! empty( $tags ) ? implode( ',', $tags ) : 'No Tags' ); - $data['ticket_content'] .= '<br/>' . ( ! empty( $custom ) ? implode( '<br/>', $custom ) : '' ); - $data_meta = array(); - switch ( $ticket->status ) { - case 'closed': - case 'solved': - $data_meta['ticket_label'] = 'label_LL02'; - break; - case 'open': - $data_meta['ticket_label'] = 'label_LL01'; - break; - case 'pending': - $data_meta['ticket_label'] = 'label_LL03'; - break; - } - $req_args = array( 'type' => 'tag' ); - $fields = array( 'slug', 'title', 'settings_id' ); - $avail_tags = eh_crm_get_settings( $req_args, $fields ); - $tagged = array(); - if ( ! empty( $avail_tags ) ) { - for ( $i = 0, $j = 0; $i < count( $avail_tags ); $i++ ) { - if ( preg_match( '/' . strtolower( $avail_tags[ $i ]['title'] ) . '/', strtolower( $data['ticket_title'] ) ) || preg_match( '/' . strtolower( $avail_tags[ $i ]['title'] ) . '/', strtolower( $data['ticket_content'] ) ) ) { - $tagged[ $j ] = $avail_tags[ $i ]['slug']; - $j++; - } - } - } - $data_meta['ticket_tags'] = $tagged; - $default_assignee = eh_crm_get_settingsmeta( '0', 'default_assignee' ); - $assignee = array(); - switch ( $default_assignee ) { - case 'ticket_tags': - $users = get_users( array( 'role__in' => array( 'WSDesk_Agents', 'WSDesk_Supervisor' ) ) ); - $user_tags = array(); - for ( $i = 0; $i < count( $users ); $i++ ) { - $current = $users[ $i ]; - $id = $current->ID; - $user_tags[ $id ] = get_user_meta( $id, 'wsdesk_tags', true ); - } - foreach ( $user_tags as $key => $value ) { - for ( $i = 0;$i < count( $value );$i++ ) { - if ( in_array( $value[ $i ], $tagged ) ) { - array_push( $assignee, $key ); - break; - } - } - } - break; - case 'no_assignee': - break; - default: - array_push( $assignee, $default_assignee ); - break; - } - $data_meta['ticket_assignee'] = $assignee; - $data_meta['ticket_source'] = 'Zendesk'; - $gen_id = eh_crm_insert_ticket( $data, $data_meta, true ); - $tt++; - $comments_next = 1; - $cc = 0; - $upload = wp_upload_dir(); - do { - $comments = $this->zendesk_get_comments( $client, $comments_next, $id ); - if ( 0 == $cc ) { - if ( 'yes' == $attachment ) { - $attachments_data = array(); - $first = $comments->comments[0]; - $attach = $first->attachments; - foreach ( $attach as $att ) { - $response = wp_remote_get( $att->content_url, array( 'timeout' => 300 ) ); - $body = $response['body']; - $file = time() . '_' . $att->file_name; - $filepath = $upload['path'] . '/' . $file; - $fileurl = $upload['url'] . '/' . $file; - $fp = fopen( $filepath, 'w' ); - fwrite( $fp, $body ); - fclose( $fp ); - $temp_array = array( - 'path' => $filepath, - 'url' => $fileurl, - ); - array_push( $attachments_data, $temp_array ); - } - $attach_path = array(); - $attach_url = array(); - foreach ( $attachments_data as $attach ) { - array_push( $attach_url, $attach['url'] ); - array_push( $attach_path, $attach['path'] ); - } - if ( ! empty( $attach_path ) && ! empty( $attach_url ) ) { - eh_crm_update_settingsmeta( $gen_id, 'ticket_attachment', $attach_url ); - eh_crm_update_settingsmeta( $gen_id, 'ticket_attachment_path', $attach_path ); - } - } - unset( $comments->comments[0] ); - } - foreach ( $comments->comments as $comment ) { - $cc_data = array(); - $cc_data['ticket_title'] = $ticket->subject; - $cc_data['ticket_content'] = str_replace( "\n", '<br/>', str_replace( "\t", '', str_replace( "\r", '', $comment->plain_body ) ) ); - $cc_data['ticket_parent'] = $gen_id; - $cc_date = strtotime( str_replace( 'Z', '', str_replace( 'T', ' ', $comment->created_at ) ) ); - $cc_data['ticket_date'] = gmdate( 'M d, Y h:i:s A', $cc_date ); - $author_id = $comment->author_id; - if ( $requester_id == $author_id ) { - $cc_data['ticket_category'] = 'raiser_reply'; - } else { - $cc_data['ticket_category'] = 'agent_reply'; - } - $cc_data['ticket_email'] = $this->zendesk_user_email( $client, $author_id ); - $cc_data['ticket_author'] = $this->zendesk_user_id( $cc_data['ticket_email'] ); - $cc_meta = array(); - if ( 'yes' == $attachment ) { - $attachments_data = array(); - $attach = $comment->attachments; - foreach ( $attach as $att ) { - $response = wp_remote_get( $att->content_url, array( 'timeout' => 300 ) ); - $body = $response['body']; - $file = time() . '_' . $att->file_name; - $filepath = $upload['path'] . '/' . $file; - $fileurl = $upload['url'] . '/' . $file; - $fp = fopen( $filepath, 'w' ); - fwrite( $fp, $body ); - fclose( $fp ); - $temp_array = array( - 'path' => $filepath, - 'url' => $fileurl, - ); - array_push( $attachments_data, $temp_array ); - } - $attach_path = array(); - $attach_url = array(); - foreach ( $attachments_data as $attach ) { - array_push( $attach_url, $attach['url'] ); - array_push( $attach_path, $attach['path'] ); - } - $cc_meta['ticket_attachment'] = $attach_url; - $cc_meta['ticket_attachment_path'] = $attach_path; - } - eh_crm_insert_ticket( $cc_data, $cc_meta, true ); - } - if ( null != $comments->next_page ) { - $comments_next = $this->zendesk_parse_url( $comments->next_page ); - } else { - $comments_next = 0; - } - } while ( 0 != $comments_next ); - eh_crm_write_log( ( ( $next_page - 2 ) * 100 ) + $tt . ' Tickets Inserted' ); - } else { - return array( - 'status' => 'failure', - 'message' => 'User Aborted the Import', - ); - } - } - return array( - 'status' => 'success', - 'next' => $next_page, - 'total' => $total, - 'finished' => $tt, - ); - } catch ( \Zendesk\API\Exceptions\ApiResponseException $e ) { - return array( - 'status' => 'failure', - 'message' => $e->getMessage(), - ); - } - - } - - public function zendesk_get_comments( $client, $page, $ticket ) { - $comments = $client->tickets( $ticket )->comments()->findAll( array( 'page' => $page ) ); - eh_crm_write_log( 'Comments Fetching' ); - return $comments; - } - - public function zendesk_parse_url( $url ) { - $parts = parse_url( $url ); - parse_str( $parts['query'], $query ); - return $query['page']; - } - - public function zendesk_user_email( $client, $requester_id ) { - $email = ''; - if ( ! isset( $this->user_id[ $requester_id ] ) ) { - switch ( $this->plan ) { - case 'essential': - sleep( 20 ); - break; - case 'team': - sleep( 5 ); - break; - default: - break; - } - $requester = $client->users()->findMany( array( 'ids' => array( $requester_id ) ) ); - eh_crm_write_log( 'User EMail Fetching' ); - foreach ( $requester->users as $user ) { - $email = $user->email; - } - $this->user_id[ $requester_id ] = $email; - return $email; - } else { - return $this->user_id[ $requester_id ]; - } - } - - public function zendesk_user_id( $email ) { - $user = get_user_by( 'email', $email ); - if ( $user ) { - return $user->ID; - } else { - return 0; - } - } -} +<?php+class EH_CRM_Import_Tickets {+ protected $user_id;+ protected $plan;+ public function zendesk_get_ticket( $page, $attachment, $plan ) {+ $this->plan = $plan;+ eh_crm_write_log( 'Start Fetching' );+ //include(EH_CRM_MAIN_VENDOR . 'zendesk/autoload.php');+ $subdomain = eh_crm_get_settingsmeta( 0, 'zendesk_subdomain' );+ $username = eh_crm_get_settingsmeta( 0, 'zendesk_username' );+ $token = eh_crm_get_settingsmeta( 0, 'zendesk_accesstoken' );+ $client = new Zendesk\API\HttpClient( $subdomain );+ $client->setAuth(+ 'basic',+ array(+ 'username' => $username,+ 'token' => $token,+ ) + );+ $next_page = 0;+ $total = 0;+ try {+ set_time_limit( 300 );+ $fields = $client->ticketFields()->findAll();+ eh_crm_write_log( 'Fields Fetching' );+ $fields_data = array();+ foreach ( $fields->ticket_fields as $field ) {+ $fields_data[ $field->id ] = $field->title;+ }+ $tickets = $client->tickets()->findAll( array( 'page' => $page ) );+ eh_crm_write_log( 'Tickets Fetching' );+ if ( null != $tickets->next_page ) {+ $next_page = $this->zendesk_parse_url( $tickets->next_page );+ } else {+ $next_page = 0;+ }+ $total = $tickets->count;+ $tt = 1;+ foreach ( $tickets->tickets as $ticket ) {+ if ( eh_crm_get_settingsmeta( 0, 'zendesk_tickets_import' ) === 'started' ) {+ set_time_limit( 300 );+ $data = array();+ $id = $ticket->id;+ $data['ticket_title'] = $ticket->subject;+ $data['ticket_content'] = str_replace( "\n", '<br/>', str_replace( "\t", '', str_replace( "\r", '', $ticket->description ) ) );+ $data['ticket_parent'] = 0;+ $data['ticket_category'] = 'raiser_reply';+ $date = strtotime( str_replace( 'Z', '', str_replace( 'T', ' ', $ticket->created_at ) ) );+ $data['ticket_date'] = gmdate( 'M d, Y h:i:s A', $date );+ $requester_id = $ticket->requester_id;+ $data['ticket_email'] = $this->zendesk_user_email( $client, $requester_id );+ $data['ticket_author'] = $this->zendesk_user_id( $data['ticket_email'] );+ $tags = $ticket->tags;+ foreach ( $tags as $key => $tag ) {+ $tags[ $key ] = ucwords( str_replace( '_', ' ', $tag ) );+ }+ $custom_fields = $ticket->custom_fields;+ $custom = array();+ foreach ( $custom_fields as $custom_field ) {+ array_push( $custom, $fields_data[ $custom_field->id ] . ' : ' . ucwords( str_replace( '_', ' ', $custom_field->value ) ) );+ }+ $data['ticket_content'] .= '<br/><br/>Zendesk Fields:<br> Tags:' . ( ! empty( $tags ) ? implode( ',', $tags ) : 'No Tags' );+ $data['ticket_content'] .= '<br/>' . ( ! empty( $custom ) ? implode( '<br/>', $custom ) : '' );+ $data_meta = array();+ switch ( $ticket->status ) {+ case 'closed':+ case 'solved':+ $data_meta['ticket_label'] = 'label_LL02';+ break;+ case 'open':+ $data_meta['ticket_label'] = 'label_LL01';+ break;+ case 'pending':+ $data_meta['ticket_label'] = 'label_LL03';+ break;+ }+ $req_args = array( 'type' => 'tag' );+ $fields = array( 'slug', 'title', 'settings_id' );+ $avail_tags = eh_crm_get_settings( $req_args, $fields );+ $tagged = array();+ if ( ! empty( $avail_tags ) ) {+ for ( $i = 0, $j = 0; $i < count( $avail_tags ); $i++ ) {+ if ( preg_match( '/' . strtolower( $avail_tags[ $i ]['title'] ) . '/', strtolower( $data['ticket_title'] ) ) || preg_match( '/' . strtolower( $avail_tags[ $i ]['title'] ) . '/', strtolower( $data['ticket_content'] ) ) ) {+ $tagged[ $j ] = $avail_tags[ $i ]['slug'];+ $j++;+ }+ }+ }+ $data_meta['ticket_tags'] = $tagged;+ $default_assignee = eh_crm_get_settingsmeta( '0', 'default_assignee' );+ $assignee = array();+ switch ( $default_assignee ) {+ case 'ticket_tags':+ $users = get_users( array( 'role__in' => array( 'WSDesk_Agents', 'WSDesk_Supervisor' ) ) );+ $user_tags = array();+ for ( $i = 0; $i < count( $users ); $i++ ) {+ $current = $users[ $i ];+ $id = $current->ID;+ $user_tags[ $id ] = get_user_meta( $id, 'wsdesk_tags', true );+ }+ foreach ( $user_tags as $key => $value ) {+ for ( $i = 0;$i < count( $value );$i++ ) {+ if ( in_array( $value[ $i ], $tagged ) ) {+ array_push( $assignee, $key );+ break;+ }+ }+ }+ break;+ case 'no_assignee':+ break;+ default:+ array_push( $assignee, $default_assignee );+ break;+ }+ $data_meta['ticket_assignee'] = $assignee;+ $data_meta['ticket_source'] = 'Zendesk';+ $gen_id = eh_crm_insert_ticket( $data, $data_meta, true );+ $tt++;+ $comments_next = 1;+ $cc = 0;+ $upload = wp_upload_dir();+ do {+ $comments = $this->zendesk_get_comments( $client, $comments_next, $id );+ if ( 0 == $cc ) {+ if ( 'yes' == $attachment ) {+ $attachments_data = array();+ $first = $comments->comments[0];+ $attach = $first->attachments;+ foreach ( $attach as $att ) {+ $response = wp_remote_get( $att->content_url, array( 'timeout' => 300 ) );+ $body = $response['body'];+ $file = time() . '_' . $att->file_name;+ $filepath = $upload['path'] . '/' . $file;+ $fileurl = $upload['url'] . '/' . $file;+ $fp = fopen( $filepath, 'w' );+ fwrite( $fp, $body );+ fclose( $fp );+ $temp_array = array(+ 'path' => $filepath,+ 'url' => $fileurl,+ );+ array_push( $attachments_data, $temp_array );+ }+ $attach_path = array();+ $attach_url = array();+ foreach ( $attachments_data as $attach ) {+ array_push( $attach_url, $attach['url'] );+ array_push( $attach_path, $attach['path'] );+ }+ if ( ! empty( $attach_path ) && ! empty( $attach_url ) ) {+ eh_crm_update_settingsmeta( $gen_id, 'ticket_attachment', $attach_url );+ eh_crm_update_settingsmeta( $gen_id, 'ticket_attachment_path', $attach_path );+ }+ }+ unset( $comments->comments[0] );+ }+ foreach ( $comments->comments as $comment ) {+ $cc_data = array();+ $cc_data['ticket_title'] = $ticket->subject;+ $cc_data['ticket_content'] = str_replace( "\n", '<br/>', str_replace( "\t", '', str_replace( "\r", '', $comment->plain_body ) ) );+ $cc_data['ticket_parent'] = $gen_id;+ $cc_date = strtotime( str_replace( 'Z', '', str_replace( 'T', ' ', $comment->created_at ) ) );+ $cc_data['ticket_date'] = gmdate( 'M d, Y h:i:s A', $cc_date );+ $author_id = $comment->author_id;+ if ( $requester_id == $author_id ) {+ $cc_data['ticket_category'] = 'raiser_reply';+ } else {+ $cc_data['ticket_category'] = 'agent_reply';+ }+ $cc_data['ticket_email'] = $this->zendesk_user_email( $client, $author_id );+ $cc_data['ticket_author'] = $this->zendesk_user_id( $cc_data['ticket_email'] );+ $cc_meta = array();+ if ( 'yes' == $attachment ) {+ $attachments_data = array();+ $attach = $comment->attachments;+ foreach ( $attach as $att ) {+ $response = wp_remote_get( $att->content_url, array( 'timeout' => 300 ) );+ $body = $response['body'];+ $file = time() . '_' . $att->file_name;+ $filepath = $upload['path'] . '/' . $file;+ $fileurl = $upload['url'] . '/' . $file;+ $fp = fopen( $filepath, 'w' );+ fwrite( $fp, $body );+ fclose( $fp );+ $temp_array = array(+ 'path' => $filepath,+ 'url' => $fileurl,+ );+ array_push( $attachments_data, $temp_array );+ }+ $attach_path = array();+ $attach_url = array();+ foreach ( $attachments_data as $attach ) {+ array_push( $attach_url, $attach['url'] );+ array_push( $attach_path, $attach['path'] );+ }+ $cc_meta['ticket_attachment'] = $attach_url;+ $cc_meta['ticket_attachment_path'] = $attach_path;+ }+ eh_crm_insert_ticket( $cc_data, $cc_meta, true );+ }+ if ( null != $comments->next_page ) {+ $comments_next = $this->zendesk_parse_url( $comments->next_page );+ } else {+ $comments_next = 0;+ }+ } while ( 0 != $comments_next );+ eh_crm_write_log( ( ( $next_page - 2 ) * 100 ) + $tt . ' Tickets Inserted' );+ } else {+ return array(+ 'status' => 'failure', + 'message' => 'User Aborted the Import',+ );+ }+ }+ return array(+ 'status' => 'success', + 'next' => $next_page, + 'total' => $total, + 'finished' => $tt,+ );+ } catch ( \Zendesk\API\Exceptions\ApiResponseException $e ) {+ return array(+ 'status' => 'failure', + 'message' => $e->getMessage(),+ );+ }++ }++ public function zendesk_get_comments( $client, $page, $ticket ) {+ $comments = $client->tickets( $ticket )->comments()->findAll( array( 'page' => $page ) );+ eh_crm_write_log( 'Comments Fetching' );+ return $comments;+ }++ public function zendesk_parse_url( $url ) {+ $parts = parse_url( $url );+ parse_str( $parts['query'], $query );+ return $query['page'];+ }++ public function zendesk_user_email( $client, $requester_id ) {+ $email = '';+ if ( ! isset( $this->user_id[ $requester_id ] ) ) {+ switch ( $this->plan ) {+ case 'essential':+ sleep( 20 );+ break;+ case 'team':+ sleep( 5 );+ break;+ default:+ break;+ }+ $requester = $client->users()->findMany( array( 'ids' => array( $requester_id ) ) );+ eh_crm_write_log( 'User EMail Fetching' );+ foreach ( $requester->users as $user ) {+ $email = $user->email;+ }+ $this->user_id[ $requester_id ] = $email;+ return $email;+ } else {+ return $this->user_id[ $requester_id ];+ }+ }++ public function zendesk_user_id( $email ) {+ $user = get_user_by( 'email', $email );+ if ( $user ) {+ return $user->ID;+ } else {+ return 0;+ }+ }+}
Vulnerability Existed: no No Security Vulnerabilities Detected Explanation: This diff represents only a line-ending normalization change (converting from CRLF to LF or vice versa). The actual code content remains identical between versions 3.3.4 and 3.3.5. There are no functional code changes, no new security fixes applied, and no vulnerabilities addressed in this update. The file maintains all the same security characteristics as before, including: - No input validation improvements - No output encoding fixes - No authentication/authorization changes - No cryptographic improvements - No file handling security enhancements Since there are no substantive code modifications between the two versions, no security vulnerability analysis is applicable.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-init-handler.php 2025-12-21 09:35:59.421065569 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-init-handler.php 2025-12-21 09:36:35.231291286 +0000@@ -1,822 +1,822 @@-<?php - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -class EH_CRM_Init_Handler { - - private $settings; - - public function __construct() { - add_action( 'admin_menu', array( $this, 'eh_crm_menu_add' ), 1 ); - add_action( 'admin_init', array( $this, 'eh_register_styles_scripts' ), 10 ); - add_action( 'wp_ajax_eh_crm_search_post', array( 'CRM_Ajax', 'eh_crm_search_post' ) ); - add_action( 'wp_ajax_nopriv_eh_crm_search_post', array( 'CRM_Ajax', 'eh_crm_search_post' ) ); - add_action( 'wp_ajax_eh_crm_search_tags', array( 'CRM_Ajax', 'eh_crm_search_tags' ) ); - add_action( 'wp_ajax_eh_crm_ticket_general', array( 'CRM_Ajax', 'eh_crm_ticket_general' ) ); - add_action( 'wp_ajax_eh_crm_ticket_appearance', array( 'CRM_Ajax', 'eh_crm_ticket_appearance' ) ); - add_action( 'wp_ajax_eh_crm_settings_initiate_ticket', array( 'CRM_Ajax', 'eh_crm_settings_initiate_ticket' ) ); - add_action( 'wp_ajax_eh_crm_settings_empty_trash', array( 'CRM_Ajax', 'eh_crm_settings_empty_trash' ) ); - add_action( 'wp_ajax_eh_crm_settings_empty_scheduled_actions', array( 'CRM_Ajax', 'eh_crm_settings_empty_scheduled_actions' ) ); - add_action( 'wp_ajax_eh_crm_settings_restore_trash', array( 'CRM_Ajax', 'eh_crm_settings_restore_trash' ) ); - add_action( 'wp_ajax_eh_crm_refresh_tickets_count', array( 'CRM_Ajax', 'eh_crm_refresh_tickets_count' ) ); - add_action( 'wp_ajax_eh_crm_ticket_refresh_left_bar', array( 'CRM_Ajax', 'eh_crm_ticket_refresh_left_bar' ) ); - add_action( 'wp_ajax_eh_crm_ticket_refresh_right_bar', array( 'CRM_Ajax', 'eh_crm_ticket_refresh_right_bar' ) ); - add_action( 'wp_ajax_eh_crm_archive_single_ticket', array( 'CRM_Ajax', 'eh_crm_archive_single_ticket' ) ); - add_action( 'wp_ajax_eh_crm_woocommerce_settings', array( 'CRM_Ajax', 'eh_crm_woocommerce_settings' ) ); - add_action( 'wp_ajax_eh_crm_ticket_field', array( 'CRM_Ajax', 'eh_crm_ticket_field' ) ); - add_action( 'wp_ajax_eh_crm_ticket_field_delete', array( 'CRM_Ajax', 'eh_crm_ticket_field_delete' ) ); - add_action( 'wp_ajax_eh_crm_ticket_field_activate_deactivate', array( 'CRM_Ajax', 'eh_crm_ticket_field_activate_deactivate' ) ); - add_action( 'wp_ajax_eh_crm_ticket_field_edit', array( 'CRM_Ajax', 'eh_crm_ticket_field_edit' ) ); - add_action( 'wp_ajax_eh_crm_ticket_label', array( 'CRM_Ajax', 'eh_crm_ticket_label' ) ); - add_action( 'wp_ajax_eh_crm_ticket_label_delete', array( 'CRM_Ajax', 'eh_crm_ticket_label_delete' ) ); - add_action( 'wp_ajax_eh_crm_ticket_label_edit', array( 'CRM_Ajax', 'eh_crm_ticket_label_edit' ) ); - add_action( 'wp_ajax_eh_crm_ticket_tag', array( 'CRM_Ajax', 'eh_crm_ticket_tag' ) ); - add_action( 'wp_ajax_eh_crm_ticket_tag_delete', array( 'CRM_Ajax', 'eh_crm_ticket_tag_delete' ) ); - add_action( 'wp_ajax_eh_crm_ticket_tag_edit', array( 'CRM_Ajax', 'eh_crm_ticket_tag_edit' ) ); - add_action( 'wp_ajax_eh_crm_ticket_view', array( 'CRM_Ajax', 'eh_crm_ticket_view' ) ); - add_action( 'wp_ajax_eh_crm_ticket_view_edit', array( 'CRM_Ajax', 'eh_crm_ticket_view_edit' ) ); - add_action( 'wp_ajax_eh_crm_ticket_view_delete', array( 'CRM_Ajax', 'eh_crm_ticket_view_delete' ) ); - add_action( 'wp_ajax_eh_crm_ticket_view_activate_deactivate', array( 'CRM_Ajax', 'eh_crm_ticket_view_activate_deactivate' ) ); - add_action( 'wp_ajax_eh_crm_trigger', array( 'CRM_Ajax', 'eh_crm_trigger' ) ); - add_action( 'wp_ajax_eh_crm_ticket_trigger_delete', array( 'CRM_Ajax', 'eh_crm_ticket_trigger_delete' ) ); - add_action( 'wp_ajax_eh_crm_ticket_trigger_activate_deactivate', array( 'CRM_Ajax', 'eh_crm_ticket_trigger_activate_deactivate' ) ); - add_action( 'wp_ajax_eh_crm_trigger_edit', array( 'CRM_Ajax', 'eh_crm_trigger_edit' ) ); - add_action( 'wp_ajax_eh_crm_agent_add', array( 'CRM_Ajax', 'eh_crm_agent_add' ) ); - add_action( 'wp_ajax_eh_crm_agent_add_user', array( 'CRM_Ajax', 'eh_crm_agent_add_user' ) ); - add_action( 'wp_ajax_eh_crm_edit_agent_html', array( 'CRM_Ajax', 'eh_crm_edit_agent_html' ) ); - add_action( 'wp_ajax_eh_crm_edit_agent', array( 'CRM_Ajax', 'eh_crm_edit_agent' ) ); - add_action( 'wp_ajax_eh_crm_remove_agent', array( 'CRM_Ajax', 'eh_crm_remove_agent' ) ); - add_action( 'wp_ajax_eh_crm_new_ticket_post', array( 'CRM_Ajax', 'eh_crm_new_ticket_post' ) ); - add_action( 'wp_ajax_nopriv_eh_crm_new_ticket_post', array( 'CRM_Ajax', 'eh_crm_new_ticket_post' ) ); - add_action( 'wp_ajax_eh_crm_new_ticket_form', array( 'CRM_Ajax', 'eh_crm_new_ticket_form' ) ); - add_action( 'wp_ajax_nopriv_eh_crm_new_ticket_form', array( 'CRM_Ajax', 'eh_crm_new_ticket_form' ) ); - add_action( 'wp_ajax_eh_crm_ticket_single_view', array( 'CRM_Ajax', 'eh_crm_ticket_single_view' ) ); - add_action( 'wp_ajax_eh_crm_ticket_single_save_props', array( 'CRM_Ajax', 'eh_crm_ticket_single_save_props' ) ); - add_action( 'wp_ajax_eh_crm_ticket_single_delete', array( 'CRM_Ajax', 'eh_crm_ticket_single_delete' ) ); - add_action( 'wp_ajax_eh_crm_ticket_multiple_delete', array( 'CRM_Ajax', 'eh_crm_ticket_multiple_delete' ) ); - add_action( 'wp_ajax_eh_crm_ticket_reply_agent', array( 'CRM_Ajax', 'eh_crm_ticket_reply_agent' ) ); - add_action( 'wp_ajax_eh_crm_ticket_single_ticket_action', array( 'CRM_Ajax', 'eh_crm_ticket_single_ticket_action' ) ); - add_action( 'wp_ajax_eh_crm_ticket_multiple_ticket_action', array( 'CRM_Ajax', 'eh_crm_ticket_multiple_ticket_action' ) ); - add_action( 'wp_ajax_eh_crm_ticket_search', array( 'CRM_Ajax', 'eh_crm_ticket_search' ) ); - add_action( 'wp_ajax_eh_crm_ticket_add_new', array( 'CRM_Ajax', 'eh_crm_ticket_add_new' ) ); - add_action( 'wp_ajax_eh_crm_ticket_new_submit', array( 'CRM_Ajax', 'eh_crm_ticket_new_submit' ) ); - add_action( 'wp_ajax_eh_crm_check_ticket_request', array( 'CRM_Ajax', 'eh_crm_check_ticket_request' ) ); - add_action( 'wp_ajax_nopriv_eh_crm_check_ticket_request', array( 'CRM_Ajax', 'eh_crm_check_ticket_request' ) ); - add_action( 'wp_ajax_eh_crm_ticket_single_view_client', array( 'CRM_Ajax', 'eh_crm_ticket_single_view_client' ) ); - add_action( 'wp_ajax_eh_crm_ticket_reply_raiser', array( 'CRM_Ajax', 'eh_crm_ticket_reply_raiser' ) ); - add_action( 'wp_ajax_eh_crm_ticket_client_section_load', array( 'CRM_Ajax', 'eh_crm_ticket_client_section_load' ) ); - add_action( 'wp_ajax_eh_crm_activate_oauth', array( 'CRM_Ajax', 'eh_crm_activate_oauth' ) ); - add_action( 'wp_ajax_eh_crm_email_block_filter', array( 'CRM_Ajax', 'eh_crm_email_block_filter' ) ); - add_action( 'wp_ajax_eh_crm_subject_block_filter', array( 'CRM_Ajax', 'eh_crm_subject_block_filter' ) ); - add_action( 'wp_ajax_eh_crm_email_block_delete', array( 'CRM_Ajax', 'eh_crm_email_block_delete' ) ); - add_action( 'wp_ajax_eh_crm_subject_block_delete', array( 'CRM_Ajax', 'eh_crm_subject_block_delete' ) ); - add_action( 'wp_ajax_eh_crm_deactivate_oauth', array( 'CRM_Ajax', 'eh_crm_deactivate_oauth' ) ); - add_action( 'wp_ajax_eh_crm_activate_email_protocol', array( 'CRM_Ajax', 'eh_crm_activate_email_protocol' ) ); - add_action( 'wp_ajax_eh_crm_deactivate_email_protocol', array( 'CRM_Ajax', 'eh_crm_deactivate_email_protocol' ) ); - add_action( 'wp_ajax_eh_crm_email_support_save', array( 'CRM_Ajax', 'eh_crm_email_support_save' ) ); - add_action( 'wp_ajax_eh_crm_backup_data', array( 'CRM_Ajax', 'eh_crm_backup_data' ) ); - add_action( 'wp_ajax_eh_crm_restore_data', array( 'CRM_Ajax', 'eh_crm_restore_data' ) ); - add_action( 'wp_ajax_eh_crm_zendesk_pull_tickets', array( 'CRM_Ajax', 'eh_crm_zendesk_pull_tickets' ) ); - add_action( 'wp_ajax_eh_crm_zendesk_stop_pull_tickets', array( 'CRM_Ajax', 'eh_crm_zendesk_stop_pull_tickets' ) ); - add_action( 'wp_ajax_eh_crm_zendesk_save_data', array( 'CRM_Ajax', 'eh_crm_zendesk_save_data' ) ); - add_action( 'wp_ajax_eh_crm_live_log', array( 'CRM_Ajax', 'eh_crm_live_log' ) ); - add_action( 'wp_ajax_eh_crm_survey_ticket_form', array( 'CRM_Ajax', 'eh_crm_survey_ticket_form' ) ); - add_action( 'wp_ajax_nopriv_eh_crm_survey_ticket_form', array( 'CRM_Ajax', 'eh_crm_survey_ticket_form' ) ); - add_action( 'wp_ajax_eh_crm_woo_report_products', array( 'CRM_Ajax', 'eh_crm_woo_report_products' ) ); - add_action( 'wp_ajax_eh_crm_woo_report_category', array( 'CRM_Ajax', 'eh_crm_woo_report_category' ) ); - add_action( 'wp_ajax_eh_crm_ticket_new_template', array( 'CRM_Ajax', 'eh_crm_ticket_new_template' ) ); - add_action( 'wp_ajax_eh_crm_ticket_template_delete', array( 'CRM_Ajax', 'eh_crm_ticket_template_delete' ) ); - add_action( 'wp_ajax_eh_crm_ticket_template_search', array( 'CRM_Ajax', 'eh_crm_ticket_template_search' ) ); - add_action( 'wp_ajax_eh_crm_ticket_template_search_single', array( 'CRM_Ajax', 'eh_crm_ticket_template_search_single' ) ); - add_action( 'wp_ajax_eh_crm_ticket_update_template', array( 'CRM_Ajax', 'eh_crm_ticket_update_template' ) ); - add_action( 'wp_ajax_eh_crm_ticket_preview_template', array( 'CRM_Ajax', 'eh_crm_ticket_preview_template' ) ); - add_action( 'wp_ajax_eh_crm_ticket_multiple_template_send', array( 'CRM_Ajax', 'eh_crm_ticket_multiple_template_send' ) ); - add_action( 'wp_ajax_eh_crm_ticket_edit_template_content', array( 'CRM_Ajax', 'eh_crm_ticket_edit_template_content' ) ); - add_action( 'wp_ajax_eh_crm_get_settingsmeta_from_slug', array( 'CRM_Ajax', 'eh_crm_get_settingsmeta_from_slug' ) ); - // add_action( 'wp_ajax_wsdesk_api_create_ticket', array( 'CRM_Ajax', 'wsdesk_api_create_ticket' ) ); - // add_action( 'wp_ajax_nopriv_wsdesk_api_create_ticket', array( 'CRM_Ajax', 'wsdesk_api_create_ticket' ) ); - add_action( 'wp_ajax_eh_crm_ticket_single_ticket_assignee', array( 'CRM_Ajax', 'eh_crm_ticket_single_ticket_assignee' ) ); - add_action( 'wp_ajax_eh_crm_bulk_edit', array( 'CRM_Ajax', 'eh_crm_bulk_edit' ) ); - add_action( 'wp_ajax_eh_crm_bulk_edit_save', array( 'CRM_Ajax', 'eh_crm_bulk_edit_save' ) ); - add_action( 'wp_ajax_eh_crm_ticket_change_label', array( 'CRM_Ajax', 'eh_crm_ticket_change_label' ) ); - add_action( 'wp_ajax_eh_crm_verify_merge_tickets', array( 'CRM_Ajax', 'eh_crm_verify_merge_tickets' ) ); - add_action( 'wp_ajax_eh_crm_confirm_merge_tickets', array( 'CRM_Ajax', 'eh_crm_confirm_merge_tickets' ) ); - add_action( 'wp_ajax_eh_crm_ticket_close_check_request', array( 'CRM_Ajax', 'eh_crm_ticket_close_check_request' ) ); - add_action( 'wp_ajax_eh_crm_export_ticket_data', array( 'CRM_Ajax', 'eh_crm_export_ticket_data' ) ); - add_action( 'wp_ajax_eh_crm_arrange_ticket_columns', array( 'CRM_Ajax', 'eh_crm_arrange_ticket_columns' ) ); - add_action( 'wp_ajax_eh_crm_activate_deactivate_ticket_columns', array( 'CRM_Ajax', 'eh_crm_activate_deactivate_ticket_columns' ) ); - //Archived Tickets - add_action( 'wp_ajax_eh_crm_refresh_tickets_count_archive', array( 'CRM_Ajax_Archive', 'eh_crm_refresh_tickets_count_archive' ) ); - add_action( 'wp_ajax_eh_crm_ticket_single_view_archive', array( 'CRM_Ajax_Archive', 'eh_crm_ticket_single_view_archive' ) ); - add_action( 'wp_ajax_eh_crm_ticket_refresh_left_bar_archive', array( 'CRM_Ajax_Archive', 'eh_crm_ticket_refresh_left_bar_archive' ) ); - add_action( 'wp_ajax_eh_crm_ticket_refresh_right_bar_archive', array( 'CRM_Ajax_Archive', 'eh_crm_ticket_refresh_right_bar_archive' ) ); - add_action( 'wp_ajax_eh_crm_ticket_search_archive', array( 'CRM_Ajax_Archive', 'eh_crm_ticket_search_archive' ) ); - add_action( 'wp_ajax_eh_crm_archive_ticket_data', array( 'CRM_Ajax_Archive', 'eh_crm_archive_ticket_data' ) ); - add_action( 'wp_ajax_eh_crm_archive_ticket_data_restored', array( 'CRM_Ajax_Archive', 'eh_crm_archive_ticket_data_restored' ) ); - add_action( 'wp_ajax_eh_crm_ticket_multiple_unarchive', array( 'CRM_Ajax_Archive', 'eh_crm_ticket_multiple_unarchive' ) ); - $selectedfields = eh_crm_get_settingsmeta( '0', 'selected_fields' ); - - $args = []; - $args['api_key'] = array( - 'validate_callback' => function( $field, $request, $key ) { - $api_key = eh_crm_get_settingsmeta( '0', 'api_key' ); - if ( $field == $api_key ) { - return true; - } else { - return false; - } - }, - ); - if ( ! empty( $selectedfields ) ) { - foreach ( $selectedfields as $key => $field ) { - $fieldvalidation = []; - $avail_fields = eh_crm_get_settings( array( 'slug' => $field ), [ 'settings_id' ] ); - $field_type = eh_crm_get_settingsmeta( $avail_fields[0]['settings_id'], 'field_type' ); - if ( 'email' == $field_type ) { - $fieldvalidation['validate_callback'] = function( $field, $request, $key ) { - return filter_var( $field, FILTER_VALIDATE_EMAIL ); - }; - } elseif ( 'number' == $field_type ) { - $fieldvalidation['validate_callback'] = function( $field, $request, $key ) { - return filter_var( $field, FILTER_VALIDATE_INT ); - }; - } - $args[ $field ] = $fieldvalidation; - } - } - add_action( - 'rest_api_init', - function () use ( $args ) { - register_rest_route( - 'wsdesk/v1', - 'wsdesk_api_create_ticket', - array( - 'methods' => 'POST', - 'callback' => array( 'CRM_Ajax', 'wsdesk_api_create_ticket' ), - 'permission_callback' => '__return_true', - 'args' => $args, - ) - ); - } - ); - - if ( EH_CRM_WOO_STATUS ) { - add_action( 'wp_ajax_eh_crm_get_woo_order_id', array( 'CRM_Ajax', 'eh_crm_get_woo_order_id' ) ); - add_action( 'wp_ajax_eh_crm_woo_product_fetch', array( 'CRM_Ajax', 'eh_crm_woo_product_fetch' ) ); - add_action( 'wp_ajax_eh_crm_woo_category_fetch', array( 'CRM_Ajax', 'eh_crm_woo_category_fetch' ) ); - add_action( 'wp_ajax_eh_crm_woo_tags_fetch', array( 'CRM_Ajax', 'eh_crm_woo_tags_fetch' ) ); - add_action( 'wp_ajax_eh_crm_woo_vendors_fetch', array( 'CRM_Ajax', 'eh_crm_woo_vendors_fetch' ) ); - } - if ( EH_CRM_EDD_STATUS ) { - add_action( 'wp_ajax_eh_crm_get_edd_products', array( 'CRM_Ajax', 'eh_crm_get_edd_products' ) ); - } - $this->settings = new EH_CRM_Settings_Handler(); - - add_shortcode( 'wsdesk_support', array( $this, 'eh_crm_support_page' ) ); - add_shortcode( 'wsdesk_satisfaction', array( $this, 'eh_crm_satisfaction_page' ) ); - - add_action( 'wp_enqueue_scripts', array( $this, 'shortcode_scripts' ) ); - add_action( 'phpmailer_init', 'eh_crm_debug_error_log' ); - add_action( 'admin_footer', array( $this, 'deactivate_scripts' ) ); - add_action( 'wp_ajax_wsdesk_submit-uninstall-reason', array( 'CRM_Ajax', 'uninstall_reason_submission' ) ); - - $this->registerTicketsV2Api(); - - \WSDesk\Tickets\Reports::init(); - - $this->register_woocommerce_menu_items(); - - add_action( 'wp_logout', array( self::class, 'redirect_after_logout' ) ); - - } - - public static function redirect_after_logout() { - $logout_redirect_url = eh_crm_get_settingsmeta( 0, 'logout_redirect_url' ); - if ( ! empty( $logout_redirect_url ) ) { - wp_redirect( $logout_redirect_url ); - exit(); - } - } - - public function register_woocommerce_menu_items() { - add_filter( - 'woocommerce_account_menu_items', - function ( $menu_links ) { - $menu_links = array_slice( $menu_links, 0, 3, true ) - + array( - 'wsdesk_my_tickets' => __( get_existing_tickets_table_label(), 'wsdesk' ), - 'wsdesk_support' => __( get_new_ticket_form_title() , 'wsdesk' ), - ) - + array_slice( $menu_links, 3, null, true ); - return $menu_links; - - - } - ); - - add_rewrite_endpoint( 'wsdesk_my_tickets', EP_PAGES ); - add_rewrite_endpoint( 'wsdesk_support', EP_PAGES ); - - add_action( - 'woocommerce_account_wsdesk_my_tickets_endpoint', - function () { - $this->load_wsdesk_support_assets(); - echo do_shortcode( '[wsdesk_support display=check_request]' ); - } - ); - - add_action( - 'woocommerce_account_wsdesk_support_endpoint', - function () { - $this->load_wsdesk_support_assets(); - echo do_shortcode( '[wsdesk_support display=form]' ); - } - ); - } - - public function load_wsdesk_support_assets() { - wp_enqueue_script( 'jquery' ); - $handle = 'bootstrap.min.js'; - $handle1 = 'bootstrap.js'; - $handle2 = 'bootstrap.css'; - $list = 'enqueued'; - if ( ! wp_script_is( $handle, $list ) && ! wp_script_is( $handle1, $list ) && ! defined( 'WSDESK_UNLOAD_BOOT_JS' ) ) { - wp_enqueue_script( 'wsdesk_bootstrap', EH_CRM_MAIN_JS . 'bootstrap.js', '', EH_CRM_VERSION ); - } - if ( ! wp_style_is( $handle2, $list ) && ! defined( 'WSDESK_UNLOAD_BOOT_CSS' ) ) { - wp_enqueue_style( 'wsdesk_bootstrap', EH_CRM_MAIN_CSS . 'bootstrap.css', '', EH_CRM_VERSION ); - } - wp_enqueue_script( 'support_scripts', EH_CRM_MAIN_JS . 'crm_support.js', '', EH_CRM_VERSION ); - wp_enqueue_style( 'slider', EH_CRM_MAIN_CSS . 'slider.css', '', EH_CRM_VERSION ); - wp_enqueue_style( 'support_styles', EH_CRM_MAIN_CSS . 'crm_support.css', '', EH_CRM_VERSION ); - wp_enqueue_style( 'new_styles', EH_CRM_MAIN_CSS . 'new-style.css', '', EH_CRM_VERSION ); - wp_enqueue_script( 'jquery-ui-datepicker' ); - wp_enqueue_style( 'jquery-ui' , EH_CRM_MAIN_CSS . 'jquery-ui.css', '', EH_CRM_VERSION ); - $selected = eh_crm_get_settingsmeta( 0, 'selected_fields' ); - if ( empty( $selected ) ) { - $selected = array(); - } - if ( in_array( 'google_captcha', $selected ) ) { - wp_enqueue_script( 'captcha_scripts', 'https://www.google.com/recaptcha/api.js', '', EH_CRM_VERSION ); - } - wp_localize_script( - 'support_scripts', - 'support_object', - array( - 'ajax_url' => admin_url( 'admin-ajax.php' ), - 'nonce' => wp_create_nonce( 'wsdesk_nonce' ), - ) - ); - - } - - public function registerTicketsV2Api() { - // Add ajax action api endpoints - add_action( 'wp_ajax_eh_crm_v2_tickets', array( 'CRM_Ajax', 'eh_crm_v2_get_tickets' ) ); - add_action( 'wp_ajax_eh_crm_v2_tickets_count', array( 'CRM_Ajax', 'eh_crm_v2_get_tickets_count' ) ); - - add_action( 'wp_ajax_eh_crm_v2_archive_tickets', array( 'CRM_Ajax', 'eh_crm_v2_get_archive_tickets' ) ); - - // Add Shortcuts - add_shortcode( 'wsdesk_table_loader', array( $this, 'eh_crm_table_loader' ) ); - } - - public function eh_crm_table_loader() { - return '<span class="spinner_loader table_loader"> - <span class="bounce1"></span> - <span class="bounce2"></span> - <span class="bounce3"></span> - </span>'; - } - - public function eh_crm_menu_add() { - $id = get_current_user_id(); - $user = new WP_User( $id ); - $auth = false; - $user_role = $user->roles; - $user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ); - foreach ( $user_role as $value ) { - if ( in_array( $value, $user_roles_default ) ) { - $auth = true; - } - } - if ( $auth ) { - if ( in_array( 'administrator', $user_role ) ) { - $cap = 'administrator'; - } else { - $cap = 'crm_role'; - } - $ticket_repo_obj = new \WSDesk\Tickets\TicketRepository(); - $default = eh_crm_get_settingsmeta( 0, 'default_label' ); - $label = eh_crm_get_settings( array( 'slug' => $default ), array( 'settings_id' ) ); - $label_color = eh_crm_get_settingsmeta( $label[0]['settings_id'], 'label_color' ); - $ticket_count = $ticket_repo_obj->count( array( 'view' => array( 'labels' => $default ) ) ); - - add_menu_page( __( 'Tickets', 'wsdesk' ), "WSDesk <span class='update-plugins' style='background-color:" . $label_color . " !important;'><span class='plugin-count' id='wsdesk_tickets_count'>" . $ticket_count . '</span></span>', $cap, 'wsdesk_tickets', array( $this->settings, 'eh_crm_tickets_main_menu_callback' ), 'dashicons-tickets', 25 ); - add_submenu_page( 'wsdesk_tickets', __( 'Tickets', 'wsdesk' ), __( 'Tickets', 'wsdesk' ), $cap, 'wsdesk_tickets', array( $this->settings, 'eh_crm_tickets_main_menu_callback' ) ); - if ( $user->has_cap( 'settings_page' ) || in_array( 'administrator', $user_role ) ) { - add_submenu_page( 'wsdesk_tickets', __( 'Settings', 'wsdesk' ), __( 'Settings', 'wsdesk' ), $cap, 'wsdesk_settings', array( $this->settings, 'eh_crm_settings_sub_menu_callback' ) ); - } - if ( $user->has_cap( 'agents_page' ) || in_array( 'administrator', $user_role ) ) { - add_submenu_page( 'wsdesk_tickets', __( 'Agents', 'wsdesk' ), __( 'Agents', 'wsdesk' ), $cap, 'wsdesk_agents', array( $this->settings, 'eh_crm_agents_sub_menu_callback' ) ); - } - add_submenu_page( 'wsdesk_tickets', __( 'Reports', 'wsdesk' ), __( 'Reports', 'wsdesk' ), $cap, 'wsdesk_reports', array( $this->settings, 'eh_crm_reports_sub_menu_callback' ) ); - if ( $user->has_cap( 'email_page' ) || in_array( 'administrator', $user_role ) ) { - add_submenu_page( 'wsdesk_tickets', __( 'E-Mail', 'wsdesk' ), __( 'E-Mail', 'wsdesk' ), $cap, 'wsdesk_email', array( $this->settings, 'eh_crm_email_sub_menu_callback' ) ); - } - if ( wsdesk_is_premium() ) { - if ( $user->has_cap( 'import_page' ) || in_array( 'administrator', $user_role ) ) { - add_submenu_page( 'wsdesk_tickets', __( 'Import', 'wsdesk' ), __( 'Import', 'wsdesk' ), $cap, 'wsdesk_import', array( $this->settings, 'eh_crm_import_sub_menu_callback' ) ); - } - add_submenu_page( 'wsdesk_tickets', __( 'Archived Tickets', 'wsdesk' ), __( 'Archived Tickets', 'wsdesk' ), $cap, 'wsdesk_archive', array( $this->settings, 'eh_crm_archive_sub_menu_callback' ) ); - } else { - add_submenu_page( 'wsdesk_tickets', __( 'Go Premium!', 'wsdesk' ), __( 'Go Premium!', 'wsdesk' ), $cap, 'wsdesk_premium', array( $this->settings, 'eh_crm_premium_sub_menu_callback' ) ); - } - } - } - - - public function eh_register_styles_scripts() { - $page = ( isset( $_GET['page'] ) ? sanitize_text_field( $_GET['page'] ) : '' ); - $include_page = array( 'wsdesk_tickets', 'wsdesk_settings', 'wsdesk_agents', 'wsdesk_email', 'wsdesk_reports', 'wsdesk_import', 'wsdesk_archive' ); - if ( in_array( $page, $include_page ) ) { - wp_dequeue_script( 'jquery-ui-tooltip' ); - if ( 'wsdesk_settings' === $page ) { - wp_enqueue_script( 'crm_settings', EH_CRM_MAIN_JS . 'crm_settings.js', array(), EH_CRM_VERSION ); - $js_var = eh_crm_js_translation_obj( 'settings', array(), EH_CRM_VERSION ); - wp_localize_script( 'crm_settings', 'js_obj', $js_var ); - wp_enqueue_style( 'crm_settings', EH_CRM_MAIN_CSS . 'crm_settings.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'dragDrop', EH_CRM_MAIN_JS . 'DragDrop.js', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'select2', EH_CRM_MAIN_CSS . 'select2.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'select2', EH_CRM_MAIN_JS . 'select2.js', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'jquery-ui-datepicker' ); - wp_enqueue_style( 'jquery-ui' , EH_CRM_MAIN_CSS . 'jquery-ui.css', array(), EH_CRM_VERSION ); - } - wp_enqueue_script( 'wsdesk_bootstrap', EH_CRM_MAIN_JS . 'bootstrap.js', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'wsdesk_bootstrap', EH_CRM_MAIN_CSS . 'bootstrap.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'dialog', EH_CRM_MAIN_JS . 'dialog.js', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'dialog', EH_CRM_MAIN_CSS . 'dialog.css', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'boot', EH_CRM_MAIN_CSS . 'boot.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'jquery' ); - wp_enqueue_style( 'quill', EH_CRM_MAIN_CSS . 'quill.snow.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'quill', EH_CRM_MAIN_JS . 'quill.min.js', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'quill-magic-url', 'https://unpkg.com/[email protected]/dist/index.js', array(), EH_CRM_VERSION ); - if ( 'wsdesk_tickets' === $page ) { - wp_enqueue_script( 'cookie', EH_CRM_MAIN_JS . 'wsdesk-cookie.js', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'quill', EH_CRM_MAIN_JS . 'quill.min.js', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'quill-magic-url', 'https://unpkg.com/[email protected]/dist/index.js', array( 'quill' ), EH_CRM_VERSION ); - wp_localize_script( - 'quill', - 'wsdesk_data', - array( - 'url' => EH_CRM_MAIN_URL, - 'ticket_admin_url' => admin_url( 'admin.php?page=wsdesk_tickets' ), - ) - ); - wp_enqueue_style( 'quill', EH_CRM_MAIN_CSS . 'quill.snow.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'crm_tickets', EH_CRM_MAIN_JS . 'crm_tickets.js', array(), EH_CRM_VERSION ); - $js_var = eh_crm_js_translation_obj( 'tickets' ); - wp_localize_script( 'crm_tickets', 'js_obj', $js_var ); - wp_enqueue_style( 'crm_tickets', EH_CRM_MAIN_CSS . 'crm_tickets.css', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'select2', EH_CRM_MAIN_CSS . 'select2.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'select2', EH_CRM_MAIN_JS . 'select2.js', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'slider', EH_CRM_MAIN_CSS . 'slider.css', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'new-admin-style', EH_CRM_MAIN_CSS . 'new-admin-styles.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'jquery-ui-datepicker' ); - wp_enqueue_style( 'jquery-ui' , EH_CRM_MAIN_CSS . 'jquery-ui.css', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'app_css', EH_CRM_MAIN_CSS . 'app.css' , array(), EH_CRM_VERSION ); - wp_enqueue_script( 'app_scripts', EH_CRM_MAIN_JS . 'app.js', array(), EH_CRM_VERSION, true ); - } - if ( 'wsdesk_agents' === $page ) { - wp_enqueue_script( 'crm_agents', EH_CRM_MAIN_JS . 'crm_agents.js', array(), EH_CRM_VERSION ); - $js_var = eh_crm_js_translation_obj( 'agents' ); - wp_localize_script( 'crm_agents', 'js_obj', $js_var ); - wp_enqueue_style( 'crm_agents', EH_CRM_MAIN_CSS . 'crm_agents.css', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'select2', EH_CRM_MAIN_CSS . 'select2.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'select2', EH_CRM_MAIN_JS . 'select2.js', array(), EH_CRM_VERSION ); - } - if ( 'wsdesk_email' === $page ) { - wp_enqueue_style( 'select2', EH_CRM_MAIN_CSS . 'select2.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'select2', EH_CRM_MAIN_JS . 'select2.js', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'crm_email', EH_CRM_MAIN_JS . 'crm_email.js', array(), EH_CRM_VERSION ); - $js_var = eh_crm_js_translation_obj( 'email' ); - wp_localize_script( 'crm_email', 'js_obj', $js_var ); - wp_enqueue_style( 'crm_email', EH_CRM_MAIN_CSS . 'crm_email.css', array(), EH_CRM_VERSION ); - } - if ( 'wsdesk_reports' === $page ) { - wp_enqueue_script( 'jquery-ui-datepicker' ); - wp_enqueue_style( 'jquery-ui', 'https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css', array(), EH_CRM_VERSION ); - //wp_enqueue_style( 'jquery-ui' ); - wp_enqueue_style( 'select2', EH_CRM_MAIN_CSS . 'select2.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'select2', EH_CRM_MAIN_JS . 'select2.js', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'raphael', EH_CRM_MAIN_JS . 'raphael.js', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'morris', EH_CRM_MAIN_JS . 'morris.js', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'crm_reports', EH_CRM_MAIN_JS . 'crm_reports.js', array(), EH_CRM_VERSION ); - $js_var = eh_crm_js_translation_obj( 'reports' ); - wp_localize_script( 'crm_reports', 'js_obj', $js_var ); - wp_enqueue_style( 'crm_reports', EH_CRM_MAIN_CSS . 'crm_reports.css', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'app_css', EH_CRM_MAIN_CSS . 'app.css' , array(), EH_CRM_VERSION ); - wp_enqueue_script( 'app_scripts', EH_CRM_MAIN_JS . 'app.js', array(), EH_CRM_VERSION ); - } - if ( 'wsdesk_import' === $page ) { - wp_enqueue_script( 'jquery-ui-sortable' ); - wp_enqueue_style( 'select2', EH_CRM_MAIN_CSS . 'select2.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'select2', EH_CRM_MAIN_JS . 'select2.js' , array(), EH_CRM_VERSION, false ); - wp_enqueue_script( 'crm_import', EH_CRM_MAIN_JS . 'crm_import.js' , array(), EH_CRM_VERSION, false ); - $js_var = eh_crm_js_translation_obj( 'import' ); - wp_localize_script( 'crm_import', 'js_obj', $js_var ); - wp_enqueue_style( 'crm_import', EH_CRM_MAIN_CSS . 'crm_import.css' , array(), EH_CRM_VERSION ); - } - if ( 'wsdesk_archive' === $page ) { - wp_enqueue_script( 'cookie', EH_CRM_MAIN_JS . 'wsdesk-cookie.js' , array(), EH_CRM_VERSION, false ); - wp_enqueue_script( 'quill', EH_CRM_MAIN_JS . 'quill.min.js' , array(), EH_CRM_VERSION, false ); - wp_localize_script( - 'quill', - 'wsdesk_data', - array( - 'url' => EH_CRM_MAIN_URL, - 'ticket_admin_url' => admin_url( 'admin.php?page=wsdesk_archive' ), - ) - ); - wp_enqueue_style( 'quill', EH_CRM_MAIN_CSS . 'quill.snow.css' , array(), EH_CRM_VERSION ); - wp_enqueue_script( 'crm_tickets', EH_CRM_MAIN_JS . 'crm_archive_tickets.js' , array(), EH_CRM_VERSION , false ); - $js_var = eh_crm_js_translation_obj( 'tickets' ); - wp_localize_script( 'crm_tickets', 'js_obj', $js_var ); - wp_enqueue_style( 'crm_tickets', EH_CRM_MAIN_CSS . 'crm_tickets.css' , array(), EH_CRM_VERSION ); - wp_enqueue_style( 'select2', EH_CRM_MAIN_CSS . 'select2.css' , array(), EH_CRM_VERSION ); - wp_enqueue_script( 'select2', EH_CRM_MAIN_JS . 'select2.js' , array(), EH_CRM_VERSION , false ); - wp_enqueue_style( 'slider', EH_CRM_MAIN_CSS . 'slider.css' , array(), EH_CRM_VERSION ); - wp_enqueue_style( 'new-admin-style', EH_CRM_MAIN_CSS . 'new-admin-styles.css' , array(), EH_CRM_VERSION ); - wp_enqueue_script( 'jquery-ui-datepicker' ); - wp_enqueue_style( 'jquery-ui' , EH_CRM_MAIN_CSS . 'jquery-ui.css', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'app_css', EH_CRM_MAIN_CSS . 'app.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'app_scripts', EH_CRM_MAIN_JS . 'app.js', array( 'jquery' ), EH_CRM_VERSION, true ); - } - } - } - - public function eh_crm_support_page( $atts ) { - $display = ''; - if ( isset( $atts['display'] ) ) { - $display = $atts['display']; - $cus_fields = ( isset( $atts['fields'] ) ? ( explode( ',', $atts['fields'] ) ) : array() ); - switch ( $display ) { - case 'form': - case 'form_only': - return include EH_CRM_MAIN_VIEWS . 'shortcodes/crm_support_new.php'; - case 'check_request': - case 'form_support_request_table': - return include EH_CRM_MAIN_VIEWS . 'shortcodes/crm_support_form_Support_Request_table.php'; - case 'form_and_check_request': - return include EH_CRM_MAIN_VIEWS . 'shortcodes/crm_support_new_and_check_request.php'; - default: - return include EH_CRM_MAIN_VIEWS . 'shortcodes/crm_support_page.php'; - } - } else { - return include EH_CRM_MAIN_VIEWS . 'shortcodes/crm_support_page.php'; - } - } - public function eh_crm_satisfaction_page() { - if ( isset( $_GET['id'] ) && isset( $_GET['wsdesk_author'] ) ) { - return include EH_CRM_MAIN_VIEWS . 'shortcodes/crm_satisfaction_page.php'; - } else { - return '<center><div class="satisfaction-div wsdesk_wrapper"><h1>Oops!</h1><h4>' . __( 'Access Denied!', 'wsdesk' ) . '</h4></div></center>'; - } - } - - public function shortcode_scripts() { - global $post; - if ( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'wsdesk_support' ) || ( isset( $post->post_content ) && strpos( $post->post_content, '.support_form' ) ) ) { - wp_enqueue_script( 'jquery' ); - $handle = 'bootstrap.min.js'; - $handle1 = 'bootstrap.js'; - $handle2 = 'bootstrap.css'; - $list = 'enqueued'; - if ( ! wp_script_is( $handle, $list ) && ! wp_script_is( $handle1, $list ) && ! defined( 'WSDESK_UNLOAD_BOOT_JS' ) ) { - wp_enqueue_script( 'wsdesk_bootstrap', EH_CRM_MAIN_JS . 'bootstrap.js', array(), EH_CRM_VERSION ); - } - if ( ! wp_style_is( $handle2, $list ) && ! defined( 'WSDESK_UNLOAD_BOOT_CSS' ) ) { - wp_enqueue_style( 'wsdesk_bootstrap', EH_CRM_MAIN_CSS . 'bootstrap.css', array(), EH_CRM_VERSION ); - } - wp_enqueue_script( 'support_scripts', EH_CRM_MAIN_JS . 'crm_support.js', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'slider', EH_CRM_MAIN_CSS . 'slider.css', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'support_styles', EH_CRM_MAIN_CSS . 'crm_support.css', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'new_styles', EH_CRM_MAIN_CSS . 'new-style.css', array(), EH_CRM_VERSION ); - wp_enqueue_script( 'jquery-ui-datepicker' ); - wp_enqueue_style( 'jquery-ui' , EH_CRM_MAIN_CSS . 'jquery-ui.css', array(), EH_CRM_VERSION ); - $selected = eh_crm_get_settingsmeta( 0, 'selected_fields' ); - if ( empty( $selected ) ) { - $selected = array(); - } - if ( in_array( 'google_captcha', $selected ) ) { - wp_enqueue_script( 'captcha_scripts', 'https://www.google.com/recaptcha/api.js', array(), EH_CRM_VERSION ); - } - wp_localize_script( - 'support_scripts', - 'support_object', - array( - 'ajax_url' => admin_url( 'admin-ajax.php' ), - 'nonce' => wp_create_nonce( 'wsdesk_nonce' ), - ) - ); - } - if ( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'wsdesk_satisfaction' ) ) { - wp_enqueue_script( 'jquery' ); - $handle = 'bootstrap.min.js'; - $handle1 = 'bootstrap.js'; - $handle2 = 'bootstrap.css'; - $list = 'enqueued'; - if ( ! wp_script_is( $handle, $list ) && ! wp_script_is( $handle1, $list ) ) { - wp_enqueue_script( 'wsdesk_bootstrap', EH_CRM_MAIN_JS . 'bootstrap.js', array(), EH_CRM_VERSION ); - } - if ( ! wp_style_is( $handle2, $list ) ) { - wp_enqueue_style( 'wsdesk_bootstrap', EH_CRM_MAIN_CSS . 'bootstrap.css', array(), EH_CRM_VERSION ); - } - wp_enqueue_script( 'satisfaction_scripts', EH_CRM_MAIN_JS . 'crm_satisfaction.js', array(), EH_CRM_VERSION ); - wp_enqueue_style( 'satisfaction_styles', EH_CRM_MAIN_CSS . 'crm_satisfaction.css', array(), EH_CRM_VERSION ); - wp_localize_script( - 'satisfaction_scripts', - 'satisfaction_object', - array( - 'ajax_url' => admin_url( 'admin-ajax.php' ), - 'nonce' => wp_create_nonce( 'wsdesk_nonce' ), - ) - ); - } - } - - private function get_uninstall_reasons() { - $reasons = array( - array( - 'id' => 'could-not-understand', - 'text' => __( 'I couldn\'t understand how to make it work', 'wsdesk' ), - 'type' => 'textarea', - 'placeholder' => __( 'Would you like us to assist you?', 'wsdesk' ), - ), - array( - 'id' => 'found-better-plugin', - 'text' => __( 'I found a better plugin', 'wsdesk' ), - 'type' => 'text', - 'placeholder' => __( 'Which plugin?', 'wsdesk' ), - ), - array( - 'id' => 'not-have-that-feature', - 'text' => __( 'The plugin is great, but I need specific feature that you don\'t support', 'wsdesk' ), - 'type' => 'textarea', - 'placeholder' => __( 'Could you tell us more about that feature?', 'wsdesk' ), - ), - array( - 'id' => 'is-not-working', - 'text' => __( 'The plugin is not working', 'wsdesk' ), - 'type' => 'textarea', - 'placeholder' => __( 'Could you tell us a bit more whats not working?', 'wsdesk' ), - ), - array( - 'id' => 'looking-for-other', - 'text' => __( 'It\'s not what I was looking for', 'wsdesk' ), - 'type' => '', - 'placeholder' => '', - ), - array( - 'id' => 'did-not-work-as-expected', - 'text' => __( 'The plugin didn\'t work as expected', 'wsdesk' ), - 'type' => 'textarea', - 'placeholder' => __( 'What did you expect?', 'wsdesk' ), - ), - array( - 'id' => 'other', - 'text' => __( 'Other', 'wsdesk' ), - 'type' => 'textarea', - 'placeholder' => __( 'Could you tell us a bit more?', 'wsdesk' ), - ), - ); - - return $reasons; - } - public function deactivate_scripts() { - global $pagenow; - - if ( 'plugins.php' != $pagenow ) { - return; - } - - $reasons = $this->get_uninstall_reasons(); - $current_user = wp_get_current_user(); - $user_email = $current_user->user_email; - ?> - - <div class="wsdesk-modal" id="wsdesk-wsdesk-modal"> - <div class="wsdesk-modal-wrap"> - <div class="wsdesk-modal-header"> - <h3><?php esc_html_e( 'If you have a moment, please let us know why you are deactivating:', 'wsdesk' ); ?></h3> - </div> - - <div class="wsdesk-modal-body"> - <ul class="reasons"> - <?php foreach ( $reasons as $reason ) { ?> - <li data-type="<?php echo esc_attr( $reason['type'] ); ?>" data-placeholder="<?php echo esc_attr( $reason['placeholder'] ); ?>"> - <label><input type="radio" name="selected-reason" value="<?php echo esc_attr( $reason['id'] ); ?>"> <?php echo esc_html( $reason['text'] ); ?></label> - </li> - <?php } ?> - </ul> - <br> - <input type="checkbox" name="allow_contacting" value="1" id="allow_contacting"> - <label> - <strong><?php esc_html_e( 'Contact me back', 'wsdesk' ); ?></strong> - <br> - <?php esc_html_e( 'Check this box to let us collect your email along with your feedback, so that we can contact you back to address your concern.', 'wsdesk' ); ?> - </label> - <br> - <input type="text" name="email" id="email" value="<?php echo esc_url( $user_email ); ?>" style="display: none;"> - <br> - <label> - <?php - esc_html_e( 'You can also contact us through the', 'wsdesk' ); - ?> - <a href="https://elextensions.com/support/">support page.</a> - </label> - </div> - - <div class="wsdesk-modal-footer"> - <a href="#" class="dont-bother-me"><?php esc_html_e( 'I rather wouldn\'t say', 'wsdesk' ); ?></a> - <button class="button-primary wsdesk-model-submit"><?php esc_html_e( 'Submit & Deactivate', 'wsdesk' ); ?></button> - <button class="button-secondary wsdesk-model-cancel"><?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - <input type="hidden" id="init_nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>"> - </div> - </div> - </div> - - <style type="text/css"> - .wsdesk-modal { - position: fixed; - z-index: 99999; - top: 0; - right: 0; - bottom: 0; - left: 0; - background: rgba(0,0,0,0.5); - display: none; - } - - .wsdesk-modal.modal-active { - display: block; - } - - .wsdesk-modal-wrap { - width: 50%; - position: relative; - margin: 10% auto; - background: #fff; - } - - .wsdesk-modal-header { - border-bottom: 1px solid #eee; - padding: 8px 20px; - } - - .wsdesk-modal-header h3 { - line-height: 150%; - margin: 0; - } - - .wsdesk-modal-body { - padding: 5px 20px 20px 20px; - } - .wsdesk-modal-body .input-text,.wsdesk-modal-body textarea { - width:75%; - } - .wsdesk-modal-body .reason-input { - margin-top: 5px; - margin-left: 20px; - } - .wsdesk-modal-footer { - border-top: 1px solid #eee; - padding: 12px 20px; - text-align: right; - } - </style> - - <script type="text/javascript"> - (function($) { - $(function() { - var modal = $( '#wsdesk-wsdesk-modal' ); - var deactivateLink = ''; - - $( '#the-list' ).on('click', 'a.wsdesk-deactivate-link', function(e) { - e.preventDefault(); - - modal.addClass('modal-active'); - deactivateLink = $(this).attr('href'); - modal.find('a.dont-bother-me').attr('href', deactivateLink).css('float', 'left'); - }); - - modal.on('click', 'button.wsdesk-model-cancel', function(e) { - e.preventDefault(); - - modal.removeClass('modal-active'); - }); - - modal.on('click', 'input[type="radio"]', function () { - var parent = $(this).parents('li:first'); - - modal.find('.reason-input').remove(); - - var inputType = parent.data('type'), - inputPlaceholder = parent.data('placeholder'), - reasonInputHtml = '<div class="reason-input">' + ( ( 'text' === inputType ) ? '<input type="text" class="input-text" size="40" />' : '<textarea rows="5" cols="45"></textarea>' ) + '</div>'; - - if ( inputType !== '' ) { - parent.append( $(reasonInputHtml) ); - parent.find('input, textarea').attr('placeholder', inputPlaceholder).focus(); - } - }); - - modal.on('click', 'button.wsdesk-model-submit', function(e) { - e.preventDefault(); - - var button = $(this); - - if ( button.hasClass('disabled') ) { - return; - } - - var $radio = $( 'input[type="radio"]:checked', modal ); - - var $selected_reason = $radio.parents('li:first'), - $input = $selected_reason.find('textarea, input[type="text"]'); - - var allow_contacting = $('#allow_contacting:checkbox:checked').length; - - var email = $("#email").val(); - var nonce = $("init_nonce").val(); - - $.ajax({ - url: ajaxurl, - type: 'POST', - data: { - action: 'wsdesk_submit-uninstall-reason', - nonce: nonce, - reason_id: ( 0 === $radio.length ) ? 'none' : $radio.val(), - reason_info: ( 0 !== $input.length ) ? $input.val().trim() : '', - allow_contacting: allow_contacting, - email: email - }, - beforeSend: function() { - button.addClass('disabled'); - button.text('Processing...'); - }, - complete: function() { - window.location.href = deactivateLink; - } - }); - }); - modal.on('click', '#allow_contacting',function(e){ - if($('#allow_contacting:checkbox:checked').length > 0) - { - $("#email").show(); - } - else - { - $("#email").hide(); - } - }); - }); - }(jQuery)); - </script> - - <?php - } - public static function factory_reset() { - - if ( isset( $_GET['page'] ) && 'wsdesk_factory_reset' === $_GET['page'] ) { - $ticket_ids = eh_crm_get_all_tickets(); - if ( ! empty( $ticket_ids ) ) { - for ( $i = 0;$i < count( $ticket_ids );$i++ ) { - $attachments = eh_crm_get_ticketmeta( $ticket_ids[ $i ]['ticket_id'], 'ticket_attachment_path' ); - if ( ! empty( $attachments ) ) { - foreach ( $attachments as $key => $value ) { - unlink( $value ); - } - } - } - } - if ( ! function_exists( 'wp_get_current_user' ) ) { - include ABSPATH . 'wp-includes/pluggable.php'; - } - require_once ABSPATH . 'wp-admin/includes/upgrade.php'; - global $wpdb; - $postid = get_option( 'wsdesk_support_page' ); - wp_delete_post( $postid, true ); - - $wpdb->get_results( $wpdb->prepare( 'DROP TABLE if exists ' . $wpdb->prefix . 'wsdesk_ticketsmeta' ) ); - $wpdb->get_results( $wpdb->prepare( 'DROP TABLE if exists ' . $wpdb->prefix . 'wsdesk_tickets' ) ); - $wpdb->get_results( $wpdb->prepare( 'DROP TABLE if exists ' . $wpdb->prefix . 'wsdesk_settingsmeta' ) ); - $wpdb->get_results( $wpdb->prepare( 'DROP TABLE if exists ' . $wpdb->prefix . 'wsdesk_settings' ) ); - $wpdb->get_results( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'options WHERE `option_name` LIKE %s', '%wsdesk%' ) ); - return true; - } - return false; - } -} +<?php++if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++class EH_CRM_Init_Handler {++ private $settings;++ public function __construct() {+ add_action( 'admin_menu', array( $this, 'eh_crm_menu_add' ), 1 );+ add_action( 'admin_init', array( $this, 'eh_register_styles_scripts' ), 10 );+ add_action( 'wp_ajax_eh_crm_search_post', array( 'CRM_Ajax', 'eh_crm_search_post' ) );+ add_action( 'wp_ajax_nopriv_eh_crm_search_post', array( 'CRM_Ajax', 'eh_crm_search_post' ) );+ add_action( 'wp_ajax_eh_crm_search_tags', array( 'CRM_Ajax', 'eh_crm_search_tags' ) );+ add_action( 'wp_ajax_eh_crm_ticket_general', array( 'CRM_Ajax', 'eh_crm_ticket_general' ) );+ add_action( 'wp_ajax_eh_crm_ticket_appearance', array( 'CRM_Ajax', 'eh_crm_ticket_appearance' ) );+ add_action( 'wp_ajax_eh_crm_settings_initiate_ticket', array( 'CRM_Ajax', 'eh_crm_settings_initiate_ticket' ) );+ add_action( 'wp_ajax_eh_crm_settings_empty_trash', array( 'CRM_Ajax', 'eh_crm_settings_empty_trash' ) );+ add_action( 'wp_ajax_eh_crm_settings_empty_scheduled_actions', array( 'CRM_Ajax', 'eh_crm_settings_empty_scheduled_actions' ) );+ add_action( 'wp_ajax_eh_crm_settings_restore_trash', array( 'CRM_Ajax', 'eh_crm_settings_restore_trash' ) );+ add_action( 'wp_ajax_eh_crm_refresh_tickets_count', array( 'CRM_Ajax', 'eh_crm_refresh_tickets_count' ) );+ add_action( 'wp_ajax_eh_crm_ticket_refresh_left_bar', array( 'CRM_Ajax', 'eh_crm_ticket_refresh_left_bar' ) );+ add_action( 'wp_ajax_eh_crm_ticket_refresh_right_bar', array( 'CRM_Ajax', 'eh_crm_ticket_refresh_right_bar' ) );+ add_action( 'wp_ajax_eh_crm_archive_single_ticket', array( 'CRM_Ajax', 'eh_crm_archive_single_ticket' ) );+ add_action( 'wp_ajax_eh_crm_woocommerce_settings', array( 'CRM_Ajax', 'eh_crm_woocommerce_settings' ) );+ add_action( 'wp_ajax_eh_crm_ticket_field', array( 'CRM_Ajax', 'eh_crm_ticket_field' ) );+ add_action( 'wp_ajax_eh_crm_ticket_field_delete', array( 'CRM_Ajax', 'eh_crm_ticket_field_delete' ) );+ add_action( 'wp_ajax_eh_crm_ticket_field_activate_deactivate', array( 'CRM_Ajax', 'eh_crm_ticket_field_activate_deactivate' ) );+ add_action( 'wp_ajax_eh_crm_ticket_field_edit', array( 'CRM_Ajax', 'eh_crm_ticket_field_edit' ) );+ add_action( 'wp_ajax_eh_crm_ticket_label', array( 'CRM_Ajax', 'eh_crm_ticket_label' ) );+ add_action( 'wp_ajax_eh_crm_ticket_label_delete', array( 'CRM_Ajax', 'eh_crm_ticket_label_delete' ) );+ add_action( 'wp_ajax_eh_crm_ticket_label_edit', array( 'CRM_Ajax', 'eh_crm_ticket_label_edit' ) );+ add_action( 'wp_ajax_eh_crm_ticket_tag', array( 'CRM_Ajax', 'eh_crm_ticket_tag' ) );+ add_action( 'wp_ajax_eh_crm_ticket_tag_delete', array( 'CRM_Ajax', 'eh_crm_ticket_tag_delete' ) );+ add_action( 'wp_ajax_eh_crm_ticket_tag_edit', array( 'CRM_Ajax', 'eh_crm_ticket_tag_edit' ) );+ add_action( 'wp_ajax_eh_crm_ticket_view', array( 'CRM_Ajax', 'eh_crm_ticket_view' ) );+ add_action( 'wp_ajax_eh_crm_ticket_view_edit', array( 'CRM_Ajax', 'eh_crm_ticket_view_edit' ) );+ add_action( 'wp_ajax_eh_crm_ticket_view_delete', array( 'CRM_Ajax', 'eh_crm_ticket_view_delete' ) );+ add_action( 'wp_ajax_eh_crm_ticket_view_activate_deactivate', array( 'CRM_Ajax', 'eh_crm_ticket_view_activate_deactivate' ) );+ add_action( 'wp_ajax_eh_crm_trigger', array( 'CRM_Ajax', 'eh_crm_trigger' ) );+ add_action( 'wp_ajax_eh_crm_ticket_trigger_delete', array( 'CRM_Ajax', 'eh_crm_ticket_trigger_delete' ) );+ add_action( 'wp_ajax_eh_crm_ticket_trigger_activate_deactivate', array( 'CRM_Ajax', 'eh_crm_ticket_trigger_activate_deactivate' ) );+ add_action( 'wp_ajax_eh_crm_trigger_edit', array( 'CRM_Ajax', 'eh_crm_trigger_edit' ) );+ add_action( 'wp_ajax_eh_crm_agent_add', array( 'CRM_Ajax', 'eh_crm_agent_add' ) );+ add_action( 'wp_ajax_eh_crm_agent_add_user', array( 'CRM_Ajax', 'eh_crm_agent_add_user' ) );+ add_action( 'wp_ajax_eh_crm_edit_agent_html', array( 'CRM_Ajax', 'eh_crm_edit_agent_html' ) );+ add_action( 'wp_ajax_eh_crm_edit_agent', array( 'CRM_Ajax', 'eh_crm_edit_agent' ) );+ add_action( 'wp_ajax_eh_crm_remove_agent', array( 'CRM_Ajax', 'eh_crm_remove_agent' ) );+ add_action( 'wp_ajax_eh_crm_new_ticket_post', array( 'CRM_Ajax', 'eh_crm_new_ticket_post' ) );+ add_action( 'wp_ajax_nopriv_eh_crm_new_ticket_post', array( 'CRM_Ajax', 'eh_crm_new_ticket_post' ) );+ add_action( 'wp_ajax_eh_crm_new_ticket_form', array( 'CRM_Ajax', 'eh_crm_new_ticket_form' ) );+ add_action( 'wp_ajax_nopriv_eh_crm_new_ticket_form', array( 'CRM_Ajax', 'eh_crm_new_ticket_form' ) );+ add_action( 'wp_ajax_eh_crm_ticket_single_view', array( 'CRM_Ajax', 'eh_crm_ticket_single_view' ) );+ add_action( 'wp_ajax_eh_crm_ticket_single_save_props', array( 'CRM_Ajax', 'eh_crm_ticket_single_save_props' ) );+ add_action( 'wp_ajax_eh_crm_ticket_single_delete', array( 'CRM_Ajax', 'eh_crm_ticket_single_delete' ) );+ add_action( 'wp_ajax_eh_crm_ticket_multiple_delete', array( 'CRM_Ajax', 'eh_crm_ticket_multiple_delete' ) );+ add_action( 'wp_ajax_eh_crm_ticket_reply_agent', array( 'CRM_Ajax', 'eh_crm_ticket_reply_agent' ) );+ add_action( 'wp_ajax_eh_crm_ticket_single_ticket_action', array( 'CRM_Ajax', 'eh_crm_ticket_single_ticket_action' ) );+ add_action( 'wp_ajax_eh_crm_ticket_multiple_ticket_action', array( 'CRM_Ajax', 'eh_crm_ticket_multiple_ticket_action' ) );+ add_action( 'wp_ajax_eh_crm_ticket_search', array( 'CRM_Ajax', 'eh_crm_ticket_search' ) );+ add_action( 'wp_ajax_eh_crm_ticket_add_new', array( 'CRM_Ajax', 'eh_crm_ticket_add_new' ) );+ add_action( 'wp_ajax_eh_crm_ticket_new_submit', array( 'CRM_Ajax', 'eh_crm_ticket_new_submit' ) );+ add_action( 'wp_ajax_eh_crm_check_ticket_request', array( 'CRM_Ajax', 'eh_crm_check_ticket_request' ) );+ add_action( 'wp_ajax_nopriv_eh_crm_check_ticket_request', array( 'CRM_Ajax', 'eh_crm_check_ticket_request' ) );+ add_action( 'wp_ajax_eh_crm_ticket_single_view_client', array( 'CRM_Ajax', 'eh_crm_ticket_single_view_client' ) );+ add_action( 'wp_ajax_eh_crm_ticket_reply_raiser', array( 'CRM_Ajax', 'eh_crm_ticket_reply_raiser' ) );+ add_action( 'wp_ajax_eh_crm_ticket_client_section_load', array( 'CRM_Ajax', 'eh_crm_ticket_client_section_load' ) );+ add_action( 'wp_ajax_eh_crm_activate_oauth', array( 'CRM_Ajax', 'eh_crm_activate_oauth' ) );+ add_action( 'wp_ajax_eh_crm_email_block_filter', array( 'CRM_Ajax', 'eh_crm_email_block_filter' ) );+ add_action( 'wp_ajax_eh_crm_subject_block_filter', array( 'CRM_Ajax', 'eh_crm_subject_block_filter' ) );+ add_action( 'wp_ajax_eh_crm_email_block_delete', array( 'CRM_Ajax', 'eh_crm_email_block_delete' ) );+ add_action( 'wp_ajax_eh_crm_subject_block_delete', array( 'CRM_Ajax', 'eh_crm_subject_block_delete' ) );+ add_action( 'wp_ajax_eh_crm_deactivate_oauth', array( 'CRM_Ajax', 'eh_crm_deactivate_oauth' ) );+ add_action( 'wp_ajax_eh_crm_activate_email_protocol', array( 'CRM_Ajax', 'eh_crm_activate_email_protocol' ) );+ add_action( 'wp_ajax_eh_crm_deactivate_email_protocol', array( 'CRM_Ajax', 'eh_crm_deactivate_email_protocol' ) );+ add_action( 'wp_ajax_eh_crm_email_support_save', array( 'CRM_Ajax', 'eh_crm_email_support_save' ) );+ add_action( 'wp_ajax_eh_crm_backup_data', array( 'CRM_Ajax', 'eh_crm_backup_data' ) );+ add_action( 'wp_ajax_eh_crm_restore_data', array( 'CRM_Ajax', 'eh_crm_restore_data' ) );+ add_action( 'wp_ajax_eh_crm_zendesk_pull_tickets', array( 'CRM_Ajax', 'eh_crm_zendesk_pull_tickets' ) );+ add_action( 'wp_ajax_eh_crm_zendesk_stop_pull_tickets', array( 'CRM_Ajax', 'eh_crm_zendesk_stop_pull_tickets' ) );+ add_action( 'wp_ajax_eh_crm_zendesk_save_data', array( 'CRM_Ajax', 'eh_crm_zendesk_save_data' ) );+ add_action( 'wp_ajax_eh_crm_live_log', array( 'CRM_Ajax', 'eh_crm_live_log' ) );+ add_action( 'wp_ajax_eh_crm_survey_ticket_form', array( 'CRM_Ajax', 'eh_crm_survey_ticket_form' ) );+ add_action( 'wp_ajax_nopriv_eh_crm_survey_ticket_form', array( 'CRM_Ajax', 'eh_crm_survey_ticket_form' ) );+ add_action( 'wp_ajax_eh_crm_woo_report_products', array( 'CRM_Ajax', 'eh_crm_woo_report_products' ) );+ add_action( 'wp_ajax_eh_crm_woo_report_category', array( 'CRM_Ajax', 'eh_crm_woo_report_category' ) );+ add_action( 'wp_ajax_eh_crm_ticket_new_template', array( 'CRM_Ajax', 'eh_crm_ticket_new_template' ) );+ add_action( 'wp_ajax_eh_crm_ticket_template_delete', array( 'CRM_Ajax', 'eh_crm_ticket_template_delete' ) );+ add_action( 'wp_ajax_eh_crm_ticket_template_search', array( 'CRM_Ajax', 'eh_crm_ticket_template_search' ) );+ add_action( 'wp_ajax_eh_crm_ticket_template_search_single', array( 'CRM_Ajax', 'eh_crm_ticket_template_search_single' ) );+ add_action( 'wp_ajax_eh_crm_ticket_update_template', array( 'CRM_Ajax', 'eh_crm_ticket_update_template' ) );+ add_action( 'wp_ajax_eh_crm_ticket_preview_template', array( 'CRM_Ajax', 'eh_crm_ticket_preview_template' ) );+ add_action( 'wp_ajax_eh_crm_ticket_multiple_template_send', array( 'CRM_Ajax', 'eh_crm_ticket_multiple_template_send' ) );+ add_action( 'wp_ajax_eh_crm_ticket_edit_template_content', array( 'CRM_Ajax', 'eh_crm_ticket_edit_template_content' ) );+ add_action( 'wp_ajax_eh_crm_get_settingsmeta_from_slug', array( 'CRM_Ajax', 'eh_crm_get_settingsmeta_from_slug' ) );+ // add_action( 'wp_ajax_wsdesk_api_create_ticket', array( 'CRM_Ajax', 'wsdesk_api_create_ticket' ) );+ // add_action( 'wp_ajax_nopriv_wsdesk_api_create_ticket', array( 'CRM_Ajax', 'wsdesk_api_create_ticket' ) );+ add_action( 'wp_ajax_eh_crm_ticket_single_ticket_assignee', array( 'CRM_Ajax', 'eh_crm_ticket_single_ticket_assignee' ) );+ add_action( 'wp_ajax_eh_crm_bulk_edit', array( 'CRM_Ajax', 'eh_crm_bulk_edit' ) );+ add_action( 'wp_ajax_eh_crm_bulk_edit_save', array( 'CRM_Ajax', 'eh_crm_bulk_edit_save' ) );+ add_action( 'wp_ajax_eh_crm_ticket_change_label', array( 'CRM_Ajax', 'eh_crm_ticket_change_label' ) );+ add_action( 'wp_ajax_eh_crm_verify_merge_tickets', array( 'CRM_Ajax', 'eh_crm_verify_merge_tickets' ) );+ add_action( 'wp_ajax_eh_crm_confirm_merge_tickets', array( 'CRM_Ajax', 'eh_crm_confirm_merge_tickets' ) );+ add_action( 'wp_ajax_eh_crm_ticket_close_check_request', array( 'CRM_Ajax', 'eh_crm_ticket_close_check_request' ) );+ add_action( 'wp_ajax_eh_crm_export_ticket_data', array( 'CRM_Ajax', 'eh_crm_export_ticket_data' ) );+ add_action( 'wp_ajax_eh_crm_arrange_ticket_columns', array( 'CRM_Ajax', 'eh_crm_arrange_ticket_columns' ) );+ add_action( 'wp_ajax_eh_crm_activate_deactivate_ticket_columns', array( 'CRM_Ajax', 'eh_crm_activate_deactivate_ticket_columns' ) );+ //Archived Tickets+ add_action( 'wp_ajax_eh_crm_refresh_tickets_count_archive', array( 'CRM_Ajax_Archive', 'eh_crm_refresh_tickets_count_archive' ) );+ add_action( 'wp_ajax_eh_crm_ticket_single_view_archive', array( 'CRM_Ajax_Archive', 'eh_crm_ticket_single_view_archive' ) );+ add_action( 'wp_ajax_eh_crm_ticket_refresh_left_bar_archive', array( 'CRM_Ajax_Archive', 'eh_crm_ticket_refresh_left_bar_archive' ) );+ add_action( 'wp_ajax_eh_crm_ticket_refresh_right_bar_archive', array( 'CRM_Ajax_Archive', 'eh_crm_ticket_refresh_right_bar_archive' ) );+ add_action( 'wp_ajax_eh_crm_ticket_search_archive', array( 'CRM_Ajax_Archive', 'eh_crm_ticket_search_archive' ) );+ add_action( 'wp_ajax_eh_crm_archive_ticket_data', array( 'CRM_Ajax_Archive', 'eh_crm_archive_ticket_data' ) );+ add_action( 'wp_ajax_eh_crm_archive_ticket_data_restored', array( 'CRM_Ajax_Archive', 'eh_crm_archive_ticket_data_restored' ) );+ add_action( 'wp_ajax_eh_crm_ticket_multiple_unarchive', array( 'CRM_Ajax_Archive', 'eh_crm_ticket_multiple_unarchive' ) );+ $selectedfields = eh_crm_get_settingsmeta( '0', 'selected_fields' );+ + $args = [];+ $args['api_key'] = array(+ 'validate_callback' => function( $field, $request, $key ) {+ $api_key = eh_crm_get_settingsmeta( '0', 'api_key' );+ if ( $field == $api_key ) {+ return true;+ } else {+ return false;+ }+ },+ );+ if ( ! empty( $selectedfields ) ) {+ foreach ( $selectedfields as $key => $field ) {+ $fieldvalidation = [];+ $avail_fields = eh_crm_get_settings( array( 'slug' => $field ), [ 'settings_id' ] );+ $field_type = eh_crm_get_settingsmeta( $avail_fields[0]['settings_id'], 'field_type' );+ if ( 'email' == $field_type ) {+ $fieldvalidation['validate_callback'] = function( $field, $request, $key ) {+ return filter_var( $field, FILTER_VALIDATE_EMAIL );+ };+ } elseif ( 'number' == $field_type ) {+ $fieldvalidation['validate_callback'] = function( $field, $request, $key ) {+ return filter_var( $field, FILTER_VALIDATE_INT );+ };+ }+ $args[ $field ] = $fieldvalidation;+ }+ }+ add_action(+ 'rest_api_init',+ function () use ( $args ) {+ register_rest_route(+ 'wsdesk/v1',+ 'wsdesk_api_create_ticket', + array(+ 'methods' => 'POST',+ 'callback' => array( 'CRM_Ajax', 'wsdesk_api_create_ticket' ),+ 'permission_callback' => '__return_true',+ 'args' => $args,+ )+ );+ }+ );++ if ( EH_CRM_WOO_STATUS ) {+ add_action( 'wp_ajax_eh_crm_get_woo_order_id', array( 'CRM_Ajax', 'eh_crm_get_woo_order_id' ) );+ add_action( 'wp_ajax_eh_crm_woo_product_fetch', array( 'CRM_Ajax', 'eh_crm_woo_product_fetch' ) );+ add_action( 'wp_ajax_eh_crm_woo_category_fetch', array( 'CRM_Ajax', 'eh_crm_woo_category_fetch' ) );+ add_action( 'wp_ajax_eh_crm_woo_tags_fetch', array( 'CRM_Ajax', 'eh_crm_woo_tags_fetch' ) );+ add_action( 'wp_ajax_eh_crm_woo_vendors_fetch', array( 'CRM_Ajax', 'eh_crm_woo_vendors_fetch' ) );+ }+ if ( EH_CRM_EDD_STATUS ) {+ add_action( 'wp_ajax_eh_crm_get_edd_products', array( 'CRM_Ajax', 'eh_crm_get_edd_products' ) );+ }+ $this->settings = new EH_CRM_Settings_Handler();
Analyzing the provided diff for security vulnerabilities... The diff shows a file conversion from CRLF (Windows) line endings to LF (Unix) line endings. This is a whitespace-only change with no actual code modifications. **Analysis Result:** Vulnerability Existed: **no** There are no security vulnerabilities in this diff. The changes consist entirely of line ending conversions (CRLF → LF), which are whitespace normalization changes that do not affect code functionality, behavior, or security posture. The file content remains identical from a functional perspective - all PHP logic, security controls, and implementation details are unchanged. This type of change is typically made for consistency with version control systems or team coding standards and has no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-install-functions.php 2025-12-21 09:35:59.421065569 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-install-functions.php 2025-12-21 09:36:35.231291286 +0000@@ -1,262 +1,262 @@-<?php - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -class EH_CRM_Install { - - - public static function install_tables() { - global $wpdb; - //Setting up the charset and collation for the database dependency. - $charset = ''; - $collate = ''; - $charset_collate = ''; - if ( ! empty( $wpdb->charset ) ) { - $charset = $wpdb->charset; - } else { - $charset = 'utf8'; - } - if ( ! empty( $wpdb->collate ) ) { - $collate = $wpdb->collate; - } elseif ( 'utf8' === $charset ) { - $collate = 'utf8_general_ci'; - } - if ( ! empty( $charset ) ) { - $charset_collate = "DEFAULT CHARACTER SET $charset"; - } - if ( ! empty( $collate ) ) { - $charset_collate .= " COLLATE $collate"; - } - - $like = '%' . $wpdb->prefix . 'wsdesk_archived_tickets%'; - if ( ! $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $like ), ARRAY_A ) ) { - $table_name = $wpdb->prefix . 'wsdesk_archived_tickets'; - $sql_tickets = "CREATE TABLE $table_name - ( `ticket_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT , - `ticket_author` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0, - `ticket_email` VARCHAR(100) CHARACTER SET $charset COLLATE $collate NOT NULL , - `ticket_date` VARCHAR(100) NOT NULL, - `ticket_updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - `ticket_title` TEXT CHARACTER SET $charset COLLATE $collate NOT NULL , - `ticket_content` LONGTEXT CHARACTER SET $charset COLLATE $collate NOT NULL , - `ticket_parent` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0, - `ticket_category` TEXT NOT NULL , - `ticket_vendor` TEXT CHARACTER SET $charset COLLATE $collate NOT NULL , - `ticket_trash` INT(20) NOT NULL DEFAULT 0, - PRIMARY KEY (`ticket_id`) - )$charset_collate;"; - dbDelta( $sql_tickets ); - - // Check if the index already exists before attempting to create it - $existing_indexes = $wpdb->get_col( 'SHOW INDEX FROM ' . $wpdb->prefix . 'wsdesk_archived_tickets' ); - $index_name = $wpdb->prefix . 'wsdesk_archived_tickets'; - if ( ! in_array( $index_name, $existing_indexes ) ) { - $wpdb->get_results( - 'CREATE INDEX ' . $wpdb->prefix . 'wsdesk_archived_tickets ON ' . $wpdb->prefix . 'wsdesk_archived_tickets (ticket_email, ticket_parent, ticket_trash)' - ); - } - } - - $like = '%' . $wpdb->prefix . 'wsdesk_archived_ticketsmeta%'; - if ( ! $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $like ), ARRAY_N ) ) { - $table_name = $wpdb->prefix . 'wsdesk_archived_ticketsmeta'; - $sql_ticketsmeta = "CREATE TABLE $table_name - ( - `meta_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT , - `ticket_id` BIGINT(20) UNSIGNED NOT NULL , - `meta_key` VARCHAR(255) CHARACTER SET $charset COLLATE $collate NULL DEFAULT NULL , - `meta_value` LONGTEXT CHARACTER SET $charset COLLATE $collate NULL DEFAULT NULL , - PRIMARY KEY (`meta_id`) - )$charset_collate;"; - dbDelta( $sql_ticketsmeta ); - $wpdb->get_results( 'CREATE INDEX ' . $wpdb->prefix . 'wsdesk_archived_tickets ON ' . $wpdb->prefix . 'wsdesk_archived_tickets (ticket_id)' ); - } - $like = '%' . $wpdb->prefix . 'wsdesk_settings%'; - if ( ! $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $like ), ARRAY_N ) ) { - $table_name = $wpdb->prefix . 'wsdesk_settings'; - $sql_settings = "CREATE TABLE $table_name - ( - `settings_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT , - `slug` VARCHAR(20) CHARACTER SET $charset COLLATE $collate NOT NULL , - `title` TEXT CHARACTER SET $charset COLLATE $collate NOT NULL , - `filter` VARCHAR(3) CHARACTER SET $charset COLLATE $collate NOT NULL DEFAULT 'no' , - `type` VARCHAR(20) CHARACTER SET $charset COLLATE $collate NOT NULL , - `vendor` TEXT CHARACTER SET $charset COLLATE $collate NOT NULL , - PRIMARY KEY (`settings_id`) - )$charset_collate;"; - dbDelta( $sql_settings ); - - // Create the index - $index_name = $wpdb->prefix . 'wsdesk_settings'; - $index_columns = array( 'settings_id', 'type', 'slug' ); - - $wpdb->get_results( - 'CREATE INDEX ' . $wpdb->prefix . 'wsdesk_settings ON ' . $wpdb->prefix . 'wsdesk_settings (settings_id, type, slug)' - ); - - self::install_defaults( 'settings' ); - } else { - self::install_dependencies( 'settings' ); - } - - $like = '%' . $wpdb->prefix . 'wsdesk_settingsmeta%'; - if ( ! $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $like ), ARRAY_N ) ) { - $table_name = $wpdb->prefix . 'wsdesk_settingsmeta'; - $sql_settingsmeta = "CREATE TABLE $table_name - ( - `meta_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT , - `settings_id` BIGINT(20) UNSIGNED NOT NULL , - `meta_key` VARCHAR(255) CHARACTER SET $charset COLLATE $collate NULL DEFAULT NULL , - `meta_value` LONGTEXT CHARACTER SET $charset COLLATE $collate NULL DEFAULT NULL , - PRIMARY KEY (`meta_id`) - )$charset_collate;"; - dbDelta( $sql_settingsmeta ); - $wpdb->get_results( 'CREATE INDEX ' . $wpdb->prefix . 'wsdesk_settingsmeta ON ' . $wpdb->prefix . 'wsdesk_settingsmeta (settings_id)' ); - self::install_defaults( 'settingsmeta' ); - } else { - self::install_dependencies( 'settingsmeta' ); - //To check old data of IMAP. - $imap_account_data = eh_crm_get_settingsmeta( '0', 'imap_account_data' ); - $server_url = eh_crm_get_settingsmeta( '0', 'imap_server_url' ); - $server_port = eh_crm_get_settingsmeta( '0', 'imap_server_port' ); - $server_email = eh_crm_get_settingsmeta( '0', 'imap_server_email' ); - $server_email_pwd = eh_crm_get_settingsmeta( '0', 'imap_server_email_pwd' ); - $imap_activation = eh_crm_get_settingsmeta( '0', 'imap_activation' ); - $delete_email = eh_crm_get_settingsmeta( '0', 'delete_email' ); - if ( empty( $imap_account_data ) ) { - - if ( 'activated' == $imap_activation ) { - $imap_account_data = array( - '0' => array( - 'imap_server_url' => $server_url, - 'imap_server_port' => $server_port, - 'imap_server_email' => $server_email, - 'imap_server_email_pwd' => $server_email_pwd, - 'imap_activation' => $imap_activation, - 'delete_email' => $delete_email, - ), - ); - eh_crm_update_settingsmeta( '0', 'imap_account_data', $imap_account_data ); - } - } - } - $like = '%' . $wpdb->prefix . 'wsdesk_tickets%'; - if ( ! $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $like ), ARRAY_N ) ) { - $table_name = $wpdb->prefix . 'wsdesk_tickets'; - $sql_tickets = "CREATE TABLE $table_name - ( `ticket_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT , - `ticket_author` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0, - `ticket_email` VARCHAR(100) CHARACTER SET $charset COLLATE $collate NOT NULL , - `ticket_date` VARCHAR(100) NOT NULL, - `ticket_updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - `ticket_title` TEXT CHARACTER SET $charset COLLATE $collate NOT NULL , - `ticket_content` LONGTEXT CHARACTER SET $charset COLLATE $collate NOT NULL , - `ticket_parent` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0, - `ticket_category` TEXT NOT NULL , - `ticket_vendor` TEXT CHARACTER SET $charset COLLATE $collate NOT NULL , - `ticket_trash` INT(20) NOT NULL DEFAULT 0, - PRIMARY KEY (`ticket_id`) - )$charset_collate;"; - dbDelta( $sql_tickets ); - $wpdb->get_results( 'CREATE INDEX ' . $wpdb->prefix . 'wsdesk_tickets ON ' . $wpdb->prefix . 'wsdesk_tickets (ticket_email,ticket_parent,ticket_trash)' ); - } - $like = '%' . $wpdb->prefix . 'wsdesk_ticketsmeta%'; - if ( ! $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $like ), ARRAY_N ) ) { - $table_name = $wpdb->prefix . 'wsdesk_ticketsmeta'; - $sql_ticketsmeta = "CREATE TABLE $table_name - ( - `meta_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT , - `ticket_id` BIGINT(20) UNSIGNED NOT NULL , - `meta_key` VARCHAR(255) CHARACTER SET $charset COLLATE $collate NULL DEFAULT NULL , - `meta_value` LONGTEXT CHARACTER SET $charset COLLATE $collate NULL DEFAULT NULL , - PRIMARY KEY (`meta_id`) - )$charset_collate;"; - dbDelta( $sql_ticketsmeta ); - $wpdb->get_results( 'CREATE INDEX ' . $wpdb->prefix . 'wsdesk_ticketsmeta ON ' . $wpdb->prefix . 'wsdesk_ticketsmeta (ticket_id)' ); - } - } - - public static function install_defaults( $type ) { - global $wpdb; - switch ( $type ) { - case 'settings': - $insert_settings = $wpdb->get_results( 'INSERT INTO ' . $wpdb->prefix . 'wsdesk_settings (`settings_id`, `slug`, `title`, `filter`, `type`, `vendor`) VALUES ("1", "request_email", "Email", "yes", "field", ""), ("2", "request_title", "Subject", "yes", "field", ""), ("3", "request_description", "Description", "yes", "field", ""), ("4", "label_LL01", "Unsolved", "yes", "label", ""), ("5", "label_LL02", "Solved", "yes", "label", ""), ("6", "label_LL03", "Pending", "yes", "label", ""), ("7", "labels_view", "Labels", "yes", "view", ""), ("8", "agents_view", "Agents", "yes", "view", ""), ("9", "tags_view", "Tags", "yes", "view", ""), ("10", "users_view", "Users", "yes", "view", ""), ("11", "tag_TT01", "Support", "yes", "tag", "")' ); - break; - case 'settingsmeta': - $insert_settingsmeta = $wpdb->get_results( 'INSERT INTO ' . $wpdb->prefix . 'wsdesk_settingsmeta (`meta_id`, `settings_id`, `meta_key`, `meta_value`) VALUES (NULL, "0", "default_assignee", "no_assignee"), (NULL, "0", "default_label", "label_LL01"), (NULL, "0", "ticket_raiser", "all"), (NULL, "0", "ticket_rows", "25"), (NULL, "0", "auto_suggestion", "disable"), (NULL, "0", "input_width", ""), (NULL, "0", "main_ticket_form_title", ""), (NULL, "0", "new_ticket_form_title", ""), (NULL, "0", "existing_ticket_title", ""), (NULL, "0", "custom_attachment_folder_enable", "no"), (NULL, "0", "custom_attachment_folder_path", ""), (NULL, "1", "field_type", "email"), (NULL, "1", "field_placeholder", "Enter Email"), (NULL, "1", "field_require", "yes"), (NULL, "1", "field_default", ""), (NULL, "1", "field_description", "Your Email by which we will get back to you."), (NULL, "2", "field_type", "text"), (NULL, "2", "field_placeholder", "Enter Subject"), (NULL, "2", "field_require", "yes"), (NULL, "2", "field_default", ""), (NULL, "2", "field_description", "Your request Subject for which you are going to raise the ticket."), (NULL, "3", "field_type", "textarea"), (NULL, "3", "field_require", "yes"), (NULL, "3", "field_default", ""), (NULL, "3", "field_description", "Please enter the details of your request. A member of our support staff will respond as soon as possible."), (NULL, "4", "label_color", "#F5CA00"), (NULL, "5", "label_color", "#94BA3C"), (NULL, "6", "label_color", "#E82A2A")' ); - if ( EH_CRM_WOO_STATUS ) { - eh_crm_update_settingsmeta( 0, 'woo_order_tickets', 'enable' ); - eh_crm_update_settingsmeta( 0, 'woo_order_price', 'enable' ); - eh_crm_update_settingsmeta( 0, 'woo_order_access', array( 'administrator' ) ); - } - eh_crm_update_settingsmeta( 0, 'selected_views', array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) ); - eh_crm_update_settingsmeta( 0, 'selected_triggers', array() ); - break; - default: - break; - } - global $wp_roles; - $user_roles = $wp_roles->role_names; - $user_roles_create = array( 'WSDesk Agents', 'WSDesk Supervisor' ); - for ( $i = 0; $i < count( $user_roles_create ); $i++ ) { - $new_user_role = str_replace( ' ', '_', $user_roles_create[ $i ] ); - if ( ( '' != $new_user_role && '' != $user_roles_create[ $i ] ) && ! ( array_key_exists( $new_user_role, $user_roles ) ) ) { - add_role( - $new_user_role, - $user_roles_create[ $i ], - array( - 'crm_role' => true, - 'read' => true, - 'view_admin_dashboard' => true, - ) - ); - } - } - } - - public static function install_dependencies( $type ) { - global $wpdb; - switch ( $type ) { - case 'settings': - if ( eh_crm_get_settings( array( 'type' => 'view' ) ) === false ) { - $wpdb->get_results( 'INSERT INTO ' . $wpdb->prefix . 'wsdesk_settings (`slug`, `title`, `filter`, `type`, `vendor`) VALUES ("labels_view", "Labels", "yes", "view", ""), ("agents_view", "Agents", "yes", "view", ""), ("tags_view", "Tags", "yes", "view", ""), ("users_view", "Users", "yes", "view", "")' ); - } - break; - case 'settings_meta': - if ( eh_crm_get_settingsmeta( 0, 'auto_suggestion' ) === false ) { - eh_crm_update_settingsmeta( 0, 'auto_suggestion', 'disable' ); - } - if ( eh_crm_get_settingsmeta( 0, 'auto_send_creation_email' ) === false ) { - eh_crm_update_settingsmeta( 0, 'auto_send_creation_email', 'disable' ); - } - if ( eh_crm_get_settingsmeta( 0, 'selected_views' ) === false ) { - eh_crm_update_settingsmeta( 0, 'selected_views', array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) ); - } - if ( eh_crm_get_settingsmeta( 0, 'selected_triggers' ) === false ) { - eh_crm_update_settingsmeta( 0, 'selected_triggers', array() ); - } - if ( EH_CRM_WOO_STATUS ) { - if ( eh_crm_get_settingsmeta( 0, 'woo_order_tickets' ) === false ) { - eh_crm_update_settingsmeta( 0, 'woo_order_tickets', 'enable' ); - } - if ( eh_crm_get_settingsmeta( 0, 'woo_order_price' ) === false ) { - eh_crm_update_settingsmeta( 0, 'woo_order_price', 'enable' ); - } - if ( eh_crm_get_settingsmeta( 0, 'woo_order_access' ) === false ) { - eh_crm_update_settingsmeta( 0, 'woo_order_access', array( 'administrator' ) ); - } - } - break; - default: - break; - } - } - - public static function update_tables( $base ) { - update_option( 'wsdesk_version_' . $base, EH_CRM_VERSION ); - require_once EH_CRM_MAIN_PATH . 'includes/class-crm-update-version.php' ; - new EH_CRM_Update_Version(); - } -} +<?php++if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++class EH_CRM_Install {+++ public static function install_tables() {+ global $wpdb;+ //Setting up the charset and collation for the database dependency.+ $charset = '';+ $collate = '';+ $charset_collate = '';+ if ( ! empty( $wpdb->charset ) ) {+ $charset = $wpdb->charset;+ } else {+ $charset = 'utf8';+ }+ if ( ! empty( $wpdb->collate ) ) {+ $collate = $wpdb->collate;+ } elseif ( 'utf8' === $charset ) {+ $collate = 'utf8_general_ci';+ }+ if ( ! empty( $charset ) ) {+ $charset_collate = "DEFAULT CHARACTER SET $charset";+ }+ if ( ! empty( $collate ) ) {+ $charset_collate .= " COLLATE $collate";+ }++ $like = '%' . $wpdb->prefix . 'wsdesk_archived_tickets%';+ if ( ! $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $like ), ARRAY_A ) ) {+ $table_name = $wpdb->prefix . 'wsdesk_archived_tickets';+ $sql_tickets = "CREATE TABLE $table_name+ ( `ticket_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT ,+ `ticket_author` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,+ `ticket_email` VARCHAR(100) CHARACTER SET $charset COLLATE $collate NOT NULL ,+ `ticket_date` VARCHAR(100) NOT NULL,+ `ticket_updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,+ `ticket_title` TEXT CHARACTER SET $charset COLLATE $collate NOT NULL ,+ `ticket_content` LONGTEXT CHARACTER SET $charset COLLATE $collate NOT NULL ,+ `ticket_parent` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,+ `ticket_category` TEXT NOT NULL ,+ `ticket_vendor` TEXT CHARACTER SET $charset COLLATE $collate NOT NULL ,+ `ticket_trash` INT(20) NOT NULL DEFAULT 0,+ PRIMARY KEY (`ticket_id`)+ )$charset_collate;";+ dbDelta( $sql_tickets );+ + // Check if the index already exists before attempting to create it+ $existing_indexes = $wpdb->get_col( 'SHOW INDEX FROM ' . $wpdb->prefix . 'wsdesk_archived_tickets' );+ $index_name = $wpdb->prefix . 'wsdesk_archived_tickets';+ if ( ! in_array( $index_name, $existing_indexes ) ) {+ $wpdb->get_results( + 'CREATE INDEX ' . $wpdb->prefix . 'wsdesk_archived_tickets ON ' . $wpdb->prefix . 'wsdesk_archived_tickets (ticket_email, ticket_parent, ticket_trash)'+ );+ }+ }+ + $like = '%' . $wpdb->prefix . 'wsdesk_archived_ticketsmeta%';+ if ( ! $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $like ), ARRAY_N ) ) {+ $table_name = $wpdb->prefix . 'wsdesk_archived_ticketsmeta';+ $sql_ticketsmeta = "CREATE TABLE $table_name+ (+ `meta_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT ,+ `ticket_id` BIGINT(20) UNSIGNED NOT NULL ,+ `meta_key` VARCHAR(255) CHARACTER SET $charset COLLATE $collate NULL DEFAULT NULL ,+ `meta_value` LONGTEXT CHARACTER SET $charset COLLATE $collate NULL DEFAULT NULL ,+ PRIMARY KEY (`meta_id`)+ )$charset_collate;";+ dbDelta( $sql_ticketsmeta );+ $wpdb->get_results( 'CREATE INDEX ' . $wpdb->prefix . 'wsdesk_archived_tickets ON ' . $wpdb->prefix . 'wsdesk_archived_tickets (ticket_id)' );+ }+ $like = '%' . $wpdb->prefix . 'wsdesk_settings%';+ if ( ! $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $like ), ARRAY_N ) ) {+ $table_name = $wpdb->prefix . 'wsdesk_settings';+ $sql_settings = "CREATE TABLE $table_name+ (+ `settings_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT ,+ `slug` VARCHAR(20) CHARACTER SET $charset COLLATE $collate NOT NULL ,+ `title` TEXT CHARACTER SET $charset COLLATE $collate NOT NULL ,+ `filter` VARCHAR(3) CHARACTER SET $charset COLLATE $collate NOT NULL DEFAULT 'no' ,+ `type` VARCHAR(20) CHARACTER SET $charset COLLATE $collate NOT NULL , + `vendor` TEXT CHARACTER SET $charset COLLATE $collate NOT NULL ,+ PRIMARY KEY (`settings_id`)+ )$charset_collate;";+ dbDelta( $sql_settings );+ + // Create the index+ $index_name = $wpdb->prefix . 'wsdesk_settings';+ $index_columns = array( 'settings_id', 'type', 'slug' );++ $wpdb->get_results(+ 'CREATE INDEX ' . $wpdb->prefix . 'wsdesk_settings ON ' . $wpdb->prefix . 'wsdesk_settings (settings_id, type, slug)'+ );++ self::install_defaults( 'settings' );+ } else {+ self::install_dependencies( 'settings' );+ }+ + $like = '%' . $wpdb->prefix . 'wsdesk_settingsmeta%';+ if ( ! $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $like ), ARRAY_N ) ) {+ $table_name = $wpdb->prefix . 'wsdesk_settingsmeta';+ $sql_settingsmeta = "CREATE TABLE $table_name+ (+ `meta_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT ,+ `settings_id` BIGINT(20) UNSIGNED NOT NULL ,+ `meta_key` VARCHAR(255) CHARACTER SET $charset COLLATE $collate NULL DEFAULT NULL ,+ `meta_value` LONGTEXT CHARACTER SET $charset COLLATE $collate NULL DEFAULT NULL ,+ PRIMARY KEY (`meta_id`)+ )$charset_collate;";+ dbDelta( $sql_settingsmeta );+ $wpdb->get_results( 'CREATE INDEX ' . $wpdb->prefix . 'wsdesk_settingsmeta ON ' . $wpdb->prefix . 'wsdesk_settingsmeta (settings_id)' );+ self::install_defaults( 'settingsmeta' );+ } else {+ self::install_dependencies( 'settingsmeta' );+ //To check old data of IMAP.+ $imap_account_data = eh_crm_get_settingsmeta( '0', 'imap_account_data' );+ $server_url = eh_crm_get_settingsmeta( '0', 'imap_server_url' );+ $server_port = eh_crm_get_settingsmeta( '0', 'imap_server_port' );+ $server_email = eh_crm_get_settingsmeta( '0', 'imap_server_email' );+ $server_email_pwd = eh_crm_get_settingsmeta( '0', 'imap_server_email_pwd' );+ $imap_activation = eh_crm_get_settingsmeta( '0', 'imap_activation' );+ $delete_email = eh_crm_get_settingsmeta( '0', 'delete_email' );+ if ( empty( $imap_account_data ) ) {++ if ( 'activated' == $imap_activation ) {+ $imap_account_data = array(+ '0' => array(+ 'imap_server_url' => $server_url,+ 'imap_server_port' => $server_port,+ 'imap_server_email' => $server_email,+ 'imap_server_email_pwd' => $server_email_pwd,+ 'imap_activation' => $imap_activation,+ 'delete_email' => $delete_email,+ ),+ );+ eh_crm_update_settingsmeta( '0', 'imap_account_data', $imap_account_data );+ }+ }+ }+ $like = '%' . $wpdb->prefix . 'wsdesk_tickets%';+ if ( ! $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $like ), ARRAY_N ) ) {+ $table_name = $wpdb->prefix . 'wsdesk_tickets';+ $sql_tickets = "CREATE TABLE $table_name+ ( `ticket_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT ,+ `ticket_author` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,+ `ticket_email` VARCHAR(100) CHARACTER SET $charset COLLATE $collate NOT NULL ,+ `ticket_date` VARCHAR(100) NOT NULL,+ `ticket_updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,+ `ticket_title` TEXT CHARACTER SET $charset COLLATE $collate NOT NULL ,+ `ticket_content` LONGTEXT CHARACTER SET $charset COLLATE $collate NOT NULL ,+ `ticket_parent` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,+ `ticket_category` TEXT NOT NULL ,+ `ticket_vendor` TEXT CHARACTER SET $charset COLLATE $collate NOT NULL ,+ `ticket_trash` INT(20) NOT NULL DEFAULT 0,+ PRIMARY KEY (`ticket_id`)+ )$charset_collate;";+ dbDelta( $sql_tickets );+ $wpdb->get_results( 'CREATE INDEX ' . $wpdb->prefix . 'wsdesk_tickets ON ' . $wpdb->prefix . 'wsdesk_tickets (ticket_email,ticket_parent,ticket_trash)' );+ }+ $like = '%' . $wpdb->prefix . 'wsdesk_ticketsmeta%';+ if ( ! $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $like ), ARRAY_N ) ) {+ $table_name = $wpdb->prefix . 'wsdesk_ticketsmeta';+ $sql_ticketsmeta = "CREATE TABLE $table_name+ (+ `meta_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT ,+ `ticket_id` BIGINT(20) UNSIGNED NOT NULL ,+ `meta_key` VARCHAR(255) CHARACTER SET $charset COLLATE $collate NULL DEFAULT NULL ,+ `meta_value` LONGTEXT CHARACTER SET $charset COLLATE $collate NULL DEFAULT NULL ,+ PRIMARY KEY (`meta_id`)+ )$charset_collate;";+ dbDelta( $sql_ticketsmeta );+ $wpdb->get_results( 'CREATE INDEX ' . $wpdb->prefix . 'wsdesk_ticketsmeta ON ' . $wpdb->prefix . 'wsdesk_ticketsmeta (ticket_id)' );+ }+ }++ public static function install_defaults( $type ) {+ global $wpdb;+ switch ( $type ) {+ case 'settings':+ $insert_settings = $wpdb->get_results( 'INSERT INTO ' . $wpdb->prefix . 'wsdesk_settings (`settings_id`, `slug`, `title`, `filter`, `type`, `vendor`) VALUES ("1", "request_email", "Email", "yes", "field", ""), ("2", "request_title", "Subject", "yes", "field", ""), ("3", "request_description", "Description", "yes", "field", ""), ("4", "label_LL01", "Unsolved", "yes", "label", ""), ("5", "label_LL02", "Solved", "yes", "label", ""), ("6", "label_LL03", "Pending", "yes", "label", ""), ("7", "labels_view", "Labels", "yes", "view", ""), ("8", "agents_view", "Agents", "yes", "view", ""), ("9", "tags_view", "Tags", "yes", "view", ""), ("10", "users_view", "Users", "yes", "view", ""), ("11", "tag_TT01", "Support", "yes", "tag", "")' );+ break;+ case 'settingsmeta':+ $insert_settingsmeta = $wpdb->get_results( 'INSERT INTO ' . $wpdb->prefix . 'wsdesk_settingsmeta (`meta_id`, `settings_id`, `meta_key`, `meta_value`) VALUES (NULL, "0", "default_assignee", "no_assignee"), (NULL, "0", "default_label", "label_LL01"), (NULL, "0", "ticket_raiser", "all"), (NULL, "0", "ticket_rows", "25"), (NULL, "0", "auto_suggestion", "disable"), (NULL, "0", "input_width", ""), (NULL, "0", "main_ticket_form_title", ""), (NULL, "0", "new_ticket_form_title", ""), (NULL, "0", "existing_ticket_title", ""), (NULL, "0", "custom_attachment_folder_enable", "no"), (NULL, "0", "custom_attachment_folder_path", ""), (NULL, "1", "field_type", "email"), (NULL, "1", "field_placeholder", "Enter Email"), (NULL, "1", "field_require", "yes"), (NULL, "1", "field_default", ""), (NULL, "1", "field_description", "Your Email by which we will get back to you."), (NULL, "2", "field_type", "text"), (NULL, "2", "field_placeholder", "Enter Subject"), (NULL, "2", "field_require", "yes"), (NULL, "2", "field_default", ""), (NULL, "2", "field_description", "Your request Subject for which you are going to raise the ticket."), (NULL, "3", "field_type", "textarea"), (NULL, "3", "field_require", "yes"), (NULL, "3", "field_default", ""), (NULL, "3", "field_description", "Please enter the details of your request. A member of our support staff will respond as soon as possible."), (NULL, "4", "label_color", "#F5CA00"), (NULL, "5", "label_color", "#94BA3C"), (NULL, "6", "label_color", "#E82A2A")' );+ if ( EH_CRM_WOO_STATUS ) {+ eh_crm_update_settingsmeta( 0, 'woo_order_tickets', 'enable' );+ eh_crm_update_settingsmeta( 0, 'woo_order_price', 'enable' );+ eh_crm_update_settingsmeta( 0, 'woo_order_access', array( 'administrator' ) );+ }+ eh_crm_update_settingsmeta( 0, 'selected_views', array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) );+ eh_crm_update_settingsmeta( 0, 'selected_triggers', array() );+ break;+ default:+ break;+ }+ global $wp_roles;+ $user_roles = $wp_roles->role_names;+ $user_roles_create = array( 'WSDesk Agents', 'WSDesk Supervisor' );+ for ( $i = 0; $i < count( $user_roles_create ); $i++ ) {+ $new_user_role = str_replace( ' ', '_', $user_roles_create[ $i ] );+ if ( ( '' != $new_user_role && '' != $user_roles_create[ $i ] ) && ! ( array_key_exists( $new_user_role, $user_roles ) ) ) {+ add_role(+ $new_user_role,+ $user_roles_create[ $i ],+ array(+ 'crm_role' => true,+ 'read' => true,+ 'view_admin_dashboard' => true,+ )+ );+ }+ }+ }++ public static function install_dependencies( $type ) {+ global $wpdb;+ switch ( $type ) {+ case 'settings':+ if ( eh_crm_get_settings( array( 'type' => 'view' ) ) === false ) {+ $wpdb->get_results( 'INSERT INTO ' . $wpdb->prefix . 'wsdesk_settings (`slug`, `title`, `filter`, `type`, `vendor`) VALUES ("labels_view", "Labels", "yes", "view", ""), ("agents_view", "Agents", "yes", "view", ""), ("tags_view", "Tags", "yes", "view", ""), ("users_view", "Users", "yes", "view", "")' );+ }+ break;+ case 'settings_meta':+ if ( eh_crm_get_settingsmeta( 0, 'auto_suggestion' ) === false ) {+ eh_crm_update_settingsmeta( 0, 'auto_suggestion', 'disable' );+ }+ if ( eh_crm_get_settingsmeta( 0, 'auto_send_creation_email' ) === false ) {+ eh_crm_update_settingsmeta( 0, 'auto_send_creation_email', 'disable' );+ }+ if ( eh_crm_get_settingsmeta( 0, 'selected_views' ) === false ) {+ eh_crm_update_settingsmeta( 0, 'selected_views', array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) );+ }+ if ( eh_crm_get_settingsmeta( 0, 'selected_triggers' ) === false ) {+ eh_crm_update_settingsmeta( 0, 'selected_triggers', array() );+ }+ if ( EH_CRM_WOO_STATUS ) {+ if ( eh_crm_get_settingsmeta( 0, 'woo_order_tickets' ) === false ) {+ eh_crm_update_settingsmeta( 0, 'woo_order_tickets', 'enable' );+ }+ if ( eh_crm_get_settingsmeta( 0, 'woo_order_price' ) === false ) {+ eh_crm_update_settingsmeta( 0, 'woo_order_price', 'enable' );+ }+ if ( eh_crm_get_settingsmeta( 0, 'woo_order_access' ) === false ) {+ eh_crm_update_settingsmeta( 0, 'woo_order_access', array( 'administrator' ) );+ }+ }+ break;+ default:+ break;+ }+ }++ public static function update_tables( $base ) {+ update_option( 'wsdesk_version_' . $base, EH_CRM_VERSION );+ require_once EH_CRM_MAIN_PATH . 'includes/class-crm-update-version.php' ;+ new EH_CRM_Update_Version();+ }+}
Based on my analysis of the provided diff for `includes/class-crm-install-functions.php`, the changes consist entirely of line ending normalization (converting from CRLF to LF format). There are no functional code changes between version 3.3.4 and 3.3.5. **Analysis Result:** Vulnerability Existed: **no** **Explanation:** The diff shows only whitespace/line ending changes with no modifications to the actual PHP code logic. The file contains the same code structure, functions, and implementations in both versions. Since there are no functional code changes, there are no new security fixes to identify, and no vulnerabilities are being addressed in this update. The code maintains the same security posture as before: - SQL queries use `$wpdb->prepare()` for table existence checks - Direct string concatenation is used for CREATE INDEX statements (which is acceptable for unquoted metadata since `$wpdb->prefix` is internal and controlled) - Database operations rely on WordPress's `dbDelta()` function for schema management This appears to be a maintenance release focused on code formatting consistency rather than security improvements or bug fixes.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-js-translation.php 2025-12-21 09:35:59.421065569 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-js-translation.php 2025-12-21 09:36:35.231291286 +0000@@ -1,277 +1,277 @@-<?php - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -function eh_crm_js_translation_obj( $page ) { - switch ( $page ) { - case 'settings': - $js_var = array( - 'Archived_Tickets' => __( 'Ticket Data is Archived Successfully!', 'wsdesk' ), - 'Unarchived_Tickets' => __( 'Ticket Data is Unarchived Successfully!', 'wsdesk' ), - 'Export_alert' => __( 'All Ticket Data is Exported to your Downloads Folder!', 'wsdesk' ), - 'Export_title' => __( 'Exported', 'wsdesk' ), - 'Choose_the_Vendors' => __( 'Choose the Vendor(s)', 'wsdesk' ), - 'No_Vendors_Found' => __( 'No Vendor Found', 'wsdesk' ), - 'No_Labels_Found' => __( 'No Status Found', 'wsdesk' ), - 'Select_Ticket_Labels' => __( 'Select Ticket Status', 'wsdesk' ), - 'Select_Ticket_Fields' => __( 'Select Ticket Fields', 'wsdesk' ), - 'No_Fields_Found' => __( 'No Fields Found', 'wsdesk' ), - 'Select_Ticket_Views' => __( 'Select Ticket Views', 'wsdesk' ), - 'No_Views_Found' => __( 'No Views Found', 'wsdesk' ), - 'Select_Triggers' => __( 'Select Triggers', 'wsdesk' ), - 'No_Triggers_Found' => __( 'No Triggers Found', 'wsdesk' ), - 'Search_and_Choose' => __( 'Search and Choose', 'wsdesk' ), - 'No_Posts_Found' => __( 'No Posts Found', 'wsdesk' ), - 'Select_Ticket_Tags' => __( 'Select Ticket Tags', 'wsdesk' ), - 'No_Tags_Found' => __( 'No Tags Found', 'wsdesk' ), - 'General' => __( 'General', 'wsdesk' ), - 'Ticket_Fields' => __( 'Ticket Fields', 'wsdesk' ), - 'Ticket_labels' => __( 'Ticket Status', 'wsdesk' ), - 'Ticket_Tags' => __( 'Ticket Tags', 'wsdesk' ), - 'Ticket_Views' => __( 'Ticket Views', 'wsdesk' ), - 'Triggers_Automation' => __( 'Triggers & Automation', 'wsdesk' ), - 'Appearance' => __( 'Form Settings', 'wsdesk' ), - 'Backup_Restore' => __( 'Backup & Restore', 'wsdesk' ), - 'Activation_of_WSDesk' => __( 'Activation of WSDesk', 'wsdesk' ), - 'General_Settings' => __( 'General Settings', 'wsdesk' ), - 'Updated_and_Saved_Successfully' => __( 'Updated and Saved Successfully', 'wsdesk' ), - 'WooCommerce_Settings' => __( 'WooCommerce Settings', 'wsdesk' ), - 'Appearance_Settings' => __( 'Appearance Settings', 'wsdesk' ), - 'Add_Ticket_Field' => __( 'Add Ticket Field', 'wsdesk' ), - 'Enter_title_for_the_Field' => __( 'Enter title for the Field', 'wsdesk' ), - 'Default_Value_is_not_Matched' => __( 'Default Value is not Matched', 'wsdesk' ), - 'Site_Key_and_Secret_Key_is_Required' => __( 'Site Key and Secret Key is Required', 'wsdesk' ), - 'Edit_Ticket_Field' => __( 'Edit Ticket Field', 'wsdesk' ), - 'Add_Value' => __( 'Add Value', 'wsdesk' ), - 'Enter_Details_for_custom' => __( 'Enter details for custom', 'wsdesk' ), - 'Enter_Title' => __( 'Enter Title', 'wsdesk' ), - 'Enter_Site_Key' => __( 'Enter Site Key', 'wsdesk' ), - 'Enter_Secret_Key' => __( 'Enter Secret Key', 'wsdesk' ), - 'Want_to_give_some_description_to_this_field' => __( 'Want to give some description to this field?', 'wsdesk' ), - 'Specify_whether_this_Field_is_Optional_or_Required_For_Agent' => __( 'Field is mandatory for Agents', 'wsdesk' ), - 'Specify_whether_this_Field_is_Optional_or_Required_For_End' => __( 'Field is mandatory for End-Users', 'wsdesk' ), - 'Specify_whether_this_Field_is_Visible_For_End' => __( 'Field is visible for End-Users', 'wsdesk' ), - 'Yes_This_Field_is_Mandatory_End' => __( 'Mandatory for End users', 'wsdesk' ), - 'Yes_This_Field_is_Mandatory_Agents' => __( 'Mandatory for Agents', 'wsdesk' ), - 'Yes_This_Field_is_Visible' => __( 'Visible for End Users', 'wsdesk' ), - 'No_Its_an_Optional_Field' => __( "No! It's an Optional Field", 'wsdesk' ), - 'Auto_fill_products' => __( 'Auto fill products', 'wsdesk' ), - 'Specify_the_Product_values' => __( 'Specify Product values', 'wsdesk' ), - 'Enter_Default_Values' => __( 'Enter Default Values', 'wsdesk' ), - 'Want_to_use_this_field_for_Filter_Tickets' => __( 'Want to use this field to filter tickets', 'wsdesk' ), - 'Yes_I_will_use_it_for_Filter' => __( 'Yes! I will use it to filter tickets', 'wsdesk' ), - 'No_Just_for_Information' => __( 'No! Just for Information', 'wsdesk' ), - 'Auto_fill_categories' => __( 'Auto fill categories', 'wsdesk' ), - 'Specify_the_Category_values' => __( 'Specify Category values', 'wsdesk' ), - 'Specify_the_Tag_values' => __( 'Specify Tag values', 'wsdesk' ), - 'Auto_fill_tags' => __( 'Auto fill tags', 'wsdesk' ), - 'Specify_the_Vendor' => __( 'Specify the Vendor', 'wsdesk' ), - 'Auto_fill_Vendors' => __( 'Auto fill Vendors', 'wsdesk' ), - 'Specify_the_Radio_values' => __( 'Specify Radio values', 'wsdesk' ), - 'Enter_first_value' => __( 'Enter first value', 'wsdesk' ), - 'Specify_the_Checkbox_values' => __( 'Specify the Checkbox values', 'wsdesk' ), - 'Specify_the_Dropdown_values' => __( 'Specify the Dropdown values', 'wsdesk' ), - 'Enter_Placeholder' => __( 'Enter Placeholder', 'wsdesk' ), - 'Enter_next_value' => __( 'Enter next value', 'wsdesk' ), - 'Remove_Values' => __( 'Remove Values', 'wsdesk' ), - 'Add_Ticket_Label' => __( 'Add Ticket Status', 'wsdesk' ), - 'Enter_title_for_the_Label' => __( 'Enter status', 'wsdesk' ), - 'Ticket_Label' => __( 'Ticket Status', 'wsdesk' ), - 'Add_Ticket_Tag' => __( 'Add Ticket Tag', 'wsdesk' ), - 'Enter_title_for_the_Tag' => __( 'Enter title for the Tag', 'wsdesk' ), - 'Ticket_Tags' => __( 'Ticket Tags', 'wsdesk' ), - 'Condition' => __( 'Condition', 'wsdesk' ), - 'Enter_Value' => __( 'Enter Value', 'wsdesk' ), - 'View_condition_field' => __( 'View condition field', 'wsdesk' ), - 'Remove_Condition' => __( 'Remove Condition', 'wsdesk' ), - 'Enter_Period_for_New_Trigger' => __( 'Enter Period for New Trigger', 'wsdesk' ), - 'Edit_Period_for_the_Trigger' => __( 'Edit Period for the Trigger', 'wsdesk' ), - 'Trigger_condition_field' => __( 'Trigger condition field', 'wsdesk' ), - 'Add_Trigger' => __( 'Add Trigger', 'wsdesk' ), - 'Enter_title_for_the_Trigger' => __( 'Enter title for the Trigger', 'wsdesk' ), - 'trigger_name_exists' => __( 'The trigger name exists', 'wsdesk' ), - 'Specify_some_action_for_the_Trigger' => __( 'Specify some action for the Trigger', 'wsdesk' ), - 'Edit_Trigger' => __( 'Edit Trigger', 'wsdesk' ), - 'Triggers' => __( 'Triggers', 'wsdesk' ), - 'Select_Condition_Values' => __( 'Select Condition Values', 'wsdesk' ), - 'No_Values_Found' => __( 'No Values Found', 'wsdesk' ), - 'Action' => __( 'Action', 'wsdesk' ), - 'Trigger_Action_field' => __( 'Trigger Action field', 'wsdesk' ), - 'Remove_Action' => __( 'Remove Action', 'wsdesk' ), - 'Backup_Restore_Alert' => __( 'Backup & Restore Alert', 'wsdesk' ), - 'Choose_some_data_to_Backup' => __( 'Choose some data to Backup', 'wsdesk' ), - 'WSDesk_Restore_Alert' => __( 'WSDesk Restore Alert', 'wsdesk' ), - 'Keep_Calm_while_Restoring_Data_Dont_Refresh_the_Page' => __( "This will erase all your existing data. Keep Calm while Restoring Data. Don't Refresh the Page.", 'wsdesk' ), - 'Yes_I_Will_Wait' => __( 'Yes! I Will Wait', 'wsdesk' ), - 'Restore_Finished' => __( 'Restore Finished', 'wsdesk' ), - 'Refresh_and_Hit_to_go' => __( 'Refresh and Hit to go', 'wsdesk' ), - 'Select_a_Backup_File' => __( 'Select a Backup File', 'wsdesk' ), - 'Specify_the_Mail_Subject' => __( 'Specify the Mail Subject', 'wsdesk' ), - 'Enter_mail_subject' => __( 'Enter mail subject', 'wsdesk' ), - 'Codes_for_Notification_EMail' => __( 'Codes for Notification EMail', 'wsdesk' ), - - 'Codes_for_Google_chat' => __( 'Codes for Notification Google Chat', 'wsdesk' ), - - 'Codes_for_Notification_SMS' => __( 'Codes for Notification SMS', 'wsdesk' ), - 'To_Insert_Ticket_Number_in_the_notification_email' => __( 'To Insert Ticket Number in the notification email', 'wsdesk' ), - 'To_Insert_Ticket_Number_in_the_notification_chat' => __( 'To Insert Ticket Number in the notification google chat', 'wsdesk' ), - 'To_Insert_Ticket_Number_in_the_notification_sms' => __( 'To Insert Ticket Number in the notification SMS', 'wsdesk' ), - 'To_Insert_Ticket_Assignee_in_the_notification_email' => __( 'To Insert Ticket Assignee in the notification email', 'wsdesk' ), - 'To_Insert_Ticket_Assignee_in_the_notification_chat' => __( 'To Insert Ticket Assignee in the notification google chat', 'wsdesk' ), - 'To_Insert_Ticket_Assignee_in_the_notification_sms' => __( 'To Insert Ticket Assignee in the notification SMS', 'wsdesk' ), - 'To_Insert_Ticket_Tags_in_the_notification_mail' => __( 'To Insert Ticket Tags in the notification mail', 'wsdesk' ), - 'To_Insert_Ticket_Tags_in_the_notification_chat' => __( 'To Insert Ticket Tags in the notification google chat', 'wsdesk' ), - 'To_Insert_Ticket_Tags_in_the_notification_sms' => __( 'To Insert Ticket Tags in the notification SMS', 'wsdesk' ), - 'To_Insert_Ticket_Date_and_Time_in_the_notification_email' => __( 'To Insert Ticket Date and Time in the notification email', 'wsdesk' ), - 'To_Insert_Ticket_Date_and_Time_in_the_notification_chat' => __( 'To Insert Ticket Date and Time in the notification google chat', 'wsdesk' ), - 'To_Insert_Ticket_Date_and_Time_in_the_notification_sms' => __( 'To Insert Ticket Date and Time in the notification SMS', 'wsdesk' ), - 'To_Insert_Ticket_Content_in_the_notification_email' => __( 'To Insert Ticket Content in the notification email', 'wsdesk' ), - 'To_Insert_Latest_Ticket_Content_in_the_notification_email' => __( 'To Insert Latest Ticket Reply in the notification email', 'wsdesk' ), - 'To_Insert_Latest_Ticket_Content_in_the_notification_chat' => __( 'To Insert Latest Ticket Reply in the notification google chat', 'wsdesk' ), - 'To_Insert_Latest_Ticket_Content_in_the_notification_sms' => __( 'To Insert Latest Ticket Reply in the notification SMS', 'wsdesk' ), - 'To_Insert_Ticket_Note_in_the_notification_email' => __( 'To Insert Latest Ticket Reply (even if it is a note) in the notification email', 'wsdesk' ), - 'To_Insert_Ticket_Note_in_the_notification_chat' => __( 'To Insert Latest Ticket Reply (even if it is a note) in the notification google chat', 'wsdesk' ), - - 'To_Insert_Ticket_Note_in_the_notification_sms' => __( 'To Insert Latest Ticket Reply (even if it is a note) in the notification SMS', 'wsdesk' ), - 'To_Insert_Satisfaction_URL_in_the_notification_email' => __( 'To Insert Satisfaction URL in the notification email', 'wsdesk' ), - 'To_Insert_Satisfaction_URL_in_the_notification_sms' => __( 'To Insert Satisfaction URL in the notification SMS', 'wsdesk' ), - 'To_Insert_Conversation_History_in_the_notification_email' => __( 'To Insert Conversation History in the notification email', 'wsdesk' ), - 'To_Insert_Conversation_History_in_the_notification_chat' => __( 'To Insert Conversation History in the notification google chat', 'wsdesk' ), - 'To_Insert_Conversation_History_With_Note_in_the_notification_email' => __( 'To Insert Conversation History with agent note in the notification email', 'wsdesk' ), - 'Note_For_Satisfaction_Survey_place_the_shortcode_in_new_page' => __( 'Note : For Satisfaction Survey place the [wsdesk_satisfaction] shortcode in new page.', 'wsdesk' ), - 'Specify_the_Mail_Body' => __( 'Specify the Mail Body', 'wsdesk' ), - 'Specify_the_Chat_Body' => __( 'Specify the Google Chat Body', 'wsdesk' ), - 'Enter_mail_body' => __( 'Enter mail body', 'wsdesk' ), - 'Enter_chat_body' => __( 'Enter Google Chat Message', 'wsdesk' ), - 'Enter_sms_body' => __( 'Enter SMS body', 'wsdesk' ), - 'Select_Action_Values' => __( 'Select Action Values', 'wsdesk' ), - 'Initiate_Ticket' => __( 'Initiate Ticket', 'wsdesk' ), - 'WSDesk_will_create_ticket_from_this_number' => __( 'WSDesk will create ticket from this number', 'wsdesk' ), - 'Okay_Set_number' => __( 'Okay! Set it', 'wsdesk' ), - 'Initiate_Ticket_Success' => __( 'Initate number successfully set!', 'wsdesk' ), - 'Empty_Trash' => __( 'Empty Trash', 'wsdesk' ), - 'Empty_Scheduled_Actions' => __( 'Empty Scheduled Actions', 'wsdesk' ), - 'WSDesk_will_Delete_the_tickets_Permanently' => __( 'WSDesk will delete the tickets permanently. Please take a backup', 'wsdesk' ), - 'WSDesk_will_Delete_the_scheduled_actions' => __( 'WSDesk will delete the scheduled actions permanently', 'wsdesk' ), - 'Okay_Empty_it' => __( 'Okay! Empty it', 'wsdesk' ), - 'Empty_Ticket_Success' => __( 'All trash tickets deleted successfully!', 'wsdesk' ), - 'Empty_Scheduled_Actions_Success' => __( 'All scheduled actions deleted successfully!', 'wsdesk' ), - 'Restore_Trash' => __( 'Restore Trash', 'wsdesk' ), - 'WSDesk_will_restore_the_trash_tickets' => __( 'WSDesk will restore the trash tickets. Please take a backup', 'wsdesk' ), - 'Okay_Restore_it' => __( 'Okay! Restore it', 'wsdesk' ), - 'Restore_Ticket_Success' => __( 'All trash tickets restored successfully!', 'wsdesk' ), - 'nonce' => wp_create_nonce( 'wsdesk_nonce' ), - ); - return $js_var; - case 'tickets': - $js_var = array( - 'WSDesk_Alert' => __( 'WSDesk Alert', 'wsdesk' ), - 'Do_You_want_to_Delete_Ticket' => __( 'Do you want to delete the ticket(s)?', 'wsdesk' ), - 'Do_You_want_to_Archive_Ticket' => __( 'Do you want to archive the ticket?', 'wsdesk' ), - 'Do_You_want_to_Unarchive_Ticket' => __( 'Do you want to restore the ticket(s)?', 'wsdesk' ), - 'Do_You_want_to_Submit_Ticket_Without_Reply' => __( 'Do you want to submit the ticket without a reply?', 'wsdesk' ), - 'Ticket_Label_Changed' => __( 'Ticket Label Successfully Changed' ), - 'Yes_Delete' => __( 'Yes! Delete', 'wsdesk' ), - 'Yes_Unarchive' => __( 'Yes! Restore', 'wsdesk' ), - 'Yes_archive' => __( 'Yes! Archive', 'wsdesk' ), - 'Yes_Send' => __( 'Yes! Send', 'wsdesk' ), - 'Yes_Submit' => __( 'Yes! Submit', 'wsdesk' ), - 'WSDesk_Tickets_Notification' => __( 'WSDesk Tickets Notification', 'wsdesk' ), - 'WSDesk_Templates_Notification' => __( 'WSDesk Template Notification', 'wsdesk' ), - 'WSDesk_Templates_Added' => __( 'Template added successfully', 'wsdesk' ), - 'WSDesk_Templates_Updated' => __( 'Template updated successfully', 'wsdesk' ), - 'WSDesk_Templates_Delete' => __( 'Do You want to Delete Template?', 'wsdesk' ), - 'WSDesk_Templates_Deleted' => __( 'Template deleted successfully', 'wsdesk' ), - 'Create_Template' => __( 'Create Template', 'wsdesk' ), - 'Tickets_Deleted_Successfully' => __( 'Tickets Deleted Successfully', 'wsdesk' ), - 'Tickets_Unarchived_Successfully' => __( 'Tickets Restored Successfully', 'wsdesk' ), - 'Do_You_want_to_Send_the_Template' => __( 'Do you want to send the template?', 'wsdesk' ), - 'Do_You_want_to_Update_Tickets_Label' => __( 'Do you want to update tickets status?', 'wsdesk' ), - 'Do_You_want_to_Archive_Tickets' => __( 'Do you want to archive tickets?', 'wsdesk' ), - 'Yes_Update' => __( 'Yes! Update', 'wsdesk' ), - 'Yes_Archived' => __( 'Yes! Update', 'wsdesk' ), - 'Tickets_Updated_Successfully' => __( 'Tickets Updated Successfully', 'wsdesk' ), - 'Tickets_Archived_Successfully' => __( 'Tickets Archived Successfully', 'wsdesk' ), - 'New_Ticket_Created_Successfully' => __( 'New Ticket Created Successfully', 'wsdesk' ), - 'Updated_and_Saved_Successfully' => __( 'Updated and Saved Successfully', 'wsdesk' ), - 'missing_some_data' => __( 'missing some data', 'wsdesk' ), - 'Replied_Successfully' => __( 'Replied Successfully', 'wsdesk' ), - 'Edited_Successfully' => __( 'have been successfully edited', 'wsdesk' ), - 'Merged_Successfully' => __( 'have been successfully merged', 'wsdesk' ), - 'needs_reply_content' => __( 'needs reply content', 'wsdesk' ), - 'No_results_found' => __( 'No results found', 'wsdesk' ), - 'Select_Tag' => __( 'Select Tag', 'wsdesk' ), - 'No_Tags_Tagged' => __( 'No Tags Tagged', 'wsdesk' ), - 'No_Cc_found' => __( 'No Cc Found', 'wsdesk' ), - 'No_Bcc_Found' => __( 'No Bcc Found', 'wsdesk' ), - 'Select_Cc' => __( 'Select Cc', 'wsdesk' ), - 'Select_Bcc' => __( 'Select Bcc', 'wsdesk' ), - 'Select_Assignee' => __( 'Select Assignee', 'wsdesk' ), - 'Select_Label' => __( 'Select Label', 'Select Label' ), - 'nonce' => wp_create_nonce( 'wsdesk_nonce' ), - ); - return $js_var; - case 'agents': - $js_var = array( - 'Search_Tags' => __( 'Search - (Eg:Support)', 'wsdesk' ), - 'No_Tags_Found' => __( 'No Tags Found', 'wsdesk' ), - 'Select_User' => __( 'Select existing users', 'wsdesk' ), - 'No_Users_Found' => __( 'No Users Found', 'wsdesk' ), - 'Add_Agents' => __( 'Add Agents', 'wsdesk' ), - 'Manage_Agents' => __( 'Manage Agents', 'wsdesk' ), - 'WSDesk_Agents' => __( 'WSDesk Agents', 'wsdesk' ), - 'Agents_Updated_Successfully' => __( 'Agents Updated Successfully', 'wsdesk' ), - 'Agents_Removed_Successfully' => __( 'Agents Removed Successfully', 'wsdesk' ), - 'Agents_added_Successfully' => __( 'Agents added Successfully', 'wsdesk' ), - 'Manage_Templates' => __( 'Manage Templates', 'wsdesk' ), - 'Show_Settings_Page' => __( 'Show Settings Page', 'wsdesk' ), - 'Show_Agents_Page' => __( 'Show Agents Page', 'wsdesk' ), - 'Show_Email_Page' => __( 'Show Email Page', 'wsdesk' ), - 'Show_Import_Page' => __( 'Show Import Page', 'wsdesk' ), - 'Merge_Tickets' => __( 'Merge Tickets', 'wsdesk' ), - 'nonce' => wp_create_nonce( 'wsdesk_nonce' ), - ); - return $js_var; - case 'email': - $js_var = array( - 'Google_OAuth_Setup' => __( 'Google OAuth Setup', 'wsdesk' ), - 'IMAP_EMail_Setup' => __( 'IMAP EMail Setup', 'wsdesk' ), - 'Support_Email' => __( 'Support Email', 'wsdesk' ), - 'EMail_Filter_Block' => __( 'EMail Filter & Block', 'wsdesk' ), - 'Select_Blocked_Address' => __( 'Select EMail', 'wsdesk' ), - 'No_Address_Found' => __( 'No Address Found', 'wsdesk' ), - 'Add_Email_Block' => __( 'Block Email', 'wsdesk' ), - 'Enter_Email_for_the_Block' => __( 'Enter Email to Block', 'wsdesk' ), - 'Google_OAuth_Revoked' => __( 'Google OAuth Revoked', 'wsdesk' ), - 'IMAP_EMail_Deactivated' => __( 'IMAP EMail Deactivated', 'wsdesk' ), - 'Updated_and_Saved_Successfully' => __( 'Updated and Saved Successfully', 'wsdesk' ), - 'Add_Subject_Block' => __( 'Subject Block', 'wsdesk' ), - 'Enter_Subject_for_the_Block' => __( 'Enter Subject to Block', 'wsdesk' ), - 'nonce' => wp_create_nonce( 'wsdesk_nonce' ), - ); - return $js_var; - case 'reports': - $js_var = array( - 'Select_Products_for_Reports' => __( 'Select Products for Reports', 'wsdesk' ), - 'No_Products_Found' => __( 'No Products Found', 'wsdesk' ), - 'Select_Category_for_Reports' => __( 'Select Category for Reports', 'wsdesk' ), - 'No_Category_Found' => __( 'No Category Found', 'wsdesk' ), - 'nonce' => wp_create_nonce( 'wsdesk_nonce' ), - ); - return $js_var; - case 'import': - $js_var = array( - 'From_Zendesk' => __( 'From Zendesk', 'wsdesk' ), - 'Zendesk_Import' => __( 'Zendesk Import', 'wsdesk' ), - 'Tickets_Import_Successful' => __( 'Tickets Import Successful', 'wsdesk' ), - 'Something_Went_Wrong' => __( 'Something Went Wrong', 'wsdesk' ), - 'Import_Stopped_Manually' => __( 'Import Stopped Manually', 'wsdesk' ), - 'nonce' => wp_create_nonce( 'wsdesk_nonce' ), - ); - return $js_var; - default: - break; - } -} +<?php++if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++function eh_crm_js_translation_obj( $page ) {+ switch ( $page ) {+ case 'settings':+ $js_var = array(+ 'Archived_Tickets' => __( 'Ticket Data is Archived Successfully!', 'wsdesk' ),+ 'Unarchived_Tickets' => __( 'Ticket Data is Unarchived Successfully!', 'wsdesk' ),+ 'Export_alert' => __( 'All Ticket Data is Exported to your Downloads Folder!', 'wsdesk' ),+ 'Export_title' => __( 'Exported', 'wsdesk' ),+ 'Choose_the_Vendors' => __( 'Choose the Vendor(s)', 'wsdesk' ),+ 'No_Vendors_Found' => __( 'No Vendor Found', 'wsdesk' ),+ 'No_Labels_Found' => __( 'No Status Found', 'wsdesk' ),+ 'Select_Ticket_Labels' => __( 'Select Ticket Status', 'wsdesk' ),+ 'Select_Ticket_Fields' => __( 'Select Ticket Fields', 'wsdesk' ),+ 'No_Fields_Found' => __( 'No Fields Found', 'wsdesk' ),+ 'Select_Ticket_Views' => __( 'Select Ticket Views', 'wsdesk' ),+ 'No_Views_Found' => __( 'No Views Found', 'wsdesk' ),+ 'Select_Triggers' => __( 'Select Triggers', 'wsdesk' ),+ 'No_Triggers_Found' => __( 'No Triggers Found', 'wsdesk' ),+ 'Search_and_Choose' => __( 'Search and Choose', 'wsdesk' ),+ 'No_Posts_Found' => __( 'No Posts Found', 'wsdesk' ),+ 'Select_Ticket_Tags' => __( 'Select Ticket Tags', 'wsdesk' ),+ 'No_Tags_Found' => __( 'No Tags Found', 'wsdesk' ),+ 'General' => __( 'General', 'wsdesk' ),+ 'Ticket_Fields' => __( 'Ticket Fields', 'wsdesk' ),+ 'Ticket_labels' => __( 'Ticket Status', 'wsdesk' ),+ 'Ticket_Tags' => __( 'Ticket Tags', 'wsdesk' ),+ 'Ticket_Views' => __( 'Ticket Views', 'wsdesk' ),+ 'Triggers_Automation' => __( 'Triggers & Automation', 'wsdesk' ),+ 'Appearance' => __( 'Form Settings', 'wsdesk' ),+ 'Backup_Restore' => __( 'Backup & Restore', 'wsdesk' ),+ 'Activation_of_WSDesk' => __( 'Activation of WSDesk', 'wsdesk' ),+ 'General_Settings' => __( 'General Settings', 'wsdesk' ),+ 'Updated_and_Saved_Successfully' => __( 'Updated and Saved Successfully', 'wsdesk' ),+ 'WooCommerce_Settings' => __( 'WooCommerce Settings', 'wsdesk' ),+ 'Appearance_Settings' => __( 'Appearance Settings', 'wsdesk' ),+ 'Add_Ticket_Field' => __( 'Add Ticket Field', 'wsdesk' ),+ 'Enter_title_for_the_Field' => __( 'Enter title for the Field', 'wsdesk' ),+ 'Default_Value_is_not_Matched' => __( 'Default Value is not Matched', 'wsdesk' ),+ 'Site_Key_and_Secret_Key_is_Required' => __( 'Site Key and Secret Key is Required', 'wsdesk' ),+ 'Edit_Ticket_Field' => __( 'Edit Ticket Field', 'wsdesk' ),+ 'Add_Value' => __( 'Add Value', 'wsdesk' ),+ 'Enter_Details_for_custom' => __( 'Enter details for custom', 'wsdesk' ),+ 'Enter_Title' => __( 'Enter Title', 'wsdesk' ),+ 'Enter_Site_Key' => __( 'Enter Site Key', 'wsdesk' ),+ 'Enter_Secret_Key' => __( 'Enter Secret Key', 'wsdesk' ),+ 'Want_to_give_some_description_to_this_field' => __( 'Want to give some description to this field?', 'wsdesk' ),+ 'Specify_whether_this_Field_is_Optional_or_Required_For_Agent' => __( 'Field is mandatory for Agents', 'wsdesk' ),+ 'Specify_whether_this_Field_is_Optional_or_Required_For_End' => __( 'Field is mandatory for End-Users', 'wsdesk' ),+ 'Specify_whether_this_Field_is_Visible_For_End' => __( 'Field is visible for End-Users', 'wsdesk' ),+ 'Yes_This_Field_is_Mandatory_End' => __( 'Mandatory for End users', 'wsdesk' ),+ 'Yes_This_Field_is_Mandatory_Agents' => __( 'Mandatory for Agents', 'wsdesk' ),+ 'Yes_This_Field_is_Visible' => __( 'Visible for End Users', 'wsdesk' ),+ 'No_Its_an_Optional_Field' => __( "No! It's an Optional Field", 'wsdesk' ),+ 'Auto_fill_products' => __( 'Auto fill products', 'wsdesk' ),+ 'Specify_the_Product_values' => __( 'Specify Product values', 'wsdesk' ),+ 'Enter_Default_Values' => __( 'Enter Default Values', 'wsdesk' ),+ 'Want_to_use_this_field_for_Filter_Tickets' => __( 'Want to use this field to filter tickets', 'wsdesk' ),+ 'Yes_I_will_use_it_for_Filter' => __( 'Yes! I will use it to filter tickets', 'wsdesk' ),+ 'No_Just_for_Information' => __( 'No! Just for Information', 'wsdesk' ),+ 'Auto_fill_categories' => __( 'Auto fill categories', 'wsdesk' ),+ 'Specify_the_Category_values' => __( 'Specify Category values', 'wsdesk' ),+ 'Specify_the_Tag_values' => __( 'Specify Tag values', 'wsdesk' ),+ 'Auto_fill_tags' => __( 'Auto fill tags', 'wsdesk' ),+ 'Specify_the_Vendor' => __( 'Specify the Vendor', 'wsdesk' ),+ 'Auto_fill_Vendors' => __( 'Auto fill Vendors', 'wsdesk' ),+ 'Specify_the_Radio_values' => __( 'Specify Radio values', 'wsdesk' ),+ 'Enter_first_value' => __( 'Enter first value', 'wsdesk' ),+ 'Specify_the_Checkbox_values' => __( 'Specify the Checkbox values', 'wsdesk' ),+ 'Specify_the_Dropdown_values' => __( 'Specify the Dropdown values', 'wsdesk' ),+ 'Enter_Placeholder' => __( 'Enter Placeholder', 'wsdesk' ),+ 'Enter_next_value' => __( 'Enter next value', 'wsdesk' ),+ 'Remove_Values' => __( 'Remove Values', 'wsdesk' ),+ 'Add_Ticket_Label' => __( 'Add Ticket Status', 'wsdesk' ),+ 'Enter_title_for_the_Label' => __( 'Enter status', 'wsdesk' ),+ 'Ticket_Label' => __( 'Ticket Status', 'wsdesk' ),+ 'Add_Ticket_Tag' => __( 'Add Ticket Tag', 'wsdesk' ),+ 'Enter_title_for_the_Tag' => __( 'Enter title for the Tag', 'wsdesk' ),+ 'Ticket_Tags' => __( 'Ticket Tags', 'wsdesk' ),+ 'Condition' => __( 'Condition', 'wsdesk' ),+ 'Enter_Value' => __( 'Enter Value', 'wsdesk' ),+ 'View_condition_field' => __( 'View condition field', 'wsdesk' ),+ 'Remove_Condition' => __( 'Remove Condition', 'wsdesk' ),+ 'Enter_Period_for_New_Trigger' => __( 'Enter Period for New Trigger', 'wsdesk' ),+ 'Edit_Period_for_the_Trigger' => __( 'Edit Period for the Trigger', 'wsdesk' ),+ 'Trigger_condition_field' => __( 'Trigger condition field', 'wsdesk' ),+ 'Add_Trigger' => __( 'Add Trigger', 'wsdesk' ),+ 'Enter_title_for_the_Trigger' => __( 'Enter title for the Trigger', 'wsdesk' ),+ 'trigger_name_exists' => __( 'The trigger name exists', 'wsdesk' ),+ 'Specify_some_action_for_the_Trigger' => __( 'Specify some action for the Trigger', 'wsdesk' ),+ 'Edit_Trigger' => __( 'Edit Trigger', 'wsdesk' ),+ 'Triggers' => __( 'Triggers', 'wsdesk' ),+ 'Select_Condition_Values' => __( 'Select Condition Values', 'wsdesk' ),+ 'No_Values_Found' => __( 'No Values Found', 'wsdesk' ),+ 'Action' => __( 'Action', 'wsdesk' ),+ 'Trigger_Action_field' => __( 'Trigger Action field', 'wsdesk' ),+ 'Remove_Action' => __( 'Remove Action', 'wsdesk' ),+ 'Backup_Restore_Alert' => __( 'Backup & Restore Alert', 'wsdesk' ),+ 'Choose_some_data_to_Backup' => __( 'Choose some data to Backup', 'wsdesk' ),+ 'WSDesk_Restore_Alert' => __( 'WSDesk Restore Alert', 'wsdesk' ),+ 'Keep_Calm_while_Restoring_Data_Dont_Refresh_the_Page' => __( "This will erase all your existing data. Keep Calm while Restoring Data. Don't Refresh the Page.", 'wsdesk' ),+ 'Yes_I_Will_Wait' => __( 'Yes! I Will Wait', 'wsdesk' ),+ 'Restore_Finished' => __( 'Restore Finished', 'wsdesk' ),+ 'Refresh_and_Hit_to_go' => __( 'Refresh and Hit to go', 'wsdesk' ),+ 'Select_a_Backup_File' => __( 'Select a Backup File', 'wsdesk' ),+ 'Specify_the_Mail_Subject' => __( 'Specify the Mail Subject', 'wsdesk' ),+ 'Enter_mail_subject' => __( 'Enter mail subject', 'wsdesk' ),+ 'Codes_for_Notification_EMail' => __( 'Codes for Notification EMail', 'wsdesk' ),++ 'Codes_for_Google_chat' => __( 'Codes for Notification Google Chat', 'wsdesk' ),++ 'Codes_for_Notification_SMS' => __( 'Codes for Notification SMS', 'wsdesk' ),+ 'To_Insert_Ticket_Number_in_the_notification_email' => __( 'To Insert Ticket Number in the notification email', 'wsdesk' ),+ 'To_Insert_Ticket_Number_in_the_notification_chat' => __( 'To Insert Ticket Number in the notification google chat', 'wsdesk' ),+ 'To_Insert_Ticket_Number_in_the_notification_sms' => __( 'To Insert Ticket Number in the notification SMS', 'wsdesk' ),+ 'To_Insert_Ticket_Assignee_in_the_notification_email' => __( 'To Insert Ticket Assignee in the notification email', 'wsdesk' ),+ 'To_Insert_Ticket_Assignee_in_the_notification_chat' => __( 'To Insert Ticket Assignee in the notification google chat', 'wsdesk' ),+ 'To_Insert_Ticket_Assignee_in_the_notification_sms' => __( 'To Insert Ticket Assignee in the notification SMS', 'wsdesk' ),+ 'To_Insert_Ticket_Tags_in_the_notification_mail' => __( 'To Insert Ticket Tags in the notification mail', 'wsdesk' ),+ 'To_Insert_Ticket_Tags_in_the_notification_chat' => __( 'To Insert Ticket Tags in the notification google chat', 'wsdesk' ),+ 'To_Insert_Ticket_Tags_in_the_notification_sms' => __( 'To Insert Ticket Tags in the notification SMS', 'wsdesk' ),+ 'To_Insert_Ticket_Date_and_Time_in_the_notification_email' => __( 'To Insert Ticket Date and Time in the notification email', 'wsdesk' ),+ 'To_Insert_Ticket_Date_and_Time_in_the_notification_chat' => __( 'To Insert Ticket Date and Time in the notification google chat', 'wsdesk' ),+ 'To_Insert_Ticket_Date_and_Time_in_the_notification_sms' => __( 'To Insert Ticket Date and Time in the notification SMS', 'wsdesk' ),+ 'To_Insert_Ticket_Content_in_the_notification_email' => __( 'To Insert Ticket Content in the notification email', 'wsdesk' ),+ 'To_Insert_Latest_Ticket_Content_in_the_notification_email' => __( 'To Insert Latest Ticket Reply in the notification email', 'wsdesk' ),+ 'To_Insert_Latest_Ticket_Content_in_the_notification_chat' => __( 'To Insert Latest Ticket Reply in the notification google chat', 'wsdesk' ),+ 'To_Insert_Latest_Ticket_Content_in_the_notification_sms' => __( 'To Insert Latest Ticket Reply in the notification SMS', 'wsdesk' ),+ 'To_Insert_Ticket_Note_in_the_notification_email' => __( 'To Insert Latest Ticket Reply (even if it is a note) in the notification email', 'wsdesk' ),+ 'To_Insert_Ticket_Note_in_the_notification_chat' => __( 'To Insert Latest Ticket Reply (even if it is a note) in the notification google chat', 'wsdesk' ),++ 'To_Insert_Ticket_Note_in_the_notification_sms' => __( 'To Insert Latest Ticket Reply (even if it is a note) in the notification SMS', 'wsdesk' ),+ 'To_Insert_Satisfaction_URL_in_the_notification_email' => __( 'To Insert Satisfaction URL in the notification email', 'wsdesk' ),+ 'To_Insert_Satisfaction_URL_in_the_notification_sms' => __( 'To Insert Satisfaction URL in the notification SMS', 'wsdesk' ),+ 'To_Insert_Conversation_History_in_the_notification_email' => __( 'To Insert Conversation History in the notification email', 'wsdesk' ),+ 'To_Insert_Conversation_History_in_the_notification_chat' => __( 'To Insert Conversation History in the notification google chat', 'wsdesk' ),+ 'To_Insert_Conversation_History_With_Note_in_the_notification_email' => __( 'To Insert Conversation History with agent note in the notification email', 'wsdesk' ),+ 'Note_For_Satisfaction_Survey_place_the_shortcode_in_new_page' => __( 'Note : For Satisfaction Survey place the [wsdesk_satisfaction] shortcode in new page.', 'wsdesk' ),+ 'Specify_the_Mail_Body' => __( 'Specify the Mail Body', 'wsdesk' ),+ 'Specify_the_Chat_Body' => __( 'Specify the Google Chat Body', 'wsdesk' ),+ 'Enter_mail_body' => __( 'Enter mail body', 'wsdesk' ),+ 'Enter_chat_body' => __( 'Enter Google Chat Message', 'wsdesk' ),+ 'Enter_sms_body' => __( 'Enter SMS body', 'wsdesk' ),+ 'Select_Action_Values' => __( 'Select Action Values', 'wsdesk' ),+ 'Initiate_Ticket' => __( 'Initiate Ticket', 'wsdesk' ),+ 'WSDesk_will_create_ticket_from_this_number' => __( 'WSDesk will create ticket from this number', 'wsdesk' ),+ 'Okay_Set_number' => __( 'Okay! Set it', 'wsdesk' ),+ 'Initiate_Ticket_Success' => __( 'Initate number successfully set!', 'wsdesk' ),+ 'Empty_Trash' => __( 'Empty Trash', 'wsdesk' ),+ 'Empty_Scheduled_Actions' => __( 'Empty Scheduled Actions', 'wsdesk' ),+ 'WSDesk_will_Delete_the_tickets_Permanently' => __( 'WSDesk will delete the tickets permanently. Please take a backup', 'wsdesk' ),+ 'WSDesk_will_Delete_the_scheduled_actions' => __( 'WSDesk will delete the scheduled actions permanently', 'wsdesk' ),+ 'Okay_Empty_it' => __( 'Okay! Empty it', 'wsdesk' ),+ 'Empty_Ticket_Success' => __( 'All trash tickets deleted successfully!', 'wsdesk' ),+ 'Empty_Scheduled_Actions_Success' => __( 'All scheduled actions deleted successfully!', 'wsdesk' ),+ 'Restore_Trash' => __( 'Restore Trash', 'wsdesk' ),+ 'WSDesk_will_restore_the_trash_tickets' => __( 'WSDesk will restore the trash tickets. Please take a backup', 'wsdesk' ),+ 'Okay_Restore_it' => __( 'Okay! Restore it', 'wsdesk' ),+ 'Restore_Ticket_Success' => __( 'All trash tickets restored successfully!', 'wsdesk' ),+ 'nonce' => wp_create_nonce( 'wsdesk_nonce' ),+ );+ return $js_var;+ case 'tickets':+ $js_var = array(+ 'WSDesk_Alert' => __( 'WSDesk Alert', 'wsdesk' ),+ 'Do_You_want_to_Delete_Ticket' => __( 'Do you want to delete the ticket(s)?', 'wsdesk' ),+ 'Do_You_want_to_Archive_Ticket' => __( 'Do you want to archive the ticket?', 'wsdesk' ),+ 'Do_You_want_to_Unarchive_Ticket' => __( 'Do you want to restore the ticket(s)?', 'wsdesk' ),+ 'Do_You_want_to_Submit_Ticket_Without_Reply' => __( 'Do you want to submit the ticket without a reply?', 'wsdesk' ),+ 'Ticket_Label_Changed' => __( 'Ticket Label Successfully Changed' ),+ 'Yes_Delete' => __( 'Yes! Delete', 'wsdesk' ),+ 'Yes_Unarchive' => __( 'Yes! Restore', 'wsdesk' ),+ 'Yes_archive' => __( 'Yes! Archive', 'wsdesk' ),+ 'Yes_Send' => __( 'Yes! Send', 'wsdesk' ),+ 'Yes_Submit' => __( 'Yes! Submit', 'wsdesk' ),+ 'WSDesk_Tickets_Notification' => __( 'WSDesk Tickets Notification', 'wsdesk' ),+ 'WSDesk_Templates_Notification' => __( 'WSDesk Template Notification', 'wsdesk' ),+ 'WSDesk_Templates_Added' => __( 'Template added successfully', 'wsdesk' ),+ 'WSDesk_Templates_Updated' => __( 'Template updated successfully', 'wsdesk' ),+ 'WSDesk_Templates_Delete' => __( 'Do You want to Delete Template?', 'wsdesk' ),+ 'WSDesk_Templates_Deleted' => __( 'Template deleted successfully', 'wsdesk' ),+ 'Create_Template' => __( 'Create Template', 'wsdesk' ),+ 'Tickets_Deleted_Successfully' => __( 'Tickets Deleted Successfully', 'wsdesk' ),+ 'Tickets_Unarchived_Successfully' => __( 'Tickets Restored Successfully', 'wsdesk' ),+ 'Do_You_want_to_Send_the_Template' => __( 'Do you want to send the template?', 'wsdesk' ),+ 'Do_You_want_to_Update_Tickets_Label' => __( 'Do you want to update tickets status?', 'wsdesk' ),+ 'Do_You_want_to_Archive_Tickets' => __( 'Do you want to archive tickets?', 'wsdesk' ),+ 'Yes_Update' => __( 'Yes! Update', 'wsdesk' ),+ 'Yes_Archived' => __( 'Yes! Update', 'wsdesk' ),+ 'Tickets_Updated_Successfully' => __( 'Tickets Updated Successfully', 'wsdesk' ),+ 'Tickets_Archived_Successfully' => __( 'Tickets Archived Successfully', 'wsdesk' ),+ 'New_Ticket_Created_Successfully' => __( 'New Ticket Created Successfully', 'wsdesk' ),+ 'Updated_and_Saved_Successfully' => __( 'Updated and Saved Successfully', 'wsdesk' ),+ 'missing_some_data' => __( 'missing some data', 'wsdesk' ),+ 'Replied_Successfully' => __( 'Replied Successfully', 'wsdesk' ),+ 'Edited_Successfully' => __( 'have been successfully edited', 'wsdesk' ),+ 'Merged_Successfully' => __( 'have been successfully merged', 'wsdesk' ),+ 'needs_reply_content' => __( 'needs reply content', 'wsdesk' ),+ 'No_results_found' => __( 'No results found', 'wsdesk' ),+ 'Select_Tag' => __( 'Select Tag', 'wsdesk' ),+ 'No_Tags_Tagged' => __( 'No Tags Tagged', 'wsdesk' ),+ 'No_Cc_found' => __( 'No Cc Found', 'wsdesk' ),+ 'No_Bcc_Found' => __( 'No Bcc Found', 'wsdesk' ),+ 'Select_Cc' => __( 'Select Cc', 'wsdesk' ),+ 'Select_Bcc' => __( 'Select Bcc', 'wsdesk' ),+ 'Select_Assignee' => __( 'Select Assignee', 'wsdesk' ),+ 'Select_Label' => __( 'Select Label', 'Select Label' ),+ 'nonce' => wp_create_nonce( 'wsdesk_nonce' ),+ );+ return $js_var;+ case 'agents':+ $js_var = array(+ 'Search_Tags' => __( 'Search - (Eg:Support)', 'wsdesk' ),+ 'No_Tags_Found' => __( 'No Tags Found', 'wsdesk' ),+ 'Select_User' => __( 'Select existing users', 'wsdesk' ),+ 'No_Users_Found' => __( 'No Users Found', 'wsdesk' ),+ 'Add_Agents' => __( 'Add Agents', 'wsdesk' ),+ 'Manage_Agents' => __( 'Manage Agents', 'wsdesk' ),+ 'WSDesk_Agents' => __( 'WSDesk Agents', 'wsdesk' ),+ 'Agents_Updated_Successfully' => __( 'Agents Updated Successfully', 'wsdesk' ),+ 'Agents_Removed_Successfully' => __( 'Agents Removed Successfully', 'wsdesk' ),+ 'Agents_added_Successfully' => __( 'Agents added Successfully', 'wsdesk' ),+ 'Manage_Templates' => __( 'Manage Templates', 'wsdesk' ),+ 'Show_Settings_Page' => __( 'Show Settings Page', 'wsdesk' ),+ 'Show_Agents_Page' => __( 'Show Agents Page', 'wsdesk' ),+ 'Show_Email_Page' => __( 'Show Email Page', 'wsdesk' ),+ 'Show_Import_Page' => __( 'Show Import Page', 'wsdesk' ),+ 'Merge_Tickets' => __( 'Merge Tickets', 'wsdesk' ),+ 'nonce' => wp_create_nonce( 'wsdesk_nonce' ),+ );+ return $js_var;+ case 'email':+ $js_var = array(+ 'Google_OAuth_Setup' => __( 'Google OAuth Setup', 'wsdesk' ),+ 'IMAP_EMail_Setup' => __( 'IMAP EMail Setup', 'wsdesk' ),+ 'Support_Email' => __( 'Support Email', 'wsdesk' ),+ 'EMail_Filter_Block' => __( 'EMail Filter & Block', 'wsdesk' ),+ 'Select_Blocked_Address' => __( 'Select EMail', 'wsdesk' ),+ 'No_Address_Found' => __( 'No Address Found', 'wsdesk' ),+ 'Add_Email_Block' => __( 'Block Email', 'wsdesk' ),+ 'Enter_Email_for_the_Block' => __( 'Enter Email to Block', 'wsdesk' ),+ 'Google_OAuth_Revoked' => __( 'Google OAuth Revoked', 'wsdesk' ),+ 'IMAP_EMail_Deactivated' => __( 'IMAP EMail Deactivated', 'wsdesk' ),+ 'Updated_and_Saved_Successfully' => __( 'Updated and Saved Successfully', 'wsdesk' ),+ 'Add_Subject_Block' => __( 'Subject Block', 'wsdesk' ),+ 'Enter_Subject_for_the_Block' => __( 'Enter Subject to Block', 'wsdesk' ),+ 'nonce' => wp_create_nonce( 'wsdesk_nonce' ),+ );+ return $js_var;+ case 'reports':+ $js_var = array(+ 'Select_Products_for_Reports' => __( 'Select Products for Reports', 'wsdesk' ),+ 'No_Products_Found' => __( 'No Products Found', 'wsdesk' ),+ 'Select_Category_for_Reports' => __( 'Select Category for Reports', 'wsdesk' ),+ 'No_Category_Found' => __( 'No Category Found', 'wsdesk' ),+ 'nonce' => wp_create_nonce( 'wsdesk_nonce' ),+ );+ return $js_var;+ case 'import':+ $js_var = array(+ 'From_Zendesk' => __( 'From Zendesk', 'wsdesk' ),+ 'Zendesk_Import' => __( 'Zendesk Import', 'wsdesk' ),+ 'Tickets_Import_Successful' => __( 'Tickets Import Successful', 'wsdesk' ),+ 'Something_Went_Wrong' => __( 'Something Went Wrong', 'wsdesk' ),+ 'Import_Stopped_Manually' => __( 'Import Stopped Manually', 'wsdesk' ),+ 'nonce' => wp_create_nonce( 'wsdesk_nonce' ),+ );+ return $js_var;+ default:+ break;+ }+}
Vulnerability Existed: no The diff shows only line ending changes (CRLF to LF conversion) in the file `includes/class-crm-js-translation.php`. The actual code content remains identical between versions 3.3.4 and 3.3.5. This file contains a translation object function that returns localized strings for JavaScript use. All the functionality, including: - Nonce generation via `wp_create_nonce()` - String localization via `__()` - Array structure and data remains unchanged. No security fixes or vulnerabilities are introduced or addressed in this version update—it's purely a formatting/normalization change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-public-functions.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-public-functions.php 2025-12-21 09:36:35.231291286 +0000@@ -1,4957 +1,4957 @@-<?php - -use WSDesk\Formatter\Cast\TimestampCaster; - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -function eh_random_slug_generate( $size ) { - $alpha_key = ''; - $keys = range( 'A', 'Z' ); - for ( $i = 0; $i < 2; $i++ ) { - $alpha_key .= $keys[ array_rand( $keys ) ]; - } - $length = $size - 2; - $key = ''; - $keys = range( 0, 9 ); - for ( $i = 0; $i < $length; $i++ ) { - $key .= $keys[ array_rand( $keys ) ]; - } - return $alpha_key . $key; -} - -/** - * Insert Data into wsdesk_settings table. - * - * @param array $args (title,filter,type,vendor) - * @param array $meta (meta_key,meta_value) | Optional - * @return int The Settings ID on success. The value 0 or false on failure. - */ -function eh_crm_insert_settings( $args, $meta = null, $override = '' ) { - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_settings'; - $defaults = array( - 'title' => '', - 'filter' => 'no', - 'type' => '', - 'vendor' => '', - ); - $data = wp_parse_args( $args, $defaults ); - $slug_check = true; - do { - if ( '' === $override ) { - $data['slug'] = $data['type'] . '_' . eh_random_slug_generate( 4 ); - } else { - $data['slug'] = $override; - } - if ( ! $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT( * ) FROM ' . $wpdb->prefix . 'wsdesk_settings WHERE slug = %s', $data['slug'] ) ) ) { - $slug_check = false; - } - } while ( $slug_check ); - $result = $wpdb->insert( $table, $data ); - $settings_id = (int) $wpdb->insert_id; - if ( null !== $meta ) { - foreach ( $meta as $key => $value ) { - eh_crm_insert_settingsmeta( $settings_id, $key, $value ); - } - } - if ( ! $result ) { - return false; - } - return $settings_id; -} - -/** - * Update Existing Data into wsdesk_settings table. - * - * @param int|string $id Corresponding Settings ID that needs to be updated - * @param array $data (title,type,filter,vendor) - * @return bool True on success. False on failure. - */ -function eh_crm_update_settings( $id, $data ) { - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_settings'; - if ( ! $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'wsdesk_settings WHERE settings_id = %d', (int) $id ) ) ) { - return false; - } - $where = array( 'settings_id' => (int) $id ); - $result = $wpdb->update( $table, $data, $where ); - if ( ! $result ) { - return false; - } - return true; -} - -/** - * Delete Existing Data from wsdesk_settings table. - * - * @param int|string $id Corresponding Settings ID that needs to be deleted - * @return bool True on success. False on failure. - */ -function eh_crm_delete_settings( $id ) { - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_settings'; - $table_meta = $wpdb->prefix . 'wsdesk_settingsmeta'; - if ( ! $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'wsdesk_settings WHERE settings_id = %d', (int) $id ) ) ) { - return false; - } - $result = $wpdb->get_var( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_settings WHERE settings_id = %d', $id ) ); - $meta_query = $wpdb->get_var( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_settingsmeta WHERE settings_id = %d', $id ) ); - if ( ! $result ) { - return false; - } - return true; -} - -/** - * Get Existing Data into wsdesk_settings table. - * - * @param array $args (type,vendor,settings_id,slug,title,filter) | Filter By column and value Eg: array('settings_id'=>4) - * @param array|string $fields (type,vendor,settings_id,slug,title,filter) | Optional (Fields to return) - * @return array Filtered or provided ID data as key value pair - */ -function eh_crm_get_settings( $args, $fields = null ) { - set_time_limit( 300 ); - $query = wpFluent()->table( 'wsdesk_settings' ); - if ( null !== $fields ) { - $fields = is_array( $fields ) ? $fields : array( $fields ); - foreach ( $fields as $field ) { - $query->select( $field ); - } - } - - if ( is_array( $args ) ) { - foreach ( $args as $key => $value ) { - $allowed_fileds = array( 'type', 'vendor', 'settings_id', 'slug', 'title', 'filter' ); - if ( in_array( $key, $allowed_fileds, true ) ) { - $query->where( $key, $value ); - } - } - } - $data = array_map( - function ( $row ) { - return (array) $row; - }, - $query->get() - ); - - return $data; -} - -/** - * Insert Data into wsdesk_settingsmeta table. - * - * @param int|string $id settings ID - * @param string $key meta key - * @param string $value meta value - * @return bool True on success. False on failure. - */ -function eh_crm_insert_settingsmeta( $id, $key, $value ) { - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_settingsmeta'; - if ( $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'wsdesk_settingsmeta WHERE meta_key = %s AND settings_id = %d', $key, (int) $id ) ) ) { - return false; - } - if ( is_array( $value ) ) { - $data = serialize( $value ); - } else { - $data = $value; - } - $result = $wpdb->insert( - $table, - array( - 'settings_id' => (int) $id, - 'meta_key' => $key, - 'meta_value' => $data, - ) - ); - if ( ! $result ) { - return false; - } - return true; -} - -/** - * Update Data into wsdesk_settingsmeta table. - * - * @param int|string $id settings ID - * @param string $key meta key - * @param string $value meta value - * @return bool True on success. False on failure. - */ -function eh_crm_update_settingsmeta( $id, $key, $value ) { - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_settingsmeta'; - if ( ! $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'wsdesk_settingsmeta WHERE meta_key = %s AND settings_id = %d', $key, (int) $id ) ) ) { - $response = eh_crm_insert_settingsmeta( $id, $key, $value ); - if ( ! $response ) { - return false; - } - return true; - } - $where = array( - 'settings_id' => (int) $id, - 'meta_key' => $key, - ); - if ( is_array( $value ) ) { - $data = array( 'meta_value' => serialize( $value ) ); - } else { - $data = array( 'meta_value' => $value ); - } - $result = $wpdb->update( $table, $data, $where ); - if ( ! $result ) { - return false; - } - return true; -} - -/** - * Delete Data from wsdesk_settingsmeta table. - * - * @param int|string $id settings ID - * @param string $key meta key - * @return bool True on success. False on failure. - */ -function eh_crm_delete_settingsmeta( $id, $key ) { - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_settingsmeta'; - if ( ! $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'wsdesk_settingsmeta WHERE meta_key = %s AND settings_id = %d', $key, (int) $id ) ) ) { - return false; - } - $result = $wpdb->get_var( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_settingsmeta WHERE settings_id = %d AND meta_key = %s', $id, $key ) ); - if ( ! $result ) { - return false; - } - return true; -} - -/** - * Delete Data from wsdesk_settingsmeta table. - * - * @param int|string $id settings ID - * @param string $key meta key | Optional - * @return mixed ( If provided will return particular value or will return array of all meta of settings ID) - */ -function eh_crm_get_settingsmeta( $id, $key = null ) { - - $query = wpFluent()->table( 'wsdesk_settingsmeta' )->where( 'settings_id', $id ); - - if ( null !== $key ) { - $query->where( 'meta_key', $key ); - } - - $data = json_decode( wp_json_encode( $query->get() ), true ); - - if ( ! $data ) { - return false; - } - - if ( null !== $key ) { - return maybe_unserialize( $data[0]['meta_value'] ); - } - - $retrived = array(); - for ( $i = 0; $i < count( $data ); $i++ ) { - $retrived[ $data[ $i ]['meta_key'] ] = maybe_unserialize( $data[ $i ]['meta_value'] ); - } - - return $retrived; -} - -/** - * Insert Data into wsdesk_tickets table. - * - * @param array $args (ticket_title,ticket_email,ticket_content,ticket_category,ticket_vendor) - * @param array $meta (meta_key,meta_value) | Optional - * @return int The Tickets ID on success. The value 0 or false on failure. - */ -function eh_crm_insert_ticket( $args, $meta = array(), $import = false ) { - - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_tickets'; - $defaults = array( - 'ticket_author' => ( is_user_logged_in() ) ? get_current_user_id() : 0, - 'ticket_date' => gmdate( 'M d, Y h:i:s A' ), - 'ticket_updated' => current_time( 'mysql' ), - 'ticket_email' => '', - 'ticket_title' => '', - 'ticket_content' => '', - 'ticket_category' => '', - 'ticket_vendor' => '', - 'ticket_trash' => 0, - ); - - $data = wp_parse_args( $args, $defaults ); - - $result = $wpdb->insert( $table, $data ); - $ticket_id = (int) $wpdb->insert_id; - if ( ! $result ) { - return false; - } - if ( ! isset( $data['ticket_parent'] ) ) { - $meta['trigger_status'] = 'created'; - $meta['trigger_changes'] = 'none'; - } else { - eh_crm_update_ticket( $data['ticket_parent'], array( 'ticket_updated' => current_time( 'mysql' ) ) ); - // eh_crm_update_ticketmeta($data['ticket_parent'], "trigger_status", "updated"); - if ( 'raiser_reply' == $data['ticket_category'] ) { - eh_crm_update_ticketmeta( $data['ticket_parent'], 'ticket_submitted', 'raiser_reply', false ); - } else { - eh_crm_update_ticketmeta( $data['ticket_parent'], 'ticket_submitted', $data['ticket_author'], false ); - } - } - if ( ! empty( $meta ) ) { - foreach ( $meta as $key => $value ) { - eh_crm_insert_ticketmeta( $ticket_id, $key, $value ); - } - } - if ( ! $import ) { - eh_crm_get_trigger_check_ticket( $ticket_id ); - } - if ( ! $result ) { - return false; - } - return $ticket_id; -} - -/** - * Update Existing Data into wsdesk_tickets table. - * - * @param int|string $id Corresponding Settings ID that needs to be updated - * @param array $data (ticket_title,ticket_email,ticket_content,ticket_category,ticket_vendor) - * @return bool True on success. False on failure. - */ -function eh_crm_update_ticket( $id, $data ) { - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_tickets'; - if ( ! $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'wsdesk_tickets WHERE ticket_id = %d', (int) $id ) ) ) { - return false; - } - $where = array( 'ticket_id' => (int) $id ); - $result = $wpdb->update( $table, $data, $where ); - if ( ! $result ) { - return false; - } - return true; -} - -/** - * Trash Existing Data from wsdesk_tickets table. - * - * @param int|string $id Corresponding Settings ID that needs to be deleted - * @return bool True on success. False on failure. - */ -function eh_crm_trash_ticket( $id ) { - $result = eh_crm_update_ticket( $id, array( 'ticket_trash' => 1 ) ); - if ( ! $result ) { - return false; - } - return true; -} - -/** - * Restore Trash Existing Data from wsdesk_tickets table. - * - * @param int|string $id Corresponding Settings ID that needs to be deleted - * @return bool True on success. False on failure. - */ -function eh_crm_restore_trash_ticket( $id ) { - $result = eh_crm_update_ticket( $id, array( 'ticket_trash' => 0 ) ); - if ( ! $result ) { - return false; - } - return true; -} - -/** - * Delete Existing Data from wsdesk_tickets table. - * - * @param int|string $id Corresponding Settings ID that needs to be deleted - * @return bool True on success. False on failure. - */ -function eh_crm_delete_ticket( $id ) { - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_tickets'; - $table_meta = $wpdb->prefix . 'wsdesk_ticketsmeta'; - if ( ! $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'wsdesk_tickets WHERE ticket_id = %d', (int) $id ) ) ) { - return false; - } - $meta = eh_crm_get_ticketmeta( $id ); - if ( isset( $meta['ticket_attachment_path'] ) ) { - $attachment = $meta['ticket_attachment_path']; - for ( $i = 0;$i < count( $attachment );$i++ ) { - wp_delete_file( $attachment[ $i ] ); - } - } - $result = $wpdb->get_results( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta WHERE ticket_id = %d', $id ) ); - $result = $wpdb->get_results( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_tickets WHERE ticket_id = %d', $id ) ); - if ( ! $result ) { - return false; - } - return true; -} - -function eh_crm_get_ticket_archive_search( $value ) { - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_archived_tickets'; - $vendor = ''; - if ( EH_CRM_WOO_VENDOR ) { - $vendor = " AND ticket_vendor = '" . EH_CRM_WOO_VENDOR . "'"; - } - $data = $wpdb->get_results( $wpdb->prepare( 'SELECT ticket_id from ' . $wpdb->prefix . 'wsdesk_archived_tickets WHERE lower(concat(ticket_title,ticket_email)) LIKE lower(%s) AND ticket_trash = 0 AND ticket_parent=0 %s ORDER BY ticket_id DESC', ' % ' . $value . ' % ', $vendor ), ARRAY_A ); - if ( ! $data ) { - return array(); - } - return $data; -} - -function eh_crm_get_ticket_search( $value ) { - set_time_limit( 300 ); - $query = wpFluent()->table( 'wsdesk_tickets' ) - ->where( 'ticket_trash', 0 ) - ->where( 'ticket_parent', 0 ) - ->select( 'ticket_id' ); - - if ( EH_CRM_WOO_VENDOR ) { - $query->where( 'ticket_vendor', EH_CRM_WOO_VENDOR ); - } - - $query->where( - function ( $query ) use ( $value ) { - $query->orwhere( 'ticket_title', 'like', '%' . $value . '%' ); - $query->orWhere( 'ticket_email', 'like', '%' . $value . '%' ); - } - ); - - $data = array_map( - function( $ticket ) { - return (array) $ticket; - }, - $query->get() - ); - - return $data; -} -/** - * Get Existing Data into wsdesk_tickets table. - * - * @param array $args (ticket_title,ticket_email,ticket_content,ticket_category,ticket_vendor,ticket_parent) | ticket_email By column and value Eg: array('ticket_id'=>4) - * @param array|string $fields (ticket_title,ticket_email,ticket_content,ticket_category,ticket_vendor) | Optional (Fields to return) - * @return array Filtered or provided ID data as key value pair - */ -function eh_crm_get_ticket( $args, $fields = null ) { - set_time_limit( 300 ); - $query = wpFluent()->table( 'wsdesk_tickets' )->where( 'ticket_trash', 0 ); - - if ( null !== $fields ) { - $fields = is_array( $fields ) ? $fields : array( $fields ); - foreach ( $fields as $field ) { - $query->select( $field ); - } - } - - if ( is_array( $args ) ) { - foreach ( $args as $key => $value ) { - $allowed_fileds = array( 'ticket_id', 'ticket_author', 'ticket_email', 'ticket_date', 'ticket_title', 'ticket_parent', 'ticket_category', 'ticket_vendor', 'ticket_trash' ); - if ( in_array( $key, $allowed_fileds, true ) ) { - $query->where( $key, $value ); - } - } - } - - $ticket = (array) $query->first(); - - if ( ! $ticket ) { - return false; - } - - if ( isset( $ticket['ticket_content'] ) ) { - $ticket['ticket_content'] = wp_kses_post( $ticket['ticket_content'] ); - } - - return array( $ticket ); -} - -function get_ticketsmeta_data( $ticket_id ) { - global $wpdb; - $ticketsmeta = $wpdb->get_results( $wpdb->prepare( 'SELECT meta_value, meta_key from ' . $wpdb->prefix . 'wsdesk_ticketsmeta WHERE ticket_id=%s', $ticket_id ), ARRAY_A ); - return $ticketsmeta; -} -function get_child_ticket_data( $ticket_id ) { - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_tickets'; - $child_tickets = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM ' . $wpdb->prefix . 'wsdesk_tickets WHERE ticket_parent = %s', $ticket_id ), ARRAY_A ); - foreach ( $child_tickets as $key => $child_ticket ) { - $child_meta = get_ticketsmeta_data( $child_ticket['ticket_id'] ); - $child_tickets[ $key ]['child_meta'] = $child_meta; - } - return $child_tickets; -} - -/** - * Get Existing Data into wsdesk_tickets table. - * - * @param array $args (ticket_title,ticket_email,ticket_content,ticket_category,ticket_vendor,ticket_parent) | ticket_email By column and value Eg: array('ticket_id'=>4) - * @param array|string $fields (ticket_title,ticket_email,ticket_content,ticket_category,ticket_vendor) | Optional (Fields to return) - * @return array Filtered or provided ID data as key value pair - */ -function eh_crm_get_ticket_archive( $args, $fields = null ) { - set_time_limit( 300 ); - $query = wpFluent()->table( 'wsdesk_archived_tickets' )->where( 'ticket_trash', 0 ); - - if ( null !== $fields ) { - $fields = is_array( $fields ) ? $fields : array( $fields ); - foreach ( $fields as $field ) { - $query->select( $field ); - } - } - - if ( is_array( $args ) ) { - foreach ( $args as $key => $value ) { - $allowed_fileds = array( 'ticket_id', 'ticket_author', 'ticket_email', 'ticket_date', 'ticket_title', 'ticket_parent', 'ticket_category', 'ticket_vendor', 'ticket_trash' ); - if ( in_array( $key, $allowed_fileds, true ) ) { - $query->where( $key, $value ); - } - } - } - - $ticket = (array) $query->first(); - - if ( ! $ticket ) { - return false; - } - - if ( isset( $ticket['ticket_content'] ) ) { - $ticket['ticket_content'] = wp_kses_post( $ticket['ticket_content'] ); - } - - return array( $ticket ); - - set_time_limit( 300 ); - $args['ticket_trash'] = 0; - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_archived_tickets'; - $query_search = ''; - $query_field = ''; - if ( null !== $fields ) { - if ( is_array( $fields ) ) { - $query_field = implode( ',', $fields ); - } else { - $query_field = $fields; - } - } else { - $query_field = '*'; - } - if ( is_array( $args ) ) { - $a = 1; - foreach ( $args as $key => $value ) { - switch ( $key ) { - case 'ticket_id': - if ( is_array( $args['ticket_id'] ) ) { - $query_search .= 'ticket_id in (' . implode( ',', $args['ticket_id'] ) . ')'; - } else { - $query_search .= 'ticket_id = ' . (int) $args['ticket_id']; - } - break; - case 'ticket_author': - $query_search .= "ticket_author = '" . $args['ticket_author'] . "'"; - break; - case 'ticket_email': - $query_search .= "ticket_email = '" . $args['ticket_email'] . "'"; - break; - case 'ticket_date': - $query_search .= "ticket_date = '" . $args['ticket_date'] . "'"; - break; - case 'ticket_title': - $query_search .= "ticket_title = '" . $args['ticket_title'] . "'"; - break; - case 'ticket_parent': - $query_search .= "ticket_parent = '" . $args['ticket_parent'] . "'"; - break; - case 'ticket_category': - $query_search .= "ticket_category = '" . $args['ticket_category'] . "'"; - break; - case 'ticket_vendor': - $query_search .= "ticket_vendor = '" . $args['ticket_vendor'] . "'"; - break; - case 'ticket_trash': - $query_search .= "ticket_trash = '" . $args['ticket_trash'] . "'"; - break; - default: - break; - } - if ( $a < count( array_keys( $args ) ) ) { - $query_search .= ' AND '; - $a++; - } - } - } - $data = $wpdb->get_results( $wpdb->prepare( 'SELECT %s from ' . $wpdb->prefix . 'wsdesk_archived_tickets WHERE %s', $query_field, $query_search ), ARRAY_A ); - if ( ! $data ) { - return false; - } - if ( isset( $data[0]['ticket_content'] ) ) { - $data[0]['ticket_content'] = preg_replace( '/<((script)[^>]*)>(.*)\<\/(script)>/Us', '<$1>$3</script>', $data[0]['ticket_content'] ); - $data[0]['ticket_content'] = htmlentities( $data[0]['ticket_content'] ); - } - return $data; -} - -/** - * Insert Data into wsdesk_ticketsmeta table. - * - * @param int|string $id ticket ID - * @param string $key meta key - * @param string $value meta value - * @return bool True on success. False on failure. - */ -function eh_crm_insert_ticketmeta( $id, $key, $value ) { - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_ticketsmeta'; - $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) from ' . $wpdb->prefix . 'wsdesk_ticketsmeta WHERE meta_key = %s AND ticket_id = %s', $key, (int) $id ), ARRAY_A ); - if ( is_array( $value ) ) { - $data = serialize( $value ); - } else { - $data = $value; - } - $result = $wpdb->insert( - $table, - array( - 'ticket_id' => (int) $id, - 'meta_key' => $key, - 'meta_value' => $data, - ) - ); - if ( ! $result ) { - return false; - } - return true; -} - -/** - * Update Data into wsdesk_ticketsmeta table. - * - * @param int|string $id ticket ID - * @param string $key meta key - * @param string $value meta value - * @return bool True on success. False on failure. - */ -function eh_crm_update_ticketmeta( $id, $key, $value, $avoid = true ) { - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_ticketsmeta'; - if ( ! $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta WHERE meta_key = %s AND ticket_id = %d', $key, (int) $id ) ) ) { - $response = eh_crm_insert_ticketmeta( $id, $key, $value ); - if ( ! $response ) { - return false; - } - return true; - } - $existing = eh_crm_get_ticketmeta( $id, $key ); - if ( is_array( $existing ) && is_array( $value ) ) { - $array_diff = array_diff( $value, $existing ); - if ( empty( $array_diff ) ) { - $avoid = false; - } - } else { - if ( $value == $existing ) { - $avoid = false; - } - } - $where = array( - 'ticket_id' => (int) $id, - 'meta_key' => $key, - ); - if ( is_array( $value ) ) { - $data = array( 'meta_value' => serialize( $value ) ); - } else { - $data = array( 'meta_value' => $value ); - } - $payload = [ - 'ticket_id' => $id, - 'meta_key' => $key, - 'meta_value' => $value, - ]; - if ( $avoid ) { - /** - * Trigger an action before update meta with payload - * - * @since 3.1.2 - * - * @param $payload - * - */ - do_action( 'wsdesk_before_add_update_ticket_meta', $payload ); - } - $result = $wpdb->update( $table, $data, $where ); - if ( $avoid ) { - $payload = [ - 'ticket_id' => $id, - 'meta_key' => $key, - 'meta_value' => $value, - ]; - - /** - * Trigger an action on update meta with payload - * - * @since 3.1.2 - * - * @param $payload - * - */ - do_action( 'wsdesk_on_add_update_ticket_meta', $payload ); - eh_crm_trigger_status_update( $id, $key ); - } - if ( ! $result ) { - return false; - } - return true; -} - -function eh_crm_trigger_status_update( $id, $key ) { - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_ticketsmeta'; - if ( ! $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(ticket_id) FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta WHERE meta_key = "trigger_status" AND ticket_id = %d', (int) $id ) ) ) { - eh_crm_insert_ticketmeta( $id, 'trigger_status', 'updated' ); - } - $value = 'updated'; - $where = array( - 'ticket_id' => (int) $id, - 'meta_key' => 'trigger_status', - ); - $data = array( 'meta_value' => $value ); - $result = $wpdb->update( $table, $data, $where ); - - if ( 'ticket_label' === $key || 'ticket_assignee' === $key || 'ticket_tags' === $key ) { - if ( ! $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta WHERE meta_key = "trigger_changes" AND ticket_id = %d', (int) $id ) ) ) { - eh_crm_insert_ticketmeta( $id, 'trigger_changes', $key ); - } - $where = array( - 'ticket_id' => (int) $id, - 'meta_key' => 'trigger_changes', - ); - $data = array( 'meta_value' => $key ); - $result = $wpdb->update( $table, $data, $where ); - } - eh_crm_get_trigger_check_ticket( $id ); - if ( ! $result ) { - return false; - } - return true; -} - -/** - * Delete Data from wsdesk_ticketsmeta table. - * - * @param int|string $id ticket ID - * @param string $key meta key - * @return bool True on success. False on failure. - */ -function eh_crm_delete_ticketmeta( $id, $key ) { - set_time_limit( 300 ); - global $wpdb; - $table = $wpdb->prefix . 'wsdesk_ticketsmeta'; - if ( ! $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta WHERE meta_key = %s AND ticket_id = %d', $key, (int) $id ) ) ) { - return false; - } - $result = $wpdb->get_results( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta WHERE ticket_id = %d AND meta_key = %s', $id, $key ) ); - if ( ! $result ) { - return false; - } - return true; -} - -/** - * Delete Data from wsdesk_ticketsmeta table. - * - * @param int|string $id ticket ID - * @param string $key meta key | Optional - * @return mixed ( If provided will return particular value or will return array of all meta of ticket ID) - */ -function eh_crm_get_ticketmeta_archive( $id, $key = null ) { - set_time_limit( 300 ); - global $wpdb; - $data = $wpdb->get_results( $wpdb->prepare( 'SELECT meta_key,meta_value FROM ' . $wpdb->prefix . 'wsdesk_archived_ticketsmeta WHERE ticket_id = %d', (int) $id ), ARRAY_A ); - $retrived = array(); - if ( null !== $key ) { - $data = $wpdb->get_results( $wpdb->prepare( 'SELECT meta_key,meta_value FROM ' . $wpdb->prefix . 'wsdesk_archived_ticketsmeta WHERE ticket_id = %d AND meta_key = %s', (int) $id, $key ), ARRAY_A ); - } - if ( ! $data ) { - return false; - } - if ( null !== $key ) { - return is_serialized( $data[0]['meta_value'] ) ? unserialize( $data[0]['meta_value'] ) : $data[0]['meta_value']; - } - for ( $i = 0; $i < count( $data ); $i++ ) { - $retrived[ $data[ $i ]['meta_key'] ] = is_serialized( $data[ $i ]['meta_value'] ) ? unserialize( $data[ $i ]['meta_value'] ) : $data[ $i ]['meta_value']; - } - return is_serialized( $retrived ) ? unserialize( $retrived ) : $retrived; -} - -/** - * Delete Data from wsdesk_ticketsmeta table. - * - * @param int|string $id ticket ID - * @param string $key meta key | Optional - * @return mixed ( If provided will return particular value or will return array of all meta of ticket ID) - */ -function eh_crm_get_ticketmeta( $id, $key = null ) { - set_time_limit( 300 ); - global $wpdb; - $data = $wpdb->get_results( $wpdb->prepare( 'SELECT meta_key,meta_value FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta WHERE ticket_id = %d', (int) $id ), ARRAY_A ); - $retrived = array(); - if ( null !== $key ) { - $data = $wpdb->get_results( $wpdb->prepare( 'SELECT meta_key,meta_value FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta WHERE ticket_id = %d AND meta_key = %s', (int) $id, $key ), ARRAY_A ); - } - if ( ! $data ) { - return false; - } - if ( null !== $key ) { - return maybe_unserialize( $data[0]['meta_value'] ); - } - for ( $i = 0; $i < count( $data ); $i++ ) { - $retrived[ $data[ $i ]['meta_key'] ] = maybe_unserialize( $data[ $i ]['meta_value'] ); - } - return maybe_unserialize( $retrived ); -} - -function eh_crm_get_vendor_tickets() { - set_time_limit( 300 ); - global $wpdb; - - if ( EH_CRM_WOO_VENDOR ) { - $data = $wpdb->get_results( $wpdb->prepare( 'SELECT ticket_id FROM ' . $wpdb->prefix . 'wsdesk_tickets WHERE ticket_vendor = %s', EH_CRM_WOO_VENDOR ), ARRAY_A ); - } else { - $data = $wpdb->get_results( 'SELECT ticket_id FROM ' . $wpdb->prefix . 'wsdesk_tickets', ARRAY_A ); - } - - $id = array(); - if ( ! $data ) { - return array(); - } else { - for ( $i = 0; $i < count( $data ); $i++ ) { - array_push( $id, $data[ $i ]['ticket_id'] ); - } - } - return $id; -} - -/** - * Get Value Count Data from wsdesk_ticketsmeta table. - * - * @param string $key meta key - * @param string $value meta value - * @param string $order order by value - * @param string $type Desc by default (sort type) - * @param string $limit limit number of rows - * @param string $offset starting from - * @return array (Returns all match ticket_id) - */ -function eh_crm_get_ticketmeta_value_count( $key, $value, $order = 'ticket_id', $type = 'DESC', $limit = 0, $offset = 0 ) { - set_time_limit( 300 ); - $where = ''; - $id = array(); - $return_id = array(); - if ( null !== $key ) { - $where = "meta_key = '%s'"; - if ( '' !== $order ) { - $where .= ' ORDER BY ' . $order; - } - if ( '' !== $type ) { - $where .= ' ' . $type; - } - } - $vendor_id = eh_crm_get_vendor_tickets(); - $query = wpFluent()->table( 'wsdesk_ticketsmeta' )->join( 'wsdesk_tickets', 'wsdesk_tickets.ticket_id', '=', 'wsdesk_ticketsmeta.ticket_id' ); - - $query->where( 'meta_key', $key ); - $query->where( 'wsdesk_tickets.ticket_trash', 0 ); - - if ( '' !== $order && '' !== $type ) { - $query->orderBy( $order, $type ); - } - - $query->select( array( 'wsdesk_ticketsmeta.ticket_id', 'wsdesk_ticketsmeta.meta_value' ) ); - - $results = $query->get(); - - $data = array(); - foreach ( (array) $results as $row ) { - $data[] = get_object_vars( $row ); - } - - unset( $results ); - - if ( ! $data ) { - return array(); - } else { - for ( $i = 0; $i < count( $data ); $i++ ) { - if ( in_array( $data[ $i ]['ticket_id'], $vendor_id ) ) { - $meta_value = is_serialized( $data[ $i ]['meta_value'] ) ? unserialize( $data[ $i ]['meta_value'] ) : $data[ $i ]['meta_value']; - if ( is_array( $meta_value ) ) { - if ( in_array( $value, $meta_value ) ) { - array_push( $id, array( 'ticket_id' => $data[ $i ]['ticket_id'] ) ); - } elseif ( is_array( $value ) ) { - if ( $meta_value === $value ) { - array_push( $id, array( 'ticket_id' => $data[ $i ]['ticket_id'] ) ); - } - } - } else { - if ( $meta_value === $value ) { - array_push( $id, array( 'ticket_id' => $data[ $i ]['ticket_id'] ) ); - } - } - } - } - if ( 0 != $limit ) { - $return_id = array_slice( $id, $offset, $limit ); - } else { - $return_id = $id; - } - } - return $return_id; -} - -/** - * Get Value Count Data from wsdesk_ticketsmeta table. - * - * @param string $key meta key - * @param string $value meta value - * @param string $order order by value - * @param string $type Desc by default (sort type) - * @param string $limit limit number of rows - * @param string $offset starting from - * @return array (Returns all match ticket_id) - */ -function eh_crm_get_ticketmeta_value_count_archive( $key, $value, $order = 'ticket_id', $type = 'DESC', $limit = 0, $offset = 0 ) { - set_time_limit( 300 ); - global $wpdb; - $tablemeta = $wpdb->prefix . 'wsdesk_archived_ticketsmeta'; - $table = $wpdb->prefix . 'wsdesk_archived_tickets'; - $where = ''; - $id = array(); - $return_id = array(); - if ( null !== $key ) { - $where = "meta_key = '%s'"; - if ( '' !== $order ) { - $where .= ' ORDER BY ' . $order; - } - if ( '' !== $type ) { - $where .= ' ' . $type; - } - } - $vendor_id = eh_crm_get_vendor_tickets(); - $data = $wpdb->get_results( $wpdb->prepare( 'SELECT m.ticket_id,m.meta_value FROM ' . $wpdb->prefix . 'wsdesk_ticketsmeta m JOIN ' . $wpdb->prefix . 'wsdesk_tickets f ON m.ticket_id = f.ticket_id WHERE m.meta_key = %s AND f.ticket_trash=0 ORDER BY f.%s %s', $key, $order, $type ), ARRAY_A ); - if ( ! $data ) { - return array(); - } else { - for ( $i = 0; $i < count( $data ); $i++ ) { - if ( in_array( $data[ $i ]['ticket_id'], $vendor_id ) ) { - $meta_value = is_serialized( $data[ $i ]['meta_value'] ) ? unserialize( $data[ $i ]['meta_value'] ) : $data[ $i ]['meta_value']; - if ( is_array( $meta_value ) ) { - if ( in_array( $value, $meta_value ) ) { - array_push( $id, array( 'ticket_id' => $data[ $i ]['ticket_id'] ) ); - } elseif ( is_array( $value ) ) { - if ( $meta_value === $value ) { - array_push( $id, array( 'ticket_id' => $data[ $i ]['ticket_id'] ) ); - } - } - } else { - if ( $meta_value === $value ) { - array_push( $id, array( 'ticket_id' => $data[ $i ]['ticket_id'] ) ); - } - } - } - } - if ( 0 != $limit ) { - $return_id = array_slice( $id, $offset, $limit ); - } else { - $return_id = $id; - } - } - return $return_id; -} - -/** - * Get Value Count Data from wsdesk_ticketsmeta table. - * - * @param string $key tickets key - * @param string $value tickets value - * @param string $not (check not equal to) | Default False - * @param string $exp_key tickets key - * @param string $exp_value tickets value - * @param string $order order by value - * @param string $type Desc by default (sort type) - * @param string $limit limit number of rows
Vulnerability Existed: not sure SQL Injection - CWE-89 - includes/class-crm-public-functions.php - Line 280 Old Code: ```php $data = $wpdb->get_results( $wpdb->prepare( 'SELECT ticket_id from ' . $wpdb->prefix . 'wsdesk_archived_tickets WHERE lower(concat(ticket_title,ticket_email)) LIKE lower(%s) AND ticket_trash = 0 AND ticket_parent=0 %s ORDER BY ticket_id DESC', ' % ' . $value . ' % ', $vendor ), ARRAY_A ); ``` Fixed Code: ```php (No changes in diff for this section) ``` Explanation: The code uses $wpdb->prepare() which provides parameterized query protection. However, the $vendor variable is concatenated directly into the query string without being part of the prepare placeholders. When EH_CRM_WOO_VENDOR is set, $vendor contains an unescaped string like `" AND ticket_vendor = '" . EH_CRM_WOO_VENDOR . "'"` which is concatenated into the SQL query. This bypasses the protection of prepare() and creates a SQL injection vulnerability. The diff does not show any fix for this issue, so the vulnerability likely persists in version 3.3.5. --- Vulnerability Existed: no SQL Injection - CWE-89 - includes/class-crm-public-functions.php - Line 600+ Old Code: ```php $query_search .= "ticket_author = '" . $args['ticket_author'] . "'"; $query_search .= "ticket_email = '" . $args['ticket_email'] . "'"; $query_search .= "ticket_date = '" . $args['ticket_date'] . "'"; // ... and similar concatenations $data = $wpdb->get_results( $wpdb->prepare( 'SELECT %s from ' . $wpdb->prefix . 'wsdesk_archived_tickets WHERE %s', $query_field, $query_search ), ARRAY_A ); ``` Fixed Code: ```php (No visible fix in provided diff) ``` Explanation: The entire section after line 594 appears to be unreachable dead code (it comes after a return statement). This code contains SQL injection vulnerabilities due to direct string concatenation with user input, but since it's unreachable dead code, it doesn't pose an active security risk in practice. The diff does not show this code being removed, which means the dead code vulnerability persists, though it's not exploitable in the current execution flow.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-settings-handler.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-settings-handler.php 2025-12-21 09:36:35.231291286 +0000@@ -1,48 +1,48 @@-<?php - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -class EH_CRM_Settings_Handler { - - public function eh_crm_tickets_main_menu_callback() { - include EH_CRM_MAIN_VIEWS . 'crm_tickets_view.php' ; - } - - public function eh_crm_settings_sub_menu_callback() { - include EH_CRM_MAIN_VIEWS . 'crm_settings_view.php' ; - } - - public function eh_crm_agents_sub_menu_callback() { - include EH_CRM_MAIN_VIEWS . 'crm_agents_view.php' ; - } - - public function eh_crm_reports_sub_menu_callback() { - include EH_CRM_MAIN_VIEWS . 'crm_reports_v2.php' ; - } - - public function eh_crm_new_reports_sub_menu_callback() { - include EH_CRM_MAIN_VIEWS . 'crm_reports_v3.php' ; - } - - public function eh_crm_premium_sub_menu_callback() { - include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_premium.php' ; - } - - public function eh_crm_email_sub_menu_callback() { - if ( isset( $_GET['code'] ) ) { - $code = sanitize_text_field( $_GET['code'] ); - $oauth_obj = new EH_CRM_OAuth(); - $oauth_obj->get_token_uri( $code, 'code' ); - } - include EH_CRM_MAIN_VIEWS . 'crm_email_view.php' ; - } - - public function eh_crm_import_sub_menu_callback() { - include EH_CRM_MAIN_VIEWS . 'crm_import_view.php' ; - } - public function eh_crm_archive_sub_menu_callback() { - include EH_CRM_MAIN_VIEWS . 'crm_archive_tickets_view.php' ; - } -} +<?php++if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++class EH_CRM_Settings_Handler {++ public function eh_crm_tickets_main_menu_callback() {+ include EH_CRM_MAIN_VIEWS . 'crm_tickets_view.php' ;+ }++ public function eh_crm_settings_sub_menu_callback() {+ include EH_CRM_MAIN_VIEWS . 'crm_settings_view.php' ;+ }++ public function eh_crm_agents_sub_menu_callback() {+ include EH_CRM_MAIN_VIEWS . 'crm_agents_view.php' ;+ }++ public function eh_crm_reports_sub_menu_callback() {+ include EH_CRM_MAIN_VIEWS . 'crm_reports_v2.php' ;+ }++ public function eh_crm_new_reports_sub_menu_callback() {+ include EH_CRM_MAIN_VIEWS . 'crm_reports_v3.php' ;+ }++ public function eh_crm_premium_sub_menu_callback() {+ include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_premium.php' ;+ }++ public function eh_crm_email_sub_menu_callback() {+ if ( isset( $_GET['code'] ) ) {+ $code = sanitize_text_field( $_GET['code'] );+ $oauth_obj = new EH_CRM_OAuth();+ $oauth_obj->get_token_uri( $code, 'code' );+ }+ include EH_CRM_MAIN_VIEWS . 'crm_email_view.php' ;+ }++ public function eh_crm_import_sub_menu_callback() {+ include EH_CRM_MAIN_VIEWS . 'crm_import_view.php' ;+ }+ public function eh_crm_archive_sub_menu_callback() {+ include EH_CRM_MAIN_VIEWS . 'crm_archive_tickets_view.php' ;+ }+}
Vulnerability Existed: no No Security Vulnerabilities Detected Explanation: The diff shows only whitespace and line ending changes (CRLF to LF conversion). The actual code content remains identical between versions 3.3.4 and 3.3.5. No functional code modifications were made, no new security measures were implemented, and no vulnerabilities were fixed or introduced. This is a cosmetic change normalizing line endings in the file.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/class-crm-update-version.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/class-crm-update-version.php 2025-12-21 09:36:35.231291286 +0000@@ -1,48 +1,48 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -class EH_CRM_Update_Version { - - - public function __construct() { - $this->date_updated_check(); - $this->trash_updated_check(); - $this->role_updated_check(); - $this->update_settings_meta(); - } - public function date_updated_check() { - global $wpdb; - if ( $wpdb->get_var( 'SHOW COLUMNS FROM ' . $wpdb->prefix . 'wsdesk_tickets' . " LIKE 'ticket_updated'" ) ) { - return false; - } - $wpdb->query( 'ALTER TABLE ' . $wpdb->prefix . 'wsdesk_tickets ADD `ticket_updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `ticket_date`;' ); - } - public function role_updated_check() { - $role = get_role( 'WSDesk_Agents' ); - if ( $role ) { - if ( isset( $role->capabilities ) && in_array( 'view_admin_dashboard', $role->capabilities ) ) { - $role->add_cap( 'view_admin_dashboard', true ); - } - } - $role = get_role( 'WSDesk_Supervisor' ); - if ( $role ) { - if ( isset( $role->capabilities ) && in_array( 'view_admin_dashboard', $role->capabilities ) ) { - $role->add_cap( 'view_admin_dashboard', true ); - } - } - } - public function update_settings_meta() { - if ( eh_crm_get_settingsmeta( 0, 'auto_send_creation_email' ) === false ) { - eh_crm_update_settingsmeta( 0, 'auto_send_creation_email', 'enable' ); - } - } - public function trash_updated_check() { - global $wpdb; - if ( $wpdb->get_var( 'SHOW COLUMNS FROM ' . $wpdb->prefix . 'wsdesk_tickets' . " LIKE 'ticket_trash'" ) ) { - return false; - } - $wpdb->query( 'ALTER TABLE ' . $wpdb->prefix . 'wsdesk_tickets ADD `ticket_trash` INT NOT NULL DEFAULT 0 AFTER `ticket_vendor`;' ); - } -} +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++class EH_CRM_Update_Version {+++ public function __construct() {+ $this->date_updated_check();+ $this->trash_updated_check();+ $this->role_updated_check();+ $this->update_settings_meta();+ }+ public function date_updated_check() {+ global $wpdb;+ if ( $wpdb->get_var( 'SHOW COLUMNS FROM ' . $wpdb->prefix . 'wsdesk_tickets' . " LIKE 'ticket_updated'" ) ) {+ return false;+ }+ $wpdb->query( 'ALTER TABLE ' . $wpdb->prefix . 'wsdesk_tickets ADD `ticket_updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `ticket_date`;' );+ }+ public function role_updated_check() {+ $role = get_role( 'WSDesk_Agents' );+ if ( $role ) {+ if ( isset( $role->capabilities ) && in_array( 'view_admin_dashboard', $role->capabilities ) ) {+ $role->add_cap( 'view_admin_dashboard', true );+ }+ } + $role = get_role( 'WSDesk_Supervisor' );+ if ( $role ) {+ if ( isset( $role->capabilities ) && in_array( 'view_admin_dashboard', $role->capabilities ) ) {+ $role->add_cap( 'view_admin_dashboard', true );+ }+ }+ }+ public function update_settings_meta() {+ if ( eh_crm_get_settingsmeta( 0, 'auto_send_creation_email' ) === false ) {+ eh_crm_update_settingsmeta( 0, 'auto_send_creation_email', 'enable' );+ }+ }+ public function trash_updated_check() {+ global $wpdb;+ if ( $wpdb->get_var( 'SHOW COLUMNS FROM ' . $wpdb->prefix . 'wsdesk_tickets' . " LIKE 'ticket_trash'" ) ) {+ return false;+ }+ $wpdb->query( 'ALTER TABLE ' . $wpdb->prefix . 'wsdesk_tickets ADD `ticket_trash` INT NOT NULL DEFAULT 0 AFTER `ticket_vendor`;' );+ }+}
Vulnerability Existed: not sure SQL Injection - CWE-89 - includes/class-crm-update-version.php Lines 18, 44 [Old Code] $wpdb->query( 'SHOW COLUMNS FROM ' . $wpdb->prefix . 'wsdesk_tickets' . " LIKE 'ticket_updated'" ) $wpdb->query( 'ALTER TABLE ' . $wpdb->prefix . 'wsdesk_tickets ADD `ticket_updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `ticket_date`;' ) $wpdb->query( 'SHOW COLUMNS FROM ' . $wpdb->prefix . 'wsdesk_tickets' . " LIKE 'ticket_trash'" ) $wpdb->query( 'ALTER TABLE ' . $wpdb->prefix . 'wsdesk_tickets ADD `ticket_trash` INT NOT NULL DEFAULT 0 AFTER `ticket_vendor`;' ) [Fixed Code] No changes detected - code remains identical between versions Explanation: The diff shows only whitespace/line ending changes (CRLF to LF conversion). No actual code logic was modified. The SQL queries still contain potential SQL injection vulnerabilities because they use string concatenation with $wpdb->prefix without proper preparation. While $wpdb->prefix is controlled by WordPress, the column names and table operations are hardcoded. However, since no actual security fix was applied in this version update, and the queries use only internal WordPress constants, the risk is limited. The code would benefit from using $wpdb->prepare() for dynamic query construction, but this patch does not address any security issues - it only reformats line endings.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/recaptcha.php 2025-12-21 09:35:59.425065817 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/recaptcha.php 2025-12-21 09:36:35.231291286 +0000@@ -1,139 +1,139 @@-<?php -/** - * This is a PHP library that handles calling reCAPTCHA. - * - Documentation and latest version - * https://developers.google.com/recaptcha/docs/php - * - Get a reCAPTCHA API Key - * https://www.google.com/recaptcha/admin/create - * - Discussion group - * http://groups.google.com/group/recaptcha - * - * @link http://www.google.com/recaptcha - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/** - * A ReCaptchaResponse is returned from checkAnswer(). - */ -class ReCaptchaResponse { - - - public $success; - public $errorCodes; -} - -class ReCaptcha { - - - private static $_signupUrl = 'https://www.google.com/recaptcha/admin'; - private static $_siteVerifyUrl = - 'https://www.google.com/recaptcha/api/siteverify?'; - private $_secret; - private static $_version = 'php_1.0'; - - /** - * Constructor. - * - * @param string $secret shared secret between site and ReCAPTCHA server. - */ - public function __construct( $secret ) { - if ( null == $secret || '' == $secret ) { - die( - "To use reCAPTCHA you must get an API key from <a href='" - . esc_url( self::$_signupUrl ) . "'>" . esc_url( self::$_signupUrl ) . '</a>' - ); - } - $this->_secret = $secret; - } - public function ReCaptcha() { - self::__construct( '' ); - } - /** - * Encodes the given data into a query string format. - * - * @param array $data array of string elements to be encoded. - * - * @return string - encoded request. - */ - private function _encodeQS( $data ) { - $req = ''; - foreach ( $data as $key => $value ) { - $req .= $key . '=' . urlencode( stripslashes( $value ) ) . '&'; - } - - // Cut the last '&' - $req = substr( $req, 0, strlen( $req ) - 1 ); - return $req; - } - - /** - * Submits an HTTP GET to a reCAPTCHA server. - * - * @param string $path url path to recaptcha server. - * @param array $data array of parameters to be sent. - * - * @return array response - */ - private function _submitHTTPGet( $path, $data ) { - $req = $this->_encodeQS( $data ); - $response = file_get_contents( $path . $req ); - return $response; - } - - /** - * Calls the reCAPTCHA siteverify API to verify whether the user passes - * CAPTCHA test. - * - * @param string $remoteIp IP address of end user. - * @param string $response response string from recaptcha verification. - * - * @return ReCaptchaResponse - */ - public function verifyResponse( $remoteIp, $response ) { - // Discard empty solution submissions - if ( null == $response || strlen( $response ) == 0 ) { - $recaptchaResponse = new ReCaptchaResponse(); - $recaptchaResponse->success = false; - $recaptchaResponse->errorCodes = 'missing-input'; - return $recaptchaResponse; - } - - $getResponse = $this->_submitHttpGet( - self::$_siteVerifyUrl, - array( - 'secret' => $this->_secret, - 'remoteip' => $remoteIp, - 'v' => self::$_version, - 'response' => $response, - ) - ); - $answers = json_decode( $getResponse, true ); - $recaptchaResponse = new ReCaptchaResponse(); - - if ( trim( $answers ['success'] ) == true ) { - $recaptchaResponse->success = true; - } else { - $recaptchaResponse->success = false; - $recaptchaResponse->errorCodes = $answers [ error - codes ]; - } - - return $recaptchaResponse; - } -} +<?php+/**+ * This is a PHP library that handles calling reCAPTCHA.+ * - Documentation and latest version+ * https://developers.google.com/recaptcha/docs/php+ * - Get a reCAPTCHA API Key+ * https://www.google.com/recaptcha/admin/create+ * - Discussion group+ * http://groups.google.com/group/recaptcha+ *+ * @link http://www.google.com/recaptcha+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */++/**+ * A ReCaptchaResponse is returned from checkAnswer().+ */+class ReCaptchaResponse {+++ public $success;+ public $errorCodes;+}++class ReCaptcha {+++ private static $_signupUrl = 'https://www.google.com/recaptcha/admin';+ private static $_siteVerifyUrl =+ 'https://www.google.com/recaptcha/api/siteverify?';+ private $_secret;+ private static $_version = 'php_1.0';++ /**+ * Constructor.+ *+ * @param string $secret shared secret between site and ReCAPTCHA server.+ */+ public function __construct( $secret ) {+ if ( null == $secret || '' == $secret ) {+ die(+ "To use reCAPTCHA you must get an API key from <a href='"+ . esc_url( self::$_signupUrl ) . "'>" . esc_url( self::$_signupUrl ) . '</a>'+ );+ }+ $this->_secret = $secret;+ }+ public function ReCaptcha() {+ self::__construct( '' );+ }+ /**+ * Encodes the given data into a query string format.+ *+ * @param array $data array of string elements to be encoded.+ *+ * @return string - encoded request.+ */+ private function _encodeQS( $data ) {+ $req = '';+ foreach ( $data as $key => $value ) {+ $req .= $key . '=' . urlencode( stripslashes( $value ) ) . '&';+ }++ // Cut the last '&'+ $req = substr( $req, 0, strlen( $req ) - 1 );+ return $req;+ }++ /**+ * Submits an HTTP GET to a reCAPTCHA server.+ *+ * @param string $path url path to recaptcha server.+ * @param array $data array of parameters to be sent.+ *+ * @return array response+ */+ private function _submitHTTPGet( $path, $data ) {+ $req = $this->_encodeQS( $data );+ $response = file_get_contents( $path . $req );+ return $response;+ }++ /**+ * Calls the reCAPTCHA siteverify API to verify whether the user passes+ * CAPTCHA test.+ *+ * @param string $remoteIp IP address of end user.+ * @param string $response response string from recaptcha verification.+ *+ * @return ReCaptchaResponse+ */+ public function verifyResponse( $remoteIp, $response ) {+ // Discard empty solution submissions+ if ( null == $response || strlen( $response ) == 0 ) {+ $recaptchaResponse = new ReCaptchaResponse();+ $recaptchaResponse->success = false;+ $recaptchaResponse->errorCodes = 'missing-input';+ return $recaptchaResponse;+ }++ $getResponse = $this->_submitHttpGet(+ self::$_siteVerifyUrl,+ array(+ 'secret' => $this->_secret,+ 'remoteip' => $remoteIp,+ 'v' => self::$_version,+ 'response' => $response,+ )+ );+ $answers = json_decode( $getResponse, true );+ $recaptchaResponse = new ReCaptchaResponse();++ if ( trim( $answers ['success'] ) == true ) {+ $recaptchaResponse->success = true;+ } else {+ $recaptchaResponse->success = false;+ $recaptchaResponse->errorCodes = $answers [ error - codes ];+ }++ return $recaptchaResponse;+ }+}
Vulnerability Existed: no No Security Vulnerabilities Detected - [File] includes/recaptcha.php [Lines 1-139] Old Code: (All 139 lines - identical content) Fixed Code: (All 139 lines - identical content) Explanation: This diff contains only line ending changes (conversion from CRLF to LF or similar whitespace normalization). There are no functional code changes, security patches, or vulnerability fixes present. The actual code content remains identical between version 3.3.4 and 3.3.5, including the existing vulnerabilities in the code itself (such as unsafe JSON access on line 137 with `$answers [ error - codes ]`, which should be `$answers['error-codes']`, and the deprecated `stripslashes()` usage on line 77), but these are pre-existing issues not addressed by this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/autoload.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/autoload.php 2025-12-21 09:36:35.235291534 +0000@@ -1,47 +1,47 @@-<?php - -// Autoload Service Container. -require 'libs/viocon/autoload.php'; - -spl_autoload_register( - function ( $class ) { - - $namespace = 'WpFluent'; - - if ( substr( $class, 0, strlen( $namespace ) ) !== $namespace ) { - return; - } - - $className = str_replace( - array( '\\', $namespace, strtolower( $namespace ) ), - array( '/', 'src', '' ), - $class - ); - - $basePath = plugin_dir_path( __FILE__ ); - - $file = $basePath . trim( $className, '/' ) . '.php'; - - if ( is_readable( $file ) ) { - include $file; - } - } -); - - -if ( ! function_exists( 'wpFluent' ) ) { - function wpFluent() { - static $wpFluent; - - if ( ! $wpFluent ) { - global $wpdb; - - $connection = new WpFluent\Connection( $wpdb, [ 'prefix' => $wpdb->prefix ], 'DB' ); - - $wpFluent = new \WpFluent\QueryBuilder\QueryBuilderHandler( $connection ); - } - - return $wpFluent; - } -} - +<?php++// Autoload Service Container.+require 'libs/viocon/autoload.php';++spl_autoload_register(+ function ( $class ) {++ $namespace = 'WpFluent';++ if ( substr( $class, 0, strlen( $namespace ) ) !== $namespace ) {+ return;+ }++ $className = str_replace(+ array( '\\', $namespace, strtolower( $namespace ) ),+ array( '/', 'src', '' ),+ $class+ );++ $basePath = plugin_dir_path( __FILE__ );++ $file = $basePath . trim( $className, '/' ) . '.php';++ if ( is_readable( $file ) ) {+ include $file;+ }+ }+);+++if ( ! function_exists( 'wpFluent' ) ) {+ function wpFluent() {+ static $wpFluent;++ if ( ! $wpFluent ) {+ global $wpdb;++ $connection = new WpFluent\Connection( $wpdb, [ 'prefix' => $wpdb->prefix ], 'DB' );++ $wpFluent = new \WpFluent\QueryBuilder\QueryBuilderHandler( $connection );+ }++ return $wpFluent;+ }+}+
Vulnerability Existed: no No Security Vulnerabilities Detected Explanation: The diff shows only whitespace/line ending changes (converting from CRLF to LF line endings). The actual code logic remains completely identical between versions 3.3.4 and 3.3.5. The autoload.php file contains: - A namespace-based autoloader that validates the WpFluent namespace before attempting to include files - Path sanitization using `trim()` to remove slashes - A readability check with `is_readable()` before including files - Standard WordPress plugin initialization While the autoloader pattern itself has potential security considerations (dynamic file inclusion based on class names), no changes were made to address or introduce vulnerabilities in this update. The security posture remains unchanged.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/libs/viocon/autoload.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/libs/viocon/autoload.php 2025-12-21 09:36:35.235291534 +0000@@ -1,26 +1,26 @@-<?php - -spl_autoload_register( - function ( $class ) { - - $namespace = 'Viocon'; - - if ( substr( $class, 0, strlen( $namespace ) ) !== $namespace ) { - return; - } - - $classPath = str_replace( - array( '\\', $namespace, strtolower( $namespace ) ), - array( '/', 'src/Viocon', '' ), - $class - ); - - $basePath = plugin_dir_path( __FILE__ ); - - $file = $basePath . trim( $classPath, '/' ) . '.php'; - - if ( is_readable( $file ) ) { - include $file; - } - } -); +<?php++spl_autoload_register(+ function ( $class ) {++ $namespace = 'Viocon';++ if ( substr( $class, 0, strlen( $namespace ) ) !== $namespace ) {+ return;+ }++ $classPath = str_replace(+ array( '\\', $namespace, strtolower( $namespace ) ),+ array( '/', 'src/Viocon', '' ),+ $class+ );++ $basePath = plugin_dir_path( __FILE__ );++ $file = $basePath . trim( $classPath, '/' ) . '.php';++ if ( is_readable( $file ) ) {+ include $file;+ }+ }+);
Vulnerability Existed: yes
FALSE POSITIVE
Arbitrary File Inclusion / Local File Inclusion (LFI) - CWE-98 - includes/wp-fluent/libs/viocon/autoload.php (Lines 1-26)
Old Code:
```php
$classPath = str_replace(
array( '\\', $namespace, strtolower( $namespace ) ),
array( '/', 'src/Viocon', '' ),
$class
);
$basePath = plugin_dir_path( __FILE__ );
$file = $basePath . trim( $classPath, '/' ) . '.php';
if ( is_readable( $file ) ) {
include $file;
}
```
Fixed Code:
```php
$classPath = str_replace(
array( '\\', $namespace, strtolower( $namespace ) ),
array( '/', 'src/Viocon', '' ),
$class
);
$basePath = plugin_dir_path( __FILE__ );
$file = $basePath . trim( $classPath, '/' ) . '.php';
if ( is_readable( $file ) ) {
include $file;
}
```
Explanation:
**No security fix detected.** The diff shows only whitespace/line ending changes (CRLF to LF conversion) with no actual code modifications. The underlying vulnerability remains unfixed: The autoloader uses user-controllable input (`$class` parameter) to construct file paths without proper validation. An attacker could exploit directory traversal sequences (e.g., `Viocon/../../../etc/passwd`) or manipulate the class name to include arbitrary PHP files via path traversal, leading to Local File Inclusion (LFI). The check `is_readable()` is insufficient as a security control—it only verifies file existence/readability, not whether the file is within the intended directory. A proper fix would require canonicalization (e.g., `realpath()`) and validation to ensure the resolved path stays within the intended `src/Viocon/` directory.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/libs/viocon/src/Viocon/AliasFacade.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/libs/viocon/src/Viocon/AliasFacade.php 2025-12-21 09:36:35.235291534 +0000@@ -1,29 +1,29 @@-<?php namespace Viocon; - -/** - * This class gives the ability to access non-static methods statically - * - * Class AliasFacade - * - * @package Viocon - */ -class AliasFacade { - - protected static $vioconInstance; - - public static function __callStatic( $method, $args ) { - if ( ! static::$vioconInstance ) { - static::$vioconInstance = new Container(); - } - - return call_user_func_array( array( static::$vioconInstance, $method ), $args ); - } - - public static function setVioconInstance( Container $instance ) { - static::$vioconInstance = $instance; - } - - public static function getVioconInstance() { - return static::$vioconInstance; - } -} +<?php namespace Viocon;++/**+ * This class gives the ability to access non-static methods statically+ *+ * Class AliasFacade+ *+ * @package Viocon+ */+class AliasFacade {++ protected static $vioconInstance;++ public static function __callStatic( $method, $args ) {+ if ( ! static::$vioconInstance ) {+ static::$vioconInstance = new Container();+ }++ return call_user_func_array( array( static::$vioconInstance, $method ), $args );+ }++ public static function setVioconInstance( Container $instance ) {+ static::$vioconInstance = $instance;+ }++ public static function getVioconInstance() {+ return static::$vioconInstance;+ }+}
Vulnerability Existed: no No Security Vulnerability - Line Ending Normalization - includes/wp-fluent/libs/viocon/src/Viocon/AliasFacade.php [1-29] Old Code: ```php <?php namespace Viocon; ... } ``` Fixed Code: ```php <?php namespace Viocon; ... } ``` Explanation: This diff contains only line ending changes (CRLF to LF normalization), with no functional code modifications. The actual PHP code logic remains identical across all lines. There are no security vulnerabilities introduced or fixed in this change. This is a formatting/whitespace normalization that has no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/libs/viocon/src/Viocon/Container.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/libs/viocon/src/Viocon/Container.php 2025-12-21 09:36:35.235291534 +0000@@ -1,129 +1,129 @@-<?php namespace Viocon; - -class Container { - - public $registry = array(); - - /** - * Singleton instances - * - * @var array - */ - public $singletons = array(); - - public function __construct( $alias = null ) { - if ( $alias ) { - AliasFacade::setVioconInstance( $this ); - class_alias( '\\Viocon\\AliasFacade', $alias ); - } - } - - /** - * Register an object with a key - * - * @param string $key - * @param mixed $object - * @param bool $singleton - * - * @return void - */ - public function set( $key, $object, $singleton = false ) { - $this->registry[ $key ] = compact( 'object', 'singleton' ); - } - - /** - * If we have a registry for the given key - * - * @param string $key - * - * @return bool - */ - public function has( $key ) { - return array_key_exists( $key, $this->registry ); - } - - /** - * Register as singleton. - * - * @param string $key - * @param mixed $object - * - * @return void - */ - public function singleton( $key, $object ) { - $this->set( $key, $object, true ); - } - - /** - * Register or replace an instance as a singleton. - * Useful for replacing with Mocked instance - * - * @param string $key - * @param mixed $instance - * - * @return void - */ - public function setInstance( $key, $instance ) { - $this->singletons[ $key ] = $instance; - } - - /** - * Build from the given key. - * If there is a class registered with Container::set() then it's instance - * will be returned. If a closure is registered, a closure's return value - * will be returned. If nothing is registered then it will try to build an - * instance with new $key(...). - * - * $parameters will be passed to closure or class constructor. - * - * @param string $key - * @param array $parameters - * - * @return mixed - */ - public function build( $key, $parameters = array() ) { - // If we have a singleton instance registered the just return it - if ( array_key_exists( $key, $this->singletons ) ) { - return $this->singletons[ $key ]; - } - - // If we don't have a registered object with the key then assume user - // is trying to build a class with the given key/name - - if ( ! array_key_exists( $key, $this->registry ) ) { - $object = $key; - } else { - $object = $this->registry[ $key ]['object']; - } - - - $instance = $this->instanciate( $object, $parameters ); - - // If the key is registered as a singleton, we can save the instance as singleton - // for later use - if ( isset( $this->registry[ $key ]['singleton'] ) && true === $this->registry[ $key ]['singleton'] ) { - $this->singletons[ $key ] = $instance; - } - - return $instance; - } - - /** - * Instantiate an instance of the given type. - * - * @param string $key - * @param array $parameters - * - * @throws \Exception - * @return mixed - */ - protected function instanciate( $key, $parameters = null ) { - - if ( $key instanceof \Closure ) { - return call_user_func_array( $key, $parameters ); - } - - $reflection = new \ReflectionClass( $key ); - return $reflection->newInstanceArgs( $parameters ); - } -} +<?php namespace Viocon;++class Container {++ public $registry = array();++ /**+ * Singleton instances+ *+ * @var array+ */+ public $singletons = array();++ public function __construct( $alias = null ) {+ if ( $alias ) {+ AliasFacade::setVioconInstance( $this );+ class_alias( '\\Viocon\\AliasFacade', $alias );+ }+ }++ /**+ * Register an object with a key+ *+ * @param string $key+ * @param mixed $object+ * @param bool $singleton+ *+ * @return void+ */+ public function set( $key, $object, $singleton = false ) {+ $this->registry[ $key ] = compact( 'object', 'singleton' );+ }++ /**+ * If we have a registry for the given key+ *+ * @param string $key+ *+ * @return bool+ */+ public function has( $key ) {+ return array_key_exists( $key, $this->registry );+ }++ /**+ * Register as singleton.+ *+ * @param string $key+ * @param mixed $object+ *+ * @return void+ */+ public function singleton( $key, $object ) {+ $this->set( $key, $object, true );+ }++ /**+ * Register or replace an instance as a singleton.+ * Useful for replacing with Mocked instance+ *+ * @param string $key+ * @param mixed $instance+ *+ * @return void+ */+ public function setInstance( $key, $instance ) {+ $this->singletons[ $key ] = $instance;+ }++ /**+ * Build from the given key.+ * If there is a class registered with Container::set() then it's instance+ * will be returned. If a closure is registered, a closure's return value+ * will be returned. If nothing is registered then it will try to build an+ * instance with new $key(...).+ *+ * $parameters will be passed to closure or class constructor.+ *+ * @param string $key+ * @param array $parameters+ *+ * @return mixed+ */+ public function build( $key, $parameters = array() ) {+ // If we have a singleton instance registered the just return it+ if ( array_key_exists( $key, $this->singletons ) ) {+ return $this->singletons[ $key ];+ }++ // If we don't have a registered object with the key then assume user+ // is trying to build a class with the given key/name++ if ( ! array_key_exists( $key, $this->registry ) ) {+ $object = $key;+ } else {+ $object = $this->registry[ $key ]['object'];+ }+++ $instance = $this->instanciate( $object, $parameters );++ // If the key is registered as a singleton, we can save the instance as singleton+ // for later use+ if ( isset( $this->registry[ $key ]['singleton'] ) && true === $this->registry[ $key ]['singleton'] ) {+ $this->singletons[ $key ] = $instance;+ }++ return $instance;+ }++ /**+ * Instantiate an instance of the given type.+ *+ * @param string $key+ * @param array $parameters+ *+ * @throws \Exception+ * @return mixed+ */+ protected function instanciate( $key, $parameters = null ) {++ if ( $key instanceof \Closure ) {+ return call_user_func_array( $key, $parameters );+ }++ $reflection = new \ReflectionClass( $key );+ return $reflection->newInstanceArgs( $parameters );+ }+}
Vulnerability Existed: no **Explanation:** This diff shows only whitespace/line ending changes (converting from Unix LF to Windows CRLF line endings or vice versa). The actual PHP code logic, syntax, and functionality remain completely identical between versions 3.3.4 and 3.3.5. No security fixes were applied in this change. The code itself contains no modifications that would address any vulnerabilities. This appears to be a formatting-only release with no functional or security-related changes to the `Container.php` file.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/libs/viocon/src/Viocon/VioconException.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/libs/viocon/src/Viocon/VioconException.php 2025-12-21 09:36:35.235291534 +0000@@ -1,6 +1,6 @@-<?php namespace Viocon; - -class VioconException extends \Exception { - - -} +<?php namespace Viocon;++class VioconException extends \Exception {+++}
Vulnerability Existed: no
No Security Vulnerabilities Detected - [File] includes/wp-fluent/libs/viocon/src/Viocon/VioconException.php [Lines 1-6]
Old Code:
```php
<?php namespace Viocon;
class VioconException extends \Exception {
}
```
Fixed Code:
```php
<?php namespace Viocon;
class VioconException extends \Exception {
}
```
Explanation:
This diff contains only whitespace changes (line ending normalization from CRLF to LF or similar formatting adjustments). The code structure and functionality remain identical. The VioconException class is a simple exception class that extends PHP's built-in Exception class with no custom logic. There are no security vulnerabilities introduced, removed, or present in either version. This appears to be a code formatting/cleanup commit with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/AliasFacade.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/AliasFacade.php 2025-12-21 09:36:35.235291534 +0000@@ -1,30 +1,30 @@-<?php -namespace WpFluent; - -use WpFluent\QueryBuilder\QueryBuilderHandler; - -/** - * This class gives the ability to access non-static methods statically - * - * Class AliasFacade - * - * @package WpFluent - */ -class AliasFacade { - - - protected static $queryBuilderInstance; - - public static function __callStatic( $method, $args ) { - if ( ! static::$queryBuilderInstance ) { - static::$queryBuilderInstance = new QueryBuilderHandler(); - } - - // Call the non-static method from the class instance - return call_user_func_array( array( static::$queryBuilderInstance, $method ), $args ); - } - - public static function setQueryBuilderInstance( $queryBuilderInstance ) { - static::$queryBuilderInstance = $queryBuilderInstance; - } -} +<?php+namespace WpFluent;++use WpFluent\QueryBuilder\QueryBuilderHandler;++/**+ * This class gives the ability to access non-static methods statically+ *+ * Class AliasFacade+ *+ * @package WpFluent+ */+class AliasFacade {+++ protected static $queryBuilderInstance;++ public static function __callStatic( $method, $args ) {+ if ( ! static::$queryBuilderInstance ) {+ static::$queryBuilderInstance = new QueryBuilderHandler();+ }++ // Call the non-static method from the class instance+ return call_user_func_array( array( static::$queryBuilderInstance, $method ), $args );+ }++ public static function setQueryBuilderInstance( $queryBuilderInstance ) {+ static::$queryBuilderInstance = $queryBuilderInstance;+ }+}
Vulnerability Existed: no **No Security Vulnerabilities Detected** Explanation: The diff shows only whitespace/line ending changes (conversion from Unix LF to Windows CRLF line endings, or vice versa). The actual code logic remains identical between versions 3.3.4 and 3.3.5. There are no changes to: - Method implementations - Input validation - Data handling - Access controls - Function calls or their parameters The `AliasFacade` class continues to use `call_user_func_array()` which is a legitimate PHP pattern for dynamic method delegation. The method name comes from the static call, not from user input, so there is no injection vulnerability. The code does not introduce, remove, or modify any security-relevant functionality.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/Connection.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/Connection.php 2025-12-21 09:36:35.235291534 +0000@@ -1,114 +1,114 @@-<?php -namespace WpFluent; - -use Viocon\Container; - -class Connection { - - - protected $container; - - protected $adapter; - - protected $adapterConfig; - - protected $dbInstance; - - protected $wpdb; - - protected static $storedConnection; - - protected $eventHandler; - - public function __construct( $wpdb, array $config = array(), $alias = null, Container $container = null ) { - $container = $container ? $container : new Container(); - - $this->container = $container; - - $this->wpdb = $wpdb; - - $this->setAdapter()->setAdapterConfig( $config )->connect(); - - // Create event dependency - $this->eventHandler = $this->container->build( '\\WpFluent\\EventHandler' ); - - if ( $alias ) { - $this->createAlias( $alias ); - } - } - - /** - * Create an easily accessible query builder alias - * - * @param $alias - */ - public function createAlias( $alias ) { - class_alias( 'WpFluent\\AliasFacade', $alias ); - - $builder = $this->container->build( '\\WpFluent\\QueryBuilder\\QueryBuilderHandler', array( $this ) ); - - AliasFacade::setQueryBuilderInstance( $builder ); - } - - /** - * Returns an instance of Query Builder - */ - public function getQueryBuilder() { - return $this->container->build( '\\WpFluent\\QueryBuilder\\QueryBuilderHandler', array( $this ) ); - } - - - /** - * Create the connection adapter - */ - protected function connect() { - $this->setDbInstance( $this->wpdb ); - - // Preserve the first database connection with a static property - if ( ! static::$storedConnection ) { - static::$storedConnection = $this; - } - } - - public function setDbInstance( $db ) { - $this->dbInstance = $db; - - return $this; - } - - public function getDbInstance() { - return $this->dbInstance; - } - - public function setAdapter( $adapter = 'mysql' ) { - $this->adapter = $adapter; - - return $this; - } - - public function getAdapter() { - return $this->adapter; - } - - public function setAdapterConfig( array $adapterConfig ) { - $this->adapterConfig = $adapterConfig; - - return $this; - } - - public function getAdapterConfig() { - return $this->adapterConfig; - } - - public function getContainer() { - return $this->container; - } - - public function getEventHandler() { - return $this->eventHandler; - } - - public static function getStoredConnection() { - return static::$storedConnection; - } -} +<?php+namespace WpFluent;++use Viocon\Container;++class Connection {+++ protected $container;++ protected $adapter;++ protected $adapterConfig;++ protected $dbInstance;++ protected $wpdb;++ protected static $storedConnection;++ protected $eventHandler;++ public function __construct( $wpdb, array $config = array(), $alias = null, Container $container = null ) {+ $container = $container ? $container : new Container();++ $this->container = $container;++ $this->wpdb = $wpdb;++ $this->setAdapter()->setAdapterConfig( $config )->connect();++ // Create event dependency+ $this->eventHandler = $this->container->build( '\\WpFluent\\EventHandler' );++ if ( $alias ) {+ $this->createAlias( $alias );+ }+ }++ /**+ * Create an easily accessible query builder alias+ *+ * @param $alias+ */+ public function createAlias( $alias ) {+ class_alias( 'WpFluent\\AliasFacade', $alias );++ $builder = $this->container->build( '\\WpFluent\\QueryBuilder\\QueryBuilderHandler', array( $this ) );++ AliasFacade::setQueryBuilderInstance( $builder );+ }++ /**+ * Returns an instance of Query Builder+ */+ public function getQueryBuilder() {+ return $this->container->build( '\\WpFluent\\QueryBuilder\\QueryBuilderHandler', array( $this ) );+ }+++ /**+ * Create the connection adapter+ */+ protected function connect() {+ $this->setDbInstance( $this->wpdb );++ // Preserve the first database connection with a static property+ if ( ! static::$storedConnection ) {+ static::$storedConnection = $this;+ }+ }++ public function setDbInstance( $db ) {+ $this->dbInstance = $db;++ return $this;+ }++ public function getDbInstance() {+ return $this->dbInstance;+ }++ public function setAdapter( $adapter = 'mysql' ) {+ $this->adapter = $adapter;++ return $this;+ }++ public function getAdapter() {+ return $this->adapter;+ }++ public function setAdapterConfig( array $adapterConfig ) {+ $this->adapterConfig = $adapterConfig;++ return $this;+ }++ public function getAdapterConfig() {+ return $this->adapterConfig;+ }++ public function getContainer() {+ return $this->container;+ }++ public function getEventHandler() {+ return $this->eventHandler;+ }++ public static function getStoredConnection() {+ return static::$storedConnection;+ }+}
Vulnerability Existed: no No Security Vulnerabilities Identified - Line Ending Changes Only Explanation: This diff shows only a change in line endings from CRLF (Windows-style, represented by the carriage return characters) to LF (Unix-style). The actual code content remains identical between versions 3.3.4 and 3.3.5. No functional code changes have been made, no new code has been introduced, and no security-related modifications are present. The file contains database connection configuration code that does not have any apparent vulnerabilities in either version. The line ending normalization is a formatting/whitespace change that has no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/EventHandler.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/EventHandler.php 2025-12-21 09:36:35.235291534 +0000@@ -1,61 +1,61 @@-<?php namespace WpFluent; - -use WpFluent\QueryBuilder\QueryBuilderHandler; -use WpFluent\QueryBuilder\Raw; - -class EventHandler { - - protected $events = array(); - - protected $firedEvents = array(); - - public function getEvents() { - return $this->events; - } - - public function getEvent( $event, $table = ':any' ) { - if ( $table instanceof Raw ) { - return null; - } - return isset( $this->events[ $table ][ $event ] ) ? $this->events[ $table ][ $event ] : null; - } - - public function registerEvent( $event, $table, \Closure $action ) { - $table = $table ? $table : ':any'; - - $this->events[ $table ][ $event ] = $action; - } - - public function removeEvent( $event, $table = ':any' ) { - unset( $this->events[ $table ][ $event ] ); - } - - public function fireEvents( $queryBuilder, $event ) { - $statements = $queryBuilder->getStatements(); - $tables = isset( $statements['tables'] ) ? $statements['tables'] : array(); - - // Events added with :any will be fired in case of any table, - // we are adding :any as a fake table at the beginning. - array_unshift( $tables, ':any' ); - - // Fire all events - foreach ( $tables as $table ) { - // Fire before events for :any table - $action = $this->getEvent( $event, $table ); - if ( $action ) { - // Make an event id, with event type and table - $eventId = $event . $table; - - // Fire event - $handlerParams = func_get_args(); - unset( $handlerParams[1] ); // we do not need $event - // Add to fired list - $this->firedEvents[] = $eventId; - $result = call_user_func_array( $action, $handlerParams ); - if ( ! is_null( $result ) ) { - return $result; - }; - } - } - } -} +<?php namespace WpFluent;++use WpFluent\QueryBuilder\QueryBuilderHandler;+use WpFluent\QueryBuilder\Raw;++class EventHandler {++ protected $events = array();++ protected $firedEvents = array();++ public function getEvents() {+ return $this->events;+ }++ public function getEvent( $event, $table = ':any' ) {+ if ( $table instanceof Raw ) {+ return null;+ }+ return isset( $this->events[ $table ][ $event ] ) ? $this->events[ $table ][ $event ] : null;+ }++ public function registerEvent( $event, $table, \Closure $action ) {+ $table = $table ? $table : ':any';++ $this->events[ $table ][ $event ] = $action;+ }++ public function removeEvent( $event, $table = ':any' ) {+ unset( $this->events[ $table ][ $event ] );+ }++ public function fireEvents( $queryBuilder, $event ) {+ $statements = $queryBuilder->getStatements();+ $tables = isset( $statements['tables'] ) ? $statements['tables'] : array();++ // Events added with :any will be fired in case of any table,+ // we are adding :any as a fake table at the beginning.+ array_unshift( $tables, ':any' );++ // Fire all events+ foreach ( $tables as $table ) {+ // Fire before events for :any table+ $action = $this->getEvent( $event, $table );+ if ( $action ) {+ // Make an event id, with event type and table+ $eventId = $event . $table;++ // Fire event+ $handlerParams = func_get_args();+ unset( $handlerParams[1] ); // we do not need $event+ // Add to fired list+ $this->firedEvents[] = $eventId;+ $result = call_user_func_array( $action, $handlerParams );+ if ( ! is_null( $result ) ) {+ return $result;+ };+ }+ }+ }+}
Vulnerability Existed: no No Vulnerability - Line Ending Normalization Only - includes/wp-fluent/src/EventHandler.php [1-61] Old Code: ``` <?php namespace WpFluent; ... } ``` (Lines 1-61 with CRLF/mixed line endings) Fixed Code: ``` <?php namespace WpFluent; ... } ``` (Lines 1-61 with consistent LF line endings) Explanation: This diff contains only whitespace/line ending changes (CRLF to LF normalization). The actual code logic, structure, and functionality remain identical. No security vulnerabilities were introduced or fixed in this change. This is a cosmetic change that standardizes line endings to Unix format, which is a best practice but has no security implications. The code does not contain any input validation, authentication, authorization, or sanitization issues that would constitute security vulnerabilities in either the old or new version.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/Exception.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/Exception.php 2025-12-21 09:36:35.235291534 +0000@@ -1,6 +1,6 @@-<?php namespace WpFluent; - -class Exception extends \Exception { - - -} +<?php namespace WpFluent;++class Exception extends \Exception {+++}
Vulnerability Existed: no
No Vulnerability - File: includes/wp-fluent/src/Exception.php
Old Code:
```php
<?php namespace WpFluent;
class Exception extends \Exception {
}
```
Fixed Code:
```php
<?php namespace WpFluent;
class Exception extends \Exception {
}
```
Explanation:
This diff contains only whitespace and line ending changes (CRLF to LF or similar). There are no functional code changes, no logic modifications, and no security-related updates. The Exception class remains structurally identical before and after the change. No security vulnerabilities exist in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/QueryBuilder/Adapters/BaseAdapter.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/QueryBuilder/Adapters/BaseAdapter.php 2025-12-21 09:36:35.235291534 +0000@@ -1,530 +1,530 @@-<?php namespace WpFluent\QueryBuilder\Adapters; - -use WpFluent\Connection; -use WpFluent\Exception; -use WpFluent\QueryBuilder\Raw; - -abstract class BaseAdapter { - - protected $connection; - - protected $container; - - public function __construct( Connection $connection ) { - $this->connection = $connection; - $this->container = $this->connection->getContainer(); - } - - /** - * Build select query string and bindings - * - * @param $statements - * - * @throws Exception - * @return array - */ - public function select( $statements ) { - if ( ! array_key_exists( 'tables', $statements ) ) { - throw new Exception( 'No table specified.', 3 ); - } elseif ( ! array_key_exists( 'selects', $statements ) ) { - $statements['selects'][] = '*'; - } - - // From - $tables = $this->arrayStr( $statements['tables'], ', ' ); - // Select - $selects = $this->arrayStr( $statements['selects'], ', ' ); - - - // Wheres - list($whereCriteria, $whereBindings) = $this->buildCriteriaWithType( $statements, 'wheres', 'WHERE' ); - // Group bys - $groupBys = ''; - if ( isset( $statements['groupBys'] ) ) { - $groupBys = $this->arrayStr( $statements['groupBys'], ', ' ); - } - - if ( $groupBys ) { - $groupBys = 'GROUP BY ' . $groupBys; - } - - // Order bys - $orderBys = ''; - if ( isset( $statements['orderBys'] ) && is_array( $statements['orderBys'] ) ) { - foreach ( $statements['orderBys'] as $orderBy ) { - $orderBys .= $this->wrapSanitizer( $orderBy['field'] ) . ' ' . $orderBy['type'] . ', '; - } - $orderBys = trim( $orderBys, ', ' ); - if ( $orderBys ) { - $orderBys = 'ORDER BY ' . $orderBys; - } - } - - // Limit and offset - $limit = isset( $statements['limit'] ) ? 'LIMIT ' . $statements['limit'] : ''; - $offset = isset( $statements['offset'] ) ? 'OFFSET ' . $statements['offset'] : ''; - - // Having - list($havingCriteria, $havingBindings) = $this->buildCriteriaWithType( $statements, 'havings', 'HAVING' ); - - // Joins - $joinString = $this->buildJoin( $statements ); - - $sqlArray = array( - 'SELECT' . ( isset( $statements['distinct'] ) ? ' DISTINCT' : '' ), - $selects, - 'FROM', - $tables, - $joinString, - $whereCriteria, - $groupBys, - $havingCriteria, - $orderBys, - $limit, - $offset, - ); - - $sql = $this->concatenateQuery( $sqlArray ); - - $bindings = array_merge( - $whereBindings, - $havingBindings - ); - - return compact( 'sql', 'bindings' ); - } - - /** - * Build just criteria part of the query - * - * @param $statements - * @param bool $bindValues - * - * @return array - */ - public function criteriaOnly( $statements, $bindValues = true ) { - $sql = array(); - $bindings = array(); - - if ( ! isset( $statements['criteria'] ) ) { - return compact( 'sql', 'bindings' ); - } - - list($sql, $bindings) = $this->buildCriteria( $statements['criteria'], $bindValues ); - - return compact( 'sql', 'bindings' ); - } - - /** - * Build a generic insert/ignore/replace query - * - * @param $statements - * @param array $data - * - * @return array - * @throws Exception - */ - private function doInsert( $statements, array $data, $type ) { - if ( ! isset( $statements['tables'] ) ) { - throw new Exception( 'No table specified', 3 ); - } - - $table = end( $statements['tables'] ); - - $bindings = array(); - $keys = array(); - $values = array(); - - foreach ( $data as $key => $value ) { - $keys[] = $key; - if ( $value instanceof Raw ) { - $values[] = (string) $value; - } else { - $values[] = '?'; - $bindings[] = $value; - } - } - - $sqlArray = array( - $type . ' INTO', - $this->wrapSanitizer( $table ), - '(' . $this->arrayStr( $keys, ',' ) . ')', - 'VALUES', - '(' . $this->arrayStr( $values, ',', false ) . ')', - ); - - if ( isset( $statements['onduplicate'] ) ) { - if ( count( $statements['onduplicate'] ) < 1 ) { - throw new Exception( 'No data given.', 4 ); - } - list($updateStatement, $updateBindings) = $this->getUpdateStatement( $statements['onduplicate'] ); - $sqlArray[] = 'ON DUPLICATE KEY UPDATE ' . $updateStatement; - $bindings = array_merge( $bindings, $updateBindings ); - } - - $sql = $this->concatenateQuery( $sqlArray ); - - return compact( 'sql', 'bindings' ); - } - - /** - * Build Insert query - * - * @param $statements - * @param array $data - * - * @return array - * @throws Exception - */ - public function insert( $statements, array $data ) { - return $this->doInsert( $statements, $data, 'INSERT' ); - } - - /** - * Build Insert Ignore query - * - * @param $statements - * @param array $data - * - * @return array - * @throws Exception - */ - public function insertIgnore( $statements, array $data ) { - return $this->doInsert( $statements, $data, 'INSERT IGNORE' ); - } - - /** - * Build Insert Ignore query - * - * @param $statements - * @param array $data - * - * @return array - * @throws Exception - */ - public function replace( $statements, array $data ) { - return $this->doInsert( $statements, $data, 'REPLACE' ); - } - - /** - * Build fields assignment part of SET ... or ON DUBLICATE KEY UPDATE ... statements - * - * @param array $data - * - * @return array - */ - private function getUpdateStatement( $data ) { - $bindings = array(); - $statement = ''; - - foreach ( $data as $key => $value ) { - if ( $value instanceof Raw ) { - $statement .= $this->wrapSanitizer( $key ) . '=' . $value . ','; - } else { - $statement .= $this->wrapSanitizer( $key ) . '=?,'; - $bindings[] = $value; - } - } - - $statement = trim( $statement, ',' ); - - return array( $statement, $bindings ); - } - - /** - * Build update query - * - * @param $statements - * @param array $data - * - * @return array - * @throws Exception - */ - public function update( $statements, array $data ) { - if ( ! isset( $statements['tables'] ) ) { - throw new Exception( 'No table specified', 3 ); - } elseif ( count( $data ) < 1 ) { - throw new Exception( 'No data given.', 4 ); - } - - $table = end( $statements['tables'] ); - - // Update statement - list($updateStatement, $bindings) = $this->getUpdateStatement( $data ); - - // Wheres - list($whereCriteria, $whereBindings) = $this->buildCriteriaWithType( $statements, 'wheres', 'WHERE' ); - - // Limit - $limit = isset( $statements['limit'] ) ? 'LIMIT ' . $statements['limit'] : ''; - - $sqlArray = array( - 'UPDATE', - $this->wrapSanitizer( $table ), - 'SET ' . $updateStatement, - $whereCriteria, - $limit, - ); - - $sql = $this->concatenateQuery( $sqlArray ); - - $bindings = array_merge( $bindings, $whereBindings ); - - return compact( 'sql', 'bindings' ); - } - - /** - * Build delete query - * - * @param $statements - * - * @return array - * @throws Exception - */ - public function delete( $statements ) { - if ( ! isset( $statements['tables'] ) ) { - throw new Exception( 'No table specified', 3 ); - } - - $table = end( $statements['tables'] ); - - // Wheres - list($whereCriteria, $whereBindings) = $this->buildCriteriaWithType( $statements, 'wheres', 'WHERE' ); - - // Limit - $limit = isset( $statements['limit'] ) ? 'LIMIT ' . $statements['limit'] : ''; - - $sqlArray = array( 'DELETE FROM', $this->wrapSanitizer( $table ), $whereCriteria ); - $sql = $this->concatenateQuery( $sqlArray ); - $bindings = $whereBindings; - - return compact( 'sql', 'bindings' ); - } - - /** - * Array concatenating method, like implode. - * But it does wrap sanitizer and trims last glue - * - * @param array $pieces - * @param $glue - * @param bool $wrapSanitizer - * - * @return string - */ - protected function arrayStr( array $pieces, $glue, $wrapSanitizer = true ) { - $str = ''; - - foreach ( $pieces as $key => $piece ) { - if ( $wrapSanitizer ) { - $piece = $this->wrapSanitizer( $piece ); - } - - if ( ! is_int( $key ) ) { - $piece = ( $wrapSanitizer ? $this->wrapSanitizer( $key ) : $key ) . ' AS ' . $piece; - } - - $str .= $piece . $glue; - } - - return trim( $str, $glue ); - } - - /** - * Join different part of queries with a space. - * - * @param array $pieces - * - * @return string - */ - protected function concatenateQuery( array $pieces ) { - $str = ''; - - foreach ( $pieces as $piece ) { - $str = trim( $str ) . ' ' . trim( $piece ); - } - - return trim( $str ); - } - - /** - * Build generic criteria string and bindings from statements, like "a = b and c = ?" - * - * @param $statements - * @param bool $bindValues - * - * @return array - */ - protected function buildCriteria( $statements, $bindValues = true ) { - $criteria = ''; - $bindings = array(); - - foreach ( $statements as $statement ) { - $key = $this->wrapSanitizer( $statement['key'] ); - $value = $statement['value']; - - if ( is_null( $value ) && $key instanceof \Closure ) { - // We have a closure, a nested criteria - - // Build a new NestedCriteria class, keep it by reference so any changes made - // in the closure should reflect here - $nestedCriteria = $this->container->build( - '\\WpFluent\\QueryBuilder\\NestedCriteria', - array( $this->connection ) - ); - - $nestedCriteria = & $nestedCriteria; - // Call the closure with our new nestedCriteria object - $key( $nestedCriteria ); - // Get the criteria only query from the nestedCriteria object - $queryObject = $nestedCriteria->getQuery( 'criteriaOnly', true ); - // Merge the bindings we get from nestedCriteria object - $bindings = array_merge( $bindings, $queryObject->getBindings() ); - // Append the sql we get from the nestedCriteria object - $criteria .= $statement['joiner'] . ' (' . $queryObject->getSql() . ') '; - } elseif ( is_array( $value ) ) { - // where_in or between like query - $criteria .= $statement['joiner'] . ' ' . $key . ' ' . $statement['operator']; - - switch ( $statement['operator'] ) { - case 'BETWEEN': - $bindings = array_merge( $bindings, $statement['value'] ); - $criteria .= ' ? AND ? '; - break; - default: - $valuePlaceholder = ''; - foreach ( $statement['value'] as $subValue ) { - $valuePlaceholder .= '?, '; - $bindings[] = $subValue; - } - - $valuePlaceholder = trim( $valuePlaceholder, ', ' ); - $criteria .= ' (' . $valuePlaceholder . ') '; - break; - } - } elseif ( $value instanceof Raw ) { - $criteria .= "{$statement['joiner']} {$key} {$statement['operator']} $value "; - } else { - // Usual where like criteria - - if ( ! $bindValues ) { - // Specially for joins - - // We are not binding values, lets sanitize then - $value = $this->wrapSanitizer( $value ); - $criteria .= $statement['joiner'] . ' ' . $key . ' ' . $statement['operator'] . ' ' . $value . ' '; - } elseif ( $statement['key'] instanceof Raw ) { - $criteria .= $statement['joiner'] . ' ' . $key . ' '; - $bindings = array_merge( $bindings, $statement['key']->getBindings() ); - } else { - // For wheres - - $valuePlaceholder = '?'; - $bindings[] = $value; - $criteria .= $statement['joiner'] . ' ' . $key . ' ' . $statement['operator'] . ' ' - . $valuePlaceholder . ' '; - } - } - } - - // Clear all white spaces, and, or from beginning and white spaces from ending - $criteria = preg_replace( '/^(\s?AND ?|\s?OR ?)|\s$/i', '', $criteria ); - - return array( $criteria, $bindings ); - } - - /** - * Wrap values with adapter's sanitizer like, '`' - * - * @param $value - * - * @return string - */ - public function wrapSanitizer( $value ) { - // Its a raw query, just cast as string, object has __toString() - if ( $value instanceof Raw ) { - return (string) $value; - } elseif ( $value instanceof \Closure ) { - return $value; - } - - // Separate our table and fields which are joined with a ".", - // like my_table.id - $valueArr = explode( '.', $value, 2 ); - - foreach ( $valueArr as $key => $subValue ) { - // Don't wrap if we have *, which is not a usual field - $valueArr[ $key ] = trim( $subValue ) == '*' ? $subValue : $this->sanitizer . $subValue . $this->sanitizer; - } - - // Join these back with "." and return - return implode( '.', $valueArr ); - } - - /** - * Build criteria string and binding with various types added, like WHERE and Having - * - * @param $statements - * @param $key - * @param $type - * @param bool $bindValues - * - * @return array - */ - protected function buildCriteriaWithType( $statements, $key, $type, $bindValues = true ) { - $criteria = ''; - $bindings = array(); - - if ( isset( $statements[ $key ] ) ) { - // Get the generic/adapter agnostic criteria string from parent - list($criteria, $bindings) = $this->buildCriteria( $statements[ $key ], $bindValues ); - - if ( $criteria ) { - $criteria = $type . ' ' . $criteria; - } - } - - return array( $criteria, $bindings ); - } - - /** - * Build join string - * - * @param $statements - * - * @return array|string - */ - protected function buildJoin( $statements ) { - $sql = ''; - - if ( ! array_key_exists( 'joins', $statements ) || ! is_array( $statements['joins'] ) ) { - return $sql; - } - - foreach ( $statements['joins'] as $joinArr ) { - if ( is_array( $joinArr['table'] ) ) { - $mainTable = $joinArr['table'][0]; - $aliasTable = $joinArr['table'][1]; - $table = $this->wrapSanitizer( $mainTable ) . ' AS ' . $this->wrapSanitizer( $aliasTable ); - } else { - $table = $joinArr['table'] instanceof Raw ? - (string) $joinArr['table'] : - $this->wrapSanitizer( $joinArr['table'] ); - } - - $joinBuilder = $joinArr['joinBuilder']; - - $sqlArr = array( - $sql, - strtoupper( $joinArr['type'] ), - 'JOIN', - $table, - 'ON', - $joinBuilder->getQuery( 'criteriaOnly', false )->getSql(), - ); - - $sql = $this->concatenateQuery( $sqlArr ); - } - - return $sql; - } -} +<?php namespace WpFluent\QueryBuilder\Adapters;++use WpFluent\Connection;+use WpFluent\Exception;+use WpFluent\QueryBuilder\Raw;++abstract class BaseAdapter {++ protected $connection;++ protected $container;++ public function __construct( Connection $connection ) {+ $this->connection = $connection;+ $this->container = $this->connection->getContainer();+ }++ /**+ * Build select query string and bindings+ *+ * @param $statements+ *+ * @throws Exception+ * @return array+ */+ public function select( $statements ) {+ if ( ! array_key_exists( 'tables', $statements ) ) {+ throw new Exception( 'No table specified.', 3 );+ } elseif ( ! array_key_exists( 'selects', $statements ) ) {+ $statements['selects'][] = '*';+ }++ // From+ $tables = $this->arrayStr( $statements['tables'], ', ' );+ // Select+ $selects = $this->arrayStr( $statements['selects'], ', ' );+++ // Wheres+ list($whereCriteria, $whereBindings) = $this->buildCriteriaWithType( $statements, 'wheres', 'WHERE' );+ // Group bys+ $groupBys = '';+ if ( isset( $statements['groupBys'] ) ) {+ $groupBys = $this->arrayStr( $statements['groupBys'], ', ' );+ }++ if ( $groupBys ) {+ $groupBys = 'GROUP BY ' . $groupBys;+ }++ // Order bys+ $orderBys = '';+ if ( isset( $statements['orderBys'] ) && is_array( $statements['orderBys'] ) ) {+ foreach ( $statements['orderBys'] as $orderBy ) {+ $orderBys .= $this->wrapSanitizer( $orderBy['field'] ) . ' ' . $orderBy['type'] . ', ';+ }+ $orderBys = trim( $orderBys, ', ' );+ if ( $orderBys ) {+ $orderBys = 'ORDER BY ' . $orderBys;+ }+ }++ // Limit and offset+ $limit = isset( $statements['limit'] ) ? 'LIMIT ' . $statements['limit'] : '';+ $offset = isset( $statements['offset'] ) ? 'OFFSET ' . $statements['offset'] : '';++ // Having+ list($havingCriteria, $havingBindings) = $this->buildCriteriaWithType( $statements, 'havings', 'HAVING' );++ // Joins+ $joinString = $this->buildJoin( $statements );++ $sqlArray = array(+ 'SELECT' . ( isset( $statements['distinct'] ) ? ' DISTINCT' : '' ),+ $selects,+ 'FROM',+ $tables,+ $joinString,+ $whereCriteria,+ $groupBys,+ $havingCriteria,+ $orderBys,+ $limit,+ $offset,+ );++ $sql = $this->concatenateQuery( $sqlArray );++ $bindings = array_merge(+ $whereBindings,+ $havingBindings+ );++ return compact( 'sql', 'bindings' );+ }++ /**+ * Build just criteria part of the query+ *+ * @param $statements+ * @param bool $bindValues+ *+ * @return array+ */+ public function criteriaOnly( $statements, $bindValues = true ) {+ $sql = array();+ $bindings = array();++ if ( ! isset( $statements['criteria'] ) ) {+ return compact( 'sql', 'bindings' );+ }++ list($sql, $bindings) = $this->buildCriteria( $statements['criteria'], $bindValues );++ return compact( 'sql', 'bindings' );+ }++ /**+ * Build a generic insert/ignore/replace query+ *+ * @param $statements+ * @param array $data+ *+ * @return array+ * @throws Exception+ */+ private function doInsert( $statements, array $data, $type ) {+ if ( ! isset( $statements['tables'] ) ) {+ throw new Exception( 'No table specified', 3 );+ }++ $table = end( $statements['tables'] );++ $bindings = array();+ $keys = array();+ $values = array();++ foreach ( $data as $key => $value ) {+ $keys[] = $key;+ if ( $value instanceof Raw ) {+ $values[] = (string) $value;+ } else {+ $values[] = '?';+ $bindings[] = $value;+ }+ }++ $sqlArray = array(+ $type . ' INTO',+ $this->wrapSanitizer( $table ),+ '(' . $this->arrayStr( $keys, ',' ) . ')',+ 'VALUES',+ '(' . $this->arrayStr( $values, ',', false ) . ')',+ );++ if ( isset( $statements['onduplicate'] ) ) {+ if ( count( $statements['onduplicate'] ) < 1 ) {+ throw new Exception( 'No data given.', 4 );+ }+ list($updateStatement, $updateBindings) = $this->getUpdateStatement( $statements['onduplicate'] );+ $sqlArray[] = 'ON DUPLICATE KEY UPDATE ' . $updateStatement;+ $bindings = array_merge( $bindings, $updateBindings );+ }++ $sql = $this->concatenateQuery( $sqlArray );++ return compact( 'sql', 'bindings' );+ }++ /**+ * Build Insert query+ *+ * @param $statements+ * @param array $data+ *+ * @return array+ * @throws Exception+ */+ public function insert( $statements, array $data ) {+ return $this->doInsert( $statements, $data, 'INSERT' );+ }++ /**+ * Build Insert Ignore query+ *+ * @param $statements+ * @param array $data+ *+ * @return array+ * @throws Exception+ */+ public function insertIgnore( $statements, array $data ) {+ return $this->doInsert( $statements, $data, 'INSERT IGNORE' );+ }++ /**+ * Build Insert Ignore query+ *+ * @param $statements+ * @param array $data+ *+ * @return array+ * @throws Exception+ */+ public function replace( $statements, array $data ) {+ return $this->doInsert( $statements, $data, 'REPLACE' );+ }++ /**+ * Build fields assignment part of SET ... or ON DUBLICATE KEY UPDATE ... statements+ *+ * @param array $data+ *+ * @return array+ */+ private function getUpdateStatement( $data ) {+ $bindings = array();+ $statement = '';++ foreach ( $data as $key => $value ) {+ if ( $value instanceof Raw ) {+ $statement .= $this->wrapSanitizer( $key ) . '=' . $value . ',';+ } else {+ $statement .= $this->wrapSanitizer( $key ) . '=?,';+ $bindings[] = $value;+ }+ }++ $statement = trim( $statement, ',' );++ return array( $statement, $bindings );+ }++ /**+ * Build update query+ *+ * @param $statements+ * @param array $data+ *+ * @return array+ * @throws Exception+ */+ public function update( $statements, array $data ) {+ if ( ! isset( $statements['tables'] ) ) {+ throw new Exception( 'No table specified', 3 );+ } elseif ( count( $data ) < 1 ) {+ throw new Exception( 'No data given.', 4 );+ }++ $table = end( $statements['tables'] );++ // Update statement+ list($updateStatement, $bindings) = $this->getUpdateStatement( $data );++ // Wheres+ list($whereCriteria, $whereBindings) = $this->buildCriteriaWithType( $statements, 'wheres', 'WHERE' );++ // Limit+ $limit = isset( $statements['limit'] ) ? 'LIMIT ' . $statements['limit'] : '';++ $sqlArray = array(+ 'UPDATE',+ $this->wrapSanitizer( $table ),+ 'SET ' . $updateStatement,+ $whereCriteria,+ $limit,+ );++ $sql = $this->concatenateQuery( $sqlArray );++ $bindings = array_merge( $bindings, $whereBindings );++ return compact( 'sql', 'bindings' );+ }++ /**+ * Build delete query+ *+ * @param $statements+ *+ * @return array+ * @throws Exception+ */+ public function delete( $statements ) {+ if ( ! isset( $statements['tables'] ) ) {+ throw new Exception( 'No table specified', 3 );+ }++ $table = end( $statements['tables'] );++ // Wheres+ list($whereCriteria, $whereBindings) = $this->buildCriteriaWithType( $statements, 'wheres', 'WHERE' );++ // Limit+ $limit = isset( $statements['limit'] ) ? 'LIMIT ' . $statements['limit'] : '';++ $sqlArray = array( 'DELETE FROM', $this->wrapSanitizer( $table ), $whereCriteria );+ $sql = $this->concatenateQuery( $sqlArray );+ $bindings = $whereBindings;++ return compact( 'sql', 'bindings' );+ }++ /**+ * Array concatenating method, like implode.+ * But it does wrap sanitizer and trims last glue+ *+ * @param array $pieces+ * @param $glue+ * @param bool $wrapSanitizer+ *+ * @return string+ */+ protected function arrayStr( array $pieces, $glue, $wrapSanitizer = true ) {+ $str = '';++ foreach ( $pieces as $key => $piece ) {+ if ( $wrapSanitizer ) {+ $piece = $this->wrapSanitizer( $piece );+ }++ if ( ! is_int( $key ) ) {+ $piece = ( $wrapSanitizer ? $this->wrapSanitizer( $key ) : $key ) . ' AS ' . $piece;+ }++ $str .= $piece . $glue;+ }++ return trim( $str, $glue );+ }++ /**+ * Join different part of queries with a space.+ *+ * @param array $pieces+ *+ * @return string+ */+ protected function concatenateQuery( array $pieces ) {+ $str = '';++ foreach ( $pieces as $piece ) {+ $str = trim( $str ) . ' ' . trim( $piece );+ }++ return trim( $str );+ }++ /**+ * Build generic criteria string and bindings from statements, like "a = b and c = ?"+ *+ * @param $statements+ * @param bool $bindValues+ *+ * @return array+ */+ protected function buildCriteria( $statements, $bindValues = true ) {+ $criteria = '';+ $bindings = array();++ foreach ( $statements as $statement ) {+ $key = $this->wrapSanitizer( $statement['key'] );+ $value = $statement['value'];++ if ( is_null( $value ) && $key instanceof \Closure ) {+ // We have a closure, a nested criteria++ // Build a new NestedCriteria class, keep it by reference so any changes made+ // in the closure should reflect here+ $nestedCriteria = $this->container->build(+ '\\WpFluent\\QueryBuilder\\NestedCriteria',+ array( $this->connection )+ );++ $nestedCriteria = & $nestedCriteria;+ // Call the closure with our new nestedCriteria object+ $key( $nestedCriteria );+ // Get the criteria only query from the nestedCriteria object+ $queryObject = $nestedCriteria->getQuery( 'criteriaOnly', true );+ // Merge the bindings we get from nestedCriteria object+ $bindings = array_merge( $bindings, $queryObject->getBindings() );+ // Append the sql we get from the nestedCriteria object+ $criteria .= $statement['joiner'] . ' (' . $queryObject->getSql() . ') ';+ } elseif ( is_array( $value ) ) {+ // where_in or between like query+ $criteria .= $statement['joiner'] . ' ' . $key . ' ' . $statement['operator'];++ switch ( $statement['operator'] ) {+ case 'BETWEEN':+ $bindings = array_merge( $bindings, $statement['value'] );+ $criteria .= ' ? AND ? ';+ break;+ default:+ $valuePlaceholder = '';+ foreach ( $statement['value'] as $subValue ) {+ $valuePlaceholder .= '?, ';+ $bindings[] = $subValue;+ }++ $valuePlaceholder = trim( $valuePlaceholder, ', ' );+ $criteria .= ' (' . $valuePlaceholder . ') ';+ break;+ }+ } elseif ( $value instanceof Raw ) {+ $criteria .= "{$statement['joiner']} {$key} {$statement['operator']} $value ";+ } else {+ // Usual where like criteria++ if ( ! $bindValues ) {+ // Specially for joins++ // We are not binding values, lets sanitize then+ $value = $this->wrapSanitizer( $value );+ $criteria .= $statement['joiner'] . ' ' . $key . ' ' . $statement['operator'] . ' ' . $value . ' ';+ } elseif ( $statement['key'] instanceof Raw ) {+ $criteria .= $statement['joiner'] . ' ' . $key . ' ';+ $bindings = array_merge( $bindings, $statement['key']->getBindings() );+ } else {+ // For wheres++ $valuePlaceholder = '?';+ $bindings[] = $value;+ $criteria .= $statement['joiner'] . ' ' . $key . ' ' . $statement['operator'] . ' '+ . $valuePlaceholder . ' ';+ }+ }+ }++ // Clear all white spaces, and, or from beginning and white spaces from ending+ $criteria = preg_replace( '/^(\s?AND ?|\s?OR ?)|\s$/i', '', $criteria );++ return array( $criteria, $bindings );+ }++ /**+ * Wrap values with adapter's sanitizer like, '`'+ *+ * @param $value+ *+ * @return string+ */+ public function wrapSanitizer( $value ) {+ // Its a raw query, just cast as string, object has __toString()+ if ( $value instanceof Raw ) {+ return (string) $value;+ } elseif ( $value instanceof \Closure ) {+ return $value;+ }++ // Separate our table and fields which are joined with a ".",+ // like my_table.id+ $valueArr = explode( '.', $value, 2 );++ foreach ( $valueArr as $key => $subValue ) {+ // Don't wrap if we have *, which is not a usual field+ $valueArr[ $key ] = trim( $subValue ) == '*' ? $subValue : $this->sanitizer . $subValue . $this->sanitizer;+ }++ // Join these back with "." and return+ return implode( '.', $valueArr );+ }++ /**+ * Build criteria string and binding with various types added, like WHERE and Having+ *+ * @param $statements+ * @param $key
Vulnerability Existed: no No Vulnerabilities Detected - BaseAdapter.php Lines 1-530 Old Code: <?php namespace WpFluent\QueryBuilder\Adapters; [entire file content with Unix line endings] Fixed Code: <?php namespace WpFluent\QueryBuilder\Adapters; [entire file content with Windows/mixed line endings] Explanation: This diff represents only a line ending conversion (CRLF to LF or vice versa) with no actual code logic changes. All functional code remains identical: - SQL query building logic unchanged - Parameter binding mechanisms unchanged - Sanitization methods (wrapSanitizer) unchanged - Criteria building with prepared statements intact - No new vulnerabilities introduced - No existing vulnerabilities fixed The file maintains proper parameterized queries throughout, using placeholders (?) for values and binding arrays to prevent SQL injection. The wrapSanitizer() function properly wraps identifiers, and the buildCriteria() method correctly separates user data from SQL structure via bound parameters.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/QueryBuilder/Adapters/Mysql.php 2025-12-21 09:35:59.429066066 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/QueryBuilder/Adapters/Mysql.php 2025-12-21 09:36:35.235291534 +0000@@ -1,6 +1,6 @@-<?php namespace WpFluent\QueryBuilder\Adapters; - -class Mysql extends BaseAdapter { - - protected $sanitizer = '`'; -} +<?php namespace WpFluent\QueryBuilder\Adapters;++class Mysql extends BaseAdapter {++ protected $sanitizer = '`';+}
Vulnerability Existed: no No Vulnerability - Formatting Change Only Explanation: This diff contains only whitespace and line ending changes (likely converting from different line ending formats, e.g., CRLF to LF, or adjusting trailing whitespace). There are no functional code changes, no logic modifications, and no security-related alterations. The `$sanitizer` property remains unchanged at the backtick character, which is the correct MySQL identifier escape character. No vulnerabilities are introduced or fixed in this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/QueryBuilder/JoinBuilder.php 2025-12-21 09:35:59.433066315 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/QueryBuilder/JoinBuilder.php 2025-12-21 09:36:35.235291534 +0000@@ -1,48 +1,48 @@-<?php namespace WpFluent\QueryBuilder; - -class JoinBuilder extends QueryBuilderHandler { - - /** - * Join on callback - * - * @param $key - * @param $operator - * @param $value - * - * @return $this - */ - public function on( $key, $operator, $value ) { - return $this->joinHandler( $key, $operator, $value, 'AND' ); - } - - /** - * Join on or callback - * - * @param $key - * @param $operator - * @param $value - * - * @return $this - */ - public function orOn( $key, $operator, $value ) { - return $this->joinHandler( $key, $operator, $value, 'OR' ); - } - - /** - * Join Hanlder - * - * @param $key - * @param null $operator - * @param null $value - * @param string $joiner - * - * @return $this - */ - protected function joinHandler( $key, $operator = null, $value = null, $joiner = 'AND' ) { - $key = $this->addTablePrefix( $key ); - $value = $this->addTablePrefix( $value ); - $this->statements['criteria'][] = compact( 'key', 'operator', 'value', 'joiner' ); - - return $this; - } -} +<?php namespace WpFluent\QueryBuilder;++class JoinBuilder extends QueryBuilderHandler {++ /**+ * Join on callback+ *+ * @param $key+ * @param $operator+ * @param $value+ *+ * @return $this+ */+ public function on( $key, $operator, $value ) {+ return $this->joinHandler( $key, $operator, $value, 'AND' );+ }++ /**+ * Join on or callback+ *+ * @param $key+ * @param $operator+ * @param $value+ *+ * @return $this+ */+ public function orOn( $key, $operator, $value ) {+ return $this->joinHandler( $key, $operator, $value, 'OR' );+ }++ /**+ * Join Hanlder+ *+ * @param $key+ * @param null $operator+ * @param null $value+ * @param string $joiner+ *+ * @return $this+ */+ protected function joinHandler( $key, $operator = null, $value = null, $joiner = 'AND' ) {+ $key = $this->addTablePrefix( $key );+ $value = $this->addTablePrefix( $value );+ $this->statements['criteria'][] = compact( 'key', 'operator', 'value', 'joiner' );++ return $this;+ }+}
Vulnerability Existed: no
No Security Vulnerability - Line Ending Change Only
Old Code:
```php
<?php namespace WpFluent\QueryBuilder;
class JoinBuilder extends QueryBuilderHandler {
// ... file content with CRLF/LF line endings
}
```
Fixed Code:
```php
<?php namespace WpFluent\QueryBuilder;
class JoinBuilder extends QueryBuilderHandler {
// ... file content with normalized line endings
}
```
Explanation:
This diff represents only a line ending normalization change (CRLF to LF or similar line ending standardization). There are no functional code changes, no logic modifications, and no security-related alterations. The file structure, function implementations, and security posture remain identical. This is a formatting/whitespace-only change with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/QueryBuilder/NestedCriteria.php 2025-12-21 09:35:59.433066315 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/QueryBuilder/NestedCriteria.php 2025-12-21 09:36:35.235291534 +0000@@ -1,21 +1,21 @@-<?php namespace WpFluent\QueryBuilder; - -class NestedCriteria extends QueryBuilderHandler { - - /** - * Nested where query handler - - * @param $key - * @param null $operator - * @param null $value - * @param string $joiner - * - * @return $this - */ - protected function whereHandler( $key, $operator = null, $value = null, $joiner = 'AND' ) { - $key = $this->addTablePrefix( $key ); - $this->statements['criteria'][] = compact( 'key', 'operator', 'value', 'joiner' ); - - return $this; - } -} +<?php namespace WpFluent\QueryBuilder;++class NestedCriteria extends QueryBuilderHandler {++ /**+ * Nested where query handler++ * @param $key+ * @param null $operator+ * @param null $value+ * @param string $joiner+ *+ * @return $this+ */+ protected function whereHandler( $key, $operator = null, $value = null, $joiner = 'AND' ) {+ $key = $this->addTablePrefix( $key );+ $this->statements['criteria'][] = compact( 'key', 'operator', 'value', 'joiner' );++ return $this;+ }+}
Vulnerability Existed: no Explanation: This diff contains only whitespace changes (line ending normalization from CRLF to LF or similar). The actual code logic remains identical: - The file structure, class definition, and method signature are unchanged - Variable handling is the same (`$key`, `$operator`, `$value`, `$joiner`) - The `addTablePrefix()` call is unchanged - The `compact()` function usage is unchanged - No new code is introduced, and no existing vulnerable code is removed or fixed Since no functional code changes are present, no security vulnerabilities are introduced or fixed. This is purely a formatting/whitespace normalization commit with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/QueryBuilder/QueryBuilderHandler.php 2025-12-21 09:35:59.433066315 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/QueryBuilder/QueryBuilderHandler.php 2025-12-21 09:36:35.235291534 +0000@@ -1,746 +1,746 @@-<?php namespace WpFluent\QueryBuilder; - -use Closure; -use WpFluent\Connection; -use WpFluent\Exception; - -class QueryBuilderHandler { - - - protected $container; - - protected $connection; - - protected $statements = array(); - - protected $db; - - protected $dbStatement = null; - - protected $tablePrefix = null; - - protected $adapterInstance; - - protected $adapter; - - protected $adapterConfig; - - protected $fetchParameters = array( 5 ); // \PDO::FETCH_OBJ is the value we are replacing because $wpdb issues - - public function __construct( Connection $connection = null ) { - if ( is_null( $connection ) ) { - $connection = Connection::getStoredConnection(); - if ( ! $connection ) { - throw new Exception( 'No database connection found.', 1 ); - } - } - - $this->connection = $connection; - $this->container = $this->connection->getContainer(); - $this->db = $this->connection->getDbInstance(); - $this->adapter = $this->connection->getAdapter(); - $this->adapterConfig = $this->connection->getAdapterConfig(); - - if ( isset( $this->adapterConfig['prefix'] ) ) { - $this->tablePrefix = $this->adapterConfig['prefix']; - } - - // Query builder adapter instance - $this->adapterInstance = $this->container->build( - '\\WpFluent\\QueryBuilder\\Adapters\\' . ucfirst( $this->adapter ), - array( $this->connection ) - ); - } - - /** - * Set the fetch mode - * - * @param $mode - * @return $this - */ - public function setFetchMode( $mode ) { - $this->fetchParameters = func_get_args(); - - return $this; - } - - /** - * Fetch query results as object of specified type - * - * @param $className - * @param array $constructorArgs - * @return QueryBuilderHandler - */ - public function asObject( $className, $constructorArgs = array() ) { - die( 'need to implement this' ); - } - - public function newQuery( Connection $connection = null ) { - if ( is_null( $connection ) ) { - $connection = $this->connection; - } - - return new static( $connection ); - } - - public function query( $sql, $bindings = array() ) { - $this->dbStatement = $this->container->build( - '\\WpFluent\\QueryBuilder\\QueryObject', - array( $sql, $bindings ) - )->getRawSql(); - - return $this; - } - - public function statement( $rawSql ) { - $start = microtime( true ); - - $this->db->query( $rawSql ); - - return microtime( true ) - $start; - } - - /** - * Get all rows - * - * @return array|object|null - * @throws \WpFluent\Exception - */ - public function get() { - $eventResult = $this->fireEvents( 'before-select' ); - - if ( ! is_null( $eventResult ) ) { - return $eventResult; - }; - - if ( is_null( $this->dbStatement ) ) { - $queryObject = $this->getQuery( 'select' ); - - $this->dbStatement = $queryObject->getRawSql(); - } - - $start = microtime( true ); - $result = $this->db->get_results( $this->dbStatement ); - $executionTime = microtime( true ) - $start; - $this->dbStatement = null; - $this->fireEvents( 'after-select', $result, $executionTime ); - - return $result; - } - - /** - * Get chunked rows - * - * @return array|object|null - * @throws \WpFluent\Exception - */ - public function chunk( $limit, Closure $callback, $chunkPage = 1 ) { - - $this->limit( $limit ); - $this->offset( $limit * ( $chunkPage - 1 ) ); - - $result = $this->get(); - - if ( count( $result ) ) { - $callback( $result ); - return $this->chunk( $limit, $callback, ++$chunkPage ); - } - - return $chunkPage; - } - - /** - * Get first row - * - * @return \stdClass|null - */ - public function first() { - $this->limit( 1 ); - $result = $this->get(); - - return empty( $result ) ? null : $result[0]; - } - - public function findAll( $fieldName, $value ) { - $this->where( $fieldName, '=', $value ); - - return $this->get(); - } - - public function find( $value, $fieldName = 'id' ) { - $this->where( $fieldName, '=', $value ); - - return $this->first(); - } - - public function count() { - // Get the current statements - $originalStatements = $this->statements; - - unset( $this->statements['orderBys'] ); - unset( $this->statements['limit'] ); - unset( $this->statements['offset'] ); - - $count = $this->aggregate( 'count' ); - $this->statements = $originalStatements; - - return $count; - } - - protected function aggregate( $type ) { - // Get the current selects - $mainSelects = isset( $this->statements['selects'] ) ? $this->statements['selects'] : null; - // Replace select with a scalar value like `count` - $this->statements['selects'] = array( $this->raw( $type . '(*) as field' ) ); - $row = $this->get(); - - // Set the select as it was - if ( $mainSelects ) { - $this->statements['selects'] = $mainSelects; - } else { - unset( $this->statements['selects'] ); - } - $count = count( $row ); - if ( $count > 1 ) { - return $count; - } else { - $item = (array) $row[0]; - - return (int) $item['field']; - } - } - - public function getQuery( $type = 'select', $dataToBePassed = array() ) { - $allowedTypes = array( 'select', 'insert', 'insertignore', 'replace', 'delete', 'update', 'criteriaonly' ); - - if ( ! in_array( strtolower( $type ), $allowedTypes, true ) ) { - throw new Exception( $type . ' is not a known type.', 2 ); - } - - $queryArr = $this->adapterInstance->$type( $this->statements, $dataToBePassed ); - - return $this->container->build( - '\\WpFluent\\QueryBuilder\\QueryObject', - array( $queryArr['sql'], $queryArr['bindings'] ) - ); - } - - public function subQuery( QueryBuilderHandler $queryBuilder, $alias = null ) { - $sql = '(' . $queryBuilder->getQuery()->getRawSql() . ')'; - - if ( $alias ) { - $sql = $sql . ' as ' . $alias; - } - - return $queryBuilder->raw( $sql ); - } - - private function doInsert( $data, $type ) { - $eventResult = $this->fireEvents( 'before-insert' ); - - if ( ! is_null( $eventResult ) ) { - return $eventResult; - } - - // If first value is not an array - // Its not a batch insert - if ( ! is_array( current( $data ) ) ) { - $start = microtime( true ); - - $queryObject = $this->getQuery( $type, $data ); - - $executionTime = $this->statement( $queryObject->getRawSql() ); - - $return = $this->db->insert_id; - } else { - // Its a batch insert - $executionTime = 0; - $return = array(); - foreach ( $data as $subData ) { - $start = microtime( true ); - - $queryObject = $this->getQuery( $type, $subData ); - - $executionTime = $this->statement( $queryObject->getRawSql() ); - - $return[] = $this->db->insert_id; - } - } - - $this->fireEvents( 'after-insert', $return, $executionTime ); - - return $return; - } - - public function insert( $data ) { - return $this->doInsert( $data, 'insert' ); - } - - public function insertIgnore( $data ) { - return $this->doInsert( $data, 'insertignore' ); - } - - public function replace( $data ) { - return $this->doInsert( $data, 'replace' ); - } - - public function update( $data ) { - $eventResult = $this->fireEvents( 'before-update' ); - - if ( ! is_null( $eventResult ) ) { - return $eventResult; - } - - $queryObject = $this->getQuery( 'update', $data ); - - $executionTime = $this->statement( $queryObject->getRawSql() ); - - $this->fireEvents( 'after-update', $queryObject, $executionTime ); - } - - public function updateOrInsert( $data ) { - if ( $this->first() ) { - return $this->update( $data ); - } else { - return $this->insert( $data ); - } - } - - public function onDuplicateKeyUpdate( $data ) { - $this->addStatement( 'onduplicate', $data ); - - return $this; - } - - public function delete() { - $eventResult = $this->fireEvents( 'before-delete' ); - - if ( ! is_null( $eventResult ) ) { - return $eventResult; - } - - $queryObject = $this->getQuery( 'delete' ); - - $executionTime = $this->statement( $queryObject->getRawSql() ); - - $this->fireEvents( 'after-delete', $queryObject, $executionTime ); - } - - public function table( $tables ) { - if ( ! is_array( $tables ) ) { - // because a single table is converted to an array anyways, - // this makes sense. - $tables = func_get_args(); - } - - $instance = new static( $this->connection ); - $tables = $this->addTablePrefix( $tables, false ); - $instance->addStatement( 'tables', $tables ); - - return $instance; - } - - public function from( $tables ) { - if ( ! is_array( $tables ) ) { - $tables = func_get_args(); - } - - $tables = $this->addTablePrefix( $tables, false ); - $this->addStatement( 'tables', $tables ); - - return $this; - } - - public function select( $fields ) { - if ( ! is_array( $fields ) ) { - $fields = func_get_args(); - } - - $fields = $this->addTablePrefix( $fields ); - $this->addStatement( 'selects', $fields ); - - return $this; - } - - public function selectDistinct( $fields ) { - $this->select( $fields ); - $this->addStatement( 'distinct', true ); - - return $this; - } - - public function groupBy( $field ) { - $field = $this->addTablePrefix( $field ); - $this->addStatement( 'groupBys', $field ); - - return $this; - } - - public function orderBy( $fields, $defaultDirection = 'ASC' ) { - if ( ! is_array( $fields ) ) { - $fields = array( $fields ); - } - - foreach ( $fields as $key => $value ) { - $field = $key; - $type = $value; - - if ( is_int( $key ) ) { - $field = $value; - $type = $defaultDirection; - } - - if ( ! $field instanceof Raw ) { - $field = $this->addTablePrefix( $field ); - } - - $this->statements['orderBys'][] = compact( 'field', 'type' ); - } - - return $this; - } - - public function limit( $limit ) { - $this->statements['limit'] = $limit; - - return $this; - } - - public function offset( $offset ) { - $this->statements['offset'] = $offset; - - return $this; - } - - public function having( $key, $operator = null, $value = null, $joiner = 'AND' ) { - $key = $this->addTablePrefix( $key ); - $this->statements['havings'][] = compact( 'key', 'operator', 'value', 'joiner' ); - - return $this; - } - - public function orHaving( $key, $operator, $value ) { - return $this->having( $key, $operator, $value, 'OR' ); - } - - public function where( $key, $operator = null, $value = null ) { - // If two params are given then assume operator is = - if ( func_num_args() === 2 ) { - $value = $operator; - $operator = '='; - } - - return $this->whereHandler( $key, $operator, $value ); - } - - public function orWhere( $key, $operator = null, $value = null ) { - // If two params are given then assume operator is = - if ( func_num_args() === 2 ) { - $value = $operator; - $operator = '='; - } - - return $this->whereHandler( $key, $operator, $value, 'OR' ); - } - - public function whereNot( $key, $operator = null, $value = null ) { - // If two params are given then assume operator is = - if ( func_num_args() == 2 ) { - $value = $operator; - $operator = '='; - } - - return $this->whereHandler( $key, $operator, $value, 'AND NOT' ); - } - - public function orWhereNot( $key, $operator = null, $value = null ) { - // If two params are given then assume operator is = - if ( func_num_args() == 2 ) { - $value = $operator; - $operator = '='; - } - - return $this->whereHandler( $key, $operator, $value, 'OR NOT' ); - } - - public function whereIn( $key, $values ) { - return $this->whereHandler( $key, 'IN', $values, 'AND' ); - } - - public function whereNotIn( $key, $values ) { - return $this->whereHandler( $key, 'NOT IN', $values, 'AND' ); - } - - public function orWhereIn( $key, $values ) { - return $this->whereHandler( $key, 'IN', $values, 'OR' ); - } - - public function orWhereNotIn( $key, $values ) { - return $this->whereHandler( $key, 'NOT IN', $values, 'OR' ); - } - - public function whereBetween( $key, $valueFrom, $valueTo ) { - return $this->whereHandler( $key, 'BETWEEN', array( $valueFrom, $valueTo ), 'AND' ); - } - - public function orWhereBetween( $key, $valueFrom, $valueTo ) { - return $this->whereHandler( $key, 'BETWEEN', array( $valueFrom, $valueTo ), 'OR' ); - } - - public function whereNull( $key ) { - return $this->whereNullHandler( $key ); - } - - public function whereNotNull( $key ) { - return $this->whereNullHandler( $key, 'NOT' ); - } - - public function orWhereNull( $key ) { - return $this->whereNullHandler( $key, '', 'or' ); - } - - public function orWhereNotNull( $key ) { - return $this->whereNullHandler( $key, 'NOT', 'or' ); - } - - protected function whereNullHandler( $key, $prefix = '', $operator = '' ) { - $key = $this->adapterInstance->wrapSanitizer( $this->addTablePrefix( $key ) ); - - return $this->{$operator . 'Where'}( $this->raw( "{$key} IS {$prefix} NULL" ) ); - } - - public function join( $table, $key, $operator = null, $value = null, $type = 'inner' ) { - if ( ! $key instanceof \Closure ) { - $key = function ( $joinBuilder ) use ( $key, $operator, $value ) { - $joinBuilder->on( $key, $operator, $value ); - }; - } - - // Build a new JoinBuilder class, keep it by reference so any changes made - // in the closure should reflect here - $joinBuilder = $this->container->build( '\\WpFluent\\QueryBuilder\\JoinBuilder', array( $this->connection ) ); - $joinBuilder = & $joinBuilder; - // Call the closure with our new joinBuilder object - $key( $joinBuilder ); - $table = $this->addTablePrefix( $table, false ); - // Get the criteria only query from the joinBuilder object - $this->statements['joins'][] = compact( 'type', 'table', 'joinBuilder' ); - - return $this; - } - - /** - * Runs a transaction - * - * @param $callback - * - * @return $this - */ - public function transaction( \Closure $callback ) { - try { - // Begin the PDO transaction - $this->db->query( 'START TRANSACTION' ); - - // Get the Transaction class - $transaction = $this->container->build( - '\\WpFluent\\QueryBuilder\\Transaction', - array( $this->connection ) - ); - - // Call closure - $callback( $transaction ); - - // If no errors have been thrown or the transaction wasn't completed within - // the closure, commit the changes - $this->db->query( 'COMMIT' ); - - return $this; - } catch ( TransactionHaltException $e ) { - // Commit or rollback behavior has been handled in the closure, so exit - return $this; - } catch ( \Exception $e ) { - // something happened, rollback changes - $this->db->query( 'ROLLBACK' ); - - return $this; - } - } - - public function leftJoin( $table, $key, $operator = null, $value = null ) { - return $this->join( $table, $key, $operator, $value, 'left' ); - } - - public function rightJoin( $table, $key, $operator = null, $value = null ) { - return $this->join( $table, $key, $operator, $value, 'right' ); - } - - public function innerJoin( $table, $key, $operator = null, $value = null ) { - return $this->join( $table, $key, $operator, $value, 'inner' ); - } - - public function raw( $value, $bindings = array() ) { - return $this->container->build( '\\WpFluent\\QueryBuilder\\Raw', array( $value, $bindings ) ); - } - - public function db() { - return $this->db; - } - - public function setConnection( Connection $connection ) { - $this->connection = $connection; - - return $this; - } - - public function getConnection() { - return $this->connection; - } - - protected function whereHandler( $key, $operator = null, $value = null, $joiner = 'AND' ) { - $key = $this->addTablePrefix( $key ); - $this->statements['wheres'][] = compact( 'key', 'operator', 'value', 'joiner' ); - - return $this; - } - - public function addTablePrefix( $values, $tableFieldMix = true ) { - if ( is_null( $this->tablePrefix ) ) { - return $values; - } - - // $value will be an array and we will add prefix to all table names - - // If supplied value is not an array then make it one - $single = false; - - if ( ! is_array( $values ) ) { - $values = array( $values ); - // We had single value, so should return a single value - $single = true; - } - - $return = array(); - - foreach ( $values as $key => $value ) { - // It's a raw query, just add it to our return array and continue next - if ( $value instanceof Raw || $value instanceof \Closure ) { - $return[ $key ] = $value; - continue; - } - - // If key is not integer, it is likely a alias mapping, - // so we need to change prefix target - $target = &$value; - if ( ! is_int( $key ) ) { - $target = &$key; - } - - if ( ! $tableFieldMix || ( $tableFieldMix && strpos( $target, '.' ) !== false ) ) { - $target = $this->tablePrefix . $target; - } - - $return[ $key ] = $value; - } - - // If we had single value then we should return a single value (end value of the array) - return $single ? end( $return ) : $return; - } - - protected function addStatement( $key, $value ) { - if ( ! is_array( $value ) ) { - $value = array( $value ); - } - - if ( ! array_key_exists( $key, $this->statements ) ) { - $this->statements[ $key ] = $value; - } else { - $this->statements[ $key ] = array_merge( $this->statements[ $key ], $value ); - } - } - - public function getEvent( $event, $table = ':any' ) { - return $this->connection->getEventHandler()->getEvent( $event, $table ); - } - - public function registerEvent( $event, $table, \Closure $action ) { - $table = $table ? $table : ':any'; - - if ( ':any' !== $table ) { - $table = $this->addTablePrefix( $table, false ); - } - - $this->connection->getEventHandler()->registerEvent( $event, $table, $action ); - } - - public function removeEvent( $event, $table = ':any' ) { - if ( ':any' !== $table ) { - $table = $this->addTablePrefix( $table, false ); - } - - $this->connection->getEventHandler()->removeEvent( $event, $table ); - } - - public function fireEvents( $event ) { - $params = func_get_args(); - array_unshift( $params, $this ); - - return call_user_func_array( - array( $this->connection->getEventHandler(), 'fireEvents' ), - $params - ); - } - - public function getStatements() { - return $this->statements; - } - - public function paginate( $perPage = null, $columns = array( '*' ) ) { - $currentPage = isset( $_GET['page'] ) ? intval( $_GET['page'] ) : 1; - - $perPage = $perPage ? $perPage : intval( isset( $_REQUEST['per_page'] ) ? sanitize_text_field( $_REQUEST['per_page'] ) : 15 ); - - $skip = $perPage * ( $currentPage - 1 ); - - $data = (array) $this->select( $columns )->limit( $perPage )->offset( $skip )->get(); - - $dataCount = count( $data ); - - $from = $dataCount > 0 ? ( $currentPage - 1 ) * $perPage + 1 : null; - - $to = $dataCount > 0 ? $from + $dataCount - 1 : null; - - $total = $this->count(); - - $lastPage = (int) ceil( $total / $perPage ); - - return array( - 'current_page' => $currentPage, - 'per_page' => $perPage, - 'from' => $from, - 'to' => $to, - 'last_page' => $lastPage, - 'total' => $total, - 'data' => $data, - ); - } - - /** - * Apply the callback's query changes if the given "value" is true. - * - * @param mixed $value - * @param callable $callback - * @param callable $default - * @return mixed - */ - public function when( $value, $callback, $default = null ) { - if ( $value ) { - $callback_response = $callback( $this, $value ); - return $callback_response ? $callback_response : $this; - } elseif ( $default ) { - $default_response = $default( $this, $value ); - return $default_response ? $default_response : $this; - } - - return $this; - } -} +<?php namespace WpFluent\QueryBuilder;++use Closure;+use WpFluent\Connection;+use WpFluent\Exception;++class QueryBuilderHandler {+++ protected $container;++ protected $connection;++ protected $statements = array();++ protected $db;++ protected $dbStatement = null;++ protected $tablePrefix = null;++ protected $adapterInstance;++ protected $adapter;++ protected $adapterConfig;++ protected $fetchParameters = array( 5 ); // \PDO::FETCH_OBJ is the value we are replacing because $wpdb issues++ public function __construct( Connection $connection = null ) {+ if ( is_null( $connection ) ) {+ $connection = Connection::getStoredConnection();+ if ( ! $connection ) {+ throw new Exception( 'No database connection found.', 1 );+ }+ }++ $this->connection = $connection;+ $this->container = $this->connection->getContainer();+ $this->db = $this->connection->getDbInstance();+ $this->adapter = $this->connection->getAdapter();+ $this->adapterConfig = $this->connection->getAdapterConfig();++ if ( isset( $this->adapterConfig['prefix'] ) ) {+ $this->tablePrefix = $this->adapterConfig['prefix'];+ }++ // Query builder adapter instance+ $this->adapterInstance = $this->container->build(+ '\\WpFluent\\QueryBuilder\\Adapters\\' . ucfirst( $this->adapter ),+ array( $this->connection )+ );+ }++ /**+ * Set the fetch mode+ *+ * @param $mode+ * @return $this+ */+ public function setFetchMode( $mode ) {+ $this->fetchParameters = func_get_args();++ return $this;+ }++ /**+ * Fetch query results as object of specified type+ *+ * @param $className+ * @param array $constructorArgs+ * @return QueryBuilderHandler+ */+ public function asObject( $className, $constructorArgs = array() ) {+ die( 'need to implement this' );+ }++ public function newQuery( Connection $connection = null ) {+ if ( is_null( $connection ) ) {+ $connection = $this->connection;+ }++ return new static( $connection );+ }++ public function query( $sql, $bindings = array() ) {+ $this->dbStatement = $this->container->build(+ '\\WpFluent\\QueryBuilder\\QueryObject',+ array( $sql, $bindings )+ )->getRawSql();++ return $this;+ }++ public function statement( $rawSql ) {+ $start = microtime( true );++ $this->db->query( $rawSql );++ return microtime( true ) - $start;+ }++ /**+ * Get all rows+ *+ * @return array|object|null+ * @throws \WpFluent\Exception+ */+ public function get() {+ $eventResult = $this->fireEvents( 'before-select' );++ if ( ! is_null( $eventResult ) ) {+ return $eventResult;+ };++ if ( is_null( $this->dbStatement ) ) {+ $queryObject = $this->getQuery( 'select' );++ $this->dbStatement = $queryObject->getRawSql();+ }++ $start = microtime( true );+ $result = $this->db->get_results( $this->dbStatement );+ $executionTime = microtime( true ) - $start;+ $this->dbStatement = null;+ $this->fireEvents( 'after-select', $result, $executionTime );++ return $result;+ }++ /**+ * Get chunked rows+ *+ * @return array|object|null+ * @throws \WpFluent\Exception+ */+ public function chunk( $limit, Closure $callback, $chunkPage = 1 ) {++ $this->limit( $limit );+ $this->offset( $limit * ( $chunkPage - 1 ) );++ $result = $this->get();++ if ( count( $result ) ) {+ $callback( $result );+ return $this->chunk( $limit, $callback, ++$chunkPage );+ }++ return $chunkPage;+ }++ /**+ * Get first row+ *+ * @return \stdClass|null+ */+ public function first() {+ $this->limit( 1 );+ $result = $this->get();++ return empty( $result ) ? null : $result[0];+ }++ public function findAll( $fieldName, $value ) {+ $this->where( $fieldName, '=', $value );++ return $this->get();+ }++ public function find( $value, $fieldName = 'id' ) {+ $this->where( $fieldName, '=', $value );++ return $this->first();+ }++ public function count() {+ // Get the current statements+ $originalStatements = $this->statements;++ unset( $this->statements['orderBys'] );+ unset( $this->statements['limit'] );+ unset( $this->statements['offset'] );++ $count = $this->aggregate( 'count' );+ $this->statements = $originalStatements;++ return $count;+ }++ protected function aggregate( $type ) {+ // Get the current selects+ $mainSelects = isset( $this->statements['selects'] ) ? $this->statements['selects'] : null;+ // Replace select with a scalar value like `count`+ $this->statements['selects'] = array( $this->raw( $type . '(*) as field' ) );+ $row = $this->get();++ // Set the select as it was+ if ( $mainSelects ) {+ $this->statements['selects'] = $mainSelects;+ } else {+ unset( $this->statements['selects'] );+ }+ $count = count( $row );+ if ( $count > 1 ) {+ return $count;+ } else {+ $item = (array) $row[0];++ return (int) $item['field'];+ }+ }++ public function getQuery( $type = 'select', $dataToBePassed = array() ) {+ $allowedTypes = array( 'select', 'insert', 'insertignore', 'replace', 'delete', 'update', 'criteriaonly' );++ if ( ! in_array( strtolower( $type ), $allowedTypes, true ) ) {+ throw new Exception( $type . ' is not a known type.', 2 );+ }++ $queryArr = $this->adapterInstance->$type( $this->statements, $dataToBePassed );++ return $this->container->build(+ '\\WpFluent\\QueryBuilder\\QueryObject',+ array( $queryArr['sql'], $queryArr['bindings'] )+ );+ }++ public function subQuery( QueryBuilderHandler $queryBuilder, $alias = null ) {+ $sql = '(' . $queryBuilder->getQuery()->getRawSql() . ')';++ if ( $alias ) {+ $sql = $sql . ' as ' . $alias;+ }++ return $queryBuilder->raw( $sql );+ }++ private function doInsert( $data, $type ) {+ $eventResult = $this->fireEvents( 'before-insert' );++ if ( ! is_null( $eventResult ) ) {+ return $eventResult;+ }++ // If first value is not an array+ // Its not a batch insert+ if ( ! is_array( current( $data ) ) ) {+ $start = microtime( true );++ $queryObject = $this->getQuery( $type, $data );+
Vulnerability Existed: no Analysis of the provided diff shows only whitespace and line ending changes (Unix line endings: `\n`). The actual code logic, structure, and security properties remain identical between versions 3.3.4 and 3.3.5. The file contains a query builder handler that: - Uses prepared statement patterns through the `QueryObject` class - Relies on adapter instances for query generation - Passes bindings separately from SQL (parameterized queries) - Includes event-driven hooks for insert/update/delete operations No security fixes were introduced in this update because no vulnerable code was modified. The diff is purely formatting-related (line ending normalization from DOS to Unix format).
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/QueryBuilder/QueryObject.php 2025-12-21 09:35:59.433066315 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/QueryBuilder/QueryObject.php 2025-12-21 09:36:35.235291534 +0000@@ -1,82 +1,82 @@-<?php - -namespace WpFluent\QueryBuilder; - -class QueryObject { - - protected $sql; - - protected $db; - - protected $bindings = array(); - - public function __construct( $sql, array $bindings ) { - $this->sql = (string) $sql; - - $this->bindings = $bindings; - - global $wpdb; - - $this->db = $wpdb; - } - - public function getSql() { - return $this->sql; - } - - public function getBindings() { - return $this->bindings; - } - - /** - * Get the raw/bound sql - * - * @return string - */ - public function getRawSql() { - return $this->interpolateQuery( $this->sql, $this->bindings ); - } - - /** - * Replaces any parameter placeholders in a query with the value of that - * parameter. Useful for debugging. Assumes anonymous parameters from - * $params are are in the same order as specified in $query - * - * Reference: http://stackoverflow.com/a/1376838/656489 - * - * @param string $query The sql query with parameter placeholders - * @param array $params The array of substitution parameters - * - * @return string The interpolated query - */ - protected function interpolateQuery( $query, $params ) { - $keys = array(); - $placeHolders = array(); - - foreach ( $params as $key => $value ) { - if ( is_string( $key ) ) { - $keys[] = '/:' . $key . '/'; - } else { - $keys[] = '/[?]/'; - } - - $placeHolders[] = $this->getPlaceHolder( $value ); - } - - $query = preg_replace( $keys, $placeHolders, $query, 1, $count ); - - return $params ? $this->db->prepare( $query, $params ) : $query; - } - - private function getPlaceHolder( $value ) { - $placeHolder = '%s'; - - if ( is_int( $value ) ) { - $placeHolder = '%d'; - } elseif ( is_float( $value ) ) { - $placeHolder = '%f'; - } - - return $placeHolder; - } -} +<?php++namespace WpFluent\QueryBuilder;++class QueryObject {++ protected $sql;++ protected $db;++ protected $bindings = array();++ public function __construct( $sql, array $bindings ) {+ $this->sql = (string) $sql;++ $this->bindings = $bindings;++ global $wpdb;++ $this->db = $wpdb;+ }++ public function getSql() {+ return $this->sql;+ }++ public function getBindings() {+ return $this->bindings;+ }++ /**+ * Get the raw/bound sql+ *+ * @return string+ */+ public function getRawSql() {+ return $this->interpolateQuery( $this->sql, $this->bindings );+ }++ /**+ * Replaces any parameter placeholders in a query with the value of that+ * parameter. Useful for debugging. Assumes anonymous parameters from+ * $params are are in the same order as specified in $query+ *+ * Reference: http://stackoverflow.com/a/1376838/656489+ *+ * @param string $query The sql query with parameter placeholders+ * @param array $params The array of substitution parameters+ *+ * @return string The interpolated query+ */+ protected function interpolateQuery( $query, $params ) {+ $keys = array();+ $placeHolders = array();++ foreach ( $params as $key => $value ) {+ if ( is_string( $key ) ) {+ $keys[] = '/:' . $key . '/';+ } else {+ $keys[] = '/[?]/';+ }++ $placeHolders[] = $this->getPlaceHolder( $value );+ }++ $query = preg_replace( $keys, $placeHolders, $query, 1, $count );++ return $params ? $this->db->prepare( $query, $params ) : $query;+ }++ private function getPlaceHolder( $value ) {+ $placeHolder = '%s';++ if ( is_int( $value ) ) {+ $placeHolder = '%d';+ } elseif ( is_float( $value ) ) {+ $placeHolder = '%f';+ }++ return $placeHolder;+ }+}
Vulnerability Existed: no File: includes/wp-fluent/src/QueryBuilder/QueryObject.php Explanation: This diff shows only a line ending change (CRLF to LF conversion) with no functional code modifications. The actual code logic remains identical between versions 3.3.4 and 3.3.5. No security fixes or vulnerabilities are present in this change. The code itself (both old and new versions) handles SQL query parameter binding through `preg_replace` with type-based placeholder substitution and ultimately relies on WordPress's `$wpdb->prepare()` method for security. While the implementation pattern is present, this specific diff contains zero functional changes and therefore zero security fixes.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/QueryBuilder/Raw.php 2025-12-21 09:35:59.433066315 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/QueryBuilder/Raw.php 2025-12-21 09:36:35.235291534 +0000@@ -1,21 +1,21 @@-<?php namespace WpFluent\QueryBuilder; - -class Raw { - - protected $value; - - protected $bindings; - - public function __construct( $value, $bindings = array() ) { - $this->value = (string) $value; - $this->bindings = (array) $bindings; - } - - public function getBindings() { - return $this->bindings; - } - - public function __toString() { - return (string) $this->value; - } -} +<?php namespace WpFluent\QueryBuilder;++class Raw {++ protected $value;++ protected $bindings;++ public function __construct( $value, $bindings = array() ) {+ $this->value = (string) $value;+ $this->bindings = (array) $bindings;+ }++ public function getBindings() {+ return $this->bindings;+ }++ public function __toString() {+ return (string) $this->value;+ }+}
Vulnerability Existed: no Explanation: This diff shows only whitespace/line ending changes (CRLF to LF conversion). The actual code logic remains identical: - Class structure unchanged - Constructor behavior unchanged - Method implementations unchanged - Type casting and binding handling unchanged No security vulnerabilities are introduced or fixed in this change. This is a code formatting/normalization update with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/QueryBuilder/Transaction.php 2025-12-21 09:35:59.433066315 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/QueryBuilder/Transaction.php 2025-12-21 09:36:35.235291534 +0000@@ -1,25 +1,25 @@-<?php - -namespace WpFluent\QueryBuilder; - -class Transaction extends QueryBuilderHandler { - - - /** - * Commit the database changes - */ - public function commit() { - $this->db->query( 'COMMIT' ); - - throw new TransactionHaltException(); - } - - /** - * Rollback the database changes - */ - public function rollback() { - $this->db->query( 'ROLLBACK' ); - - throw new TransactionHaltException(); - } -} +<?php++namespace WpFluent\QueryBuilder;++class Transaction extends QueryBuilderHandler {+++ /**+ * Commit the database changes+ */+ public function commit() {+ $this->db->query( 'COMMIT' );++ throw new TransactionHaltException();+ }++ /**+ * Rollback the database changes+ */+ public function rollback() {+ $this->db->query( 'ROLLBACK' );++ throw new TransactionHaltException();+ }+}
Vulnerability Existed: no Explanation: This diff contains only whitespace changes (line ending normalization from CRLF to LF). There are no functional code modifications, security-relevant changes, or vulnerability fixes present. The code structure, logic, and all statements remain identical between versions 3.3.4 and 3.3.5. No security vulnerabilities are introduced, fixed, or modified in this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/includes/wp-fluent/src/QueryBuilder/TransactionHaltException.php 2025-12-21 09:35:59.433066315 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/includes/wp-fluent/src/QueryBuilder/TransactionHaltException.php 2025-12-21 09:36:35.235291534 +0000@@ -1,7 +1,7 @@-<?php - -namespace WpFluent\QueryBuilder; - -class TransactionHaltException extends \Exception { - -} +<?php++namespace WpFluent\QueryBuilder;++class TransactionHaltException extends \Exception {++}
Vulnerability Existed: no No Security Vulnerabilities Detected Explanation: This diff contains only whitespace/line ending changes (CRLF to LF conversion). The file structure, namespace declaration, and class definition remain functionally identical. There are no code logic changes, no new inputs being processed, no changes to exception handling, and no modifications to security-critical functionality. This is a formatting-only change that does not introduce, fix, or relate to any security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/index.php 2025-12-21 09:35:59.433066315 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/index.php 2025-12-21 09:36:35.235291534 +0000@@ -1 +1 @@-<?php //silence is golden +<?php //silence is golden
Vulnerability Existed: no Explanation: This diff shows no meaningful changes to the file. Both versions contain identical content: `<?php //silence is golden`. The file is a standard WordPress plugin safety file that prevents direct access to the plugin directory by outputting nothing when accessed directly. There are no code changes that could introduce or fix security vulnerabilities. The diff appears to be a no-op (no operation), possibly from a version bump with no actual modifications to this file.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/review_and_troubleshoot_notify/resources/logo.php 2025-12-21 09:35:59.449067309 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/review_and_troubleshoot_notify/resources/logo.php 2025-12-21 09:36:35.263293274 +0000@@ -1,91 +1,91 @@-<div class="elex-banner-row-logo"> - <svg xmlns="http://www.w3.org/2000/svg" class="elex-banner-logo" viewBox="0 0 319.225 134.495"> - <g id="ELEXtensions_-_New_Logo" data-name="ELEXtensions - New Logo" transform="translate(-35.925 -120.696)"> - <g id="Group_375" data-name="Group 375" transform="translate(35.925 164.737)"> - <g id="Group_374" data-name="Group 374" transform="translate(0 0)"> - <g id="Group_373" data-name="Group 373" transform="translate(0 0)"> - <path id="Path_460" data-name="Path 460" d="M34.985-7,35.447.423q-6.232.657-21.206.653a10.405,10.405,0,0,1-7.3-2.485A8.83,8.83,0,0,1,4.156-8.132V-35.838a8.836,8.836,0,0,1,2.788-6.723,10.405,10.405,0,0,1,7.3-2.485q14.972,0,21.206.669l-.462,7.488H17.412a3.113,3.113,0,0,0-2.39.8,3.814,3.814,0,0,0-.717,2.581v6.962H32.531v7.281H14.305v8.826A3.913,3.913,0,0,0,15.022-7.8a3.1,3.1,0,0,0,2.39.8Zm0,0" transform="translate(-4.156 45.047)" fill="#10518d" /> - </g> - </g> - </g> - <g id="Group_378" data-name="Group 378" transform="translate(75.692 164.944)"> - <g id="Group_377" data-name="Group 377" transform="translate(0 0)"> - <g id="Group_376" data-name="Group 376" transform="translate(0 0)"> - <path id="Path_461" data-name="Path 461" d="M14.491-44.844v34.127a3.445,3.445,0,0,0,.828,2.581,3.883,3.883,0,0,0,2.756.8H33.785l.462,7.7q-6.692.717-19.358.717Q9.584,1.073,7-1.572a9.711,9.711,0,0,1-2.581-7.09V-44.844Zm0,0" transform="translate(-4.422 44.844)" fill="#10518d" /> - </g> - </g> - </g> - <g id="Group_381" data-name="Group 381" transform="translate(111.993 164.737)"> - <g id="Group_380" data-name="Group 380" transform="translate(0 0)"> - <g id="Group_379" data-name="Group 379" transform="translate(0 0)"> - <path id="Path_462" data-name="Path 462" d="M34.985-7,35.447.423q-6.232.657-21.206.653a10.405,10.405,0,0,1-7.3-2.485A8.83,8.83,0,0,1,4.156-8.132V-35.838a8.836,8.836,0,0,1,2.788-6.723,10.405,10.405,0,0,1,7.3-2.485q14.972,0,21.206.669l-.462,7.488H17.412a3.113,3.113,0,0,0-2.39.8,3.814,3.814,0,0,0-.717,2.581v6.962H32.531v7.281H14.305v8.826A3.913,3.913,0,0,0,15.022-7.8a3.1,3.1,0,0,0,2.39.8Zm0,0" transform="translate(-4.156 45.047)" fill="#ed1f24" /> - </g> - </g> - </g> - <g id="Group_384" data-name="Group 384" transform="translate(146.01 120.696)"> - <g id="Group_383" data-name="Group 383" transform="translate(0 0)"> - <g id="Group_382" data-name="Group 382"> - <path id="Path_463" data-name="Path 463" d="M-41.083,52.081c.992,0,2.183-1.589,3.178-3.178.4-.6.4-1.191,0-1.39C-19.033,17.911,5-13.081,29.64-41.887c17.286-.8,34.967-.8,51.851-.2.8,0,1.195-.4,1.195-.992a1.115,1.115,0,0,0-1-1.195c-16.49-.593-33.374-.593-49.864,0C42.553-56.787,53.283-68.908,64.009-80.431a1.181,1.181,0,0,0,.2-.793,1.144,1.144,0,0,0-1.191-1.191,1.53,1.53,0,0,0-.8.394C51.1-69.9,39.773-57.186,28.648-44.073c-17.88.6-35.162,1.988-50.66,3.975A1.254,1.254,0,0,0-23-38.907a1.278,1.278,0,0,0,1.191,1.191h.2c14.7-1.988,31.191-3.378,48.274-4.17C1.631-12.484-22.41,18.7-41.481,48.7c-.2.4-.4.8-.6,1.191l-.2.2C-42.672,51.284-42.473,52.081-41.083,52.081Zm0,0" transform="translate(42.455 82.414)" fill="#ed1f24" /> - </g> - </g> - </g> - <g id="Group_387" data-name="Group 387" transform="translate(194.198 187.236)"> - <g id="Group_386" data-name="Group 386" transform="translate(0 0)"> - <g id="Group_385" data-name="Group 385" transform="translate(0 0)"> - <path id="Path_464" data-name="Path 464" d="M17.638-10.329a1.177,1.177,0,0,1-.255.717q-3.346,2.838-5.672,4.636T8.031-2.267Q1.578,2.046-3.647,2.178q-4.445,0-4.509-4.573,0-2.832,3.282-6.644,3.555-3.68,5.943-3.68a2.057,2.057,0,0,1,1.482.653,1.658,1.658,0,0,1,.7,1.29,2.81,2.81,0,0,1-.223,1.1,4.241,4.241,0,0,1-.94,1.211A11.575,11.575,0,0,1,.893-7.381C.531-7.1.12-6.8-.349-6.457Q-1.383-5.693-2.58-4.88A22.988,22.988,0,0,1-5.32-3.3,2.977,2.977,0,0,0-4.03-.722,4.29,4.29,0,0,0-1.64,0Q1.706,0,8.349-4.323,9-4.783,11.122-6.33t5.815-4.318a1.485,1.485,0,0,1,.446-.064C17.51-10.711,17.594-10.584,17.638-10.329ZM.415-10.074c0-.339-.275-.51-.828-.51a2.533,2.533,0,0,0-1.227.494,8.042,8.042,0,0,0-1.689,1.5A9.539,9.539,0,0,0-4.476-6.967a5.058,5.058,0,0,0-.653,1.609A2.077,2.077,0,0,0-4.6-5.486a2.919,2.919,0,0,0,.7-.335,14.034,14.034,0,0,0,3-2.119A3.289,3.289,0,0,0,.415-10.074Zm0,0" transform="translate(8.156 12.719)" fill="#ed1f24" /> - </g> - </g> - </g> - <g id="Group_390" data-name="Group 390" transform="translate(212.779 189.052)"> - <g id="Group_389" data-name="Group 389" transform="translate(0 0)"> - <g id="Group_388" data-name="Group 388" transform="translate(0)"> - <path id="Path_465" data-name="Path 465" d="M33.049-10.364a1.177,1.177,0,0,1-.255.717Q26.533-4.5,24.016-2.812q-5.867,4-10.133,4-3.668,0-3.664-3.872a11.962,11.962,0,0,1,.159-1.768A24.933,24.933,0,0,1,10.92-7q-2.456,1.422-5,2.932T.659-.757A27.055,27.055,0,0,1-3.467,1.76a2.689,2.689,0,0,1-.51-.255c-.255-.127-.382-.279-.382-.446A3.784,3.784,0,0,1-3.818-.422,27.328,27.328,0,0,1-1.985-3.274Q-.629-5.264.181-6.461c.542-.8.916-1.362,1.131-1.7a2,2,0,0,1-.255-1.1c0-.351.275-.717.828-1.1A4.367,4.367,0,0,1,3.3-10.937q2.2,0,2.2,1.673A13.273,13.273,0,0,1,3.447-5.983Q2.474-4.752,1.79-3.911A13.729,13.729,0,0,1,.6-2.557q12.266-8.376,15.8-8.38c.223,0,.4.279.526.828a22.535,22.535,0,0,1-2.007,2.39A13.518,13.518,0,0,0,13.5-5.489a4.843,4.843,0,0,0-.51,2.151q0,2.39,3.282,2.39,2.45,0,8.205-3.872,1.081-.633,7.855-5.8a1.638,1.638,0,0,1,.462-.064C32.922-10.683,33.006-10.575,33.049-10.364Zm0,0" transform="translate(4.359 10.938)" fill="#ed1f24" /> - </g> - </g> - </g> - <g id="Group_393" data-name="Group 393" transform="translate(234.829 188.654)"> - <g id="Group_392" data-name="Group 392" transform="translate(0 0)"> - <g id="Group_391" data-name="Group 391" transform="translate(0 0)"> - <path id="Path_466" data-name="Path 466" d="M22.755-10.356a1.177,1.177,0,0,1-.255.717q-7.492,6.118-9.161,7.217A27.163,27.163,0,0,1-1.112,1.959,6.721,6.721,0,0,1-4.919,1,16.035,16.035,0,0,1-7.245-1.068a1.738,1.738,0,0,1,.127-.717c-.721.438-1.418.828-2.087,1.179s-1.326.637-1.976.892c-.733,0-1.119-.1-1.163-.319a.84.84,0,0,1,.175-.446q.161-.269.478-.717A58.22,58.22,0,0,0-5.461-4.764q3.19-2.1,6.612-4.812a.587.587,0,0,1,.064-.207,6.867,6.867,0,0,1,3.872-1.545q3.214,0,3.218,2.9A8.113,8.113,0,0,1,6.313-3.84,12.567,12.567,0,0,1,2.824-.415q4,0,10.515-4.142A39.279,39.279,0,0,0,16.94-6.9q2.133-1.529,5.114-3.776a1.485,1.485,0,0,1,.446-.064C22.627-10.739,22.711-10.611,22.755-10.356ZM5.213-7.584c0-1.071-.566-1.609-1.689-1.609h-.7a.911.911,0,0,0-.51.127Q-.142-6.993-2.227-5.354q-2.1,1.643-3.919,2.932a1.373,1.373,0,0,1,.589.127A8.851,8.851,0,0,0-1.829-.813,6.122,6.122,0,0,0,.816-1.418a7.053,7.053,0,0,0,2.39-1.976A8.613,8.613,0,0,0,4.624-5.481,7.013,7.013,0,0,0,5.213-7.584Zm0,0" transform="translate(12.344 11.328)" fill="#ed1f24" /> - </g> - </g> - </g> - <g id="Group_396" data-name="Group 396" transform="translate(263.094 182.919)"> - <g id="Group_395" data-name="Group 395" transform="translate(0 0)"> - <g id="Group_394" data-name="Group 394" transform="translate(0 0)"> - <path id="Path_467" data-name="Path 467" d="M8.2-15.089q0,1.816-2.581,1.816c-1.681,0-2.517-.605-2.517-1.816,0-1.243.836-1.864,2.517-1.864Q8.2-16.953,8.2-15.089Zm10.515,4.843a.785.785,0,0,1-.319.637q-3.489,3.047-5.624,4.78T9.685-2.439Q4.01,1.749,1.05,1.751A5.972,5.972,0,0,1-2.375.652,3.434,3.434,0,0,1-3.984-1.929q0-2.39,2.517-5.608Q.8-10.5,2.532-10.9c.55,0,.828.2.828.589q0,.514-2.055,2.836A8.269,8.269,0,0,0-.639-3.092q0,2.581,2.39,2.645,2.706,0,16.267-10.053a.521.521,0,0,1,.382-.127C18.528-10.628,18.631-10.5,18.719-10.246Zm0,0" transform="translate(3.984 16.953)" fill="#ed1f24" /> - </g> - </g> - </g> - <g id="Group_399" data-name="Group 399" transform="translate(275.538 188.208)"> - <g id="Group_398" data-name="Group 398" transform="translate(0 0)"> - <g id="Group_397" data-name="Group 397" transform="translate(0 0)"> - <path id="Path_468" data-name="Path 468" d="M22.4-10.348a1.879,1.879,0,0,1-.032.35,1.3,1.3,0,0,1-.223.43A33.2,33.2,0,0,1,15.04-3.513,28.388,28.388,0,0,1,10.515-.725,9.027,9.027,0,0,1,7.3.231,4.313,4.313,0,0,1,4.206-1,10.583,10.583,0,0,1,1.242,1.139,11.045,11.045,0,0,1-3.92,2.621q-3.358,0-3.362-2.645a6.53,6.53,0,0,1,1.29-3.648A23.576,23.576,0,0,1-2.247-7.767,19.357,19.357,0,0,1,2.23-10.794a9.2,9.2,0,0,1,3.776-.972q3.3,0,3.3,3.091,0,3.429-3.872,6.707A2.8,2.8,0,0,0,7.5-1.123q2.181,0,7.154-3.553,2.133-1.482,3.9-2.963A40.107,40.107,0,0,0,21.747-10.6c.04-.127.175-.147.4-.064C22.313-10.666,22.4-10.559,22.4-10.348ZM8.4-9.185c0-.689-.39-1.075-1.163-1.163A3.3,3.3,0,0,0,4.652-9.057,4.856,4.856,0,0,0,3.569-6.285q0,2.39.828,3.155Q8.269-6.154,8.4-9.185ZM3.425-2.095A4.547,4.547,0,0,1,2.151-5.441,5.5,5.5,0,0,1,3.3-9.376Q-4.362-5.839-4.366-1.967q0,2.39,1.864,2.39A9.536,9.536,0,0,0,3.425-2.095Zm0,0" transform="translate(7.281 11.766)" fill="#ed1f24" /> - </g> - </g> - </g> - <g id="Group_402" data-name="Group 402" transform="translate(298.001 189.052)"> - <g id="Group_401" data-name="Group 401" transform="translate(0 0)"> - <g id="Group_400" data-name="Group 400" transform="translate(0)"> - <path id="Path_469" data-name="Path 469" d="M33.049-10.364a1.177,1.177,0,0,1-.255.717Q26.533-4.5,24.016-2.812q-5.867,4-10.133,4-3.668,0-3.664-3.872a11.962,11.962,0,0,1,.159-1.768A24.933,24.933,0,0,1,10.92-7q-2.456,1.422-5,2.932T.659-.757A27.055,27.055,0,0,1-3.467,1.76a2.689,2.689,0,0,1-.51-.255c-.255-.127-.382-.279-.382-.446A3.784,3.784,0,0,1-3.818-.422,27.328,27.328,0,0,1-1.985-3.274Q-.629-5.264.181-6.461c.542-.8.916-1.362,1.131-1.7a2,2,0,0,1-.255-1.1c0-.351.275-.717.828-1.1A4.367,4.367,0,0,1,3.3-10.937q2.2,0,2.2,1.673A13.273,13.273,0,0,1,3.447-5.983Q2.474-4.752,1.79-3.911A13.729,13.729,0,0,1,.6-2.557q12.266-8.376,15.8-8.38c.223,0,.4.279.526.828a22.535,22.535,0,0,1-2.007,2.39A13.518,13.518,0,0,0,13.5-5.489a4.843,4.843,0,0,0-.51,2.151q0,2.39,3.282,2.39,2.45,0,8.205-3.872,1.081-.633,7.855-5.8a1.638,1.638,0,0,1,.462-.064C32.922-10.683,33.006-10.575,33.049-10.364Zm0,0" transform="translate(4.359 10.938)" fill="#ed1f24" /> - </g> - </g> - </g> - <g id="Group_405" data-name="Group 405" transform="translate(320.051 188.654)"> - <g id="Group_404" data-name="Group 404" transform="translate(0 0)"> - <g id="Group_403" data-name="Group 403" transform="translate(0 0)"> - <path id="Path_470" data-name="Path 470" d="M22.755-10.356a1.177,1.177,0,0,1-.255.717q-7.492,6.118-9.161,7.217A27.163,27.163,0,0,1-1.112,1.959,6.721,6.721,0,0,1-4.919,1,16.035,16.035,0,0,1-7.245-1.068a1.738,1.738,0,0,1,.127-.717c-.721.438-1.418.828-2.087,1.179s-1.326.637-1.976.892c-.733,0-1.119-.1-1.163-.319a.84.84,0,0,1,.175-.446q.161-.269.478-.717A58.22,58.22,0,0,0-5.461-4.764q3.19-2.1,6.612-4.812a.587.587,0,0,1,.064-.207,6.867,6.867,0,0,1,3.872-1.545q3.214,0,3.218,2.9A8.113,8.113,0,0,1,6.313-3.84,12.567,12.567,0,0,1,2.824-.415q4,0,10.515-4.142A39.279,39.279,0,0,0,16.94-6.9q2.133-1.529,5.114-3.776a1.485,1.485,0,0,1,.446-.064C22.627-10.739,22.711-10.611,22.755-10.356ZM5.213-7.584c0-1.071-.566-1.609-1.689-1.609h-.7a.911.911,0,0,0-.51.127Q-.142-6.993-2.227-5.354q-2.1,1.643-3.919,2.932a1.373,1.373,0,0,1,.589.127A8.851,8.851,0,0,0-1.829-.813,6.122,6.122,0,0,0,.816-1.418a7.053,7.053,0,0,0,2.39-1.976A8.613,8.613,0,0,0,4.624-5.481,7.013,7.013,0,0,0,5.213-7.584Zm0,0" transform="translate(12.344 11.328)" fill="#ed1f24" /> - </g> - </g> - </g> - <g id="Group_408" data-name="Group 408" transform="translate(148.015 172.907)"> - <g id="Group_407" data-name="Group 407" transform="translate(0 0)"> - <g id="Group_406" data-name="Group 406" transform="translate(0 0)"> - <path id="Path_471" data-name="Path 471" d="M17.418-12.085h-.366L9.9.581H.594L9.9-14.9,1.279-29.578H10.5L16.94-17.964h.605l6.421-11.615h9.241L24.588-14.9,33.876.581H24.588Zm0,0" transform="translate(-0.594 29.578)" fill="#ed1f24" /> - </g> - </g> - </g> - </g> - </svg> - -</div> +<div class="elex-banner-row-logo">+ <svg xmlns="http://www.w3.org/2000/svg" class="elex-banner-logo" viewBox="0 0 319.225 134.495">+ <g id="ELEXtensions_-_New_Logo" data-name="ELEXtensions - New Logo" transform="translate(-35.925 -120.696)">+ <g id="Group_375" data-name="Group 375" transform="translate(35.925 164.737)">+ <g id="Group_374" data-name="Group 374" transform="translate(0 0)">+ <g id="Group_373" data-name="Group 373" transform="translate(0 0)">+ <path id="Path_460" data-name="Path 460" d="M34.985-7,35.447.423q-6.232.657-21.206.653a10.405,10.405,0,0,1-7.3-2.485A8.83,8.83,0,0,1,4.156-8.132V-35.838a8.836,8.836,0,0,1,2.788-6.723,10.405,10.405,0,0,1,7.3-2.485q14.972,0,21.206.669l-.462,7.488H17.412a3.113,3.113,0,0,0-2.39.8,3.814,3.814,0,0,0-.717,2.581v6.962H32.531v7.281H14.305v8.826A3.913,3.913,0,0,0,15.022-7.8a3.1,3.1,0,0,0,2.39.8Zm0,0" transform="translate(-4.156 45.047)" fill="#10518d" />+ </g>+ </g>+ </g>+ <g id="Group_378" data-name="Group 378" transform="translate(75.692 164.944)">+ <g id="Group_377" data-name="Group 377" transform="translate(0 0)">+ <g id="Group_376" data-name="Group 376" transform="translate(0 0)">+ <path id="Path_461" data-name="Path 461" d="M14.491-44.844v34.127a3.445,3.445,0,0,0,.828,2.581,3.883,3.883,0,0,0,2.756.8H33.785l.462,7.7q-6.692.717-19.358.717Q9.584,1.073,7-1.572a9.711,9.711,0,0,1-2.581-7.09V-44.844Zm0,0" transform="translate(-4.422 44.844)" fill="#10518d" />+ </g>+ </g>+ </g>+ <g id="Group_381" data-name="Group 381" transform="translate(111.993 164.737)">+ <g id="Group_380" data-name="Group 380" transform="translate(0 0)">+ <g id="Group_379" data-name="Group 379" transform="translate(0 0)">+ <path id="Path_462" data-name="Path 462" d="M34.985-7,35.447.423q-6.232.657-21.206.653a10.405,10.405,0,0,1-7.3-2.485A8.83,8.83,0,0,1,4.156-8.132V-35.838a8.836,8.836,0,0,1,2.788-6.723,10.405,10.405,0,0,1,7.3-2.485q14.972,0,21.206.669l-.462,7.488H17.412a3.113,3.113,0,0,0-2.39.8,3.814,3.814,0,0,0-.717,2.581v6.962H32.531v7.281H14.305v8.826A3.913,3.913,0,0,0,15.022-7.8a3.1,3.1,0,0,0,2.39.8Zm0,0" transform="translate(-4.156 45.047)" fill="#ed1f24" />+ </g>+ </g>+ </g>+ <g id="Group_384" data-name="Group 384" transform="translate(146.01 120.696)">+ <g id="Group_383" data-name="Group 383" transform="translate(0 0)">+ <g id="Group_382" data-name="Group 382">+ <path id="Path_463" data-name="Path 463" d="M-41.083,52.081c.992,0,2.183-1.589,3.178-3.178.4-.6.4-1.191,0-1.39C-19.033,17.911,5-13.081,29.64-41.887c17.286-.8,34.967-.8,51.851-.2.8,0,1.195-.4,1.195-.992a1.115,1.115,0,0,0-1-1.195c-16.49-.593-33.374-.593-49.864,0C42.553-56.787,53.283-68.908,64.009-80.431a1.181,1.181,0,0,0,.2-.793,1.144,1.144,0,0,0-1.191-1.191,1.53,1.53,0,0,0-.8.394C51.1-69.9,39.773-57.186,28.648-44.073c-17.88.6-35.162,1.988-50.66,3.975A1.254,1.254,0,0,0-23-38.907a1.278,1.278,0,0,0,1.191,1.191h.2c14.7-1.988,31.191-3.378,48.274-4.17C1.631-12.484-22.41,18.7-41.481,48.7c-.2.4-.4.8-.6,1.191l-.2.2C-42.672,51.284-42.473,52.081-41.083,52.081Zm0,0" transform="translate(42.455 82.414)" fill="#ed1f24" />+ </g>+ </g>+ </g>+ <g id="Group_387" data-name="Group 387" transform="translate(194.198 187.236)">+ <g id="Group_386" data-name="Group 386" transform="translate(0 0)">+ <g id="Group_385" data-name="Group 385" transform="translate(0 0)">+ <path id="Path_464" data-name="Path 464" d="M17.638-10.329a1.177,1.177,0,0,1-.255.717q-3.346,2.838-5.672,4.636T8.031-2.267Q1.578,2.046-3.647,2.178q-4.445,0-4.509-4.573,0-2.832,3.282-6.644,3.555-3.68,5.943-3.68a2.057,2.057,0,0,1,1.482.653,1.658,1.658,0,0,1,.7,1.29,2.81,2.81,0,0,1-.223,1.1,4.241,4.241,0,0,1-.94,1.211A11.575,11.575,0,0,1,.893-7.381C.531-7.1.12-6.8-.349-6.457Q-1.383-5.693-2.58-4.88A22.988,22.988,0,0,1-5.32-3.3,2.977,2.977,0,0,0-4.03-.722,4.29,4.29,0,0,0-1.64,0Q1.706,0,8.349-4.323,9-4.783,11.122-6.33t5.815-4.318a1.485,1.485,0,0,1,.446-.064C17.51-10.711,17.594-10.584,17.638-10.329ZM.415-10.074c0-.339-.275-.51-.828-.51a2.533,2.533,0,0,0-1.227.494,8.042,8.042,0,0,0-1.689,1.5A9.539,9.539,0,0,0-4.476-6.967a5.058,5.058,0,0,0-.653,1.609A2.077,2.077,0,0,0-4.6-5.486a2.919,2.919,0,0,0,.7-.335,14.034,14.034,0,0,0,3-2.119A3.289,3.289,0,0,0,.415-10.074Zm0,0" transform="translate(8.156 12.719)" fill="#ed1f24" />+ </g>+ </g>+ </g>+ <g id="Group_390" data-name="Group 390" transform="translate(212.779 189.052)">+ <g id="Group_389" data-name="Group 389" transform="translate(0 0)">+ <g id="Group_388" data-name="Group 388" transform="translate(0)">+ <path id="Path_465" data-name="Path 465" d="M33.049-10.364a1.177,1.177,0,0,1-.255.717Q26.533-4.5,24.016-2.812q-5.867,4-10.133,4-3.668,0-3.664-3.872a11.962,11.962,0,0,1,.159-1.768A24.933,24.933,0,0,1,10.92-7q-2.456,1.422-5,2.932T.659-.757A27.055,27.055,0,0,1-3.467,1.76a2.689,2.689,0,0,1-.51-.255c-.255-.127-.382-.279-.382-.446A3.784,3.784,0,0,1-3.818-.422,27.328,27.328,0,0,1-1.985-3.274Q-.629-5.264.181-6.461c.542-.8.916-1.362,1.131-1.7a2,2,0,0,1-.255-1.1c0-.351.275-.717.828-1.1A4.367,4.367,0,0,1,3.3-10.937q2.2,0,2.2,1.673A13.273,13.273,0,0,1,3.447-5.983Q2.474-4.752,1.79-3.911A13.729,13.729,0,0,1,.6-2.557q12.266-8.376,15.8-8.38c.223,0,.4.279.526.828a22.535,22.535,0,0,1-2.007,2.39A13.518,13.518,0,0,0,13.5-5.489a4.843,4.843,0,0,0-.51,2.151q0,2.39,3.282,2.39,2.45,0,8.205-3.872,1.081-.633,7.855-5.8a1.638,1.638,0,0,1,.462-.064C32.922-10.683,33.006-10.575,33.049-10.364Zm0,0" transform="translate(4.359 10.938)" fill="#ed1f24" />+ </g>+ </g>+ </g>+ <g id="Group_393" data-name="Group 393" transform="translate(234.829 188.654)">+ <g id="Group_392" data-name="Group 392" transform="translate(0 0)">+ <g id="Group_391" data-name="Group 391" transform="translate(0 0)">+ <path id="Path_466" data-name="Path 466" d="M22.755-10.356a1.177,1.177,0,0,1-.255.717q-7.492,6.118-9.161,7.217A27.163,27.163,0,0,1-1.112,1.959,6.721,6.721,0,0,1-4.919,1,16.035,16.035,0,0,1-7.245-1.068a1.738,1.738,0,0,1,.127-.717c-.721.438-1.418.828-2.087,1.179s-1.326.637-1.976.892c-.733,0-1.119-.1-1.163-.319a.84.84,0,0,1,.175-.446q.161-.269.478-.717A58.22,58.22,0,0,0-5.461-4.764q3.19-2.1,6.612-4.812a.587.587,0,0,1,.064-.207,6.867,6.867,0,0,1,3.872-1.545q3.214,0,3.218,2.9A8.113,8.113,0,0,1,6.313-3.84,12.567,12.567,0,0,1,2.824-.415q4,0,10.515-4.142A39.279,39.279,0,0,0,16.94-6.9q2.133-1.529,5.114-3.776a1.485,1.485,0,0,1,.446-.064C22.627-10.739,22.711-10.611,22.755-10.356ZM5.213-7.584c0-1.071-.566-1.609-1.689-1.609h-.7a.911.911,0,0,0-.51.127Q-.142-6.993-2.227-5.354q-2.1,1.643-3.919,2.932a1.373,1.373,0,0,1,.589.127A8.851,8.851,0,0,0-1.829-.813,6.122,6.122,0,0,0,.816-1.418a7.053,7.053,0,0,0,2.39-1.976A8.613,8.613,0,0,0,4.624-5.481,7.013,7.013,0,0,0,5.213-7.584Zm0,0" transform="translate(12.344 11.328)" fill="#ed1f24" />+ </g>+ </g>+ </g>+ <g id="Group_396" data-name="Group 396" transform="translate(263.094 182.919)">+ <g id="Group_395" data-name="Group 395" transform="translate(0 0)">+ <g id="Group_394" data-name="Group 394" transform="translate(0 0)">+ <path id="Path_467" data-name="Path 467" d="M8.2-15.089q0,1.816-2.581,1.816c-1.681,0-2.517-.605-2.517-1.816,0-1.243.836-1.864,2.517-1.864Q8.2-16.953,8.2-15.089Zm10.515,4.843a.785.785,0,0,1-.319.637q-3.489,3.047-5.624,4.78T9.685-2.439Q4.01,1.749,1.05,1.751A5.972,5.972,0,0,1-2.375.652,3.434,3.434,0,0,1-3.984-1.929q0-2.39,2.517-5.608Q.8-10.5,2.532-10.9c.55,0,.828.2.828.589q0,.514-2.055,2.836A8.269,8.269,0,0,0-.639-3.092q0,2.581,2.39,2.645,2.706,0,16.267-10.053a.521.521,0,0,1,.382-.127C18.528-10.628,18.631-10.5,18.719-10.246Zm0,0" transform="translate(3.984 16.953)" fill="#ed1f24" />+ </g>+ </g>+ </g>+ <g id="Group_399" data-name="Group 399" transform="translate(275.538 188.208)">+ <g id="Group_398" data-name="Group 398" transform="translate(0 0)">+ <g id="Group_397" data-name="Group 397" transform="translate(0 0)">+ <path id="Path_468" data-name="Path 468" d="M22.4-10.348a1.879,1.879,0,0,1-.032.35,1.3,1.3,0,0,1-.223.43A33.2,33.2,0,0,1,15.04-3.513,28.388,28.388,0,0,1,10.515-.725,9.027,9.027,0,0,1,7.3.231,4.313,4.313,0,0,1,4.206-1,10.583,10.583,0,0,1,1.242,1.139,11.045,11.045,0,0,1-3.92,2.621q-3.358,0-3.362-2.645a6.53,6.53,0,0,1,1.29-3.648A23.576,23.576,0,0,1-2.247-7.767,19.357,19.357,0,0,1,2.23-10.794a9.2,9.2,0,0,1,3.776-.972q3.3,0,3.3,3.091,0,3.429-3.872,6.707A2.8,2.8,0,0,0,7.5-1.123q2.181,0,7.154-3.553,2.133-1.482,3.9-2.963A40.107,40.107,0,0,0,21.747-10.6c.04-.127.175-.147.4-.064C22.313-10.666,22.4-10.559,22.4-10.348ZM8.4-9.185c0-.689-.39-1.075-1.163-1.163A3.3,3.3,0,0,0,4.652-9.057,4.856,4.856,0,0,0,3.569-6.285q0,2.39.828,3.155Q8.269-6.154,8.4-9.185ZM3.425-2.095A4.547,4.547,0,0,1,2.151-5.441,5.5,5.5,0,0,1,3.3-9.376Q-4.362-5.839-4.366-1.967q0,2.39,1.864,2.39A9.536,9.536,0,0,0,3.425-2.095Zm0,0" transform="translate(7.281 11.766)" fill="#ed1f24" />+ </g>+ </g>+ </g>+ <g id="Group_402" data-name="Group 402" transform="translate(298.001 189.052)">+ <g id="Group_401" data-name="Group 401" transform="translate(0 0)">+ <g id="Group_400" data-name="Group 400" transform="translate(0)">+ <path id="Path_469" data-name="Path 469" d="M33.049-10.364a1.177,1.177,0,0,1-.255.717Q26.533-4.5,24.016-2.812q-5.867,4-10.133,4-3.668,0-3.664-3.872a11.962,11.962,0,0,1,.159-1.768A24.933,24.933,0,0,1,10.92-7q-2.456,1.422-5,2.932T.659-.757A27.055,27.055,0,0,1-3.467,1.76a2.689,2.689,0,0,1-.51-.255c-.255-.127-.382-.279-.382-.446A3.784,3.784,0,0,1-3.818-.422,27.328,27.328,0,0,1-1.985-3.274Q-.629-5.264.181-6.461c.542-.8.916-1.362,1.131-1.7a2,2,0,0,1-.255-1.1c0-.351.275-.717.828-1.1A4.367,4.367,0,0,1,3.3-10.937q2.2,0,2.2,1.673A13.273,13.273,0,0,1,3.447-5.983Q2.474-4.752,1.79-3.911A13.729,13.729,0,0,1,.6-2.557q12.266-8.376,15.8-8.38c.223,0,.4.279.526.828a22.535,22.535,0,0,1-2.007,2.39A13.518,13.518,0,0,0,13.5-5.489a4.843,4.843,0,0,0-.51,2.151q0,2.39,3.282,2.39,2.45,0,8.205-3.872,1.081-.633,7.855-5.8a1.638,1.638,0,0,1,.462-.064C32.922-10.683,33.006-10.575,33.049-10.364Zm0,0" transform="translate(4.359 10.938)" fill="#ed1f24" />+ </g>+ </g>+ </g>+ <g id="Group_405" data-name="Group 405" transform="translate(320.051 188.654)">+ <g id="Group_404" data-name="Group 404" transform="translate(0 0)">+ <g id="Group_403" data-name="Group 403" transform="translate(0 0)">+ <path id="Path_470" data-name="Path 470" d="M22.755-10.356a1.177,1.177,0,0,1-.255.717q-7.492,6.118-9.161,7.217A27.163,27.163,0,0,1-1.112,1.959,6.721,6.721,0,0,1-4.919,1,16.035,16.035,0,0,1-7.245-1.068a1.738,1.738,0,0,1,.127-.717c-.721.438-1.418.828-2.087,1.179s-1.326.637-1.976.892c-.733,0-1.119-.1-1.163-.319a.84.84,0,0,1,.175-.446q.161-.269.478-.717A58.22,58.22,0,0,0-5.461-4.764q3.19-2.1,6.612-4.812a.587.587,0,0,1,.064-.207,6.867,6.867,0,0,1,3.872-1.545q3.214,0,3.218,2.9A8.113,8.113,0,0,1,6.313-3.84,12.567,12.567,0,0,1,2.824-.415q4,0,10.515-4.142A39.279,39.279,0,0,0,16.94-6.9q2.133-1.529,5.114-3.776a1.485,1.485,0,0,1,.446-.064C22.627-10.739,22.711-10.611,22.755-10.356ZM5.213-7.584c0-1.071-.566-1.609-1.689-1.609h-.7a.911.911,0,0,0-.51.127Q-.142-6.993-2.227-5.354q-2.1,1.643-3.919,2.932a1.373,1.373,0,0,1,.589.127A8.851,8.851,0,0,0-1.829-.813,6.122,6.122,0,0,0,.816-1.418a7.053,7.053,0,0,0,2.39-1.976A8.613,8.613,0,0,0,4.624-5.481,7.013,7.013,0,0,0,5.213-7.584Zm0,0" transform="translate(12.344 11.328)" fill="#ed1f24" />+ </g>+ </g>+ </g>+ <g id="Group_408" data-name="Group 408" transform="translate(148.015 172.907)">+ <g id="Group_407" data-name="Group 407" transform="translate(0 0)">+ <g id="Group_406" data-name="Group 406" transform="translate(0 0)">+ <path id="Path_471" data-name="Path 471" d="M17.418-12.085h-.366L9.9.581H.594L9.9-14.9,1.279-29.578H10.5L16.94-17.964h.605l6.421-11.615h9.241L24.588-14.9,33.876.581H24.588Zm0,0" transform="translate(-0.594 29.578)" fill="#ed1f24" />+ </g>+ </g>+ </g>+ </g>+ </svg>++</div>
Vulnerability Existed: no
No Vulnerability Found - CWE Analysis - review_and_troubleshoot_notify/resources/logo.php (All lines)
Old Code:
```
<div class="elex-banner-row-logo">
<svg xmlns="http://www.w3.org/2000/svg" class="elex-banner-logo" viewBox="0 0 319.225 134.495">
<!-- SVG content with nested groups and paths -->
</svg>
</div>
```
Fixed Code:
```
<div class="elex-banner-row-logo">
<svg xmlns="http://www.w3.org/2000/svg" class="elex-banner-logo" viewBox="0 0 319.225 134.495">
<!-- SVG content with nested groups and paths (identical content) -->
</svg>
</div>
```
Explanation:
This diff shows a whitespace-only change (reformatting of indentation/line endings). The file content between versions 3.3.4 and 3.3.5 is functionally identical - it's an SVG logo definition with no executable code, dynamic content, or security-sensitive operations. The change appears to be a code style or formatting normalization (likely converting line endings or adjusting indentation). No security vulnerabilities exist in either version of this static SVG asset file.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/review_and_troubleshoot_notify/resources/review.php 2025-12-21 09:35:59.449067309 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/review_and_troubleshoot_notify/resources/review.php 2025-12-21 09:36:35.263293274 +0000@@ -1,123 +1,123 @@-<style> - .elex-banner-notice{ - border: 1px solid #2271b1 !important; - border-left:4px solid #2271b1 !important; -} -.elex-banner-wrap .elex-banner-row { - font-family:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; - display: flex; - flex-wrap: wrap; - justify-content: space-between; - gap: 10px; - padding: 0.7rem 0; - align-items: center; -} - -.elex-banner-wrap .elex-banner-row-content { - width: calc(100% - 260px); - min-width: 400px; - max-width: 1100px; -} - -.elex-banner-wrap .elex-banner-row-logo { - width: 250px; -} - -.elex-banner-wrap .elex-banner-row-logo svg { - width: 100%; -} - -.elex-banner-wrap .elex-banner-button-wrap { - display: flex; - gap: 10px; - flex-wrap: wrap; -} - -.elex-banner-wrap .elex-banner-button-wrap .button-plain { - border: none; - background: transparent; -} - -.elex-banner-wrap .elex-banner-button-wrap a { - padding: .25rem .7rem; - display: flex !important; - align-items: center; - gap: 5px; -} - -.elex-banner-wrap button.elex-btn-hover-light:hover { - background-color: #E7F4FF !important; -} -</style> -<div class="notice elex-banner-notice "> - <div class="elex-banner-wrap"> - <div class="elex-banner-row"> - <div class="elex-banner-row-content"> - <h2 style="font-size: 18px;margin-top:0;margin-bottom:10px;">Leave Us a Review</h2> - <p style="font-size:16px ; line-height: 1.5;margin-top:0;margin-bottom:10px;"> - Hi there! You`ve been using <?php echo esc_attr( $this->data['name'] ); ?> plugin for over 7 days now. Hope it helps you run your business smoothly. Please take a moment to rate us 5 star! - </p> - - <div class="elex-banner-button-wrap"> - <a class="button-plain elex-btn-hover-light " href = " - <?php - echo esc_url( - wp_nonce_url( - add_query_arg( - array( - 'review_component_action' => 'review_never_ask_again', - 'plugin_basename' => $this->data['basename'], - ) - ) - ) - ); - ?> - "> - <svg xmlns="http://www.w3.org/2000/svg" width="18.167" height="18.167" viewBox="0 0 18.167 18.167"> - <g id="Icon_feather-x-circle" data-name="Icon feather-x-circle" transform="translate(0.75 0.75)"> - <path id="Path_650" data-name="Path 650" d="M18.333,10A8.333,8.333,0,1,1,10,1.667,8.333,8.333,0,0,1,18.333,10Z" transform="translate(-1.667 -1.667)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> - <path id="Path_651" data-name="Path 651" d="M12.5,7.5l-5,5" transform="translate(-1.667 -1.667)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> - <path id="Path_652" data-name="Path 652" d="M7.5,7.5l5,5" transform="translate(-1.667 -1.667)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> - </g> - </svg> - Never ask again - </a> - <a class="button elex-btn-hover-light " href = " - <?php - echo esc_url( - wp_nonce_url( - add_query_arg( - array( - 'review_component_action' => 'review_will_do_it_later', - 'plugin_basename' => $this->data['basename'], - ) - ) - ) - ); - ?> - "> - <svg xmlns="http://www.w3.org/2000/svg" width="13.417" height="18.394" viewBox="0 0 13.417 18.394"> - <g id="later_icon" data-name="later icon" transform="translate(0.893 1.284)"> - <path id="Path_648" data-name="Path 648" d="M1328.213,1024.895s-10.494,2.358-10.671-6.072c.059-9.9,9.643-7.065,9.643-7.065" transform="translate(-1317.686 -1008.864)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-width="1.5" /> - <path id="Path_649" data-name="Path 649" d="M0,0,4.114,2.057,0,5.571" transform="matrix(0.951, 0.309, -0.309, 0.951, 7.587, 0)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> - </g> - </svg> - I will do it later - </a> - <a class="button button-primary " href="<?php echo esc_url( $this->data['rating_url'] ); ?>" target="_blank" > - <svg xmlns="http://www.w3.org/2000/svg" width="16.707" height="16.692" viewBox="0 0 16.707 16.692"> - <g id="Icon_feather-link" data-name="Icon feather-link" transform="translate(0.75 0.75)"> - <path id="Path_646" data-name="Path 646" d="M15,11.363a3.8,3.8,0,0,0,5.73.41l2.28-2.28A3.8,3.8,0,1,0,17.637,4.12L16.33,5.42" transform="translate(-8.916 -3.008)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> - <path id="Path_647" data-name="Path 647" d="M12.116,15.016a3.8,3.8,0,0,0-5.73-.41l-2.28,2.28a3.8,3.8,0,1,0,5.373,5.373l1.3-1.3" transform="translate(-2.993 -8.18)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> - </g> - </svg> - Sure! I`d love to rate - </a> - </div> - </div> - <?php - require __DIR__ . '/logo.php'; - ?> - </div> - </div> - </div> +<style>+ .elex-banner-notice{+ border: 1px solid #2271b1 !important;+ border-left:4px solid #2271b1 !important;+}+.elex-banner-wrap .elex-banner-row {+ font-family:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;+ display: flex;+ flex-wrap: wrap;+ justify-content: space-between;+ gap: 10px;+ padding: 0.7rem 0;+ align-items: center;+}++.elex-banner-wrap .elex-banner-row-content {+ width: calc(100% - 260px);+ min-width: 400px;+ max-width: 1100px;+}++.elex-banner-wrap .elex-banner-row-logo {+ width: 250px;+}++.elex-banner-wrap .elex-banner-row-logo svg {+ width: 100%;+}++.elex-banner-wrap .elex-banner-button-wrap {+ display: flex;+ gap: 10px;+ flex-wrap: wrap;+}++.elex-banner-wrap .elex-banner-button-wrap .button-plain {+ border: none;+ background: transparent;+}++.elex-banner-wrap .elex-banner-button-wrap a {+ padding: .25rem .7rem;+ display: flex !important;+ align-items: center;+ gap: 5px;+}++.elex-banner-wrap button.elex-btn-hover-light:hover {+ background-color: #E7F4FF !important;+}+</style>+<div class="notice elex-banner-notice ">+ <div class="elex-banner-wrap">+ <div class="elex-banner-row">+ <div class="elex-banner-row-content">+ <h2 style="font-size: 18px;margin-top:0;margin-bottom:10px;">Leave Us a Review</h2>+ <p style="font-size:16px ; line-height: 1.5;margin-top:0;margin-bottom:10px;">+ Hi there! You`ve been using <?php echo esc_attr( $this->data['name'] ); ?> plugin for over 7 days now. Hope it helps you run your business smoothly. Please take a moment to rate us 5 star!+ </p>++ <div class="elex-banner-button-wrap">+ <a class="button-plain elex-btn-hover-light " href = "+ <?php + echo esc_url(+ wp_nonce_url(+ add_query_arg(+ array(+ 'review_component_action' => 'review_never_ask_again',+ 'plugin_basename' => $this->data['basename'],+ ) + ) + ) + ); + ?>+ ">+ <svg xmlns="http://www.w3.org/2000/svg" width="18.167" height="18.167" viewBox="0 0 18.167 18.167">+ <g id="Icon_feather-x-circle" data-name="Icon feather-x-circle" transform="translate(0.75 0.75)">+ <path id="Path_650" data-name="Path 650" d="M18.333,10A8.333,8.333,0,1,1,10,1.667,8.333,8.333,0,0,1,18.333,10Z" transform="translate(-1.667 -1.667)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />+ <path id="Path_651" data-name="Path 651" d="M12.5,7.5l-5,5" transform="translate(-1.667 -1.667)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />+ <path id="Path_652" data-name="Path 652" d="M7.5,7.5l5,5" transform="translate(-1.667 -1.667)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />+ </g>+ </svg>+ Never ask again+ </a>+ <a class="button elex-btn-hover-light " href = "+ <?php + echo esc_url(+ wp_nonce_url(+ add_query_arg(+ array(+ 'review_component_action' => 'review_will_do_it_later',+ 'plugin_basename' => $this->data['basename'],+ ) + ) + ) + ); + ?>+ ">+ <svg xmlns="http://www.w3.org/2000/svg" width="13.417" height="18.394" viewBox="0 0 13.417 18.394">+ <g id="later_icon" data-name="later icon" transform="translate(0.893 1.284)">+ <path id="Path_648" data-name="Path 648" d="M1328.213,1024.895s-10.494,2.358-10.671-6.072c.059-9.9,9.643-7.065,9.643-7.065" transform="translate(-1317.686 -1008.864)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-width="1.5" />+ <path id="Path_649" data-name="Path 649" d="M0,0,4.114,2.057,0,5.571" transform="matrix(0.951, 0.309, -0.309, 0.951, 7.587, 0)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />+ </g>+ </svg>+ I will do it later+ </a>+ <a class="button button-primary " href="<?php echo esc_url( $this->data['rating_url'] ); ?>" target="_blank" >+ <svg xmlns="http://www.w3.org/2000/svg" width="16.707" height="16.692" viewBox="0 0 16.707 16.692">+ <g id="Icon_feather-link" data-name="Icon feather-link" transform="translate(0.75 0.75)">+ <path id="Path_646" data-name="Path 646" d="M15,11.363a3.8,3.8,0,0,0,5.73.41l2.28-2.28A3.8,3.8,0,1,0,17.637,4.12L16.33,5.42" transform="translate(-8.916 -3.008)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />+ <path id="Path_647" data-name="Path 647" d="M12.116,15.016a3.8,3.8,0,0,0-5.73-.41l-2.28,2.28a3.8,3.8,0,1,0,5.373,5.373l1.3-1.3" transform="translate(-2.993 -8.18)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />+ </g>+ </svg>+ Sure! I`d love to rate+ </a>+ </div>+ </div>+ <?php+ require __DIR__ . '/logo.php';+ ?>+ </div>+ </div>+ </div>
Vulnerability Existed: No No Security Vulnerabilities Detected - review_and_troubleshoot_notify/resources/review.php Explanation: This diff represents a line-ending normalization change (converting from DOS/Windows line endings to Unix line endings). The actual code content remains identical between versions 3.3.4 and 3.3.5. No security fixes or vulnerabilities are present in this change. The file contains proper security practices: - Uses `esc_attr()` for escaping the plugin name in HTML attributes (line 60) - Uses `esc_url()` for escaping URLs in href attributes (lines 66-77, 82-93, 104) - Uses `wp_nonce_url()` for CSRF protection on action URLs - Uses `add_query_arg()` for safe query parameter construction This is purely a formatting/normalization commit with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/review_and_troubleshoot_notify/resources/troubleshoot.php 2025-12-21 09:35:59.449067309 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/review_and_troubleshoot_notify/resources/troubleshoot.php 2025-12-21 09:36:35.263293274 +0000@@ -1,115 +1,115 @@-<style> -.elex-banner-notice{ - border: 1px solid #2271b1 !important; - border-left:4px solid #2271b1 !important; -} -.elex-banner-wrap .elex-banner-row { - font-family:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; - display: flex; - flex-wrap: wrap; - justify-content: space-between; - gap: 10px; - padding: 0.7rem 0; - align-items: center; -} - -.elex-banner-wrap .elex-banner-row-content { - width: calc(100% - 260px); - min-width: 400px; - max-width: 1100px; -} - -.elex-banner-wrap .elex-banner-row-logo { - width: 250px; -} - -.elex-banner-wrap .elex-banner-row-logo svg { - width: 100%; -} - -.elex-banner-wrap .elex-banner-button-wrap { - display: flex; - gap: 10px; - flex-wrap: wrap; -} - -.elex-banner-wrap .elex-banner-button-wrap .button-plain { - border: none; - background: transparent; -} - -.elex-banner-wrap .elex-banner-button-wrap a { - padding: .25rem .7rem; - display: flex !important; - align-items: center !important; - gap: 5px; -} - -.elex-banner-wrap button.elex-btn-hover-light:hover { - background-color: #E7F4FF !important; -} -</style> -<div class="notice elex-banner-notice"> - <div class="elex-banner-wrap"> - <div class="elex-banner-row"> - - <div class="elex-banner-row-content" id='elex-review-component'> - <h5 style="font-size: 18px;margin-top:0;margin-bottom:10px;">Trouble setting up the Plugin?</h5> - <p style="font-size:16px ; line-height: 1.5;margin-top:0;margin-bottom:10px;"> - Need help on setting up <?php echo esc_attr( $this->data['name'] ); ?> plugin? You may go through our detailed documentation. For any further assistance, please don`t hesitate to reach out to our amazing support team. - </p> - - <div class="elex-banner-button-wrap"> - <a class="button-plain elex-btn-hover-light" id = 'elex_review_never_ask' href = " - <?php - echo esc_url( - wp_nonce_url( - add_query_arg( - array( - 'review_component_action' => 'troubleshoot_never_ask_again', - 'plugin_basename' => $this->data['basename'], - ) - ) - ) - ); - ?> - "> - <svg xmlns="http://www.w3.org/2000/svg" width="18.167" height="18.167" viewBox="0 0 18.167 18.167"> - <g id="Icon_feather-x-circle" data-name="Icon feather-x-circle" transform="translate(0.75 0.75)"> - <path id="Path_650" data-name="Path 650" d="M18.333,10A8.333,8.333,0,1,1,10,1.667,8.333,8.333,0,0,1,18.333,10Z" transform="translate(-1.667 -1.667)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> - <path id="Path_651" data-name="Path 651" d="M12.5,7.5l-5,5" transform="translate(-1.667 -1.667)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> - <path id="Path_652" data-name="Path 652" d="M7.5,7.5l5,5" transform="translate(-1.667 -1.667)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> - </g> - </svg> - Never ask again - </a> - <a class="button elex-btn-hover-light text-nowrap d-flex align-items-center gap-2" href="<?php echo esc_url( $this->data['documentation_url'] ); ?>" target="_blank"> - <svg xmlns="http://www.w3.org/2000/svg" width="18" height="22" viewBox="0 0 18 22"> - <g id="Icon_feather-book" data-name="Icon feather-book" transform="translate(-3 -1)"> - <path id="Path_659" data-name="Path 659" d="M4,19.5A2.5,2.5,0,0,1,6.5,17H20" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" /> - <path id="Path_660" data-name="Path 660" d="M6.5,2H20V22H6.5A2.5,2.5,0,0,1,4,19.5V4.5A2.5,2.5,0,0,1,6.5,2Z" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" /> - </g> - </svg> - Read Documentation - </a> - <a class="button button-primary" href="<?php echo esc_url( $this->data['support_url'] ); ?>" target="_blank"> - <svg xmlns="http://www.w3.org/2000/svg" width="30" height="20.087" viewBox="0 0 30 20.087" > - <g id="Icon_feather-users" data-name="Icon feather-users" transform="translate(6 -1.913)"> - <path id="Path_653" data-name="Path 653" d="M17,21V19a4,4,0,0,0-4-4H5a4,4,0,0,0-4,4v2" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" /> - <path id="Path_654" data-name="Path 654" d="M13,7A4,4,0,1,1,9,3,4,4,0,0,1,13,7Z" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" /> - <path id="Path_655" data-name="Path 655" d="M23,21V19a4,4,0,0,0-3-3.87" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" /> - <path id="Path_657" data-name="Path 657" d="M20,21V19a4,4,0,0,1,3-3.87" transform="translate(-25 0)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" /> - <path id="Path_656" data-name="Path 656" d="M16,3.13a4,4,0,0,1,0,7.75" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" /> - <path id="Path_658" data-name="Path 658" d="M19.008,3.13a4,4,0,0,0,0,7.75" transform="translate(-17.008 0)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" /> - </g> - </svg> - Contact Support - </a> - </div> - </div> - <?php - require __DIR__ . '/logo.php'; - ?> - </div> - </div> - </div> +<style>+.elex-banner-notice{+ border: 1px solid #2271b1 !important;+ border-left:4px solid #2271b1 !important;+}+.elex-banner-wrap .elex-banner-row {+ font-family:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;+ display: flex;+ flex-wrap: wrap;+ justify-content: space-between;+ gap: 10px;+ padding: 0.7rem 0;+ align-items: center;+}++.elex-banner-wrap .elex-banner-row-content {+ width: calc(100% - 260px);+ min-width: 400px;+ max-width: 1100px;+}++.elex-banner-wrap .elex-banner-row-logo {+ width: 250px;+}++.elex-banner-wrap .elex-banner-row-logo svg {+ width: 100%;+}++.elex-banner-wrap .elex-banner-button-wrap {+ display: flex;+ gap: 10px;+ flex-wrap: wrap;+}++.elex-banner-wrap .elex-banner-button-wrap .button-plain {+ border: none;+ background: transparent;+}++.elex-banner-wrap .elex-banner-button-wrap a {+ padding: .25rem .7rem;+ display: flex !important;+ align-items: center !important;+ gap: 5px;+}++.elex-banner-wrap button.elex-btn-hover-light:hover {+ background-color: #E7F4FF !important;+}+</style>+<div class="notice elex-banner-notice">+ <div class="elex-banner-wrap">+ <div class="elex-banner-row">++ <div class="elex-banner-row-content" id='elex-review-component'>+ <h5 style="font-size: 18px;margin-top:0;margin-bottom:10px;">Trouble setting up the Plugin?</h5>+ <p style="font-size:16px ; line-height: 1.5;margin-top:0;margin-bottom:10px;">+ Need help on setting up <?php echo esc_attr( $this->data['name'] ); ?> plugin? You may go through our detailed documentation. For any further assistance, please don`t hesitate to reach out to our amazing support team.+ </p>++ <div class="elex-banner-button-wrap">+ <a class="button-plain elex-btn-hover-light" id = 'elex_review_never_ask' href = "+ <?php + echo esc_url(+ wp_nonce_url(+ add_query_arg(+ array(+ 'review_component_action' => 'troubleshoot_never_ask_again',+ 'plugin_basename' => $this->data['basename'],+ ) + ) + ) + ); + ?>+ ">+ <svg xmlns="http://www.w3.org/2000/svg" width="18.167" height="18.167" viewBox="0 0 18.167 18.167">+ <g id="Icon_feather-x-circle" data-name="Icon feather-x-circle" transform="translate(0.75 0.75)">+ <path id="Path_650" data-name="Path 650" d="M18.333,10A8.333,8.333,0,1,1,10,1.667,8.333,8.333,0,0,1,18.333,10Z" transform="translate(-1.667 -1.667)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />+ <path id="Path_651" data-name="Path 651" d="M12.5,7.5l-5,5" transform="translate(-1.667 -1.667)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />+ <path id="Path_652" data-name="Path 652" d="M7.5,7.5l5,5" transform="translate(-1.667 -1.667)" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />+ </g>+ </svg>+ Never ask again+ </a>+ <a class="button elex-btn-hover-light text-nowrap d-flex align-items-center gap-2" href="<?php echo esc_url( $this->data['documentation_url'] ); ?>" target="_blank">+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="22" viewBox="0 0 18 22">+ <g id="Icon_feather-book" data-name="Icon feather-book" transform="translate(-3 -1)">+ <path id="Path_659" data-name="Path 659" d="M4,19.5A2.5,2.5,0,0,1,6.5,17H20" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />+ <path id="Path_660" data-name="Path 660" d="M6.5,2H20V22H6.5A2.5,2.5,0,0,1,4,19.5V4.5A2.5,2.5,0,0,1,6.5,2Z" fill="none" stroke="#10518d" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />+ </g>+ </svg>+ Read Documentation+ </a>+ <a class="button button-primary" href="<?php echo esc_url( $this->data['support_url'] ); ?>" target="_blank">+ <svg xmlns="http://www.w3.org/2000/svg" width="30" height="20.087" viewBox="0 0 30 20.087" >+ <g id="Icon_feather-users" data-name="Icon feather-users" transform="translate(6 -1.913)">+ <path id="Path_653" data-name="Path 653" d="M17,21V19a4,4,0,0,0-4-4H5a4,4,0,0,0-4,4v2" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />+ <path id="Path_654" data-name="Path 654" d="M13,7A4,4,0,1,1,9,3,4,4,0,0,1,13,7Z" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />+ <path id="Path_655" data-name="Path 655" d="M23,21V19a4,4,0,0,0-3-3.87" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />+ <path id="Path_657" data-name="Path 657" d="M20,21V19a4,4,0,0,1,3-3.87" transform="translate(-25 0)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />+ <path id="Path_656" data-name="Path 656" d="M16,3.13a4,4,0,0,1,0,7.75" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />+ <path id="Path_658" data-name="Path 658" d="M19.008,3.13a4,4,0,0,0,0,7.75" transform="translate(-17.008 0)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />+ </g>+ </svg>+ Contact Support+ </a>+ </div>+ </div>+ <?php+ require __DIR__ . '/logo.php';+ ?>+ </div>+ </div>+ </div>
Vulnerability Existed: no No Security Vulnerabilities Detected - File: review_and_troubleshoot_notify/resources/troubleshoot.php Lines 1-115 Old Code: [Lines 1-115 with CRLF line endings] Fixed Code: [Lines 1-115 with LF line endings] Explanation: This diff represents a line ending normalization change (CRLF → LF conversion), not a security fix. The actual code content remains identical across all 115 lines. No functional changes, no security vulnerabilities introduced or fixed. The file contains: - Properly escaped output using `esc_attr()` and `esc_url()` functions - WordPress nonce protection via `wp_nonce_url()` - Standard HTML/CSS markup with no injection vectors The line ending conversion is a formatting/repository maintenance task with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/review_and_troubleshoot_notify/review-and-troubleshoot-notify-class.php 2025-12-21 09:35:59.449067309 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/review_and_troubleshoot_notify/review-and-troubleshoot-notify-class.php 2025-12-21 09:36:35.263293274 +0000@@ -1,109 +1,109 @@-<?php -if ( ! class_exists( 'Elex_Review_Components' ) ) { - class Elex_Review_Components { - /** - * Initiate review component - * - * @param array $data - * $data = [ - * 'name' => (string) Plugin name - * 'basename' => (string) Plugin basename folder/main_file.php - * 'rating_url' => (string) Url to review the plugin - * 'documentation_url' => (string) Url to the plugin document - * 'support_url' => (string) Url to the support form - * ] - */ - protected $data = array(); - public function __construct( array $data ) { - $this->data = $data; - add_action( 'activate_' . $data['basename'], array( $this, 'on_activation' ) ); - add_action( 'admin_notices', array( $this, 'admin_notice' ) ); - add_action( 'admin_init', array( $this, 'update_get_options' ) ); - add_action( 'deactivate_' . $data['basename'], array( $this, 'delete_options' ), 1 ); - } - - public function update_get_options() { - - if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_GET['_wpnonce'] ) ) ) { - return; - } - - if ( ! isset( $_GET['review_component_action'] ) || ! isset( $_GET['plugin_basename'] ) ) { - return; - } - - if ( sanitize_text_field( $_GET['plugin_basename'] ) !== $this->data['basename'] ) { - return; - } - - $review_component_action = sanitize_text_field( $_GET['review_component_action'] ); - - if ( 'troubleshoot_never_ask_again' === $review_component_action ) { - $this->update_option( 'troubleshoot_never_ask_again', true ); - } - - if ( 'review_never_ask_again' === $review_component_action ) { - $this->update_option( 'review_never_ask_again', true ); - } - - if ( 'review_will_do_it_later' === $review_component_action ) { - $this->update_option( 'review_will_do_it_later', strtotime( '+1 day' ) ); - } - - wp_redirect( remove_query_arg( array( 'plugin_basename', 'review_component_action' ) ) ); - } - - public function on_activation() { - $this->update_option( 'activation_date', current_time( 'mysql' ) ); - } - public function get_option( $key ) { - return get_option( $this->data['basename'] . '_' . $key ); - } - public function update_option( $key, $value ) { - update_option( $this->data['basename'] . '_' . $key, $value ); - } - public function admin_notice() { - $activattion_date = date_create( $this->get_option( 'activation_date' ) ); - - if ( ! $activattion_date ) { - return; - } - - $current_date = date_create(); - $diff = date_diff( $activattion_date, $current_date ); - - if ( $diff->format( '%R%a days' ) < 7 ) { - $this->show_trubleshoot(); - } else { - $this->show_review(); - } - } - - public function show_trubleshoot() { - $trouble = $this->get_option( 'troubleshoot_never_ask_again' ); - if ( $trouble ) { - return; - } - - include __DIR__ . '/resources/troubleshoot.php'; - } - - public function show_review() { - $never_ask_again = $this->get_option( 'review_never_ask_again' ); - if ( $never_ask_again ) { - return; - } - - if ( $this->get_option( 'review_will_do_it_later' ) > strtotime( 'now' ) ) { - return; - } - - include __DIR__ . '/resources/review.php'; - } - public function delete_options() { - delete_option( $this->data['basename'] . '_review_never_ask_again' ); - delete_option( $this->data['basename'] . '_review_will_do_it_later' ); - delete_option( $this->data['basename'] . '_troubleshoot_never_ask_again' ); - } - } -} +<?php+if ( ! class_exists( 'Elex_Review_Components' ) ) {+ class Elex_Review_Components {+ /**+ * Initiate review component+ *+ * @param array $data+ * $data = [+ * 'name' => (string) Plugin name+ * 'basename' => (string) Plugin basename folder/main_file.php+ * 'rating_url' => (string) Url to review the plugin+ * 'documentation_url' => (string) Url to the plugin document+ * 'support_url' => (string) Url to the support form+ * ]+ */+ protected $data = array();+ public function __construct( array $data ) {+ $this->data = $data;+ add_action( 'activate_' . $data['basename'], array( $this, 'on_activation' ) );+ add_action( 'admin_notices', array( $this, 'admin_notice' ) );+ add_action( 'admin_init', array( $this, 'update_get_options' ) );+ add_action( 'deactivate_' . $data['basename'], array( $this, 'delete_options' ), 1 );+ }++ public function update_get_options() {++ if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_GET['_wpnonce'] ) ) ) {+ return;+ }++ if ( ! isset( $_GET['review_component_action'] ) || ! isset( $_GET['plugin_basename'] ) ) {+ return;+ }+ + if ( sanitize_text_field( $_GET['plugin_basename'] ) !== $this->data['basename'] ) {+ return;+ }++ $review_component_action = sanitize_text_field( $_GET['review_component_action'] );++ if ( 'troubleshoot_never_ask_again' === $review_component_action ) {+ $this->update_option( 'troubleshoot_never_ask_again', true );+ }++ if ( 'review_never_ask_again' === $review_component_action ) {+ $this->update_option( 'review_never_ask_again', true );+ }++ if ( 'review_will_do_it_later' === $review_component_action ) {+ $this->update_option( 'review_will_do_it_later', strtotime( '+1 day' ) );+ }++ wp_redirect( remove_query_arg( array( 'plugin_basename', 'review_component_action' ) ) );+ }++ public function on_activation() {+ $this->update_option( 'activation_date', current_time( 'mysql' ) );+ }+ public function get_option( $key ) {+ return get_option( $this->data['basename'] . '_' . $key );+ }+ public function update_option( $key, $value ) {+ update_option( $this->data['basename'] . '_' . $key, $value );+ }+ public function admin_notice() {+ $activattion_date = date_create( $this->get_option( 'activation_date' ) );++ if ( ! $activattion_date ) {+ return;+ }++ $current_date = date_create();+ $diff = date_diff( $activattion_date, $current_date );++ if ( $diff->format( '%R%a days' ) < 7 ) {+ $this->show_trubleshoot();+ } else {+ $this->show_review();+ }+ }++ public function show_trubleshoot() {+ $trouble = $this->get_option( 'troubleshoot_never_ask_again' );+ if ( $trouble ) {+ return;+ }++ include __DIR__ . '/resources/troubleshoot.php';+ }++ public function show_review() {+ $never_ask_again = $this->get_option( 'review_never_ask_again' );+ if ( $never_ask_again ) {+ return;+ }++ if ( $this->get_option( 'review_will_do_it_later' ) > strtotime( 'now' ) ) {+ return;+ }++ include __DIR__ . '/resources/review.php';+ }+ public function delete_options() {+ delete_option( $this->data['basename'] . '_review_never_ask_again' );+ delete_option( $this->data['basename'] . '_review_will_do_it_later' );+ delete_option( $this->data['basename'] . '_troubleshoot_never_ask_again' );+ }+ }+}
Vulnerability Existed: no Explanation: This diff contains only whitespace changes (line ending conversion from CRLF to LF or similar line ending normalization). The actual code content remains identical between versions 3.3.4 and 3.3.5. No security fixes, vulnerabilities, or code logic changes are present in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/autoload.php 2025-12-21 09:35:59.449067309 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/autoload.php 2025-12-21 09:36:35.263293274 +0000@@ -14,12 +14,9 @@ echo $err; } }- trigger_error(- $err,- E_USER_ERROR- );+ throw new RuntimeException($err); } require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit8e6cef26cd70b7fee2740e066e9a2431::getLoader();+return ComposerAutoloaderInit12bd507041a61d7a2b04e74ca1404740::getLoader();
```
Vulnerability Existed: no
Exception Handling Improvement - No CWE - vendor/autoload.php Lines 17-20
[Old Code]
trigger_error(
$err,
E_USER_ERROR
);
[Fixed Code]
throw new RuntimeException($err);
Explanation:
This is not a security vulnerability fix, but rather an improvement to error handling. The change replaces `trigger_error()` with throwing a `RuntimeException`, which is a better practice for modern PHP error handling. The `trigger_error()` function with `E_USER_ERROR` was deprecated in PHP 8.0 and removed in PHP 8.0+. Throwing an exception provides better error propagation, stack trace information, and is more appropriate for fatal errors. This is a code quality improvement rather than a security fix.
---
Vulnerability Existed: no
Autoloader Hash Update - No CWE - vendor/autoload.php Line 23
[Old Code]
return ComposerAutoloaderInit8e6cef26cd70b7fee2740e066e9a2431::getLoader();
[Fixed Code]
return ComposerAutoloaderInit12bd507041a61d7a2b04e74ca1404740::getLoader();
Explanation:
This is not a security vulnerability. The autoloader class name hash has been updated, which is a normal occurrence when Composer regenerates the autoloader files. This is typically done during `composer install` or `composer update` and is not indicative of a security issue. The different hash reflects changes in package dependencies or Composer configuration, not a security fix.
```
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonDoctrineType.php@@ -0,0 +1,14 @@+<?php++namespace Carbon\Doctrine;++use Doctrine\DBAL\Platforms\AbstractPlatform;++interface CarbonDoctrineType+{+ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform);++ public function convertToPHPValue($value, AbstractPlatform $platform);++ public function convertToDatabaseValue($value, AbstractPlatform $platform);+}
Vulnerability Existed: no Analysis Complete - No Security Vulnerabilities Detected This is a new interface definition file for Carbon Doctrine types. The code: - Defines a simple PHP interface with three method signatures - Contains no executable logic, only type declarations - Has no data validation, user input handling, or external operations - Uses proper namespace declaration - References standard Doctrine DBAL classes **Explanation:** This is a straightforward interface definition with no security implications. It's part of a library's type system for Doctrine ORM integration. Interface files by themselves cannot introduce vulnerabilities as they don't execute code - they only define contracts that implementing classes must follow. The security posture depends entirely on how implementations use these methods.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonImmutableType.php@@ -0,0 +1,7 @@+<?php++namespace Carbon\Doctrine;++class CarbonImmutableType extends DateTimeImmutableType implements CarbonDoctrineType+{+}
Vulnerability Existed: no
No CWE violations identified - File: vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonImmutableType.php [Lines 1-7]
Old Code:
[File did not exist]
Fixed Code:
```php
<?php
namespace Carbon\Doctrine;
class CarbonImmutableType extends DateTimeImmutableType implements CarbonDoctrineType
{
}
```
Explanation:
This is a new file addition containing a simple class definition with no executable logic. The class is a minimal type wrapper that extends `DateTimeImmutableType` and implements the `CarbonDoctrineType` interface. There are no security vulnerabilities present:
- No user input handling
- No database operations
- No file I/O operations
- No external API calls
- Proper namespace declaration
- No hardcoded credentials or sensitive data
- No unsafe deserialization or eval-like operations
This is a safe vendor library type definition file with no security concerns.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonType.php@@ -0,0 +1,7 @@+<?php++namespace Carbon\Doctrine;++class CarbonType extends DateTimeType implements CarbonDoctrineType+{+}
Vulnerability Existed: no
No Vulnerabilities Detected - [N/A] - [vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonType.php] [Lines 1-7]
[Old Code]
File did not exist (new file creation)
[Fixed Code]
```php
<?php
namespace Carbon\Doctrine;
class CarbonType extends DateTimeType implements CarbonDoctrineType
{
}
```
Explanation:
This is a new file containing a simple class definition that extends DateTimeType and implements the CarbonDoctrineType interface. There are no security vulnerabilities present in this code:
1. The class definition is straightforward with no executable logic
2. No user input is processed
3. No database queries, file operations, or external resource access
4. No hardcoded credentials or sensitive information
5. Proper namespace declaration follows PSR standards
6. No obvious injection vectors, access control issues, or cryptographic weaknesses
This appears to be a legitimate vendor library file for Doctrine ORM integration with Carbon datetime library. The empty class body suggests it may be relying on inherited functionality from the parent DateTimeType class.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonTypeConverter.php@@ -0,0 +1,141 @@+<?php++namespace Carbon\Doctrine;++use Carbon\Carbon;+use Carbon\CarbonInterface;+use DateTimeInterface;+use Doctrine\DBAL\Platforms\AbstractPlatform;+use Doctrine\DBAL\Platforms\DB2Platform;+use Doctrine\DBAL\Platforms\OraclePlatform;+use Doctrine\DBAL\Platforms\SqlitePlatform;+use Doctrine\DBAL\Platforms\SQLServerPlatform;+use Doctrine\DBAL\Types\ConversionException;+use Exception;++/**+ * @template T of CarbonInterface+ */+trait CarbonTypeConverter+{+ /**+ * This property differentiates types installed by carbonphp/carbon-doctrine-types+ * from the ones embedded previously in nesbot/carbon source directly.+ *+ * @readonly+ */+ public bool $external = true;++ /**+ * @return class-string<T>+ */+ protected function getCarbonClassName(): string+ {+ return Carbon::class;+ }++ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string+ {+ $precision = min(+ $fieldDeclaration['precision'] ?? DateTimeDefaultPrecision::get(),+ $this->getMaximumPrecision($platform),+ );++ $type = parent::getSQLDeclaration($fieldDeclaration, $platform);++ if (!$precision) {+ return $type;+ }++ if (str_contains($type, '(')) {+ return preg_replace('/\(\d+\)/', "($precision)", $type);+ }++ [$before, $after] = explode(' ', "$type ");++ return trim("$before($precision) $after");+ }++ /**+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)+ *+ * @return T|null+ */+ public function convertToPHPValue($value, AbstractPlatform $platform)+ {+ $class = $this->getCarbonClassName();++ if ($value === null || is_a($value, $class)) {+ return $value;+ }++ if ($value instanceof DateTimeInterface) {+ return $class::instance($value);+ }++ $date = null;+ $error = null;++ try {+ $date = $class::parse($value);+ } catch (Exception $exception) {+ $error = $exception;+ }++ if (!$date) {+ throw ConversionException::conversionFailedFormat(+ $value,+ $this->getTypeName(),+ 'Y-m-d H:i:s.u or any format supported by '.$class.'::parse()',+ $error+ );+ }++ return $date;+ }++ /**+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)+ */+ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string+ {+ if ($value === null) {+ return $value;+ }++ if ($value instanceof DateTimeInterface) {+ return $value->format('Y-m-d H:i:s.u');+ }++ throw ConversionException::conversionFailedInvalidType(+ $value,+ $this->getTypeName(),+ ['null', 'DateTime', 'Carbon']+ );+ }++ private function getTypeName(): string+ {+ $chunks = explode('\\', static::class);+ $type = preg_replace('/Type$/', '', end($chunks));++ return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $type));+ }++ private function getMaximumPrecision(AbstractPlatform $platform): int+ {+ if ($platform instanceof DB2Platform) {+ return 12;+ }++ if ($platform instanceof OraclePlatform) {+ return 9;+ }++ if ($platform instanceof SQLServerPlatform || $platform instanceof SqlitePlatform) {+ return 3;+ }++ return 6;+ }+}
Vulnerability Existed: no Analysis of the provided code diff: This is a new file addition (vendor library code) containing a Doctrine DBAL type converter trait for Carbon datetime objects. After thorough analysis, no security vulnerabilities were identified in this code. **Detailed Security Assessment:** 1. **Input Validation**: The `convertToPHPValue()` method properly validates input by: - Checking for null values - Verifying instanceof relationships - Using try-catch exception handling around date parsing - Throwing ConversionException on invalid formats 2. **SQL Injection Prevention**: The `getSQLDeclaration()` method uses `preg_replace()` for type string manipulation, which is safe in this context since: - It's replacing numeric patterns within SQL type declarations - No user input is directly concatenated into SQL - The precision value comes from configuration, not user input 3. **Type Safety**: - Proper type hints and return types are declared - DateTimeInterface instanceof checks prevent type confusion - Exception handling is appropriate 4. **Data Format Handling**: The `convertToDatabaseValue()` method uses a safe hardcoded date format (`'Y-m-d H:i:s.u'`) for database serialization. 5. **Code Integrity**: The `getTypeName()` method safely processes class names using standard string functions without security implications. **Conclusion**: This is a vendor library file providing a secure implementation of Doctrine type conversion for Carbon datetime objects. No CWE-relevant vulnerabilities exist in the provided code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeDefaultPrecision.php@@ -0,0 +1,28 @@+<?php++namespace Carbon\Doctrine;++class DateTimeDefaultPrecision+{+ private static $precision = 6;++ /**+ * Change the default Doctrine datetime and datetime_immutable precision.+ *+ * @param int $precision+ */+ public static function set(int $precision): void+ {+ self::$precision = $precision;+ }++ /**+ * Get the default Doctrine datetime and datetime_immutable precision.+ *+ * @return int+ */+ public static function get(): int+ {+ return self::$precision;+ }+}
Vulnerability Existed: no No Security Vulnerabilities Detected Explanation: This is a new file containing a simple utility class for managing default datetime precision in Doctrine. The code is a basic configuration helper with the following characteristics: 1. **Static precision storage**: The class uses a private static property to store an integer precision value, initialized to 6 (a reasonable default for microseconds). 2. **Simple getter/setter pattern**: Two public static methods provide controlled access to the precision value: - `set(int $precision)`: Accepts a type-hinted integer parameter - `get()`: Returns the stored precision value 3. **No input validation issues**: While the setter accepts any integer without range validation, this is acceptable for this use case since: - Precision values for datetime fractional seconds typically range from 0-6, but the caller is responsible for providing valid values - This is internal configuration, not user-facing input - Invalid precision values would be caught by Doctrine itself when applied 4. **No security-relevant operations**: The class doesn't handle: - User input directly - Database queries - File operations - External data sources - Serialization/deserialization - Authentication/authorization This is a straightforward configuration utility class with no apparent security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeImmutableType.php@@ -0,0 +1,20 @@+<?php++namespace Carbon\Doctrine;++use Carbon\CarbonImmutable;+use Doctrine\DBAL\Types\VarDateTimeImmutableType;++class DateTimeImmutableType extends VarDateTimeImmutableType implements CarbonDoctrineType+{+ /** @use CarbonTypeConverter<CarbonImmutable> */+ use CarbonTypeConverter;++ /**+ * @return class-string<CarbonImmutable>+ */+ protected function getCarbonClassName(): string+ {+ return CarbonImmutable::class;+ }+}
Vulnerability Existed: no
No Vulnerabilities Detected - [N/A] - vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeImmutableType.php [1-20]
[Old Code]
N/A - This is a new file addition
[Fixed Code]
```php
<?php
namespace Carbon\Doctrine;
use Carbon\CarbonImmutable;
use Doctrine\DBAL\Types\VarDateTimeImmutableType;
class DateTimeImmutableType extends VarDateTimeImmutableType implements CarbonDoctrineType
{
/** @use CarbonTypeConverter<CarbonImmutable> */
use CarbonTypeConverter;
/**
* @return class-string<CarbonImmutable>
*/
protected function getCarbonClassName(): string
{
return CarbonImmutable::class;
}
}
```
Explanation:
This is a new file containing a standard Doctrine type converter class for Carbon immutable dates. The code follows secure practices:
- It properly uses namespacing and class inheritance
- Uses type hints and return type declarations
- Extends from a trusted Doctrine DBAL base class
- Returns a hardcoded class name without any dynamic evaluation
- No user input is processed
- No database queries are executed
- No file operations or external data handling occurs
- Standard OOP patterns are followed correctly
This is a legitimate library addition with no security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeType.php@@ -0,0 +1,12 @@+<?php++namespace Carbon\Doctrine;++use Carbon\Carbon;+use Doctrine\DBAL\Types\VarDateTimeType;++class DateTimeType extends VarDateTimeType implements CarbonDoctrineType+{+ /** @use CarbonTypeConverter<Carbon> */+ use CarbonTypeConverter;+}
I'll analyze this code diff for security vulnerabilities. **Vulnerability Existed: no** This is a new file addition containing a simple PHP class definition with no security vulnerabilities detected. **Analysis:** The code is a straightforward Doctrine type class that: - Extends `VarDateTimeType` from Doctrine DBAL - Implements `CarbonDoctrineType` interface - Uses the `CarbonTypeConverter` trait **Security Assessment:** 1. **No Input Validation Issues** - This is a type definition class with no user input handling 2. **No SQL Injection Risk** - No SQL queries or dynamic SQL construction present 3. **No Code Injection** - No `eval()`, `unserialize()`, or similar dangerous functions 4. **No Authentication/Authorization Issues** - This is a data type mapper, not an access control mechanism 5. **No Information Disclosure** - No sensitive data exposure in the code 6. **Safe Dependencies** - Uses legitimate Doctrine DBAL and Carbon library classes The code follows standard Doctrine patterns for custom type handling and presents no exploitable security vulnerabilities in its implementation.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/composer/ClassLoader.php 2025-12-21 09:35:59.449067309 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/composer/ClassLoader.php 2025-12-21 09:36:35.267293523 +0000@@ -42,35 +42,37 @@ */ class ClassLoader {- /** @var ?string */+ /** @var \Closure(string):void */+ private static $includeFile;++ /** @var string|null */ private $vendorDir; // PSR-4 /**- * @var array[]- * @psalm-var array<string, array<string, int>>+ * @var array<string, array<string, int>> */ private $prefixLengthsPsr4 = array(); /**- * @var array[]- * @psalm-var array<string, array<int, string>>+ * @var array<string, list<string>> */ private $prefixDirsPsr4 = array(); /**- * @var array[]- * @psalm-var array<string, string>+ * @var list<string> */ private $fallbackDirsPsr4 = array(); // PSR-0 /**- * @var array[]- * @psalm-var array<string, array<string, string[]>>+ * List of PSR-0 prefixes+ *+ * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))+ *+ * @var array<string, array<string, list<string>>> */ private $prefixesPsr0 = array(); /**- * @var array[]- * @psalm-var array<string, string>+ * @var list<string> */ private $fallbackDirsPsr0 = array(); @@ -78,8 +80,7 @@ private $useIncludePath = false; /**- * @var string[]- * @psalm-var array<string, string>+ * @var array<string, string> */ private $classMap = array(); @@ -87,29 +88,29 @@ private $classMapAuthoritative = false; /**- * @var bool[]- * @psalm-var array<string, bool>+ * @var array<string, bool> */ private $missingClasses = array(); - /** @var ?string */+ /** @var string|null */ private $apcuPrefix; /**- * @var self[]+ * @var array<string, self> */ private static $registeredLoaders = array(); /**- * @param ?string $vendorDir+ * @param string|null $vendorDir */ public function __construct($vendorDir = null) { $this->vendorDir = $vendorDir;+ self::initializeIncludeClosure(); } /**- * @return string[]+ * @return array<string, list<string>> */ public function getPrefixes() {@@ -121,8 +122,7 @@ } /**- * @return array[]- * @psalm-return array<string, array<int, string>>+ * @return array<string, list<string>> */ public function getPrefixesPsr4() {@@ -130,8 +130,7 @@ } /**- * @return array[]- * @psalm-return array<string, string>+ * @return list<string> */ public function getFallbackDirs() {@@ -139,8 +138,7 @@ } /**- * @return array[]- * @psalm-return array<string, string>+ * @return list<string> */ public function getFallbackDirsPsr4() {@@ -148,8 +146,7 @@ } /**- * @return string[] Array of classname => path- * @psalm-return array<string, string>+ * @return array<string, string> Array of classname => path */ public function getClassMap() {@@ -157,8 +154,7 @@ } /**- * @param string[] $classMap Class to filename map- * @psalm-param array<string, string> $classMap+ * @param array<string, string> $classMap Class to filename map * * @return void */@@ -175,24 +171,25 @@ * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. *- * @param string $prefix The prefix- * @param string[]|string $paths The PSR-0 root directories- * @param bool $prepend Whether to prepend the directories+ * @param string $prefix The prefix+ * @param list<string>|string $paths The PSR-0 root directories+ * @param bool $prepend Whether to prepend the directories * * @return void */ public function add($prefix, $paths, $prepend = false) {+ $paths = (array) $paths; if (!$prefix) { if ($prepend) { $this->fallbackDirsPsr0 = array_merge(- (array) $paths,+ $paths, $this->fallbackDirsPsr0 ); } else { $this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0,- (array) $paths+ $paths ); } @@ -201,19 +198,19 @@ $first = $prefix[0]; if (!isset($this->prefixesPsr0[$first][$prefix])) {- $this->prefixesPsr0[$first][$prefix] = (array) $paths;+ $this->prefixesPsr0[$first][$prefix] = $paths; return; } if ($prepend) { $this->prefixesPsr0[$first][$prefix] = array_merge(- (array) $paths,+ $paths, $this->prefixesPsr0[$first][$prefix] ); } else { $this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix],- (array) $paths+ $paths ); } }@@ -222,9 +219,9 @@ * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. *- * @param string $prefix The prefix/namespace, with trailing '\\'- * @param string[]|string $paths The PSR-4 base directories- * @param bool $prepend Whether to prepend the directories+ * @param string $prefix The prefix/namespace, with trailing '\\'+ * @param list<string>|string $paths The PSR-4 base directories+ * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException *@@ -232,17 +229,18 @@ */ public function addPsr4($prefix, $paths, $prepend = false) {+ $paths = (array) $paths; if (!$prefix) { // Register directories for the root namespace. if ($prepend) { $this->fallbackDirsPsr4 = array_merge(- (array) $paths,+ $paths, $this->fallbackDirsPsr4 ); } else { $this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4,- (array) $paths+ $paths ); } } elseif (!isset($this->prefixDirsPsr4[$prefix])) {@@ -252,18 +250,18 @@ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;- $this->prefixDirsPsr4[$prefix] = (array) $paths;+ $this->prefixDirsPsr4[$prefix] = $paths; } elseif ($prepend) { // Prepend directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge(- (array) $paths,+ $paths, $this->prefixDirsPsr4[$prefix] ); } else { // Append directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix],- (array) $paths+ $paths ); } }@@ -272,8 +270,8 @@ * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. *- * @param string $prefix The prefix- * @param string[]|string $paths The PSR-0 base directories+ * @param string $prefix The prefix+ * @param list<string>|string $paths The PSR-0 base directories * * @return void */@@ -290,8 +288,8 @@ * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. *- * @param string $prefix The prefix/namespace, with trailing '\\'- * @param string[]|string $paths The PSR-4 base directories+ * @param string $prefix The prefix/namespace, with trailing '\\'+ * @param list<string>|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException *@@ -425,7 +423,8 @@ public function loadClass($class) { if ($file = $this->findFile($class)) {- includeFile($file);+ $includeFile = self::$includeFile;+ $includeFile($file); return true; }@@ -476,9 +475,9 @@ } /**- * Returns the currently registered loaders indexed by their corresponding vendor directories.+ * Returns the currently registered loaders keyed by their corresponding vendor directories. *- * @return self[]+ * @return array<string, self> */ public static function getRegisteredLoaders() {@@ -555,18 +554,26 @@ return false; }-} -/**- * Scope isolated include.- *- * Prevents access to $this/self from included files.- *- * @param string $file- * @return void- * @private- */-function includeFile($file)-{- include $file;+ /**+ * @return void+ */+ private static function initializeIncludeClosure()+ {+ if (self::$includeFile !== null) {+ return;+ }++ /**+ * Scope isolated include.+ *+ * Prevents access to $this/self from included files.+ *+ * @param string $file+ * @return void+ */+ self::$includeFile = \Closure::bind(static function($file) {+ include $file;+ }, null, null);+ } }
Vulnerability Existed: yes
FALSE POSITIVE
[Code Injection / Local File Inclusion via Unsafe Include] - [CWE-95 / CWE-426] - [vendor/composer/ClassLoader.php] [Lines 425-428 (old), 428-429 (new)]
**Old Code:**
```php
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
```
**Fixed Code:**
```php
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
```
**Explanation:**
The vulnerability existed in the original code's use of a global `includeFile()` function that was defined at the bottom of the file in global scope. This created a potential attack surface where:
1. **Function Hijacking Risk**: The global `includeFile()` function could be shadowed or overridden by user code or malicious actors in shared environments
2. **Namespace Pollution**: Global function definitions pollute the namespace and can be replaced at runtime
3. **Lack of Scope Isolation**: The function's accessibility from multiple contexts increases the attack surface
The fix addresses this by:
1. **Moving to Static Closure**: The include operation is now encapsulated in a static `Closure` bound to an isolated scope using `Closure::bind(static function($file) { include $file; }, null, null)`
2. **Eliminating Global Function**: The global `includeFile()` function is removed, reducing namespace pollution
3. **Scope Isolation**: The closure's null context (`null, null` parameters) prevents access to `$this` or `self` from the included file, preventing unintended state manipulation
4. **Lazy Initialization**: The `initializeIncludeClosure()` method ensures the closure is initialized once per class loader instance, reducing overhead
This is a **security hardening** fix that prevents potential code injection attacks through function hijacking and improves the robustness of the autoloader mechanism used by Composer.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/composer/InstalledVersions.php 2025-12-21 09:35:59.449067309 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/composer/InstalledVersions.php 2025-12-21 09:36:35.267293523 +0000@@ -27,6 +27,12 @@ class InstalledVersions { /**+ * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to+ * @internal+ */+ private static $selfDir = null;++ /** * @var mixed[]|null * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null */@@ -98,7 +104,7 @@ { foreach (self::getInstalled() as $installed) { if (isset($installed['versions'][$packageName])) {- return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);+ return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; } } @@ -119,7 +125,7 @@ */ public static function satisfies(VersionParser $parser, $packageName, $constraint) {- $constraint = $parser->parseConstraints($constraint);+ $constraint = $parser->parseConstraints((string) $constraint); $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); return $provided->matches($constraint);@@ -312,6 +318,18 @@ } /**+ * @return string+ */+ private static function getSelfDir()+ {+ if (self::$selfDir === null) {+ self::$selfDir = strtr(__DIR__, '\\', '/');+ }++ return self::$selfDir;+ }++ /** * @return array[] * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> */@@ -322,15 +340,20 @@ } $installed = array();+ $copiedLocalDir = false; if (self::$canGetVendors) { foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) {- $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';- if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {- self::$installed = $installed[count($installed) - 1];+ /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */+ $required = require $vendorDir.'/composer/installed.php';+ self::$installedByVendor[$vendorDir] = $required;+ $installed[] = $required;+ if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {+ self::$installed = $required;+ $copiedLocalDir = true; } } }@@ -340,12 +363,17 @@ // only require the installed.php file if this file is loaded from its dumped location, // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 if (substr(__DIR__, -8, 1) !== 'C') {- self::$installed = require __DIR__ . '/installed.php';+ /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */+ $required = require __DIR__ . '/installed.php';+ self::$installed = $required; } else { self::$installed = array(); } }- $installed[] = self::$installed;++ if (self::$installed !== array() && !$copiedLocalDir) {+ $installed[] = self::$installed;+ } return $installed; }
Based on my analysis of the provided code diff from `vendor/composer/InstalledVersions.php`, here is the security analysis:
---
**Vulnerability 1: Type Confusion / Unexpected Type**
Vulnerability Existed: yes
TRUE POSITIVE
Type Juggling / Type Confusion - CWE-1025 - InstalledVersions.php [Line 107]
Old Code:
```php
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
```
Fixed Code:
```php
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
```
Explanation:
The original code used `empty()` which could incorrectly evaluate values like `0`, `"0"`, `false`, or `null` as empty. The fix explicitly checks with `!isset()` and strict comparison `=== false`. This prevents type juggling bugs where a falsy value might be misinterpreted. This is important for security in package version checking where a missing `dev_requirement` flag or an explicit `false` value should have different semantics.
---
**Vulnerability 2: Type Coercion / String Injection**
Vulnerability Existed: yes
TRUE POSITIVE
Improper Input Validation / Type Coercion - CWE-1025 - InstalledVersions.php [Line 128]
Old Code:
```php
$constraint = $parser->parseConstraints($constraint);
```
Fixed Code:
```php
$constraint = $parser->parseConstraints((string) $constraint);
```
Explanation:
The fix explicitly casts `$constraint` to a string before passing to `parseConstraints()`. This prevents potential type confusion attacks where an object or array might be passed instead of a string. By forcing a string type, it prevents unexpected behavior from object-to-string conversions or array serialization that could lead to parsing errors or security issues.
---
**Vulnerability 3: Path Traversal / Directory Information Disclosure**
Vulnerability Existed: not sure
Improper Restriction of Rendered UI Layers or Frames / Directory Path Manipulation - CWE-22 - InstalledVersions.php [Lines 318-326, 340-376]
Old Code:
```php
// Line 332: $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
// Line 333: if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
// Line 334: self::$installed = $installed[count($installed) - 1];
```
Fixed Code:
```php
$required = require $vendorDir.'/composer/installed.php';
self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required;
if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $required;
$copiedLocalDir = true;
}
```
Explanation:
The fix adds more explicit path comparison logic and introduces a `$copiedLocalDir` flag to prevent duplicate processing of the same directory. While the original code had path normalization using `strtr()`, the refactoring makes the logic clearer and adds a guard (`if (self::$installed !== array() && !$copiedLocalDir)`) to prevent re-including the same installed.php file twice, which could lead to inconsistent state or denial of service through repeated file I/O operations.
---
**Summary:**
The diff contains improvements to type safety and path handling logic. The primary security improvements are:
1. Explicit type checking instead of loose `empty()` evaluation
2. Type coercion for constraint parsing to prevent object injection
3. Clearer path comparison logic with duplicate prevention guards
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/composer/autoload_psr4.php 2025-12-21 09:35:59.449067309 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/composer/autoload_psr4.php 2025-12-21 09:36:35.267293523 +0000@@ -12,14 +12,16 @@ 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), 'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'), 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),- 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'),+ 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),- 'Illuminate\\Support\\' => array($vendorDir . '/illuminate/macroable', $vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/support'),+ 'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'),+ 'Illuminate\\Support\\' => array($vendorDir . '/illuminate/support', $vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/macroable'), 'Illuminate\\Contracts\\' => array($vendorDir . '/illuminate/contracts'), 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),- 'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector'),+ 'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/src'),+ 'Carbon\\Doctrine\\' => array($vendorDir . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine'), 'Carbon\\' => array($vendorDir . '/nesbot/carbon/src/Carbon'), );
Analyzing the provided code diff for security fixes: --- **Vulnerability Existed: no** **No Direct Security Vulnerability - CWE-N/A - vendor/composer/autoload_psr4.php - Lines 15, 19, 26, 28** **Old Code:** ```php 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'), 'Illuminate\\Support\\' => array($vendorDir . '/illuminate/macroable', $vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/support'), 'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector'), ``` **Fixed Code:** ```php 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), 'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'), 'Illuminate\\Support\\' => array($vendorDir . '/illuminate/support', $vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/macroable'), 'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/src'), 'Carbon\\Doctrine\\' => array($vendorDir . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine'), ``` **Explanation:** This diff represents composer autoloader configuration updates, not security fixes. The changes include: 1. **Reordering of PSR paths** - Array element order change for `Psr\\Http\\Message\\` namespace. This is a dependency resolution optimization, not a security fix. 2. **Addition of new namespace mappings** - `Psr\\Clock\\` and `Carbon\\Doctrine\\` are added to support new library dependencies. This is a dependency management update. 3. **Path updates** - `Doctrine\\Inflector\\` path changed from `lib/Doctrine/Inflector` to `src`. This reflects a package structure update in the dependency, not a security vulnerability fix. 4. **Reordering of Illuminate paths** - Array element reordering for namespace precedence. This is configuration optimization, not security-related. These are standard composer dependency management updates (version upgrade from 3.3.4 to 3.3.5) with no apparent security vulnerabilities being fixed or introduced.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/composer/autoload_real.php 2025-12-21 09:35:59.449067309 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/composer/autoload_real.php 2025-12-21 09:36:35.267293523 +0000@@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit8e6cef26cd70b7fee2740e066e9a2431+class ComposerAutoloaderInit12bd507041a61d7a2b04e74ca1404740 { private static $loader; @@ -24,34 +24,27 @@ require __DIR__ . '/platform_check.php'; - spl_autoload_register(array('ComposerAutoloaderInit8e6cef26cd70b7fee2740e066e9a2431', 'loadClassLoader'), true, true);+ spl_autoload_register(array('ComposerAutoloaderInit12bd507041a61d7a2b04e74ca1404740', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));- spl_autoload_unregister(array('ComposerAutoloaderInit8e6cef26cd70b7fee2740e066e9a2431', 'loadClassLoader'));+ spl_autoload_unregister(array('ComposerAutoloaderInit12bd507041a61d7a2b04e74ca1404740', 'loadClassLoader')); require __DIR__ . '/autoload_static.php';- call_user_func(\Composer\Autoload\ComposerStaticInit8e6cef26cd70b7fee2740e066e9a2431::getInitializer($loader));+ call_user_func(\Composer\Autoload\ComposerStaticInit12bd507041a61d7a2b04e74ca1404740::getInitializer($loader)); $loader->register(true); - $includeFiles = \Composer\Autoload\ComposerStaticInit8e6cef26cd70b7fee2740e066e9a2431::$files;- foreach ($includeFiles as $fileIdentifier => $file) {- composerRequire8e6cef26cd70b7fee2740e066e9a2431($fileIdentifier, $file);+ $filesToLoad = \Composer\Autoload\ComposerStaticInit12bd507041a61d7a2b04e74ca1404740::$files;+ $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {+ if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {+ $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;++ require $file;+ }+ }, null, null);+ foreach ($filesToLoad as $fileIdentifier => $file) {+ $requireFile($fileIdentifier, $file); } return $loader; } }--/**- * @param string $fileIdentifier- * @param string $file- * @return void- */-function composerRequire8e6cef26cd70b7fee2740e066e9a2431($fileIdentifier, $file)-{- if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {- $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;-- require $file;- }-}
Vulnerability Existed: no
[No Vulnerability] - N/A - vendor/composer/autoload_real.php [Lines 2-56]
Old Code:
```php
class ComposerAutoloaderInit8e6cef26cd70b7fee2740e066e9a2431
{
// ...
function composerRequire8e6cef26cd70b7fee2740e066e9a2431($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
}
}
}
```
Fixed Code:
```php
class ComposerAutoloaderInit12bd507041a61d7a2b04e74ca1404740
{
// ...
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
}
}, null, null);
foreach ($filesToLoad as $fileIdentifier => $file) {
$requireFile($fileIdentifier, $file);
}
}
```
Explanation:
This diff represents a Composer autoloader update from version 3.3.4 to 3.3.5. The changes include:
1. **Class name hash update**: The autoloader class name hash was regenerated (8e6cef26... → 12bd507...), which is a standard Composer practice when dependencies change.
2. **Refactored file loading mechanism**: The standalone function `composerRequire8e6cef26cd70b7fee2740e066e9a2431()` was replaced with a closure bound using `\Closure::bind()`. This is not a security fix but rather a code modernization.
The original code was not vulnerable. The `require $file;` statement in both versions uses a dynamic include, but this is safe within Composer's autoloader context because:
- The `$file` variable comes from Composer's static configuration (autoload_static.php)
- The file paths are pre-determined by Composer during installation
- User input is not involved in path construction
The refactoring to use a closure is a style improvement but does not address or fix any existing security vulnerabilities. No security issue existed in the original code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/composer/autoload_static.php 2025-12-21 09:35:59.449067309 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/composer/autoload_static.php 2025-12-21 09:36:35.267293523 +0000@@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit8e6cef26cd70b7fee2740e066e9a2431+class ComposerStaticInit12bd507041a61d7a2b04e74ca1404740 { public static $files = array ( '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',@@ -38,6 +38,7 @@ 'Psr\\Http\\Message\\' => 17, 'Psr\\Http\\Client\\' => 16, 'Psr\\Container\\' => 14,+ 'Psr\\Clock\\' => 10, ), 'I' => array (@@ -56,6 +57,7 @@ ), 'C' => array (+ 'Carbon\\Doctrine\\' => 16, 'Carbon\\' => 7, ), );@@ -87,8 +89,8 @@ ), 'Psr\\Http\\Message\\' => array (- 0 => __DIR__ . '/..' . '/psr/http-message/src',- 1 => __DIR__ . '/..' . '/psr/http-factory/src',+ 0 => __DIR__ . '/..' . '/psr/http-factory/src',+ 1 => __DIR__ . '/..' . '/psr/http-message/src', ), 'Psr\\Http\\Client\\' => array (@@ -98,11 +100,15 @@ array ( 0 => __DIR__ . '/..' . '/psr/container/src', ),+ 'Psr\\Clock\\' => + array (+ 0 => __DIR__ . '/..' . '/psr/clock/src',+ ), 'Illuminate\\Support\\' => array (- 0 => __DIR__ . '/..' . '/illuminate/macroable',+ 0 => __DIR__ . '/..' . '/illuminate/support', 1 => __DIR__ . '/..' . '/illuminate/collections',- 2 => __DIR__ . '/..' . '/illuminate/support',+ 2 => __DIR__ . '/..' . '/illuminate/macroable', ), 'Illuminate\\Contracts\\' => array (@@ -122,7 +128,11 @@ ), 'Doctrine\\Inflector\\' => array (- 0 => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Inflector',+ 0 => __DIR__ . '/..' . '/doctrine/inflector/src',+ ),+ 'Carbon\\Doctrine\\' => + array (+ 0 => __DIR__ . '/..' . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine', ), 'Carbon\\' => array (@@ -163,10 +173,10 @@ public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) {- $loader->prefixLengthsPsr4 = ComposerStaticInit8e6cef26cd70b7fee2740e066e9a2431::$prefixLengthsPsr4;- $loader->prefixDirsPsr4 = ComposerStaticInit8e6cef26cd70b7fee2740e066e9a2431::$prefixDirsPsr4;- $loader->prefixesPsr0 = ComposerStaticInit8e6cef26cd70b7fee2740e066e9a2431::$prefixesPsr0;- $loader->classMap = ComposerStaticInit8e6cef26cd70b7fee2740e066e9a2431::$classMap;+ $loader->prefixLengthsPsr4 = ComposerStaticInit12bd507041a61d7a2b04e74ca1404740::$prefixLengthsPsr4;+ $loader->prefixDirsPsr4 = ComposerStaticInit12bd507041a61d7a2b04e74ca1404740::$prefixDirsPsr4;+ $loader->prefixesPsr0 = ComposerStaticInit12bd507041a61d7a2b04e74ca1404740::$prefixesPsr0;+ $loader->classMap = ComposerStaticInit12bd507041a61d7a2b04e74ca1404740::$classMap; }, null, ClassLoader::class); }
Vulnerability Existed: no This diff represents an update to the Composer autoloader static initialization file, which is automatically generated by Composer when dependencies are updated. The changes reflect: 1. **Class name hash update** - The class name changed from `ComposerStaticInit8e6cef26cd70b7fee2740e066e9a2431` to `ComposerStaticInit12bd507041a61d7a2b04e74ca1404740` (lines 7, 166-169). This is a normal Composer autoload cache update. 2. **New namespace mappings** - Added support for `Psr\Clock\` (PSR-20 Clock interface) and `Carbon\Doctrine\` namespaces, reflecting new dependencies or dependency updates. 3. **Reordered path mappings** - Minor reordering of include paths for existing namespaces like `Psr\Http\Message\`, `Illuminate\Support\`, and `Doctrine\Inflector\`. **Analysis**: This is an auto-generated Composer dependency file. No actual code logic was modified, no user input is being processed, no external calls were altered, and no security-relevant functionality changed. The file only registers namespace-to-directory mappings for PHP's autoloader. These changes are consistent with normal Composer dependency management and pose no security vulnerability.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/composer/installed.php 2025-12-21 09:35:59.449067309 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/composer/installed.php 2025-12-21 09:36:35.267293523 +0000@@ -1,55 +1,64 @@ <?php return array( 'root' => array( 'name' => 'elula/wsdesk',- 'pretty_version' => 'dev-master',- 'version' => 'dev-master',- 'reference' => 'e991a1022d94ea32266f37ab6ed26a006efe4e6b',+ 'pretty_version' => '1.0.0+no-version-set',+ 'version' => '1.0.0.0',+ 'reference' => null, 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(),- 'dev' => false,+ 'dev' => true, ), 'versions' => array(+ 'carbonphp/carbon-doctrine-types' => array(+ 'pretty_version' => '2.1.0',+ 'version' => '2.1.0.0',+ 'reference' => '99f76ffa36cce3b70a4a6abce41dba15ca2e84cb',+ 'type' => 'library',+ 'install_path' => __DIR__ . '/../carbonphp/carbon-doctrine-types',+ 'aliases' => array(),+ 'dev_requirement' => false,+ ), 'doctrine/inflector' => array(- 'pretty_version' => '2.0.8',- 'version' => '2.0.8.0',- 'reference' => 'f9301a5b2fb1216b2b08f02ba04dc45423db6bff',+ 'pretty_version' => '2.1.0',+ 'version' => '2.1.0.0',+ 'reference' => '6d6c96277ea252fc1304627204c3d5e6e15faa3b', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/inflector', 'aliases' => array(), 'dev_requirement' => false, ), 'elula/wsdesk' => array(- 'pretty_version' => 'dev-master',- 'version' => 'dev-master',- 'reference' => 'e991a1022d94ea32266f37ab6ed26a006efe4e6b',+ 'pretty_version' => '1.0.0+no-version-set',+ 'version' => '1.0.0.0',+ 'reference' => null, 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => false, ), 'guzzlehttp/guzzle' => array(- 'pretty_version' => '7.7.0',- 'version' => '7.7.0.0',- 'reference' => 'fb7566caccf22d74d1ab270de3551f72a58399f5',+ 'pretty_version' => '7.10.0',+ 'version' => '7.10.0.0',+ 'reference' => 'b51ac707cfa420b7bfd4e4d5e510ba8008e822b4', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/guzzle', 'aliases' => array(), 'dev_requirement' => false, ), 'guzzlehttp/promises' => array(- 'pretty_version' => '2.0.1',- 'version' => '2.0.1.0',- 'reference' => '111166291a0f8130081195ac4556a5587d7f1b5d',+ 'pretty_version' => '2.3.0',+ 'version' => '2.3.0.0',+ 'reference' => '481557b130ef3790cf82b713667b43030dc9c957', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/promises', 'aliases' => array(), 'dev_requirement' => false, ), 'guzzlehttp/psr7' => array(- 'pretty_version' => '2.6.0',- 'version' => '2.6.0.0',- 'reference' => '8bd7c33a0734ae1c5d074360512beb716bef3f77',+ 'pretty_version' => '2.8.0',+ 'version' => '2.8.0.0',+ 'reference' => '21dc724a0583619cd1652f673303492272778051', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/psr7', 'aliases' => array(),@@ -101,14 +110,29 @@ 'dev_requirement' => false, ), 'nesbot/carbon' => array(- 'pretty_version' => '2.68.1',- 'version' => '2.68.1.0',- 'reference' => '4f991ed2a403c85efbc4f23eb4030063fdbe01da',+ 'pretty_version' => '2.73.0',+ 'version' => '2.73.0.0',+ 'reference' => '9228ce90e1035ff2f0db84b40ec2e023ed802075', 'type' => 'library', 'install_path' => __DIR__ . '/../nesbot/carbon', 'aliases' => array(), 'dev_requirement' => false, ),+ 'psr/clock' => array(+ 'pretty_version' => '1.0.0',+ 'version' => '1.0.0.0',+ 'reference' => 'e41a24703d4560fd0acb709162f73b8adfc3aa0d',+ 'type' => 'library',+ 'install_path' => __DIR__ . '/../psr/clock',+ 'aliases' => array(),+ 'dev_requirement' => false,+ ),+ 'psr/clock-implementation' => array(+ 'dev_requirement' => false,+ 'provided' => array(+ 0 => '1.0',+ ),+ ), 'psr/container' => array( 'pretty_version' => '1.1.2', 'version' => '1.1.2.0',@@ -119,9 +143,9 @@ 'dev_requirement' => false, ), 'psr/http-client' => array(- 'pretty_version' => '1.0.2',- 'version' => '1.0.2.0',- 'reference' => '0955afe48220520692d2d09f7ab7e0f93ffd6a31',+ 'pretty_version' => '1.0.3',+ 'version' => '1.0.3.0',+ 'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-client', 'aliases' => array(),@@ -134,9 +158,9 @@ ), ), 'psr/http-factory' => array(- 'pretty_version' => '1.0.2',- 'version' => '1.0.2.0',- 'reference' => 'e616d01114759c4c489f93b099585439f795fe35',+ 'pretty_version' => '1.1.0',+ 'version' => '1.1.0.0',+ 'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-factory', 'aliases' => array(),@@ -182,9 +206,9 @@ 'dev_requirement' => false, ), 'symfony/deprecation-contracts' => array(- 'pretty_version' => 'v2.5.2',- 'version' => '2.5.2.0',- 'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66',+ 'pretty_version' => 'v2.5.4',+ 'version' => '2.5.4.0',+ 'reference' => '605389f2a7e5625f273b53960dc46aeaf9c62918', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'aliases' => array(),@@ -200,9 +224,9 @@ 'dev_requirement' => false, ), 'symfony/polyfill-php80' => array(- 'pretty_version' => 'v1.27.0',- 'version' => '1.27.0.0',- 'reference' => '7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936',+ 'pretty_version' => 'v1.33.0',+ 'version' => '1.33.0.0',+ 'reference' => '0cc9dd0f17f61d8131e7df6b84bd344899fe2608', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php80', 'aliases' => array(),
Vulnerability Existed: no [No Security Vulnerabilities Found] - [N/A] - [vendor/composer/installed.php] [N/A] [N/A] Explanation: This diff shows updates to the Composer dependency manifest file (vendor/composer/installed.php). The changes consist entirely of: 1. **Dependency version updates**: Multiple packages are updated to newer versions (e.g., guzzlehttp/guzzle 7.7.0 → 7.10.0, nesbot/carbon 2.68.1 → 2.73.0, symfony components, etc.) 2. **New dependencies added**: carbonphp/carbon-doctrine-types and psr/clock/psr/clock-implementation are introduced 3. **Version metadata changes**: The root package version changed from 'dev-master' to '1.0.0+no-version-set' 4. **Dev flag update**: Changed from 'dev' => false to 'dev' => true None of these changes introduce security vulnerabilities. This is a standard dependency management update file that reflects library version upgrades and additions. The Composer lock file itself (installed.php) is not executable code that could contain vulnerabilities—it's metadata. The actual security depends on whether the updated library versions themselves contain security fixes, but those are external to this file's content.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/CachedWordInflector.php+++ /dev/null@@ -1,24 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector;--class CachedWordInflector implements WordInflector-{- /** @var WordInflector */- private $wordInflector;-- /** @var string[] */- private $cache = [];-- public function __construct(WordInflector $wordInflector)- {- $this->wordInflector = $wordInflector;- }-- public function inflect(string $word): string- {- return $this->cache[$word] ?? $this->cache[$word] = $this->wordInflector->inflect($word);- }-}
Vulnerability Existed: no
**File Deletion - No Vulnerability**
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector;
class CachedWordInflector implements WordInflector
{
/** @var WordInflector */
private $wordInflector;
/** @var string[] */
private $cache = [];
public function __construct(WordInflector $wordInflector)
{
$this->wordInflector = $wordInflector;
}
public function inflect(string $word): string
{
return $this->cache[$word] ?? $this->cache[$word] = $this->wordInflector->inflect($word);
}
}
```
Fixed Code:
(File deleted)
Explanation:
This diff shows the deletion of the `CachedWordInflector.php` file from the vendor directory. This is a removal of third-party library code, not a security fix. The deleted code itself does not contain any security vulnerabilities - it's a simple caching wrapper for word inflection operations. The file deletion appears to be a dependency update or cleanup operation, not a response to a security issue. No vulnerability exists in the removed code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/GenericLanguageInflectorFactory.php+++ /dev/null@@ -1,66 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector;--use Doctrine\Inflector\Rules\Ruleset;--use function array_unshift;--abstract class GenericLanguageInflectorFactory implements LanguageInflectorFactory-{- /** @var Ruleset[] */- private $singularRulesets = [];-- /** @var Ruleset[] */- private $pluralRulesets = [];-- final public function __construct()- {- $this->singularRulesets[] = $this->getSingularRuleset();- $this->pluralRulesets[] = $this->getPluralRuleset();- }-- final public function build(): Inflector- {- return new Inflector(- new CachedWordInflector(new RulesetInflector(- ...$this->singularRulesets- )),- new CachedWordInflector(new RulesetInflector(- ...$this->pluralRulesets- ))- );- }-- final public function withSingularRules(?Ruleset $singularRules, bool $reset = false): LanguageInflectorFactory- {- if ($reset) {- $this->singularRulesets = [];- }-- if ($singularRules instanceof Ruleset) {- array_unshift($this->singularRulesets, $singularRules);- }-- return $this;- }-- final public function withPluralRules(?Ruleset $pluralRules, bool $reset = false): LanguageInflectorFactory- {- if ($reset) {- $this->pluralRulesets = [];- }-- if ($pluralRules instanceof Ruleset) {- array_unshift($this->pluralRulesets, $pluralRules);- }-- return $this;- }-- abstract protected function getSingularRuleset(): Ruleset;-- abstract protected function getPluralRuleset(): Ruleset;-}
Vulnerability Existed: no No Vulnerabilities Detected - File Deletion Explanation: This diff shows the deletion of the entire `GenericLanguageInflectorFactory.php` file from the Doctrine Inflector library. This is a file removal operation, not a code modification that could introduce or fix vulnerabilities. The deleted file contains a generic factory class for language inflectors with standard object-oriented design patterns (abstract class, dependency injection, etc.). There are no security vulnerabilities present in the deleted code: - No SQL injection vectors - No command injection possibilities - No authentication/authorization issues - No sensitive data exposure - No unsafe deserialization - No buffer overflows or memory safety issues - No improper input validation - Proper type hints and parameter validation Since this is a deletion rather than a fix, there is no "before/after" comparison to analyze for security improvements. If this file was removed as part of a dependency update or code cleanup, it simply means this component is no longer part of the codebase.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Inflector.php+++ /dev/null@@ -1,507 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector;--use RuntimeException;--use function chr;-use function function_exists;-use function lcfirst;-use function mb_strtolower;-use function ord;-use function preg_match;-use function preg_replace;-use function sprintf;-use function str_replace;-use function strlen;-use function strtolower;-use function strtr;-use function trim;-use function ucwords;--class Inflector-{- private const ACCENTED_CHARACTERS = [- 'À' => 'A',- 'Á' => 'A',- 'Â' => 'A',- 'Ã' => 'A',- 'Ä' => 'Ae',- 'Æ' => 'Ae',- 'Å' => 'Aa',- 'æ' => 'a',- 'Ç' => 'C',- 'È' => 'E',- 'É' => 'E',- 'Ê' => 'E',- 'Ë' => 'E',- 'Ì' => 'I',- 'Í' => 'I',- 'Î' => 'I',- 'Ï' => 'I',- 'Ñ' => 'N',- 'Ò' => 'O',- 'Ó' => 'O',- 'Ô' => 'O',- 'Õ' => 'O',- 'Ö' => 'Oe',- 'Ù' => 'U',- 'Ú' => 'U',- 'Û' => 'U',- 'Ü' => 'Ue',- 'Ý' => 'Y',- 'ß' => 'ss',- 'à' => 'a',- 'á' => 'a',- 'â' => 'a',- 'ã' => 'a',- 'ä' => 'ae',- 'å' => 'aa',- 'ç' => 'c',- 'è' => 'e',- 'é' => 'e',- 'ê' => 'e',- 'ë' => 'e',- 'ì' => 'i',- 'í' => 'i',- 'î' => 'i',- 'ï' => 'i',- 'ñ' => 'n',- 'ò' => 'o',- 'ó' => 'o',- 'ô' => 'o',- 'õ' => 'o',- 'ö' => 'oe',- 'ù' => 'u',- 'ú' => 'u',- 'û' => 'u',- 'ü' => 'ue',- 'ý' => 'y',- 'ÿ' => 'y',- 'Ā' => 'A',- 'ā' => 'a',- 'Ă' => 'A',- 'ă' => 'a',- 'Ą' => 'A',- 'ą' => 'a',- 'Ć' => 'C',- 'ć' => 'c',- 'Ĉ' => 'C',- 'ĉ' => 'c',- 'Ċ' => 'C',- 'ċ' => 'c',- 'Č' => 'C',- 'č' => 'c',- 'Ď' => 'D',- 'ď' => 'd',- 'Đ' => 'D',- 'đ' => 'd',- 'Ē' => 'E',- 'ē' => 'e',- 'Ĕ' => 'E',- 'ĕ' => 'e',- 'Ė' => 'E',- 'ė' => 'e',- 'Ę' => 'E',- 'ę' => 'e',- 'Ě' => 'E',- 'ě' => 'e',- 'Ĝ' => 'G',- 'ĝ' => 'g',- 'Ğ' => 'G',- 'ğ' => 'g',- 'Ġ' => 'G',- 'ġ' => 'g',- 'Ģ' => 'G',- 'ģ' => 'g',- 'Ĥ' => 'H',- 'ĥ' => 'h',- 'Ħ' => 'H',- 'ħ' => 'h',- 'Ĩ' => 'I',- 'ĩ' => 'i',- 'Ī' => 'I',- 'ī' => 'i',- 'Ĭ' => 'I',- 'ĭ' => 'i',- 'Į' => 'I',- 'į' => 'i',- 'İ' => 'I',- 'ı' => 'i',- 'IJ' => 'IJ',- 'ij' => 'ij',- 'Ĵ' => 'J',- 'ĵ' => 'j',- 'Ķ' => 'K',- 'ķ' => 'k',- 'ĸ' => 'k',- 'Ĺ' => 'L',- 'ĺ' => 'l',- 'Ļ' => 'L',- 'ļ' => 'l',- 'Ľ' => 'L',- 'ľ' => 'l',- 'Ŀ' => 'L',- 'ŀ' => 'l',- 'Ł' => 'L',- 'ł' => 'l',- 'Ń' => 'N',- 'ń' => 'n',- 'Ņ' => 'N',- 'ņ' => 'n',- 'Ň' => 'N',- 'ň' => 'n',- 'ʼn' => 'N',- 'Ŋ' => 'n',- 'ŋ' => 'N',- 'Ō' => 'O',- 'ō' => 'o',- 'Ŏ' => 'O',- 'ŏ' => 'o',- 'Ő' => 'O',- 'ő' => 'o',- 'Œ' => 'OE',- 'œ' => 'oe',- 'Ø' => 'O',- 'ø' => 'o',- 'Ŕ' => 'R',- 'ŕ' => 'r',- 'Ŗ' => 'R',- 'ŗ' => 'r',- 'Ř' => 'R',- 'ř' => 'r',- 'Ś' => 'S',- 'ś' => 's',- 'Ŝ' => 'S',- 'ŝ' => 's',- 'Ş' => 'S',- 'ş' => 's',- 'Š' => 'S',- 'š' => 's',- 'Ţ' => 'T',- 'ţ' => 't',- 'Ť' => 'T',- 'ť' => 't',- 'Ŧ' => 'T',- 'ŧ' => 't',- 'Ũ' => 'U',- 'ũ' => 'u',- 'Ū' => 'U',- 'ū' => 'u',- 'Ŭ' => 'U',- 'ŭ' => 'u',- 'Ů' => 'U',- 'ů' => 'u',- 'Ű' => 'U',- 'ű' => 'u',- 'Ų' => 'U',- 'ų' => 'u',- 'Ŵ' => 'W',- 'ŵ' => 'w',- 'Ŷ' => 'Y',- 'ŷ' => 'y',- 'Ÿ' => 'Y',- 'Ź' => 'Z',- 'ź' => 'z',- 'Ż' => 'Z',- 'ż' => 'z',- 'Ž' => 'Z',- 'ž' => 'z',- 'ſ' => 's',- '€' => 'E',- '£' => '',- ];-- /** @var WordInflector */- private $singularizer;-- /** @var WordInflector */- private $pluralizer;-- public function __construct(WordInflector $singularizer, WordInflector $pluralizer)- {- $this->singularizer = $singularizer;- $this->pluralizer = $pluralizer;- }-- /**- * Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'.- */- public function tableize(string $word): string- {- $tableized = preg_replace('~(?<=\\w)([A-Z])~u', '_$1', $word);-- if ($tableized === null) {- throw new RuntimeException(sprintf(- 'preg_replace returned null for value "%s"',- $word- ));- }-- return mb_strtolower($tableized);- }-- /**- * Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'.- */- public function classify(string $word): string- {- return str_replace([' ', '_', '-'], '', ucwords($word, ' _-'));- }-- /**- * Camelizes a word. This uses the classify() method and turns the first character to lowercase.- */- public function camelize(string $word): string- {- return lcfirst($this->classify($word));- }-- /**- * Uppercases words with configurable delimiters between words.- *- * Takes a string and capitalizes all of the words, like PHP's built-in- * ucwords function. This extends that behavior, however, by allowing the- * word delimiters to be configured, rather than only separating on- * whitespace.- *- * Here is an example:- * <code>- * <?php- * $string = 'top-o-the-morning to all_of_you!';- * echo $inflector->capitalize($string);- * // Top-O-The-Morning To All_of_you!- *- * echo $inflector->capitalize($string, '-_ ');- * // Top-O-The-Morning To All_Of_You!- * ?>- * </code>- *- * @param string $string The string to operate on.- * @param string $delimiters A list of word separators.- *- * @return string The string with all delimiter-separated words capitalized.- */- public function capitalize(string $string, string $delimiters = " \n\t\r\0\x0B-"): string- {- return ucwords($string, $delimiters);- }-- /**- * Checks if the given string seems like it has utf8 characters in it.- *- * @param string $string The string to check for utf8 characters in.- */- public function seemsUtf8(string $string): bool- {- for ($i = 0; $i < strlen($string); $i++) {- if (ord($string[$i]) < 0x80) {- continue; // 0bbbbbbb- }-- if ((ord($string[$i]) & 0xE0) === 0xC0) {- $n = 1; // 110bbbbb- } elseif ((ord($string[$i]) & 0xF0) === 0xE0) {- $n = 2; // 1110bbbb- } elseif ((ord($string[$i]) & 0xF8) === 0xF0) {- $n = 3; // 11110bbb- } elseif ((ord($string[$i]) & 0xFC) === 0xF8) {- $n = 4; // 111110bb- } elseif ((ord($string[$i]) & 0xFE) === 0xFC) {- $n = 5; // 1111110b- } else {- return false; // Does not match any model- }-- for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?- if (++$i === strlen($string) || ((ord($string[$i]) & 0xC0) !== 0x80)) {- return false;- }- }- }-- return true;- }-- /**- * Remove any illegal characters, accents, etc.- *- * @param string $string String to unaccent- *- * @return string Unaccented string- */- public function unaccent(string $string): string- {- if (preg_match('/[\x80-\xff]/', $string) === false) {- return $string;- }-- if ($this->seemsUtf8($string)) {- $string = strtr($string, self::ACCENTED_CHARACTERS);- } else {- $characters = [];-- // Assume ISO-8859-1 if not UTF-8- $characters['in'] =- chr(128)- . chr(131)- . chr(138)- . chr(142)- . chr(154)- . chr(158)- . chr(159)- . chr(162)- . chr(165)- . chr(181)- . chr(192)- . chr(193)- . chr(194)- . chr(195)- . chr(196)- . chr(197)- . chr(199)- . chr(200)- . chr(201)- . chr(202)- . chr(203)- . chr(204)- . chr(205)- . chr(206)- . chr(207)- . chr(209)- . chr(210)- . chr(211)- . chr(212)- . chr(213)- . chr(214)- . chr(216)- . chr(217)- . chr(218)- . chr(219)- . chr(220)- . chr(221)- . chr(224)- . chr(225)- . chr(226)- . chr(227)- . chr(228)- . chr(229)- . chr(231)- . chr(232)- . chr(233)- . chr(234)- . chr(235)- . chr(236)- . chr(237)- . chr(238)- . chr(239)- . chr(241)- . chr(242)- . chr(243)- . chr(244)- . chr(245)- . chr(246)- . chr(248)- . chr(249)- . chr(250)- . chr(251)- . chr(252)- . chr(253)- . chr(255);-- $characters['out'] = 'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy';-- $string = strtr($string, $characters['in'], $characters['out']);-- $doubleChars = [];-- $doubleChars['in'] = [- chr(140),- chr(156),- chr(198),- chr(208),- chr(222),- chr(223),- chr(230),- chr(240),- chr(254),- ];-- $doubleChars['out'] = ['OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th'];-- $string = str_replace($doubleChars['in'], $doubleChars['out'], $string);- }-- return $string;- }-- /**- * Convert any passed string to a url friendly string.- * Converts 'My first blog post' to 'my-first-blog-post'- *- * @param string $string String to urlize.- *- * @return string Urlized string.- */- public function urlize(string $string): string- {- // Remove all non url friendly characters with the unaccent function- $unaccented = $this->unaccent($string);-- if (function_exists('mb_strtolower')) {- $lowered = mb_strtolower($unaccented);- } else {- $lowered = strtolower($unaccented);- }-- $replacements = [- '/\W/' => ' ',- '/([A-Z]+)([A-Z][a-z])/' => '\1_\2',- '/([a-z\d])([A-Z])/' => '\1_\2',- '/[^A-Z^a-z^0-9^\/]+/' => '-',- ];-- $urlized = $lowered;-- foreach ($replacements as $pattern => $replacement) {- $replaced = preg_replace($pattern, $replacement, $urlized);-- if ($replaced === null) {- throw new RuntimeException(sprintf(- 'preg_replace returned null for value "%s"',- $urlized- ));- }-- $urlized = $replaced;- }-- return trim($urlized, '-');- }-- /**- * Returns a word in singular form.- *- * @param string $word The word in plural form.- *- * @return string The word in singular form.- */- public function singularize(string $word): string- {- return $this->singularizer->inflect($word);- }-- /**- * Returns a word in plural form.- *- * @param string $word The word in singular form.- *- * @return string The word in plural form.- */- public function pluralize(string $word): string- {- return $this->pluralizer->inflect($word);- }-}
Vulnerability Existed: no
Removal of Doctrine Inflector Library - File: vendor/doctrine/inflector/lib/Doctrine/Inflector/Inflector.php (Lines 1-507)
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector;
use RuntimeException;
use function chr;
use function function_exists;
use function lcfirst;
use function mb_strtolower;
use function ord;
use function preg_match;
use function preg_replace;
use function sprintf;
use function str_replace;
use function strlen;
use function strtolower;
use function strtr;
use function trim;
use function ucwords;
class Inflector
{
// ... full Inflector class implementation
}
```
Fixed Code:
```
[File deleted - /dev/null]
```
Explanation:
This diff shows the complete removal of the Doctrine Inflector library file. This is not a security vulnerability fix, but rather a dependency removal or refactoring change. The Inflector class itself contains no security vulnerabilities - it implements string manipulation utilities for converting between naming conventions (camelCase, snake_case, pluralization, etc.). The removal does not indicate a security issue was discovered in this code. The class properly handles edge cases (e.g., preg_replace null checks) and does not expose dangerous functionality. This appears to be a legitimate code cleanup or dependency management decision rather than a security-driven removal.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/InflectorFactory.php+++ /dev/null@@ -1,52 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector;--use Doctrine\Inflector\Rules\English;-use Doctrine\Inflector\Rules\French;-use Doctrine\Inflector\Rules\NorwegianBokmal;-use Doctrine\Inflector\Rules\Portuguese;-use Doctrine\Inflector\Rules\Spanish;-use Doctrine\Inflector\Rules\Turkish;-use InvalidArgumentException;--use function sprintf;--final class InflectorFactory-{- public static function create(): LanguageInflectorFactory- {- return self::createForLanguage(Language::ENGLISH);- }-- public static function createForLanguage(string $language): LanguageInflectorFactory- {- switch ($language) {- case Language::ENGLISH:- return new English\InflectorFactory();-- case Language::FRENCH:- return new French\InflectorFactory();-- case Language::NORWEGIAN_BOKMAL:- return new NorwegianBokmal\InflectorFactory();-- case Language::PORTUGUESE:- return new Portuguese\InflectorFactory();-- case Language::SPANISH:- return new Spanish\InflectorFactory();-- case Language::TURKISH:- return new Turkish\InflectorFactory();-- default:- throw new InvalidArgumentException(sprintf(- 'Language "%s" is not supported.',- $language- ));- }- }-}
Vulnerability Existed: no No Vulnerability Identified - File Deletion This diff shows the complete deletion of `vendor/doctrine/inflector/lib/Doctrine/Inflector/InflectorFactory.php`, which is a vendor library file. Explanation: This is a file removal from a third-party dependency (Doctrine Inflector library), not a security fix to application code. The deleted file contains a factory class for creating language-specific inflectors with proper input validation (the `createForLanguage` method validates the language parameter and throws an `InvalidArgumentException` for unsupported languages). The deletion itself does not represent a security vulnerability fix - it's a dependency update or cleanup operation. The code being removed had no apparent security vulnerabilities: - Proper type hints are used (`string $language`) - Input validation is present (switch statement with default exception) - No injection vulnerabilities, hardcoded credentials, or unsafe operations exist - Proper use of `sprintf` for error message formatting prevents format string attacks This appears to be a routine vendor dependency update rather than a security patch.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Language.php+++ /dev/null@@ -1,19 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector;--final class Language-{- public const ENGLISH = 'english';- public const FRENCH = 'french';- public const NORWEGIAN_BOKMAL = 'norwegian-bokmal';- public const PORTUGUESE = 'portuguese';- public const SPANISH = 'spanish';- public const TURKISH = 'turkish';-- private function __construct()- {- }-}
Vulnerability Existed: no
File Deletion - No CWE Applicable
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector;
final class Language
{
public const ENGLISH = 'english';
public const FRENCH = 'french';
public const NORWEGIAN_BOKMAL = 'norwegian-bokmal';
public const PORTUGUESE = 'portuguese';
public const SPANISH = 'spanish';
public const TURKISH = 'turkish';
private function __construct()
{
}
}
```
Fixed Code:
File deleted (no replacement)
Explanation:
This diff shows the deletion of a vendor library file (`Doctrine\Inflector\Language.php`). The file contains only language constant definitions in a final class with a private constructor, which is a standard utility class pattern. There are no security vulnerabilities present in this code. The deletion itself is not a security fix but rather a vendor dependency change or cleanup. No security issues are addressed or introduced by this removal.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/LanguageInflectorFactory.php+++ /dev/null@@ -1,33 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector;--use Doctrine\Inflector\Rules\Ruleset;--interface LanguageInflectorFactory-{- /**- * Applies custom rules for singularisation- *- * @param bool $reset If true, will unset default inflections for all new rules- *- * @return $this- */- public function withSingularRules(?Ruleset $singularRules, bool $reset = false): self;-- /**- * Applies custom rules for pluralisation- *- * @param bool $reset If true, will unset default inflections for all new rules- *- * @return $this- */- public function withPluralRules(?Ruleset $pluralRules, bool $reset = false): self;-- /**- * Builds the inflector instance with all applicable rules- */- public function build(): Inflector;-}
Vulnerability Existed: no No Security Vulnerability Detected - File Deletion File: vendor/doctrine/inflector/lib/Doctrine/Inflector/LanguageInflectorFactory.php Explanation: This diff shows the complete removal of a PHP interface file from the vendor directory. The file being deleted is `LanguageInflectorFactory.php`, which is a third-party library interface (Doctrine Inflector). Since this is a **deletion** rather than a code modification, there are no security vulnerabilities being introduced or fixed. The removal of this interface file does not create, expose, or remediate any security issues. This appears to be a dependency cleanup or version update where this interface is no longer needed or has been replaced in a newer version of the Doctrine Inflector library. **Key Points:** - No code execution changes - No input validation modifications - No authentication/authorization changes - No cryptographic operations altered - This is purely a removal of unused dependency code **Conclusion:** No security vulnerability analysis is applicable to file deletions unless they specifically remove security mitigations (which is not the case here).
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/NoopWordInflector.php+++ /dev/null@@ -1,13 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector;--class NoopWordInflector implements WordInflector-{- public function inflect(string $word): string- {- return $word;- }-}
Vulnerability Existed: no
No CWE vulnerability identified - File deletion
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector;
class NoopWordInflector implements WordInflector
{
public function inflect(string $word): string
{
return $word;
}
}
```
Fixed Code:
File removed (null)
Explanation:
This diff shows the deletion of a legitimate utility class (`NoopWordInflector`) from the Doctrine Inflector library. The class is a simple no-operation inflector that returns the input word unchanged. This is a benign file removal with no security implications. The class implements the `WordInflector` interface and contains no vulnerable code patterns such as:
- SQL injection vectors
- Command injection risks
- Unvalidated user input handling
- Insecure cryptographic operations
- Path traversal vulnerabilities
- Privilege escalation vectors
The removal itself does not introduce or fix any security vulnerabilities. This appears to be a refactoring or dependency cleanup action.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Inflectible.php+++ /dev/null@@ -1,181 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\English;--use Doctrine\Inflector\Rules\Pattern;-use Doctrine\Inflector\Rules\Substitution;-use Doctrine\Inflector\Rules\Transformation;-use Doctrine\Inflector\Rules\Word;--class Inflectible-{- /** @return Transformation[] */- public static function getSingular(): iterable- {- yield new Transformation(new Pattern('(s)tatuses$'), '\1\2tatus');- yield new Transformation(new Pattern('(s)tatus$'), '\1\2tatus');- yield new Transformation(new Pattern('(c)ampus$'), '\1\2ampus');- yield new Transformation(new Pattern('^(.*)(menu)s$'), '\1\2');- yield new Transformation(new Pattern('(quiz)zes$'), '\\1');- yield new Transformation(new Pattern('(matr)ices$'), '\1ix');- yield new Transformation(new Pattern('(vert|ind)ices$'), '\1ex');- yield new Transformation(new Pattern('^(ox)en'), '\1');- yield new Transformation(new Pattern('(alias)(es)*$'), '\1');- yield new Transformation(new Pattern('(buffal|her|potat|tomat|volcan)oes$'), '\1o');- yield new Transformation(new Pattern('(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$'), '\1us');- yield new Transformation(new Pattern('([ftw]ax)es'), '\1');- yield new Transformation(new Pattern('(analys|ax|cris|test|thes)es$'), '\1is');- yield new Transformation(new Pattern('(shoe|slave)s$'), '\1');- yield new Transformation(new Pattern('(o)es$'), '\1');- yield new Transformation(new Pattern('ouses$'), 'ouse');- yield new Transformation(new Pattern('([^a])uses$'), '\1us');- yield new Transformation(new Pattern('([m|l])ice$'), '\1ouse');- yield new Transformation(new Pattern('(x|ch|ss|sh)es$'), '\1');- yield new Transformation(new Pattern('(m)ovies$'), '\1\2ovie');- yield new Transformation(new Pattern('(s)eries$'), '\1\2eries');- yield new Transformation(new Pattern('([^aeiouy]|qu)ies$'), '\1y');- yield new Transformation(new Pattern('([lr])ves$'), '\1f');- yield new Transformation(new Pattern('(tive)s$'), '\1');- yield new Transformation(new Pattern('(hive)s$'), '\1');- yield new Transformation(new Pattern('(drive)s$'), '\1');- yield new Transformation(new Pattern('(dive)s$'), '\1');- yield new Transformation(new Pattern('(olive)s$'), '\1');- yield new Transformation(new Pattern('([^fo])ves$'), '\1fe');- yield new Transformation(new Pattern('(^analy)ses$'), '\1sis');- yield new Transformation(new Pattern('(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$'), '\1\2sis');- yield new Transformation(new Pattern('(tax)a$'), '\1on');- yield new Transformation(new Pattern('(c)riteria$'), '\1riterion');- yield new Transformation(new Pattern('([ti])a$'), '\1um');- yield new Transformation(new Pattern('(p)eople$'), '\1\2erson');- yield new Transformation(new Pattern('(m)en$'), '\1an');- yield new Transformation(new Pattern('(c)hildren$'), '\1\2hild');- yield new Transformation(new Pattern('(f)eet$'), '\1oot');- yield new Transformation(new Pattern('(n)ews$'), '\1\2ews');- yield new Transformation(new Pattern('eaus$'), 'eau');- yield new Transformation(new Pattern('^tights$'), 'tights');- yield new Transformation(new Pattern('^shorts$'), 'shorts');- yield new Transformation(new Pattern('s$'), '');- }-- /** @return Transformation[] */- public static function getPlural(): iterable- {- yield new Transformation(new Pattern('(s)tatus$'), '\1\2tatuses');- yield new Transformation(new Pattern('(quiz)$'), '\1zes');- yield new Transformation(new Pattern('^(ox)$'), '\1\2en');- yield new Transformation(new Pattern('([m|l])ouse$'), '\1ice');- yield new Transformation(new Pattern('(matr|vert|ind)(ix|ex)$'), '\1ices');- yield new Transformation(new Pattern('(x|ch|ss|sh)$'), '\1es');- yield new Transformation(new Pattern('([^aeiouy]|qu)y$'), '\1ies');- yield new Transformation(new Pattern('(hive|gulf)$'), '\1s');- yield new Transformation(new Pattern('(?:([^f])fe|([lr])f)$'), '\1\2ves');- yield new Transformation(new Pattern('sis$'), 'ses');- yield new Transformation(new Pattern('([ti])um$'), '\1a');- yield new Transformation(new Pattern('(tax)on$'), '\1a');- yield new Transformation(new Pattern('(c)riterion$'), '\1riteria');- yield new Transformation(new Pattern('(p)erson$'), '\1eople');- yield new Transformation(new Pattern('(m)an$'), '\1en');- yield new Transformation(new Pattern('(c)hild$'), '\1hildren');- yield new Transformation(new Pattern('(f)oot$'), '\1eet');- yield new Transformation(new Pattern('(buffal|her|potat|tomat|volcan)o$'), '\1\2oes');- yield new Transformation(new Pattern('(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$'), '\1i');- yield new Transformation(new Pattern('us$'), 'uses');- yield new Transformation(new Pattern('(alias)$'), '\1es');- yield new Transformation(new Pattern('(analys|ax|cris|test|thes)is$'), '\1es');- yield new Transformation(new Pattern('s$'), 's');- yield new Transformation(new Pattern('^$'), '');- yield new Transformation(new Pattern('$'), 's');- }-- /** @return Substitution[] */- public static function getIrregular(): iterable- {- yield new Substitution(new Word('atlas'), new Word('atlases'));- yield new Substitution(new Word('axe'), new Word('axes'));- yield new Substitution(new Word('beef'), new Word('beefs'));- yield new Substitution(new Word('blouse'), new Word('blouses'));- yield new Substitution(new Word('brother'), new Word('brothers'));- yield new Substitution(new Word('cafe'), new Word('cafes'));- yield new Substitution(new Word('cave'), new Word('caves'));- yield new Substitution(new Word('chateau'), new Word('chateaux'));- yield new Substitution(new Word('niveau'), new Word('niveaux'));- yield new Substitution(new Word('child'), new Word('children'));- yield new Substitution(new Word('canvas'), new Word('canvases'));- yield new Substitution(new Word('cookie'), new Word('cookies'));- yield new Substitution(new Word('corpus'), new Word('corpuses'));- yield new Substitution(new Word('cow'), new Word('cows'));- yield new Substitution(new Word('criterion'), new Word('criteria'));- yield new Substitution(new Word('curriculum'), new Word('curricula'));- yield new Substitution(new Word('demo'), new Word('demos'));- yield new Substitution(new Word('domino'), new Word('dominoes'));- yield new Substitution(new Word('echo'), new Word('echoes'));- yield new Substitution(new Word('foot'), new Word('feet'));- yield new Substitution(new Word('fungus'), new Word('fungi'));- yield new Substitution(new Word('ganglion'), new Word('ganglions'));- yield new Substitution(new Word('gas'), new Word('gases'));- yield new Substitution(new Word('genie'), new Word('genies'));- yield new Substitution(new Word('genus'), new Word('genera'));- yield new Substitution(new Word('goose'), new Word('geese'));- yield new Substitution(new Word('graffito'), new Word('graffiti'));- yield new Substitution(new Word('hippopotamus'), new Word('hippopotami'));- yield new Substitution(new Word('hoof'), new Word('hoofs'));- yield new Substitution(new Word('human'), new Word('humans'));- yield new Substitution(new Word('iris'), new Word('irises'));- yield new Substitution(new Word('larva'), new Word('larvae'));- yield new Substitution(new Word('leaf'), new Word('leaves'));- yield new Substitution(new Word('lens'), new Word('lenses'));- yield new Substitution(new Word('loaf'), new Word('loaves'));- yield new Substitution(new Word('man'), new Word('men'));- yield new Substitution(new Word('medium'), new Word('media'));- yield new Substitution(new Word('memorandum'), new Word('memoranda'));- yield new Substitution(new Word('money'), new Word('monies'));- yield new Substitution(new Word('mongoose'), new Word('mongooses'));- yield new Substitution(new Word('motto'), new Word('mottoes'));- yield new Substitution(new Word('move'), new Word('moves'));- yield new Substitution(new Word('mythos'), new Word('mythoi'));- yield new Substitution(new Word('niche'), new Word('niches'));- yield new Substitution(new Word('nucleus'), new Word('nuclei'));- yield new Substitution(new Word('numen'), new Word('numina'));- yield new Substitution(new Word('occiput'), new Word('occiputs'));- yield new Substitution(new Word('octopus'), new Word('octopuses'));- yield new Substitution(new Word('opus'), new Word('opuses'));- yield new Substitution(new Word('ox'), new Word('oxen'));- yield new Substitution(new Word('passerby'), new Word('passersby'));- yield new Substitution(new Word('penis'), new Word('penises'));- yield new Substitution(new Word('person'), new Word('people'));- yield new Substitution(new Word('plateau'), new Word('plateaux'));- yield new Substitution(new Word('runner-up'), new Word('runners-up'));- yield new Substitution(new Word('safe'), new Word('safes'));- yield new Substitution(new Word('sex'), new Word('sexes'));- yield new Substitution(new Word('sieve'), new Word('sieves'));- yield new Substitution(new Word('soliloquy'), new Word('soliloquies'));- yield new Substitution(new Word('son-in-law'), new Word('sons-in-law'));- yield new Substitution(new Word('syllabus'), new Word('syllabi'));- yield new Substitution(new Word('testis'), new Word('testes'));- yield new Substitution(new Word('thief'), new Word('thieves'));- yield new Substitution(new Word('tooth'), new Word('teeth'));- yield new Substitution(new Word('tornado'), new Word('tornadoes'));- yield new Substitution(new Word('trilby'), new Word('trilbys'));- yield new Substitution(new Word('turf'), new Word('turfs'));- yield new Substitution(new Word('valve'), new Word('valves'));- yield new Substitution(new Word('volcano'), new Word('volcanoes'));- yield new Substitution(new Word('abuse'), new Word('abuses'));- yield new Substitution(new Word('avalanche'), new Word('avalanches'));- yield new Substitution(new Word('cache'), new Word('caches'));- yield new Substitution(new Word('criterion'), new Word('criteria'));- yield new Substitution(new Word('curve'), new Word('curves'));- yield new Substitution(new Word('emphasis'), new Word('emphases'));- yield new Substitution(new Word('foe'), new Word('foes'));- yield new Substitution(new Word('grave'), new Word('graves'));- yield new Substitution(new Word('hoax'), new Word('hoaxes'));- yield new Substitution(new Word('medium'), new Word('media'));- yield new Substitution(new Word('neurosis'), new Word('neuroses'));- yield new Substitution(new Word('save'), new Word('saves'));- yield new Substitution(new Word('wave'), new Word('waves'));- yield new Substitution(new Word('oasis'), new Word('oases'));- yield new Substitution(new Word('valve'), new Word('valves'));- yield new Substitution(new Word('zombie'), new Word('zombies'));- }-}
Vulnerability Existed: no
[No Vulnerability] - [N/A] - vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Inflectible.php [1-181]
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\English;
use Doctrine\Inflector\Rules\Pattern;
use Doctrine\Inflector\Rules\Substitution;
use Doctrine\Inflector\Rules\Transformation;
use Doctrine\Inflector\Rules\Word;
class Inflectible
{
// ... 181 lines of inflection rules for English language pluralization
}
```
Fixed Code:
```
File deleted
```
Explanation:
This diff represents the deletion of a vendor library file (Doctrine Inflector's Inflectible class). This is a refactoring/cleanup operation, not a security fix. The file contains only data-driven inflection rules for English language pluralization (singular/plural conversions, irregular word mappings). There are no security vulnerabilities present in the deleted code. The file contains no user input handling, no authentication logic, no cryptographic operations, or any other security-sensitive operations. Deleting vendor files is a normal part of dependency management and does not constitute a security fix.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/InflectorFactory.php+++ /dev/null@@ -1,21 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\English;--use Doctrine\Inflector\GenericLanguageInflectorFactory;-use Doctrine\Inflector\Rules\Ruleset;--final class InflectorFactory extends GenericLanguageInflectorFactory-{- protected function getSingularRuleset(): Ruleset- {- return Rules::getSingularRuleset();- }-- protected function getPluralRuleset(): Ruleset- {- return Rules::getPluralRuleset();- }-}
Vulnerability Existed: no No Vulnerability Identified - File Deletion Explanation: This diff shows the deletion of a vendor file (`vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/InflectorFactory.php`). The file being deleted contains a simple PHP class that extends `GenericLanguageInflectorFactory` and provides English language inflection rules. Deletion of vendor files does not introduce security vulnerabilities. In fact, removing unused or obsolete vendor dependencies can improve security posture by reducing the attack surface. The deleted code itself contains no security vulnerabilities - it's a straightforward factory implementation with no dangerous operations, unvalidated inputs, or insecure patterns. This appears to be a legitimate dependency cleanup or version update where this particular file is no longer needed.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Rules.php+++ /dev/null@@ -1,31 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\English;--use Doctrine\Inflector\Rules\Patterns;-use Doctrine\Inflector\Rules\Ruleset;-use Doctrine\Inflector\Rules\Substitutions;-use Doctrine\Inflector\Rules\Transformations;--final class Rules-{- public static function getSingularRuleset(): Ruleset- {- return new Ruleset(- new Transformations(...Inflectible::getSingular()),- new Patterns(...Uninflected::getSingular()),- (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()- );- }-- public static function getPluralRuleset(): Ruleset- {- return new Ruleset(- new Transformations(...Inflectible::getPlural()),- new Patterns(...Uninflected::getPlural()),- new Substitutions(...Inflectible::getIrregular())- );- }-}
Vulnerability Existed: no
No CWE - N/A - vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Rules.php (entire file deletion)
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\English;
use Doctrine\Inflector\Rules\Patterns;
use Doctrine\Inflector\Rules\Ruleset;
use Doctrine\Inflector\Rules\Substitutions;
use Doctrine\Inflector\Rules\Transformations;
final class Rules
{
public static function getSingularRuleset(): Ruleset
{
return new Ruleset(
new Transformations(...Inflectible::getSingular()),
new Patterns(...Uninflected::getSingular()),
(new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()
);
}
public static function getPluralRuleset(): Ruleset
{
return new Ruleset(
new Transformations(...Inflectible::getPlural()),
new Patterns(...Uninflected::getPlural()),
new Substitutions(...Inflectible::getIrregular())
);
}
}
```
Fixed Code:
(File deleted)
Explanation:
This diff shows the deletion of a vendor library file from the Doctrine Inflector package. File deletions from vendor directories are not security fixes but rather dependency management changes (likely version updates or removal of unused dependencies). The deleted code itself contains no security vulnerabilities - it's standard PHP code implementing inflection rules with proper type declarations and namespacing. The deletion does not fix any vulnerability; it simply removes a library file that is no longer needed or has been replaced by an updated version.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php+++ /dev/null@@ -1,189 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\English;--use Doctrine\Inflector\Rules\Pattern;--final class Uninflected-{- /** @return Pattern[] */- public static function getSingular(): iterable- {- yield from self::getDefault();-- yield new Pattern('.*ss');- yield new Pattern('clothes');- yield new Pattern('data');- yield new Pattern('fascia');- yield new Pattern('fuchsia');- yield new Pattern('galleria');- yield new Pattern('mafia');- yield new Pattern('militia');- yield new Pattern('pants');- yield new Pattern('petunia');- yield new Pattern('sepia');- yield new Pattern('trivia');- yield new Pattern('utopia');- }-- /** @return Pattern[] */- public static function getPlural(): iterable- {- yield from self::getDefault();-- yield new Pattern('people');- yield new Pattern('trivia');- yield new Pattern('\w+ware$');- yield new Pattern('media');- }-- /** @return Pattern[] */- private static function getDefault(): iterable- {- yield new Pattern('\w+media');- yield new Pattern('advice');- yield new Pattern('aircraft');- yield new Pattern('amoyese');- yield new Pattern('art');- yield new Pattern('audio');- yield new Pattern('baggage');- yield new Pattern('bison');- yield new Pattern('borghese');- yield new Pattern('bream');- yield new Pattern('breeches');- yield new Pattern('britches');- yield new Pattern('buffalo');- yield new Pattern('butter');- yield new Pattern('cantus');- yield new Pattern('carp');- yield new Pattern('cattle');- yield new Pattern('chassis');- yield new Pattern('clippers');- yield new Pattern('clothing');- yield new Pattern('coal');- yield new Pattern('cod');- yield new Pattern('coitus');- yield new Pattern('compensation');- yield new Pattern('congoese');- yield new Pattern('contretemps');- yield new Pattern('coreopsis');- yield new Pattern('corps');- yield new Pattern('cotton');- yield new Pattern('data');- yield new Pattern('debris');- yield new Pattern('deer');- yield new Pattern('diabetes');- yield new Pattern('djinn');- yield new Pattern('education');- yield new Pattern('eland');- yield new Pattern('elk');- yield new Pattern('emoji');- yield new Pattern('equipment');- yield new Pattern('evidence');- yield new Pattern('faroese');- yield new Pattern('feedback');- yield new Pattern('fish');- yield new Pattern('flounder');- yield new Pattern('flour');- yield new Pattern('foochowese');- yield new Pattern('food');- yield new Pattern('furniture');- yield new Pattern('gallows');- yield new Pattern('genevese');- yield new Pattern('genoese');- yield new Pattern('gilbertese');- yield new Pattern('gold');- yield new Pattern('headquarters');- yield new Pattern('herpes');- yield new Pattern('hijinks');- yield new Pattern('homework');- yield new Pattern('hottentotese');- yield new Pattern('impatience');- yield new Pattern('information');- yield new Pattern('innings');- yield new Pattern('jackanapes');- yield new Pattern('jeans');- yield new Pattern('jedi');- yield new Pattern('kin');- yield new Pattern('kiplingese');- yield new Pattern('knowledge');- yield new Pattern('kongoese');- yield new Pattern('leather');- yield new Pattern('love');- yield new Pattern('lucchese');- yield new Pattern('luggage');- yield new Pattern('mackerel');- yield new Pattern('Maltese');- yield new Pattern('management');- yield new Pattern('metadata');- yield new Pattern('mews');- yield new Pattern('money');- yield new Pattern('moose');- yield new Pattern('mumps');- yield new Pattern('music');- yield new Pattern('nankingese');- yield new Pattern('news');- yield new Pattern('nexus');- yield new Pattern('niasese');- yield new Pattern('nutrition');- yield new Pattern('offspring');- yield new Pattern('oil');- yield new Pattern('patience');- yield new Pattern('pekingese');- yield new Pattern('piedmontese');- yield new Pattern('pincers');- yield new Pattern('pistoiese');- yield new Pattern('plankton');- yield new Pattern('pliers');- yield new Pattern('pokemon');- yield new Pattern('police');- yield new Pattern('polish');- yield new Pattern('portuguese');- yield new Pattern('proceedings');- yield new Pattern('progress');- yield new Pattern('rabies');- yield new Pattern('rain');- yield new Pattern('research');- yield new Pattern('rhinoceros');- yield new Pattern('rice');- yield new Pattern('salmon');- yield new Pattern('sand');- yield new Pattern('sarawakese');- yield new Pattern('scissors');- yield new Pattern('sea[- ]bass');- yield new Pattern('series');- yield new Pattern('shavese');- yield new Pattern('shears');- yield new Pattern('sheep');- yield new Pattern('siemens');- yield new Pattern('silk');- yield new Pattern('sms');- yield new Pattern('soap');- yield new Pattern('social media');- yield new Pattern('spam');- yield new Pattern('species');- yield new Pattern('staff');- yield new Pattern('sugar');- yield new Pattern('swine');- yield new Pattern('talent');- yield new Pattern('toothpaste');- yield new Pattern('traffic');- yield new Pattern('travel');- yield new Pattern('trousers');- yield new Pattern('trout');- yield new Pattern('tuna');- yield new Pattern('us');- yield new Pattern('vermontese');- yield new Pattern('vinegar');- yield new Pattern('weather');- yield new Pattern('wenchowese');- yield new Pattern('wheat');- yield new Pattern('whiting');- yield new Pattern('wildebeest');- yield new Pattern('wood');- yield new Pattern('wool');- yield new Pattern('yengeese');- }-}
Vulnerability Existed: no This diff shows the deletion of a vendor file (`vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php`), which is a third-party dependency file containing English language inflection rules for the Doctrine Inflector library. **Analysis:** The removed code is a simple data structure class that defines patterns for English language singular/plural word forms. It contains no executable logic that could introduce security vulnerabilities—it only defines regex patterns used for linguistic transformations. Key observations: - The file contains only pattern definitions (word lists and regex patterns) - No user input handling, external API calls, or data processing logic - No database queries, file operations, or system calls - The patterns themselves (e.g., `'.*ss'`, `'\w+ware$'`) are standard regex that don't pose injection risks in this context - Deletion of vendor code typically indicates a dependency cleanup or version update, not a security fix **Conclusion:** There is no security vulnerability in this code. The deletion appears to be part of normal dependency management (removing unused or outdated vendor files), not a security remediation. No security issue existed in the original file that required fixing.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Inflectible.php+++ /dev/null@@ -1,44 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\French;--use Doctrine\Inflector\Rules\Pattern;-use Doctrine\Inflector\Rules\Substitution;-use Doctrine\Inflector\Rules\Transformation;-use Doctrine\Inflector\Rules\Word;--class Inflectible-{- /** @return Transformation[] */- public static function getSingular(): iterable- {- yield new Transformation(new Pattern('/(b|cor|ém|gemm|soupir|trav|vant|vitr)aux$/'), '\1ail');- yield new Transformation(new Pattern('/ails$/'), 'ail');- yield new Transformation(new Pattern('/(journ|chev)aux$/'), '\1al');- yield new Transformation(new Pattern('/(bijou|caillou|chou|genou|hibou|joujou|pou|au|eu|eau)x$/'), '\1');- yield new Transformation(new Pattern('/s$/'), '');- }-- /** @return Transformation[] */- public static function getPlural(): iterable- {- yield new Transformation(new Pattern('/(s|x|z)$/'), '\1');- yield new Transformation(new Pattern('/(b|cor|ém|gemm|soupir|trav|vant|vitr)ail$/'), '\1aux');- yield new Transformation(new Pattern('/ail$/'), 'ails');- yield new Transformation(new Pattern('/(chacal|carnaval|festival|récital)$/'), '\1s');- yield new Transformation(new Pattern('/al$/'), 'aux');- yield new Transformation(new Pattern('/(bleu|émeu|landau|pneu|sarrau)$/'), '\1s');- yield new Transformation(new Pattern('/(bijou|caillou|chou|genou|hibou|joujou|lieu|pou|au|eu|eau)$/'), '\1x');- yield new Transformation(new Pattern('/$/'), 's');- }-- /** @return Substitution[] */- public static function getIrregular(): iterable- {- yield new Substitution(new Word('monsieur'), new Word('messieurs'));- yield new Substitution(new Word('madame'), new Word('mesdames'));- yield new Substitution(new Word('mademoiselle'), new Word('mesdemoiselles'));- }-}
Vulnerability Existed: no
File Deletion - No Security Vulnerability - vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Inflectible.php (Lines 1-44)
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\French;
use Doctrine\Inflector\Rules\Pattern;
use Doctrine\Inflector\Rules\Substitution;
use Doctrine\Inflector\Rules\Transformation;
use Doctrine\Inflector\Rules\Word;
class Inflectible
{
/** @return Transformation[] */
public static function getSingular(): iterable
{
yield new Transformation(new Pattern('/(b|cor|ém|gemm|soupir|trav|vant|vitr)aux$/'), '\1ail');
yield new Transformation(new Pattern('/ails$/'), 'ail');
yield new Transformation(new Pattern('/(journ|chev)aux$/'), '\1al');
yield new Transformation(new Pattern('/(bijou|caillou|chou|genou|hibou|joujou|pou|au|eu|eau)x$/'), '\1');
yield new Transformation(new Pattern('/s$/'), '');
}
/** @return Transformation[] */
public static function getPlural(): iterable
{
yield new Transformation(new Pattern('/(s|x|z)$/'), '\1');
yield new Transformation(new Pattern('/(b|cor|ém|gemm|soupir|trav|vant|vitr)ail$/'), '\1aux');
yield new Transformation(new Pattern('/ail$/'), 'ails');
yield new Transformation(new Pattern('/(chacal|carnaval|festival|récital)$/'), '\1s');
yield new Transformation(new Pattern('/al$/'), 'aux');
yield new Transformation(new Pattern('/(bleu|émeu|landau|pneu|sarrau)$/'), '\1s');
yield new Transformation(new Pattern('/(bijou|caillou|chou|genou|hibou|joujou|lieu|pou|au|eu|eau)$/'), '\1x');
yield new Transformation(new Pattern('/$/'), 's');
}
/** @return Substitution[] */
public static function getIrregular(): iterable
{
yield new Substitution(new Word('monsieur'), new Word('messieurs'));
yield new Substitution(new Word('madame'), new Word('mesdames'));
yield new Substitution(new Word('mademoiselle'), new Word('mesdemoiselles'));
}
}
```
Fixed Code:
(File deleted)
Explanation:
This diff shows the deletion of a Doctrine Inflector vendor library file. The file contains only text transformation rules for French language pluralization/singularization and poses no security vulnerability. It contains no sensitive data, no executable code with security implications, and no secrets. The deletion appears to be a cleanup of unused vendor files, which is a safe operation. There are no security fixes or vulnerabilities addressed by this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/InflectorFactory.php+++ /dev/null@@ -1,21 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\French;--use Doctrine\Inflector\GenericLanguageInflectorFactory;-use Doctrine\Inflector\Rules\Ruleset;--final class InflectorFactory extends GenericLanguageInflectorFactory-{- protected function getSingularRuleset(): Ruleset- {- return Rules::getSingularRuleset();- }-- protected function getPluralRuleset(): Ruleset- {- return Rules::getPluralRuleset();- }-}
Vulnerability Existed: no No Vulnerability Identified - File Deletion Explanation: This diff shows the deletion of a vendor file (`vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/InflectorFactory.php`). The file contains a standard PHP class that extends `GenericLanguageInflectorFactory` and implements language-specific inflection rules for French. The deletion itself does not represent a security fix or indicate a security vulnerability. This appears to be: 1. A cleanup operation (removing unused or redundant code from the vendor directory) 2. A dependency update or version change 3. A legitimate refactoring of the Doctrine Inflector library The code being removed contains no security vulnerabilities such as injection flaws, authentication issues, cryptographic weaknesses, or other OWASP top 10 risks. It is simple utility code for linguistic string transformations. **Assessment:** No security-related changes present in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Rules.php+++ /dev/null@@ -1,31 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\French;--use Doctrine\Inflector\Rules\Patterns;-use Doctrine\Inflector\Rules\Ruleset;-use Doctrine\Inflector\Rules\Substitutions;-use Doctrine\Inflector\Rules\Transformations;--final class Rules-{- public static function getSingularRuleset(): Ruleset- {- return new Ruleset(- new Transformations(...Inflectible::getSingular()),- new Patterns(...Uninflected::getSingular()),- (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()- );- }-- public static function getPluralRuleset(): Ruleset- {- return new Ruleset(- new Transformations(...Inflectible::getPlural()),- new Patterns(...Uninflected::getPlural()),- new Substitutions(...Inflectible::getIrregular())- );- }-}
Vulnerability Existed: no No vulnerabilities detected - File Deletion Explanation: This diff shows the complete removal of a PHP file (`vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Rules.php`) from the codebase. The file contains only standard, non-vulnerable code - it's a rule set class for French language inflection in the Doctrine Inflector library. The deletion itself does not introduce, fix, or relate to any security vulnerabilities. This appears to be a dependency cleanup or refactoring operation, possibly removing unused or outdated vendor code. The original code had no security issues: - No user input handling - No file operations - No SQL or command execution - No cryptographic operations - Standard object-oriented PHP patterns **Assessment:** No security fix is present in this diff, as there was no vulnerability to fix in the deleted code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php+++ /dev/null@@ -1,28 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\French;--use Doctrine\Inflector\Rules\Pattern;--final class Uninflected-{- /** @return Pattern[] */- public static function getSingular(): iterable- {- yield from self::getDefault();- }-- /** @return Pattern[] */- public static function getPlural(): iterable- {- yield from self::getDefault();- }-- /** @return Pattern[] */- private static function getDefault(): iterable- {- yield new Pattern('');- }-}
Vulnerability Existed: no
File Deletion - No Security Vulnerability - vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php [Lines 1-28]
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\French;
use Doctrine\Inflector\Rules\Pattern;
final class Uninflected
{
/** @return Pattern[] */
public static function getSingular(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
public static function getPlural(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
private static function getDefault(): iterable
{
yield new Pattern('');
}
}
```
Fixed Code:
File deleted (removed entirely)
Explanation:
This diff shows the deletion of a vendor library file (`Doctrine/Inflector/Rules/French/Uninflected.php`). The file contains a legitimate utility class for French language inflection rules and poses no security vulnerabilities. The removal is likely part of a dependency update, cleanup, or refactoring process. Deleting unused vendor files is a normal maintenance operation and does not represent a security fix. There are no code injection risks, authentication/authorization issues, data exposure, or other OWASP vulnerabilities present in this file that would require fixing through deletion.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Inflectible.php+++ /dev/null@@ -1,34 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\NorwegianBokmal;--use Doctrine\Inflector\Rules\Pattern;-use Doctrine\Inflector\Rules\Substitution;-use Doctrine\Inflector\Rules\Transformation;-use Doctrine\Inflector\Rules\Word;--class Inflectible-{- /** @return Transformation[] */- public static function getSingular(): iterable- {- yield new Transformation(new Pattern('/re$/i'), 'r');- yield new Transformation(new Pattern('/er$/i'), '');- }-- /** @return Transformation[] */- public static function getPlural(): iterable- {- yield new Transformation(new Pattern('/e$/i'), 'er');- yield new Transformation(new Pattern('/r$/i'), 're');- yield new Transformation(new Pattern('/$/'), 'er');- }-- /** @return Substitution[] */- public static function getIrregular(): iterable- {- yield new Substitution(new Word('konto'), new Word('konti'));- }-}
Vulnerability Existed: no No Vulnerabilities Detected - File Deletion Explanation: This diff shows the deletion of a file (`Inflectible.php`) from the Doctrine Inflector library's Norwegian Bokmål rules directory. The file contained only language inflection rules with no security-sensitive code: - No user input handling - No database queries - No file operations - No authentication/authorization logic - No cryptographic operations - No external service calls - No template rendering with user data The file deletion itself is not a security fix but rather a dependency or vendor file cleanup. There are no vulnerabilities being addressed in this change, nor are any vulnerabilities introduced by removing this declarative configuration file.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/InflectorFactory.php+++ /dev/null@@ -1,21 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\NorwegianBokmal;--use Doctrine\Inflector\GenericLanguageInflectorFactory;-use Doctrine\Inflector\Rules\Ruleset;--final class InflectorFactory extends GenericLanguageInflectorFactory-{- protected function getSingularRuleset(): Ruleset- {- return Rules::getSingularRuleset();- }-- protected function getPluralRuleset(): Ruleset- {- return Rules::getPluralRuleset();- }-}
Vulnerability Existed: no No Security Vulnerability Detected - File Deletion Explanation: This diff shows the deletion of a vendor library file (Doctrine Inflector's Norwegian Bokmal InflectorFactory class). This is not a security fix but rather a dependency cleanup or version update. The file contains only harmless factory pattern implementation code for language inflection rules with no security-sensitive operations, credentials, or vulnerable code patterns. The deletion itself does not represent a security fix, as there are no vulnerabilities present in the deleted code. It appears to be a routine removal of unused or outdated vendor code during a dependency update or cleanup process.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Rules.php+++ /dev/null@@ -1,31 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\NorwegianBokmal;--use Doctrine\Inflector\Rules\Patterns;-use Doctrine\Inflector\Rules\Ruleset;-use Doctrine\Inflector\Rules\Substitutions;-use Doctrine\Inflector\Rules\Transformations;--final class Rules-{- public static function getSingularRuleset(): Ruleset- {- return new Ruleset(- new Transformations(...Inflectible::getSingular()),- new Patterns(...Uninflected::getSingular()),- (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()- );- }-- public static function getPluralRuleset(): Ruleset- {- return new Ruleset(- new Transformations(...Inflectible::getPlural()),- new Patterns(...Uninflected::getPlural()),- new Substitutions(...Inflectible::getIrregular())- );- }-}
Vulnerability Existed: no
File Deletion - No Security Vulnerability - vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Rules.php [Lines 1-31]
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\NorwegianBokmal;
use Doctrine\Inflector\Rules\Patterns;
use Doctrine\Inflector\Rules\Ruleset;
use Doctrine\Inflector\Rules\Substitutions;
use Doctrine\Inflector\Rules\Transformations;
final class Rules
{
public static function getSingularRuleset(): Ruleset
{
return new Ruleset(
new Transformations(...Inflectible::getSingular()),
new Patterns(...Uninflected::getSingular()),
(new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()
);
}
public static function getPluralRuleset(): Ruleset
{
return new Ruleset(
new Transformations(...Inflectible::getPlural()),
new Patterns(...Uninflected::getPlural()),
new Substitutions(...Inflectible::getIrregular())
);
}
}
```
Fixed Code:
File deleted (no code remains)
Explanation:
This diff shows the deletion of a vendor library file (Doctrine Inflector Rules for Norwegian Bokmål language). The file contains only class definitions with public static methods that create and return Ruleset objects for linguistic transformations. There are no security vulnerabilities present in this code:
1. No hardcoded credentials or secrets
2. No injection vulnerabilities
3. No authentication/authorization issues
4. No unsafe operations
The file deletion itself is not a security fix but rather a cleanup or dependency update. The removal of unused vendor code does not address any existing security vulnerability—it simply removes unnecessary code from the codebase.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php+++ /dev/null@@ -1,30 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\NorwegianBokmal;--use Doctrine\Inflector\Rules\Pattern;--final class Uninflected-{- /** @return Pattern[] */- public static function getSingular(): iterable- {- yield from self::getDefault();- }-- /** @return Pattern[] */- public static function getPlural(): iterable- {- yield from self::getDefault();- }-- /** @return Pattern[] */- private static function getDefault(): iterable- {- yield new Pattern('barn');- yield new Pattern('fjell');- yield new Pattern('hus');- }-}
Vulnerability Existed: no No Vulnerability Detected - File Deletion Explanation: This diff shows the deletion of a file from the vendor directory (`vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php`). The file contains only a simple utility class for Norwegian Bokmål word inflection rules with no security-sensitive operations. The deleted code: - Contains only static methods that yield Pattern objects - Has no user input handling - Has no file I/O operations - Has no database queries - Has no authentication/authorization logic - Has no cryptographic operations - Has no external service calls This appears to be a dependency cleanup or refactoring operation. Removing unused or outdated vendor code is a good practice and does not introduce or remove security vulnerabilities. The deletion itself is a neutral security event.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Pattern.php+++ /dev/null@@ -1,42 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules;--use function preg_match;--final class Pattern-{- /** @var string */- private $pattern;-- /** @var string */- private $regex;-- public function __construct(string $pattern)- {- $this->pattern = $pattern;-- if (isset($this->pattern[0]) && $this->pattern[0] === '/') {- $this->regex = $this->pattern;- } else {- $this->regex = '/' . $this->pattern . '/i';- }- }-- public function getPattern(): string- {- return $this->pattern;- }-- public function getRegex(): string- {- return $this->regex;- }-- public function matches(string $word): bool- {- return preg_match($this->getRegex(), $word) === 1;- }-}
Vulnerability Existed: no
**No Vulnerability** - Vendor File Deletion
File: vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Pattern.php
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules;
use function preg_match;
final class Pattern
{
/** @var string */
private $pattern;
/** @var string */
private $regex;
public function __construct(string $pattern)
{
$this->pattern = $pattern;
if (isset($this->pattern[0]) && $this->pattern[0] === '/') {
$this->regex = $this->pattern;
} else {
$this->regex = '/' . $this->pattern . '/i';
}
}
public function getPattern(): string
{
return $this->pattern;
}
public function getRegex(): string
{
return $this->regex;
}
public function matches(string $word): bool
{
return preg_match($this->getRegex(), $word) === 1;
}
}
```
Fixed Code:
```
[File deleted]
```
Explanation:
This diff shows the deletion of a vendor library file (Doctrine Inflector). The code itself contains no security vulnerabilities - it's a simple pattern matching utility class with proper regex escaping via the constructor logic. The deletion is a dependency management change, not a security fix. Vendor files are typically managed through package managers (Composer) and should not be directly committed or deleted in source control. This appears to be a cleanup operation rather than a security-related fix.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Patterns.php+++ /dev/null@@ -1,34 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules;--use function array_map;-use function implode;-use function preg_match;--class Patterns-{- /** @var Pattern[] */- private $patterns;-- /** @var string */- private $regex;-- public function __construct(Pattern ...$patterns)- {- $this->patterns = $patterns;-- $patterns = array_map(static function (Pattern $pattern): string {- return $pattern->getPattern();- }, $this->patterns);-- $this->regex = '/^(?:' . implode('|', $patterns) . ')$/i';- }-- public function matches(string $word): bool- {- return preg_match($this->regex, $word, $regs) === 1;- }-}
Vulnerability Existed: no
File Deletion - vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Patterns.php (Lines 1-34)
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules;
use function array_map;
use function implode;
use function preg_match;
class Patterns
{
/** @var Pattern[] */
private $patterns;
/** @var string */
private $regex;
public function __construct(Pattern ...$patterns)
{
$this->patterns = $patterns;
$patterns = array_map(static function (Pattern $pattern): string {
return $pattern->getPattern();
}, $this->patterns);
$this->regex = '/^(?:' . implode('|', $patterns) . ')$/i';
}
public function matches(string $word): bool
{
return preg_match($this->regex, $word, $regs) === 1;
}
}
```
Fixed Code:
(File deleted - no replacement)
Explanation:
This diff shows the deletion of a Doctrine Inflector library file. The code itself does not contain exploitable vulnerabilities. The `preg_match()` function is used safely here - the regex pattern is constructed from trusted Pattern objects within the application's control, not from user input. The file deletion appears to be a dependency cleanup or vendor update rather than a security fix. No vulnerability was present in the original code that required patching.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Inflectible.php+++ /dev/null@@ -1,98 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\Portuguese;--use Doctrine\Inflector\Rules\Pattern;-use Doctrine\Inflector\Rules\Substitution;-use Doctrine\Inflector\Rules\Transformation;-use Doctrine\Inflector\Rules\Word;--class Inflectible-{- /** @return Transformation[] */- public static function getSingular(): iterable- {- yield new Transformation(new Pattern('/^(g|)ases$/i'), '\1ás');- yield new Transformation(new Pattern('/(japon|escoc|ingl|dinamarqu|fregu|portugu)eses$/i'), '\1ês');- yield new Transformation(new Pattern('/(ae|ao|oe)s$/'), 'ao');- yield new Transformation(new Pattern('/(ãe|ão|õe)s$/'), 'ão');- yield new Transformation(new Pattern('/^(.*[^s]s)es$/i'), '\1');- yield new Transformation(new Pattern('/sses$/i'), 'sse');- yield new Transformation(new Pattern('/ns$/i'), 'm');- yield new Transformation(new Pattern('/(r|t|f|v)is$/i'), '\1il');- yield new Transformation(new Pattern('/uis$/i'), 'ul');- yield new Transformation(new Pattern('/ois$/i'), 'ol');- yield new Transformation(new Pattern('/eis$/i'), 'ei');- yield new Transformation(new Pattern('/éis$/i'), 'el');- yield new Transformation(new Pattern('/([^p])ais$/i'), '\1al');- yield new Transformation(new Pattern('/(r|z)es$/i'), '\1');- yield new Transformation(new Pattern('/^(á|gá)s$/i'), '\1s');- yield new Transformation(new Pattern('/([^ê])s$/i'), '\1');- }-- /** @return Transformation[] */- public static function getPlural(): iterable- {- yield new Transformation(new Pattern('/^(alem|c|p)ao$/i'), '\1aes');- yield new Transformation(new Pattern('/^(irm|m)ao$/i'), '\1aos');- yield new Transformation(new Pattern('/ao$/i'), 'oes');- yield new Transformation(new Pattern('/^(alem|c|p)ão$/i'), '\1ães');- yield new Transformation(new Pattern('/^(irm|m)ão$/i'), '\1ãos');- yield new Transformation(new Pattern('/ão$/i'), 'ões');- yield new Transformation(new Pattern('/^(|g)ás$/i'), '\1ases');- yield new Transformation(new Pattern('/^(japon|escoc|ingl|dinamarqu|fregu|portugu)ês$/i'), '\1eses');- yield new Transformation(new Pattern('/m$/i'), 'ns');- yield new Transformation(new Pattern('/([^aeou])il$/i'), '\1is');- yield new Transformation(new Pattern('/ul$/i'), 'uis');- yield new Transformation(new Pattern('/ol$/i'), 'ois');- yield new Transformation(new Pattern('/el$/i'), 'eis');- yield new Transformation(new Pattern('/al$/i'), 'ais');- yield new Transformation(new Pattern('/(z|r)$/i'), '\1es');- yield new Transformation(new Pattern('/(s)$/i'), '\1');- yield new Transformation(new Pattern('/$/'), 's');- }-- /** @return Substitution[] */- public static function getIrregular(): iterable- {- yield new Substitution(new Word('abdomen'), new Word('abdomens'));- yield new Substitution(new Word('alemão'), new Word('alemães'));- yield new Substitution(new Word('artesã'), new Word('artesãos'));- yield new Substitution(new Word('álcool'), new Word('álcoois'));- yield new Substitution(new Word('árvore'), new Word('árvores'));- yield new Substitution(new Word('bencão'), new Word('bencãos'));- yield new Substitution(new Word('cão'), new Word('cães'));- yield new Substitution(new Word('campus'), new Word('campi'));- yield new Substitution(new Word('cadáver'), new Word('cadáveres'));- yield new Substitution(new Word('capelão'), new Word('capelães'));- yield new Substitution(new Word('capitão'), new Word('capitães'));- yield new Substitution(new Word('chão'), new Word('chãos'));- yield new Substitution(new Word('charlatão'), new Word('charlatães'));- yield new Substitution(new Word('cidadão'), new Word('cidadãos'));- yield new Substitution(new Word('consul'), new Word('consules'));- yield new Substitution(new Word('cristão'), new Word('cristãos'));- yield new Substitution(new Word('difícil'), new Word('difíceis'));- yield new Substitution(new Word('email'), new Word('emails'));- yield new Substitution(new Word('escrivão'), new Word('escrivães'));- yield new Substitution(new Word('fóssil'), new Word('fósseis'));- yield new Substitution(new Word('gás'), new Word('gases'));- yield new Substitution(new Word('germens'), new Word('germen'));- yield new Substitution(new Word('grão'), new Word('grãos'));- yield new Substitution(new Word('hífen'), new Word('hífens'));- yield new Substitution(new Word('irmão'), new Word('irmãos'));- yield new Substitution(new Word('liquens'), new Word('liquen'));- yield new Substitution(new Word('mal'), new Word('males'));- yield new Substitution(new Word('mão'), new Word('mãos'));- yield new Substitution(new Word('orfão'), new Word('orfãos'));- yield new Substitution(new Word('país'), new Word('países'));- yield new Substitution(new Word('pai'), new Word('pais'));- yield new Substitution(new Word('pão'), new Word('pães'));- yield new Substitution(new Word('projétil'), new Word('projéteis'));- yield new Substitution(new Word('réptil'), new Word('répteis'));- yield new Substitution(new Word('sacristão'), new Word('sacristães'));- yield new Substitution(new Word('sotão'), new Word('sotãos'));- yield new Substitution(new Word('tabelião'), new Word('tabeliães'));- }-}
Vulnerability Existed: no No Security Vulnerability Detected - File Deletion File: vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Inflectible.php Explanation: This diff represents the deletion of a vendor library file (Doctrine Inflector Portuguese language rules). The file contains only linguistic transformation and substitution rules for Portuguese language pluralization and singularization. The code itself contains no security vulnerabilities: - No input validation issues (this is a static rule definition class) - No injection vectors (only contains hardcoded regex patterns and string mappings) - No authentication or authorization logic - No external data handling - No dynamic code execution - No sensitive data exposure The file deletion itself is not a security fix but rather a dependency or cleanup operation. This appears to be removing vendor code as part of a codebase update or dependency management change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/InflectorFactory.php+++ /dev/null@@ -1,21 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\Portuguese;--use Doctrine\Inflector\GenericLanguageInflectorFactory;-use Doctrine\Inflector\Rules\Ruleset;--final class InflectorFactory extends GenericLanguageInflectorFactory-{- protected function getSingularRuleset(): Ruleset- {- return Rules::getSingularRuleset();- }-- protected function getPluralRuleset(): Ruleset- {- return Rules::getPluralRuleset();- }-}
Vulnerability Existed: no
File Deletion - No Security Vulnerability - vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/InflectorFactory.php [All lines deleted]
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\Portuguese;
use Doctrine\Inflector\GenericLanguageInflectorFactory;
use Doctrine\Inflector\Rules\Ruleset;
final class InflectorFactory extends GenericLanguageInflectorFactory
{
protected function getSingularRuleset(): Ruleset
{
return Rules::getSingularRuleset();
}
protected function getPluralRuleset(): Ruleset
{
return Rules::getPluralRuleset();
}
}
```
Fixed Code:
[File deleted]
Explanation:
This diff shows the removal of a vendor library file (Doctrine Inflector Portuguese language rules). This is a file deletion from a third-party dependency, not a security fix. The removed code contains no security vulnerabilities—it's a simple factory class that returns language-specific inflection rules. The deletion appears to be part of dependency management or cleanup, not a security patch. No security vulnerability exists in this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Rules.php+++ /dev/null@@ -1,31 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\Portuguese;--use Doctrine\Inflector\Rules\Patterns;-use Doctrine\Inflector\Rules\Ruleset;-use Doctrine\Inflector\Rules\Substitutions;-use Doctrine\Inflector\Rules\Transformations;--final class Rules-{- public static function getSingularRuleset(): Ruleset- {- return new Ruleset(- new Transformations(...Inflectible::getSingular()),- new Patterns(...Uninflected::getSingular()),- (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()- );- }-- public static function getPluralRuleset(): Ruleset- {- return new Ruleset(- new Transformations(...Inflectible::getPlural()),- new Patterns(...Uninflected::getPlural()),- new Substitutions(...Inflectible::getIrregular())- );- }-}
Vulnerability Existed: no No Vulnerability Identified - File Deletion Explanation: This diff shows the deletion of a PHP file (Portuguese/Rules.php) from the Doctrine Inflector library. The file contained only a utility class with two static methods that return Ruleset objects for Portuguese language inflection rules. There are no security vulnerabilities in this code: 1. **No Input Validation Issues**: The methods don't accept user input; they only return pre-configured Ruleset objects. 2. **No Code Injection**: The code doesn't evaluate, execute, or process dynamic strings that could be exploited. 3. **No Authentication/Authorization Flaws**: No security mechanisms are implemented or bypassed. 4. **No Sensitive Data Exposure**: No credentials, secrets, or sensitive information is present. 5. **Safe Namespace Usage**: The code properly uses namespace declarations and imports. The deletion itself is a refactoring operation (likely removing unused Portuguese language support) and does not represent a security fix. This is a benign change with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Uninflected.php+++ /dev/null@@ -1,32 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\Portuguese;--use Doctrine\Inflector\Rules\Pattern;--final class Uninflected-{- /** @return Pattern[] */- public static function getSingular(): iterable- {- yield from self::getDefault();- }-- /** @return Pattern[] */- public static function getPlural(): iterable- {- yield from self::getDefault();- }-- /** @return Pattern[] */- private static function getDefault(): iterable- {- yield new Pattern('tórax');- yield new Pattern('tênis');- yield new Pattern('ônibus');- yield new Pattern('lápis');- yield new Pattern('fênix');- }-}
Vulnerability Existed: no No Vulnerabilities Detected - File Deletion Explanation: This diff shows the deletion of a Portuguese language inflection rules file from the Doctrine Inflector library. The file contains only data definitions (Pattern objects for Portuguese language words) with no executable code that could introduce security vulnerabilities. The removal of this file represents a cleanup or refactoring operation with no security implications. There are no input validation issues, injection vulnerabilities, authentication/authorization problems, or any other security concerns associated with deleting this static data file.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Ruleset.php+++ /dev/null@@ -1,39 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules;--class Ruleset-{- /** @var Transformations */- private $regular;-- /** @var Patterns */- private $uninflected;-- /** @var Substitutions */- private $irregular;-- public function __construct(Transformations $regular, Patterns $uninflected, Substitutions $irregular)- {- $this->regular = $regular;- $this->uninflected = $uninflected;- $this->irregular = $irregular;- }-- public function getRegular(): Transformations- {- return $this->regular;- }-- public function getUninflected(): Patterns- {- return $this->uninflected;- }-- public function getIrregular(): Substitutions- {- return $this->irregular;- }-}
Vulnerability Existed: no This diff shows the deletion of a file (`vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Ruleset.php`) from a vendor directory. The file is a simple data container class with no security vulnerabilities. **Analysis:** - **File Deletion**: The file is being removed entirely (indicated by `/dev/null` destination), not modified. - **Code Content**: The `Ruleset` class is a straightforward dependency injection container that stores and retrieves three immutable object references (`$regular`, `$uninflected`, `$irregular`). - **No Security Issues**: The code contains: - No user input handling - No database queries - No cryptographic operations - No file operations - No network calls - Proper encapsulation with private properties and getter methods - No injection vulnerabilities **Conclusion:** This is a vendor library file removal, likely as part of a dependency update or cleanup. There are no security vulnerabilities present in the deleted code, and the removal itself does not introduce or fix any security issues.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Inflectible.php+++ /dev/null@@ -1,47 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\Spanish;--use Doctrine\Inflector\Rules\Pattern;-use Doctrine\Inflector\Rules\Substitution;-use Doctrine\Inflector\Rules\Transformation;-use Doctrine\Inflector\Rules\Word;--class Inflectible-{- /** @return Transformation[] */- public static function getSingular(): iterable- {- yield new Transformation(new Pattern('/ereses$/'), 'erés');- yield new Transformation(new Pattern('/iones$/'), 'ión');- yield new Transformation(new Pattern('/ces$/'), 'z');- yield new Transformation(new Pattern('/es$/'), '');- yield new Transformation(new Pattern('/s$/'), '');- }-- /** @return Transformation[] */- public static function getPlural(): iterable- {- yield new Transformation(new Pattern('/ú([sn])$/i'), 'u\1es');- yield new Transformation(new Pattern('/ó([sn])$/i'), 'o\1es');- yield new Transformation(new Pattern('/í([sn])$/i'), 'i\1es');- yield new Transformation(new Pattern('/é([sn])$/i'), 'e\1es');- yield new Transformation(new Pattern('/á([sn])$/i'), 'a\1es');- yield new Transformation(new Pattern('/z$/i'), 'ces');- yield new Transformation(new Pattern('/([aeiou]s)$/i'), '\1');- yield new Transformation(new Pattern('/([^aeéiou])$/i'), '\1es');- yield new Transformation(new Pattern('/$/'), 's');- }-- /** @return Substitution[] */- public static function getIrregular(): iterable- {- yield new Substitution(new Word('el'), new Word('los'));- yield new Substitution(new Word('papá'), new Word('papás'));- yield new Substitution(new Word('mamá'), new Word('mamás'));- yield new Substitution(new Word('sofá'), new Word('sofás'));- yield new Substitution(new Word('mes'), new Word('meses'));- }-}
Vulnerability Existed: no
File Deletion - Not a Security Vulnerability - vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Inflectible.php [Lines 1-47]
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\Spanish;
use Doctrine\Inflector\Rules\Pattern;
use Doctrine\Inflector\Rules\Substitution;
use Doctrine\Inflector\Rules\Transformation;
use Doctrine\Inflector\Rules\Word;
class Inflectible
{
/** @return Transformation[] */
public static function getSingular(): iterable
{
yield new Transformation(new Pattern('/ereses$/'), 'erés');
yield new Transformation(new Pattern('/iones$/'), 'ión');
yield new Transformation(new Pattern('/ces$/'), 'z');
yield new Transformation(new Pattern('/es$/'), '');
yield new Transformation(new Pattern('/s$/'), '');
}
/** @return Transformation[] */
public static function getPlural(): iterable
{
yield new Transformation(new Pattern('/ú([sn])$/i'), 'u\1es');
yield new Transformation(new Pattern('/ó([sn])$/i'), 'o\1es');
yield new Transformation(new Pattern('/í([sn])$/i'), 'i\1es');
yield new Transformation(new Pattern('/é([sn])$/i'), 'e\1es');
yield new Transformation(new Pattern('/á([sn])$/i'), 'a\1es');
yield new Transformation(new Pattern('/z$/i'), 'ces');
yield new Transformation(new Pattern('/([aeiou]s)$/i'), '\1');
yield new Transformation(new Pattern('/([^aeéiou])$/i'), '\1es');
yield new Transformation(new Pattern('/$/'), 's');
}
/** @return Substitution[] */
public static function getIrregular(): iterable
{
yield new Substitution(new Word('el'), new Word('los'));
yield new Substitution(new Word('papá'), new Word('papás'));
yield new Substitution(new Word('mamá'), new Word('mamás'));
yield new Substitution(new Word('sofá'), new Word('sofás'));
yield new Substitution(new Word('mes'), new Word('meses'));
}
}
```
Fixed Code:
File deleted (content removed entirely)
Explanation:
This diff shows the deletion of a vendor library file (Doctrine Inflector Spanish language rules). This is a removal operation on third-party library code, not a security fix. The file contains linguistic transformation rules for Spanish word inflection and does not contain any security vulnerabilities. Deleting vendor files is typically part of dependency management or cleanup, not a security remediation. There are no security implications to analyze in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/InflectorFactory.php+++ /dev/null@@ -1,21 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\Spanish;--use Doctrine\Inflector\GenericLanguageInflectorFactory;-use Doctrine\Inflector\Rules\Ruleset;--final class InflectorFactory extends GenericLanguageInflectorFactory-{- protected function getSingularRuleset(): Ruleset- {- return Rules::getSingularRuleset();- }-- protected function getPluralRuleset(): Ruleset- {- return Rules::getPluralRuleset();- }-}
Vulnerability Existed: no Explanation: This diff shows the deletion of a vendor file (`vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/InflectorFactory.php`). The removed code is a simple factory class that extends `GenericLanguageInflectorFactory` and provides Spanish language inflection rules. **Analysis:** 1. **No Security Vulnerability**: The deleted code contains no security vulnerabilities. It is a standard factory pattern implementation for language-specific text inflection rules in the Doctrine Inflector library. 2. **File Deletion Context**: This appears to be a cleanup operation removing unused or redundant vendor files. Removing unused code is generally a security best practice as it: - Reduces the attack surface by eliminating unnecessary code - Decreases dependency bloat - Simplifies maintenance 3. **Content Safety**: The class itself performs no dangerous operations—it only returns rule objects for Spanish language text inflection processing. **Conclusion**: This is a file removal that does not represent a security fix for an existing vulnerability, but rather a code cleanup or dependency management change. No CWE applies here.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Rules.php+++ /dev/null@@ -1,31 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\Spanish;--use Doctrine\Inflector\Rules\Patterns;-use Doctrine\Inflector\Rules\Ruleset;-use Doctrine\Inflector\Rules\Substitutions;-use Doctrine\Inflector\Rules\Transformations;--final class Rules-{- public static function getSingularRuleset(): Ruleset- {- return new Ruleset(- new Transformations(...Inflectible::getSingular()),- new Patterns(...Uninflected::getSingular()),- (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()- );- }-- public static function getPluralRuleset(): Ruleset- {- return new Ruleset(- new Transformations(...Inflectible::getPlural()),- new Patterns(...Uninflected::getPlural()),- new Substitutions(...Inflectible::getIrregular())- );- }-}
I notice the provided diff shows a file deletion from a vendor directory (Doctrine Inflector library), not a code security fix. This is a legitimate removal of third-party code that does not itself contain security vulnerabilities being fixed. **Analysis:** Vulnerability Existed: **no** This diff represents a **file deletion**, not a security fix. The deleted file (`vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Rules.php`) is: 1. **Vendor code** - Part of the Doctrine Inflector third-party library 2. **Not modified** - No vulnerable code is being patched; the entire file is being removed 3. **No vulnerability present** - The file contains standard Spanish language inflection rules with no apparent security issues The removal itself could be due to: - Dependency cleanup/version updates - Removal of unused language rules - Refactoring of vendor dependencies **Conclusion:** There is no security vulnerability to analyze in this diff. It is a routine vendor directory modification (file deletion).
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Uninflected.php+++ /dev/null@@ -1,30 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\Spanish;--use Doctrine\Inflector\Rules\Pattern;--final class Uninflected-{- /** @return Pattern[] */- public static function getSingular(): iterable- {- yield from self::getDefault();- }-- /** @return Pattern[] */- public static function getPlural(): iterable- {- yield from self::getDefault();- }-- /** @return Pattern[] */- private static function getDefault(): iterable- {- yield new Pattern('lunes');- yield new Pattern('rompecabezas');- yield new Pattern('crisis');- }-}
Vulnerability Existed: no
No Vulnerability Detected - File Deletion
File: vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Uninflected.php
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\Spanish;
use Doctrine\Inflector\Rules\Pattern;
final class Uninflected
{
/** @return Pattern[] */
public static function getSingular(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
public static function getPlural(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
private static function getDefault(): iterable
{
yield new Pattern('lunes');
yield new Pattern('rompecabezas');
yield new Pattern('crisis');
}
}
```
Fixed Code:
[File deleted]
Explanation:
This diff represents the deletion of a vendor library file (Doctrine Inflector Spanish language rules). The file itself contains no security vulnerabilities—it is a simple data class that yields linguistic pattern objects. The deletion of this file does not fix any security issue; it appears to be a dependency cleanup or refactoring. No vulnerability was introduced or fixed by this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitution.php+++ /dev/null@@ -1,30 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules;--final class Substitution-{- /** @var Word */- private $from;-- /** @var Word */- private $to;-- public function __construct(Word $from, Word $to)- {- $this->from = $from;- $this->to = $to;- }-- public function getFrom(): Word- {- return $this->from;- }-- public function getTo(): Word- {- return $this->to;- }-}
Vulnerability Existed: no No Vulnerability Identified - File Deletion Explanation: This diff shows the deletion of a vendor file (`Substitution.php` from the Doctrine Inflector library). This is a file removal operation, not a code modification that introduces or fixes a vulnerability. The deleted code is a simple utility class that stores word substitution rules with getter methods. There are no security vulnerabilities in the code being removed, and removing vendor files does not constitute a security fix—it's merely a dependency management operation. No CWE or security issue is applicable to this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitutions.php+++ /dev/null@@ -1,57 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules;--use Doctrine\Inflector\WordInflector;--use function strtolower;-use function strtoupper;-use function substr;--class Substitutions implements WordInflector-{- /** @var Substitution[] */- private $substitutions;-- public function __construct(Substitution ...$substitutions)- {- foreach ($substitutions as $substitution) {- $this->substitutions[$substitution->getFrom()->getWord()] = $substitution;- }- }-- public function getFlippedSubstitutions(): Substitutions- {- $substitutions = [];-- foreach ($this->substitutions as $substitution) {- $substitutions[] = new Substitution(- $substitution->getTo(),- $substitution->getFrom()- );- }-- return new Substitutions(...$substitutions);- }-- public function inflect(string $word): string- {- $lowerWord = strtolower($word);-- if (isset($this->substitutions[$lowerWord])) {- $firstLetterUppercase = $lowerWord[0] !== $word[0];-- $toWord = $this->substitutions[$lowerWord]->getTo()->getWord();-- if ($firstLetterUppercase) {- return strtoupper($toWord[0]) . substr($toWord, 1);- }-- return $toWord;- }-- return $word;- }-}
Vulnerability Existed: no No Security Vulnerability Detected - File Deletion File: vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitutions.php Explanation: This diff represents the deletion of a file from the vendor directory (a third-party dependency). The file itself (`Substitutions.php`) contains no security vulnerabilities in its code. It is a standard PHP class implementing word inflection rules with proper type declarations and no unsafe operations. The deletion of this file is likely due to: 1. A dependency version update or removal 2. Refactoring of the Doctrine Inflector library 3. Cleanup of unused code Since this is a vendor file being removed entirely, there is no security fix being applied to vulnerable code. The file deletion does not represent a security patch for a vulnerability that existed in this particular file.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformation.php+++ /dev/null@@ -1,39 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules;--use Doctrine\Inflector\WordInflector;--use function preg_replace;--final class Transformation implements WordInflector-{- /** @var Pattern */- private $pattern;-- /** @var string */- private $replacement;-- public function __construct(Pattern $pattern, string $replacement)- {- $this->pattern = $pattern;- $this->replacement = $replacement;- }-- public function getPattern(): Pattern- {- return $this->pattern;- }-- public function getReplacement(): string- {- return $this->replacement;- }-- public function inflect(string $word): string- {- return (string) preg_replace($this->pattern->getRegex(), $this->replacement, $word);- }-}
Vulnerability Existed: no No Vulnerabilities Detected - File Deletion Explanation: This diff represents the deletion of the `Transformation.php` file from the vendor directory. The file itself does not contain security vulnerabilities. It is a legitimate class from the Doctrine Inflector library that implements a `WordInflector` interface for performing regex-based string transformations. The code uses `preg_replace()` with a pattern object that controls the regex, and a replacement string. There are no obvious injection vulnerabilities, hardcoded secrets, or unsafe operations. The parameters come from constructor injection, not from untrusted user input. The deletion of this file from the vendor directory appears to be part of a dependency cleanup or version update rather than a security fix for a vulnerability in this code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformations.php+++ /dev/null@@ -1,29 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules;--use Doctrine\Inflector\WordInflector;--class Transformations implements WordInflector-{- /** @var Transformation[] */- private $transformations;-- public function __construct(Transformation ...$transformations)- {- $this->transformations = $transformations;- }-- public function inflect(string $word): string- {- foreach ($this->transformations as $transformation) {- if ($transformation->getPattern()->matches($word)) {- return $transformation->inflect($word);- }- }-- return $word;- }-}
Vulnerability Existed: no
File Deletion - No Active Vulnerability - vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformations.php
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules;
use Doctrine\Inflector\WordInflector;
class Transformations implements WordInflector
{
/** @var Transformation[] */
private $transformations;
public function __construct(Transformation ...$transformations)
{
$this->transformations = $transformations;
}
public function inflect(string $word): string
{
foreach ($this->transformations as $transformation) {
if ($transformation->getPattern()->matches($word)) {
return $transformation->inflect($word);
}
}
return $word;
}
}
```
Fixed Code:
(File deleted)
Explanation:
This diff represents a file deletion rather than a code modification. The deleted file is a class from the Doctrine Inflector library that implements word transformation logic. There is no security vulnerability being fixed here—this is simply a removal of a file, likely as part of a dependency cleanup, version update, or refactoring of the vendor directory. The class itself contains no security vulnerabilities; it performs safe string pattern matching and word inflection operations with proper type declarations.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Inflectible.php+++ /dev/null@@ -1,34 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\Turkish;--use Doctrine\Inflector\Rules\Pattern;-use Doctrine\Inflector\Rules\Substitution;-use Doctrine\Inflector\Rules\Transformation;-use Doctrine\Inflector\Rules\Word;--class Inflectible-{- /** @return Transformation[] */- public static function getSingular(): iterable- {- yield new Transformation(new Pattern('/l[ae]r$/i'), '');- }-- /** @return Transformation[] */- public static function getPlural(): iterable- {- yield new Transformation(new Pattern('/([eöiü][^aoıueöiü]{0,6})$/u'), '\1ler');- yield new Transformation(new Pattern('/([aoıu][^aoıueöiü]{0,6})$/u'), '\1lar');- }-- /** @return Substitution[] */- public static function getIrregular(): iterable- {- yield new Substitution(new Word('ben'), new Word('biz'));- yield new Substitution(new Word('sen'), new Word('siz'));- yield new Substitution(new Word('o'), new Word('onlar'));- }-}
Vulnerability Existed: no
**File Deletion - No Security Vulnerability**
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\Turkish;
use Doctrine\Inflector\Rules\Pattern;
use Doctrine\Inflector\Rules\Substitution;
use Doctrine\Inflector\Rules\Transformation;
use Doctrine\Inflector\Rules\Word;
class Inflectible
{
/** @return Transformation[] */
public static function getSingular(): iterable
{
yield new Transformation(new Pattern('/l[ae]r$/i'), '');
}
/** @return Transformation[] */
public static function getPlural(): iterable
{
yield new Transformation(new Pattern('/([eöiü][^aoıueöiü]{0,6})$/u'), '\1ler');
yield new Transformation(new Pattern('/([aoıu][^aoıueöiü]{0,6})$/u'), '\1lar');
}
/** @return Substitution[] */
public static function getIrregular(): iterable
{
yield new Substitution(new Word('ben'), new Word('biz'));
yield new Substitution(new Word('sen'), new Word('siz'));
yield new Substitution(new Word('o'), new Word('onlar'));
}
}
```
Fixed Code:
```
[File deleted]
```
Explanation:
This diff shows the deletion of a vendor file (`vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Inflectible.php`). The removed code contains legitimate language inflection rules for Turkish text processing from the Doctrine Inflector library. There are no security vulnerabilities in the deleted code itself—it's a standard PHP class with pattern matching rules for Turkish word transformations. The deletion appears to be part of a dependency update or cleanup, not a security fix. No security issues were present that required remediation.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/InflectorFactory.php+++ /dev/null@@ -1,21 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\Turkish;--use Doctrine\Inflector\GenericLanguageInflectorFactory;-use Doctrine\Inflector\Rules\Ruleset;--final class InflectorFactory extends GenericLanguageInflectorFactory-{- protected function getSingularRuleset(): Ruleset- {- return Rules::getSingularRuleset();- }-- protected function getPluralRuleset(): Ruleset- {- return Rules::getPluralRuleset();- }-}
Vulnerability Existed: no
No Vulnerability - File Deletion
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\Turkish;
use Doctrine\Inflector\GenericLanguageInflectorFactory;
use Doctrine\Inflector\Rules\Ruleset;
final class InflectorFactory extends GenericLanguageInflectorFactory
{
protected function getSingularRuleset(): Ruleset
{
return Rules::getSingularRuleset();
}
protected function getPluralRuleset(): Ruleset
{
return Rules::getPluralRuleset();
}
}
```
Fixed Code:
[File deleted]
Explanation:
This diff shows the deletion of a vendor library file (Doctrine Inflector Turkish language ruleset factory). File deletions from vendor directories do not constitute security fixes—they are typically the result of dependency updates, cleanup, or version changes. The removed code itself contains no security vulnerabilities. There are no CWE-applicable issues with removing this legitimate, non-vulnerable code. This is a dependency management change, not a security fix.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Rules.php+++ /dev/null@@ -1,31 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\Turkish;--use Doctrine\Inflector\Rules\Patterns;-use Doctrine\Inflector\Rules\Ruleset;-use Doctrine\Inflector\Rules\Substitutions;-use Doctrine\Inflector\Rules\Transformations;--final class Rules-{- public static function getSingularRuleset(): Ruleset- {- return new Ruleset(- new Transformations(...Inflectible::getSingular()),- new Patterns(...Uninflected::getSingular()),- (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()- );- }-- public static function getPluralRuleset(): Ruleset- {- return new Ruleset(- new Transformations(...Inflectible::getPlural()),- new Patterns(...Uninflected::getPlural()),- new Substitutions(...Inflectible::getIrregular())- );- }-}
Vulnerability Existed: no Explanation: This diff shows the deletion of a PHP file (`vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Rules.php`) from a vendor directory. The file contains a utility class for Turkish language inflection rules with two static methods that return ruleset objects. Since this is a file deletion rather than a code modification, there are no security vulnerabilities being introduced or fixed. The file being removed is: 1. Part of the vendor/third-party dependency directory (Doctrine Inflector library) 2. A legitimate library class with no apparent security issues 3. Being completely removed, not modified with vulnerable code No CWE violations are present in this diff as no code modifications exist. File deletion from vendor dependencies is a normal operation and does not constitute a security vulnerability fix or introduction.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Uninflected.php+++ /dev/null@@ -1,30 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules\Turkish;--use Doctrine\Inflector\Rules\Pattern;--final class Uninflected-{- /** @return Pattern[] */- public static function getSingular(): iterable- {- yield from self::getDefault();- }-- /** @return Pattern[] */- public static function getPlural(): iterable- {- yield from self::getDefault();- }-- /** @return Pattern[] */- private static function getDefault(): iterable- {- yield new Pattern('lunes');- yield new Pattern('rompecabezas');- yield new Pattern('crisis');- }-}
Vulnerability Existed: no
File Deletion - No Security Vulnerability - vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Uninflected.php (Lines 1-30)
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\Turkish;
use Doctrine\Inflector\Rules\Pattern;
final class Uninflected
{
/** @return Pattern[] */
public static function getSingular(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
public static function getPlural(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
private static function getDefault(): iterable
{
yield new Pattern('lunes');
yield new Pattern('rompecabezas');
yield new Pattern('crisis');
}
}
```
Fixed Code:
(File deleted - no replacement code)
Explanation:
This diff shows the deletion of a vendor library file (`Doctrine\Inflector\Rules\Turkish\Uninflected.php`). The deleted code is a simple class that defines Turkish language inflection rules for plural/singular word patterns. There are no security vulnerabilities in this code:
1. The class is properly namespaced and typed with `declare(strict_types=1)`
2. No user input is processed or unsanitized
3. No database queries, file operations, or external system calls are made
4. The code simply yields hardcoded pattern objects
The file deletion itself is not a security fix but rather a dependency management action (likely removing unused or conflicting vendor code during a package update or cleanup). No security vulnerability existed in the deleted code, and no vulnerability fix is being applied.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Word.php+++ /dev/null@@ -1,21 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector\Rules;--class Word-{- /** @var string */- private $word;-- public function __construct(string $word)- {- $this->word = $word;- }-- public function getWord(): string- {- return $this->word;- }-}
Vulnerability Existed: no
No Vulnerability - File Deletion - vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Word.php (Lines 1-21)
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules;
class Word
{
/** @var string */
private $word;
public function __construct(string $word)
{
$this->word = $word;
}
public function getWord(): string
{
return $this->word;
}
}
```
Fixed Code:
```
[File deleted]
```
Explanation:
This diff shows the deletion of a vendor file (Doctrine Inflector library component). The `Word` class is a simple data container with no security vulnerabilities. It contains only a private property, constructor, and getter method with proper type hints. The removal of this file does not represent a security fix, but rather a dependency cleanup or version update. No vulnerability existed in this code, and the deletion itself does not address any security concern - it is simply a file that is no longer needed in the codebase.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php+++ /dev/null@@ -1,56 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector;--use Doctrine\Inflector\Rules\Ruleset;--use function array_merge;--/**- * Inflects based on multiple rulesets.- *- * Rules:- * - If the word matches any uninflected word pattern, it is not inflected- * - The first ruleset that returns a different value for an irregular word wins- * - The first ruleset that returns a different value for a regular word wins- * - If none of the above match, the word is left as-is- */-class RulesetInflector implements WordInflector-{- /** @var Ruleset[] */- private $rulesets;-- public function __construct(Ruleset $ruleset, Ruleset ...$rulesets)- {- $this->rulesets = array_merge([$ruleset], $rulesets);- }-- public function inflect(string $word): string- {- if ($word === '') {- return '';- }-- foreach ($this->rulesets as $ruleset) {- if ($ruleset->getUninflected()->matches($word)) {- return $word;- }-- $inflected = $ruleset->getIrregular()->inflect($word);-- if ($inflected !== $word) {- return $inflected;- }-- $inflected = $ruleset->getRegular()->inflect($word);-- if ($inflected !== $word) {- return $inflected;- }- }-- return $word;- }-}
Vulnerability Existed: no
No Security Vulnerability Detected - File Deletion
File: vendor/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector;
use Doctrine\Inflector\Rules\Ruleset;
use function array_merge;
/**
* Inflects based on multiple rulesets.
*
* Rules:
* - If the word matches any uninflected word pattern, it is not inflected
* - The first ruleset that returns a different value for an irregular word wins
* - The first ruleset that returns a different value for a regular word wins
* - If none of the above match, the word is left as-is
*/
class RulesetInflector implements WordInflector
{
/** @var Ruleset[] */
private $rulesets;
public function __construct(Ruleset $ruleset, Ruleset ...$rulesets)
{
$this->rulesets = array_merge([$ruleset], $rulesets);
}
public function inflect(string $word): string
{
if ($word === '') {
return '';
}
foreach ($this->rulesets as $ruleset) {
if ($ruleset->getUninflected()->matches($word)) {
return $word;
}
$inflected = $ruleset->getIrregular()->inflect($word);
if ($inflected !== $word) {
return $inflected;
}
$inflected = $ruleset->getRegular()->inflect($word);
if ($inflected !== $word) {
return $inflected;
}
}
return $word;
}
}
```
Fixed Code:
File deleted (removed from codebase)
Explanation:
This diff represents the deletion of a vendor library file (Doctrine Inflector's RulesetInflector class). The original code contains no security vulnerabilities. The class implements string inflection logic with proper type declarations (declare(strict_types=1)), type hints, and safe string comparisons. The deletion of this file is a dependency management change (likely due to updating or removing the Doctrine Inflector library), not a security fix. No vulnerabilities were remediated by this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php+++ /dev/null@@ -1,10 +0,0 @@-<?php--declare(strict_types=1);--namespace Doctrine\Inflector;--interface WordInflector-{- public function inflect(string $word): string;-}
Vulnerability Existed: no
No Security Vulnerability - File Deletion
Old Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector;
interface WordInflector
{
public function inflect(string $word): string;
}
```
Fixed Code:
File removed/deleted
Explanation:
This diff shows the deletion of a vendor library file (`vendor/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php`). The removed code is a simple interface definition with no security vulnerabilities. It declares a `WordInflector` interface with a single method `inflect()` that takes a string parameter and returns a string. There are no injection points, unsafe operations, or security-sensitive logic. The deletion itself does not represent a security fix—it appears to be a dependency cleanup or version update of the Doctrine Inflector library. No vulnerability is present in the deleted code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/CachedWordInflector.php@@ -0,0 +1,24 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector;++class CachedWordInflector implements WordInflector+{+ /** @var WordInflector */+ private $wordInflector;++ /** @var string[] */+ private $cache = [];++ public function __construct(WordInflector $wordInflector)+ {+ $this->wordInflector = $wordInflector;+ }++ public function inflect(string $word): string+ {+ return $this->cache[$word] ?? $this->cache[$word] = $this->wordInflector->inflect($word);+ }+}
``` Vulnerability Existed: no No Vulnerabilities Detected Explanation: This is a new file addition containing a simple caching wrapper class for word inflection. The code: 1. Implements a standard caching pattern with no external input processing 2. Contains no dynamic SQL queries, command execution, or unsafe operations 3. Uses type hints (string parameter and return type) for input/output safety 4. Has no file operations, deserialization, or network calls 5. Simply caches and delegates inflection operations to an injected WordInflector dependency 6. The cache is stored in memory as a private array with no persistence or serialization The implementation is straightforward and follows secure coding practices. No CWE vulnerabilities are present in this code. ```
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/GenericLanguageInflectorFactory.php@@ -0,0 +1,66 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector;++use Doctrine\Inflector\Rules\Ruleset;++use function array_unshift;++abstract class GenericLanguageInflectorFactory implements LanguageInflectorFactory+{+ /** @var Ruleset[] */+ private $singularRulesets = [];++ /** @var Ruleset[] */+ private $pluralRulesets = [];++ final public function __construct()+ {+ $this->singularRulesets[] = $this->getSingularRuleset();+ $this->pluralRulesets[] = $this->getPluralRuleset();+ }++ final public function build(): Inflector+ {+ return new Inflector(+ new CachedWordInflector(new RulesetInflector(+ ...$this->singularRulesets+ )),+ new CachedWordInflector(new RulesetInflector(+ ...$this->pluralRulesets+ ))+ );+ }++ final public function withSingularRules(?Ruleset $singularRules, bool $reset = false): LanguageInflectorFactory+ {+ if ($reset) {+ $this->singularRulesets = [];+ }++ if ($singularRules instanceof Ruleset) {+ array_unshift($this->singularRulesets, $singularRules);+ }++ return $this;+ }++ final public function withPluralRules(?Ruleset $pluralRules, bool $reset = false): LanguageInflectorFactory+ {+ if ($reset) {+ $this->pluralRulesets = [];+ }++ if ($pluralRules instanceof Ruleset) {+ array_unshift($this->pluralRulesets, $pluralRules);+ }++ return $this;+ }++ abstract protected function getSingularRuleset(): Ruleset;++ abstract protected function getPluralRuleset(): Ruleset;+}
Vulnerability Existed: no No Security Vulnerabilities Detected - GenericLanguageInflectorFactory.php Explanation: This is a new file containing a PHP class from the Doctrine Inflector library. The code implements a generic language inflector factory pattern with the following security characteristics: 1. **Type Safety**: The class uses strict type declarations (`declare(strict_types=1)`) and proper type hints for all parameters and return values, reducing type-confusion vulnerabilities. 2. **Access Control**: All public methods are declared `final`, preventing malicious subclass overrides. Private properties (`$singularRulesets`, `$pluralRulesets`) are properly encapsulated. 3. **Input Validation**: The `withSingularRules()` and `withPluralRules()` methods properly validate input with `instanceof Ruleset` checks before using the values, preventing injection of arbitrary objects. 4. **No User Input**: The class does not process any external user input, file operations, or dynamic code execution. 5. **No SQL/Command Injection**: No database queries or system commands are executed. 6. **Immutable Design Pattern**: The class uses a fluent interface that returns `$this`, allowing for safe method chaining without state corruption. 7. **Proper Array Handling**: Uses the built-in `array_unshift()` function correctly for array manipulation. This code follows secure coding practices and contains no identifiable security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Inflector.php@@ -0,0 +1,507 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector;++use RuntimeException;++use function chr;+use function function_exists;+use function lcfirst;+use function mb_strtolower;+use function ord;+use function preg_match;+use function preg_replace;+use function sprintf;+use function str_replace;+use function strlen;+use function strtolower;+use function strtr;+use function trim;+use function ucwords;++class Inflector+{+ private const ACCENTED_CHARACTERS = [+ 'À' => 'A',+ 'Á' => 'A',+ 'Â' => 'A',+ 'Ã' => 'A',+ 'Ä' => 'Ae',+ 'Æ' => 'Ae',+ 'Å' => 'Aa',+ 'æ' => 'a',+ 'Ç' => 'C',+ 'È' => 'E',+ 'É' => 'E',+ 'Ê' => 'E',+ 'Ë' => 'E',+ 'Ì' => 'I',+ 'Í' => 'I',+ 'Î' => 'I',+ 'Ï' => 'I',+ 'Ñ' => 'N',+ 'Ò' => 'O',+ 'Ó' => 'O',+ 'Ô' => 'O',+ 'Õ' => 'O',+ 'Ö' => 'Oe',+ 'Ù' => 'U',+ 'Ú' => 'U',+ 'Û' => 'U',+ 'Ü' => 'Ue',+ 'Ý' => 'Y',+ 'ß' => 'ss',+ 'à' => 'a',+ 'á' => 'a',+ 'â' => 'a',+ 'ã' => 'a',+ 'ä' => 'ae',+ 'å' => 'aa',+ 'ç' => 'c',+ 'è' => 'e',+ 'é' => 'e',+ 'ê' => 'e',+ 'ë' => 'e',+ 'ì' => 'i',+ 'í' => 'i',+ 'î' => 'i',+ 'ï' => 'i',+ 'ñ' => 'n',+ 'ò' => 'o',+ 'ó' => 'o',+ 'ô' => 'o',+ 'õ' => 'o',+ 'ö' => 'oe',+ 'ù' => 'u',+ 'ú' => 'u',+ 'û' => 'u',+ 'ü' => 'ue',+ 'ý' => 'y',+ 'ÿ' => 'y',+ 'Ā' => 'A',+ 'ā' => 'a',+ 'Ă' => 'A',+ 'ă' => 'a',+ 'Ą' => 'A',+ 'ą' => 'a',+ 'Ć' => 'C',+ 'ć' => 'c',+ 'Ĉ' => 'C',+ 'ĉ' => 'c',+ 'Ċ' => 'C',+ 'ċ' => 'c',+ 'Č' => 'C',+ 'č' => 'c',+ 'Ď' => 'D',+ 'ď' => 'd',+ 'Đ' => 'D',+ 'đ' => 'd',+ 'Ē' => 'E',+ 'ē' => 'e',+ 'Ĕ' => 'E',+ 'ĕ' => 'e',+ 'Ė' => 'E',+ 'ė' => 'e',+ 'Ę' => 'E',+ 'ę' => 'e',+ 'Ě' => 'E',+ 'ě' => 'e',+ 'Ĝ' => 'G',+ 'ĝ' => 'g',+ 'Ğ' => 'G',+ 'ğ' => 'g',+ 'Ġ' => 'G',+ 'ġ' => 'g',+ 'Ģ' => 'G',+ 'ģ' => 'g',+ 'Ĥ' => 'H',+ 'ĥ' => 'h',+ 'Ħ' => 'H',+ 'ħ' => 'h',+ 'Ĩ' => 'I',+ 'ĩ' => 'i',+ 'Ī' => 'I',+ 'ī' => 'i',+ 'Ĭ' => 'I',+ 'ĭ' => 'i',+ 'Į' => 'I',+ 'į' => 'i',+ 'İ' => 'I',+ 'ı' => 'i',+ 'IJ' => 'IJ',+ 'ij' => 'ij',+ 'Ĵ' => 'J',+ 'ĵ' => 'j',+ 'Ķ' => 'K',+ 'ķ' => 'k',+ 'ĸ' => 'k',+ 'Ĺ' => 'L',+ 'ĺ' => 'l',+ 'Ļ' => 'L',+ 'ļ' => 'l',+ 'Ľ' => 'L',+ 'ľ' => 'l',+ 'Ŀ' => 'L',+ 'ŀ' => 'l',+ 'Ł' => 'L',+ 'ł' => 'l',+ 'Ń' => 'N',+ 'ń' => 'n',+ 'Ņ' => 'N',+ 'ņ' => 'n',+ 'Ň' => 'N',+ 'ň' => 'n',+ 'ʼn' => 'N',+ 'Ŋ' => 'n',+ 'ŋ' => 'N',+ 'Ō' => 'O',+ 'ō' => 'o',+ 'Ŏ' => 'O',+ 'ŏ' => 'o',+ 'Ő' => 'O',+ 'ő' => 'o',+ 'Œ' => 'OE',+ 'œ' => 'oe',+ 'Ø' => 'O',+ 'ø' => 'o',+ 'Ŕ' => 'R',+ 'ŕ' => 'r',+ 'Ŗ' => 'R',+ 'ŗ' => 'r',+ 'Ř' => 'R',+ 'ř' => 'r',+ 'Ś' => 'S',+ 'ś' => 's',+ 'Ŝ' => 'S',+ 'ŝ' => 's',+ 'Ş' => 'S',+ 'ş' => 's',+ 'Š' => 'S',+ 'š' => 's',+ 'Ţ' => 'T',+ 'ţ' => 't',+ 'Ť' => 'T',+ 'ť' => 't',+ 'Ŧ' => 'T',+ 'ŧ' => 't',+ 'Ũ' => 'U',+ 'ũ' => 'u',+ 'Ū' => 'U',+ 'ū' => 'u',+ 'Ŭ' => 'U',+ 'ŭ' => 'u',+ 'Ů' => 'U',+ 'ů' => 'u',+ 'Ű' => 'U',+ 'ű' => 'u',+ 'Ų' => 'U',+ 'ų' => 'u',+ 'Ŵ' => 'W',+ 'ŵ' => 'w',+ 'Ŷ' => 'Y',+ 'ŷ' => 'y',+ 'Ÿ' => 'Y',+ 'Ź' => 'Z',+ 'ź' => 'z',+ 'Ż' => 'Z',+ 'ż' => 'z',+ 'Ž' => 'Z',+ 'ž' => 'z',+ 'ſ' => 's',+ '€' => 'E',+ '£' => '',+ ];++ /** @var WordInflector */+ private $singularizer;++ /** @var WordInflector */+ private $pluralizer;++ public function __construct(WordInflector $singularizer, WordInflector $pluralizer)+ {+ $this->singularizer = $singularizer;+ $this->pluralizer = $pluralizer;+ }++ /**+ * Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'.+ */+ public function tableize(string $word): string+ {+ $tableized = preg_replace('~(?<=\\w)([A-Z])~u', '_$1', $word);++ if ($tableized === null) {+ throw new RuntimeException(sprintf(+ 'preg_replace returned null for value "%s"',+ $word+ ));+ }++ return mb_strtolower($tableized);+ }++ /**+ * Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'.+ */+ public function classify(string $word): string+ {+ return str_replace([' ', '_', '-'], '', ucwords($word, ' _-'));+ }++ /**+ * Camelizes a word. This uses the classify() method and turns the first character to lowercase.+ */+ public function camelize(string $word): string+ {+ return lcfirst($this->classify($word));+ }++ /**+ * Uppercases words with configurable delimiters between words.+ *+ * Takes a string and capitalizes all of the words, like PHP's built-in+ * ucwords function. This extends that behavior, however, by allowing the+ * word delimiters to be configured, rather than only separating on+ * whitespace.+ *+ * Here is an example:+ * <code>+ * <?php+ * $string = 'top-o-the-morning to all_of_you!';+ * echo $inflector->capitalize($string);+ * // Top-O-The-Morning To All_of_you!+ *+ * echo $inflector->capitalize($string, '-_ ');+ * // Top-O-The-Morning To All_Of_You!+ * ?>+ * </code>+ *+ * @param string $string The string to operate on.+ * @param string $delimiters A list of word separators.+ *+ * @return string The string with all delimiter-separated words capitalized.+ */+ public function capitalize(string $string, string $delimiters = " \n\t\r\0\x0B-"): string+ {+ return ucwords($string, $delimiters);+ }++ /**+ * Checks if the given string seems like it has utf8 characters in it.+ *+ * @param string $string The string to check for utf8 characters in.+ */+ public function seemsUtf8(string $string): bool+ {+ for ($i = 0; $i < strlen($string); $i++) {+ if (ord($string[$i]) < 0x80) {+ continue; // 0bbbbbbb+ }++ if ((ord($string[$i]) & 0xE0) === 0xC0) {+ $n = 1; // 110bbbbb+ } elseif ((ord($string[$i]) & 0xF0) === 0xE0) {+ $n = 2; // 1110bbbb+ } elseif ((ord($string[$i]) & 0xF8) === 0xF0) {+ $n = 3; // 11110bbb+ } elseif ((ord($string[$i]) & 0xFC) === 0xF8) {+ $n = 4; // 111110bb+ } elseif ((ord($string[$i]) & 0xFE) === 0xFC) {+ $n = 5; // 1111110b+ } else {+ return false; // Does not match any model+ }++ for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?+ if (++$i === strlen($string) || ((ord($string[$i]) & 0xC0) !== 0x80)) {+ return false;+ }+ }+ }++ return true;+ }++ /**+ * Remove any illegal characters, accents, etc.+ *+ * @param string $string String to unaccent+ *+ * @return string Unaccented string+ */+ public function unaccent(string $string): string+ {+ if (preg_match('/[\x80-\xff]/', $string) === false) {+ return $string;+ }++ if ($this->seemsUtf8($string)) {+ $string = strtr($string, self::ACCENTED_CHARACTERS);+ } else {+ $characters = [];++ // Assume ISO-8859-1 if not UTF-8+ $characters['in'] =+ chr(128)+ . chr(131)+ . chr(138)+ . chr(142)+ . chr(154)+ . chr(158)+ . chr(159)+ . chr(162)+ . chr(165)+ . chr(181)+ . chr(192)+ . chr(193)+ . chr(194)+ . chr(195)+ . chr(196)+ . chr(197)+ . chr(199)+ . chr(200)+ . chr(201)+ . chr(202)+ . chr(203)+ . chr(204)+ . chr(205)+ . chr(206)+ . chr(207)+ . chr(209)+ . chr(210)+ . chr(211)+ . chr(212)+ . chr(213)+ . chr(214)+ . chr(216)+ . chr(217)+ . chr(218)+ . chr(219)+ . chr(220)+ . chr(221)+ . chr(224)+ . chr(225)+ . chr(226)+ . chr(227)+ . chr(228)+ . chr(229)+ . chr(231)+ . chr(232)+ . chr(233)+ . chr(234)+ . chr(235)+ . chr(236)+ . chr(237)+ . chr(238)+ . chr(239)+ . chr(241)+ . chr(242)+ . chr(243)+ . chr(244)+ . chr(245)+ . chr(246)+ . chr(248)+ . chr(249)+ . chr(250)+ . chr(251)+ . chr(252)+ . chr(253)+ . chr(255);++ $characters['out'] = 'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy';++ $string = strtr($string, $characters['in'], $characters['out']);++ $doubleChars = [];++ $doubleChars['in'] = [+ chr(140),+ chr(156),+ chr(198),+ chr(208),+ chr(222),+ chr(223),+ chr(230),+ chr(240),+ chr(254),+ ];++ $doubleChars['out'] = ['OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th'];++ $string = str_replace($doubleChars['in'], $doubleChars['out'], $string);+ }++ return $string;+ }++ /**+ * Convert any passed string to a url friendly string.+ * Converts 'My first blog post' to 'my-first-blog-post'+ *+ * @param string $string String to urlize.+ *+ * @return string Urlized string.+ */+ public function urlize(string $string): string+ {+ // Remove all non url friendly characters with the unaccent function+ $unaccented = $this->unaccent($string);++ if (function_exists('mb_strtolower')) {+ $lowered = mb_strtolower($unaccented);+ } else {+ $lowered = strtolower($unaccented);+ }++ $replacements = [+ '/\W/' => ' ',+ '/([A-Z]+)([A-Z][a-z])/' => '\1_\2',+ '/([a-z\d])([A-Z])/' => '\1_\2',+ '/[^A-Z^a-z^0-9^\/]+/' => '-',+ ];++ $urlized = $lowered;++ foreach ($replacements as $pattern => $replacement) {+ $replaced = preg_replace($pattern, $replacement, $urlized);++ if ($replaced === null) {+ throw new RuntimeException(sprintf(+ 'preg_replace returned null for value "%s"',+ $urlized+ ));+ }++ $urlized = $replaced;+ }++ return trim($urlized, '-');+ }++ /**+ * Returns a word in singular form.+ *+ * @param string $word The word in plural form.+ *+ * @return string The word in singular form.+ */+ public function singularize(string $word): string+ {+ return $this->singularizer->inflect($word);+ }++ /**+ * Returns a word in plural form.+ *+ * @param string $word The word in singular form.+ *+ * @return string The word in plural form.+ */+ public function pluralize(string $word): string+ {+ return $this->pluralizer->inflect($word);+ }+}
Vulnerability Existed: no No Vulnerabilities Identified - File: vendor/doctrine/inflector/src/Inflector.php Explanation: This is a newly added file (vendor dependency) containing a string inflection utility class. The code exhibits secure practices throughout: 1. **Input Validation**: The `preg_replace()` calls properly check for null returns (lines 225, 386-390), throwing RuntimeException if regex operations fail. 2. **No Injection Vectors**: The class operates solely on string transformations using built-in PHP functions (strtr, str_replace, ucwords, preg_replace) with hardcoded patterns and character mappings. There are no dynamic SQL queries, command execution, or unsafe deserialization. 3. **Safe String Operations**: Character encoding is handled safely using ord(), chr(), and mb_strtolower() for UTF-8 detection and conversion. 4. **Immutable Mapping**: The ACCENTED_CHARACTERS constant is a private, hardcoded mapping that cannot be modified at runtime. 5. **No External Dependencies**: The class only imports standard PHP functions, reducing attack surface. 6. **Proper Type Declarations**: Uses strict types declaration and proper type hints on all methods. This is a standard utility class with no security vulnerabilities present in the provided code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/InflectorFactory.php@@ -0,0 +1,60 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector;++use Doctrine\Inflector\Rules\English;+use Doctrine\Inflector\Rules\Esperanto;+use Doctrine\Inflector\Rules\French;+use Doctrine\Inflector\Rules\Italian;+use Doctrine\Inflector\Rules\NorwegianBokmal;+use Doctrine\Inflector\Rules\Portuguese;+use Doctrine\Inflector\Rules\Spanish;+use Doctrine\Inflector\Rules\Turkish;+use InvalidArgumentException;++use function sprintf;++final class InflectorFactory+{+ public static function create(): LanguageInflectorFactory+ {+ return self::createForLanguage(Language::ENGLISH);+ }++ public static function createForLanguage(string $language): LanguageInflectorFactory+ {+ switch ($language) {+ case Language::ENGLISH:+ return new English\InflectorFactory();++ case Language::ESPERANTO:+ return new Esperanto\InflectorFactory();++ case Language::FRENCH:+ return new French\InflectorFactory();++ case Language::ITALIAN:+ return new Italian\InflectorFactory();++ case Language::NORWEGIAN_BOKMAL:+ return new NorwegianBokmal\InflectorFactory();++ case Language::PORTUGUESE:+ return new Portuguese\InflectorFactory();++ case Language::SPANISH:+ return new Spanish\InflectorFactory();++ case Language::TURKISH:+ return new Turkish\InflectorFactory();++ default:+ throw new InvalidArgumentException(sprintf(+ 'Language "%s" is not supported.',+ $language+ ));+ }+ }+}
Vulnerability Existed: no No vulnerabilities identified - File Added Explanation: This is a new file addition containing a factory class for creating language-specific inflector instances. The code follows secure practices: 1. **Input Validation**: The `createForLanguage()` method uses a switch statement to validate the `$language` parameter against predefined Language constants, throwing an `InvalidArgumentException` for unsupported values. This prevents arbitrary code execution or unexpected behavior. 2. **No Dynamic Instantiation**: The factory uses explicit case statements rather than dynamic class instantiation (e.g., no `new $className()`), eliminating class injection vulnerabilities. 3. **Type Declarations**: The code uses strict type declarations (`declare(strict_types=1)`) and type hints, reducing type-related vulnerabilities. 4. **Controlled Factory Pattern**: The factory pattern is properly implemented with no external data influence on the instantiation logic. 5. **No Data Processing**: The code doesn't process, serialize, or deserialize untrusted data; it only instantiates predefined factory classes. The addition of this file introduces no new security vulnerabilities to the codebase.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Language.php@@ -0,0 +1,21 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector;++final class Language+{+ public const ENGLISH = 'english';+ public const ESPERANTO = 'esperanto';+ public const FRENCH = 'french';+ public const ITALIAN = 'italian';+ public const NORWEGIAN_BOKMAL = 'norwegian-bokmal';+ public const PORTUGUESE = 'portuguese';+ public const SPANISH = 'spanish';+ public const TURKISH = 'turkish';++ private function __construct()+ {+ }+}
Vulnerability Existed: no This is a new file addition (not a fix to existing code), so there are no security vulnerabilities being introduced or fixed. Explanation: The file `vendor/doctrine/inflector/src/Language.php` is a new addition that defines a simple language constants class. It contains: - A final class with private constructor preventing instantiation - Public const declarations for supported language codes - No code execution, user input handling, or security-sensitive operations This is a standard constant definition class with no security vulnerabilities. The private constructor is actually a security best practice to prevent instantiation of a utility class.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/LanguageInflectorFactory.php@@ -0,0 +1,33 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector;++use Doctrine\Inflector\Rules\Ruleset;++interface LanguageInflectorFactory+{+ /**+ * Applies custom rules for singularisation+ *+ * @param bool $reset If true, will unset default inflections for all new rules+ *+ * @return $this+ */+ public function withSingularRules(?Ruleset $singularRules, bool $reset = false): self;++ /**+ * Applies custom rules for pluralisation+ *+ * @param bool $reset If true, will unset default inflections for all new rules+ *+ * @return $this+ */+ public function withPluralRules(?Ruleset $pluralRules, bool $reset = false): self;++ /**+ * Builds the inflector instance with all applicable rules+ */+ public function build(): Inflector;+}
Vulnerability Existed: no This is a new file containing a PHP interface definition with no security vulnerabilities. **Analysis:** The file `LanguageInflectorFactory.php` is a newly created interface that defines three public methods: - `withSingularRules()` - accepts an optional Ruleset and a boolean flag - `withPluralRules()` - accepts an optional Ruleset and a boolean flag - `build()` - returns an Inflector instance **Security Assessment:** 1. **No Input Validation Issues** - This is an interface definition only, containing no implementation code that processes user input. 2. **No Code Injection Risks** - The interface does not handle strings, SQL, shell commands, or any data that could be exploited. 3. **No Authentication/Authorization Issues** - This is a factory interface with no security-sensitive operations. 4. **Type Safety** - The interface uses proper type hints (`?Ruleset`, `bool`, `Inflector`, `self`), which provides compile-time type checking. 5. **Proper Declaration** - Uses `declare(strict_types=1)` which enforces strict type checking in PHP. This is a well-formed interface definition from the Doctrine Inflector library with no security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/NoopWordInflector.php@@ -0,0 +1,13 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector;++class NoopWordInflector implements WordInflector+{+ public function inflect(string $word): string+ {+ return $word;+ }+}
Vulnerability Existed: no Analysis of the provided diff: **File:** vendor/doctrine/inflector/src/NoopWordInflector.php **Summary:** This is a new file addition (vendor dependency code) containing a simple NoopWordInflector class implementation. The code is a straightforward pass-through inflector that returns the input word unchanged. **Security Assessment:** 1. **No Input Validation Issues** - The method accepts a string parameter and returns it as-is. There is no processing that could introduce vulnerabilities. 2. **No Injection Vulnerabilities** - The code does not use the input in any dynamic context (SQL, commands, eval, etc.), so there are no SQL injection, command injection, or code injection risks. 3. **No Information Disclosure** - The method is simple and does not leak sensitive information. 4. **No Unsafe Operations** - No use of unsafe functions or risky operations. 5. **Proper Type Declarations** - The code uses strict types (`declare(strict_types=1)`) and proper type hints (`string`), which is a security best practice. 6. **Interface Compliance** - The class correctly implements the `WordInflector` interface as intended. This is vendor code (third-party library) implementing a legitimate noop pattern for word inflection, which is a common and safe design pattern. No security vulnerabilities are present in this code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/English/Inflectible.php@@ -0,0 +1,185 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\English;++use Doctrine\Inflector\Rules\Pattern;+use Doctrine\Inflector\Rules\Substitution;+use Doctrine\Inflector\Rules\Transformation;+use Doctrine\Inflector\Rules\Word;++class Inflectible+{+ /** @return Transformation[] */+ public static function getSingular(): iterable+ {+ yield new Transformation(new Pattern('(s)tatuses$'), '\1\2tatus');+ yield new Transformation(new Pattern('(s)tatus$'), '\1\2tatus');+ yield new Transformation(new Pattern('(c)ampus$'), '\1\2ampus');+ yield new Transformation(new Pattern('^(.*)(menu)s$'), '\1\2');+ yield new Transformation(new Pattern('(quiz)zes$'), '\\1');+ yield new Transformation(new Pattern('(matr)ices$'), '\1ix');+ yield new Transformation(new Pattern('(vert|ind)ices$'), '\1ex');+ yield new Transformation(new Pattern('^(ox)en'), '\1');+ yield new Transformation(new Pattern('(alias)(es)*$'), '\1');+ yield new Transformation(new Pattern('(buffal|her|potat|tomat|volcan)oes$'), '\1o');+ yield new Transformation(new Pattern('(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$'), '\1us');+ yield new Transformation(new Pattern('([ftw]ax)es'), '\1');+ yield new Transformation(new Pattern('(analys|ax|cris|test|thes)es$'), '\1is');+ yield new Transformation(new Pattern('(shoe|slave)s$'), '\1');+ yield new Transformation(new Pattern('(o)es$'), '\1');+ yield new Transformation(new Pattern('ouses$'), 'ouse');+ yield new Transformation(new Pattern('([^a])uses$'), '\1us');+ yield new Transformation(new Pattern('([m|l])ice$'), '\1ouse');+ yield new Transformation(new Pattern('(x|ch|ss|sh)es$'), '\1');+ yield new Transformation(new Pattern('(m)ovies$'), '\1\2ovie');+ yield new Transformation(new Pattern('(s)eries$'), '\1\2eries');+ yield new Transformation(new Pattern('([^aeiouy]|qu)ies$'), '\1y');+ yield new Transformation(new Pattern('([lr])ves$'), '\1f');+ yield new Transformation(new Pattern('(tive)s$'), '\1');+ yield new Transformation(new Pattern('(hive)s$'), '\1');+ yield new Transformation(new Pattern('(drive)s$'), '\1');+ yield new Transformation(new Pattern('(dive)s$'), '\1');+ yield new Transformation(new Pattern('(olive)s$'), '\1');+ yield new Transformation(new Pattern('([^fo])ves$'), '\1fe');+ yield new Transformation(new Pattern('(^analy)ses$'), '\1sis');+ yield new Transformation(new Pattern('(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$'), '\1\2sis');+ yield new Transformation(new Pattern('(tax)a$'), '\1on');+ yield new Transformation(new Pattern('(c)riteria$'), '\1riterion');+ yield new Transformation(new Pattern('([ti])a(?<!regatta)$'), '\1um');+ yield new Transformation(new Pattern('(p)eople$'), '\1\2erson');+ yield new Transformation(new Pattern('(m)en$'), '\1an');+ yield new Transformation(new Pattern('(c)hildren$'), '\1\2hild');+ yield new Transformation(new Pattern('(f)eet$'), '\1oot');+ yield new Transformation(new Pattern('(n)ews$'), '\1\2ews');+ yield new Transformation(new Pattern('eaus$'), 'eau');+ yield new Transformation(new Pattern('^tights$'), 'tights');+ yield new Transformation(new Pattern('^shorts$'), 'shorts');+ yield new Transformation(new Pattern('s$'), '');+ }++ /** @return Transformation[] */+ public static function getPlural(): iterable+ {+ yield new Transformation(new Pattern('(s)tatus$'), '\1\2tatuses');+ yield new Transformation(new Pattern('(quiz)$'), '\1zes');+ yield new Transformation(new Pattern('^(ox)$'), '\1\2en');+ yield new Transformation(new Pattern('([m|l])ouse$'), '\1ice');+ yield new Transformation(new Pattern('(matr|vert|ind)(ix|ex)$'), '\1ices');+ yield new Transformation(new Pattern('(x|ch|ss|sh)$'), '\1es');+ yield new Transformation(new Pattern('([^aeiouy]|qu)y$'), '\1ies');+ yield new Transformation(new Pattern('(hive|gulf)$'), '\1s');+ yield new Transformation(new Pattern('(?:([^f])fe|([lr])f)$'), '\1\2ves');+ yield new Transformation(new Pattern('sis$'), 'ses');+ yield new Transformation(new Pattern('([ti])um$'), '\1a');+ yield new Transformation(new Pattern('(tax)on$'), '\1a');+ yield new Transformation(new Pattern('(c)riterion$'), '\1riteria');+ yield new Transformation(new Pattern('(p)erson$'), '\1eople');+ yield new Transformation(new Pattern('(m)an$'), '\1en');+ yield new Transformation(new Pattern('(c)hild$'), '\1hildren');+ yield new Transformation(new Pattern('(f)oot$'), '\1eet');+ yield new Transformation(new Pattern('(buffal|her|potat|tomat|volcan)o$'), '\1\2oes');+ yield new Transformation(new Pattern('(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$'), '\1i');+ yield new Transformation(new Pattern('us$'), 'uses');+ yield new Transformation(new Pattern('(alias)$'), '\1es');+ yield new Transformation(new Pattern('(analys|ax|cris|test|thes)is$'), '\1es');+ yield new Transformation(new Pattern('s$'), 's');+ yield new Transformation(new Pattern('^$'), '');+ yield new Transformation(new Pattern('$'), 's');+ }++ /** @return Substitution[] */+ public static function getIrregular(): iterable+ {+ yield new Substitution(new Word('abuse'), new Word('abuses'));+ yield new Substitution(new Word('alga'), new Word('algae'));+ yield new Substitution(new Word('atlas'), new Word('atlases'));+ yield new Substitution(new Word('avalanche'), new Word('avalanches'));+ yield new Substitution(new Word('axis'), new Word('axes'));+ yield new Substitution(new Word('axe'), new Word('axes'));+ yield new Substitution(new Word('beef'), new Word('beefs'));+ yield new Substitution(new Word('blouse'), new Word('blouses'));+ yield new Substitution(new Word('brother'), new Word('brothers'));+ yield new Substitution(new Word('brownie'), new Word('brownies'));+ yield new Substitution(new Word('cache'), new Word('caches'));+ yield new Substitution(new Word('cafe'), new Word('cafes'));+ yield new Substitution(new Word('canvas'), new Word('canvases'));+ yield new Substitution(new Word('cave'), new Word('caves'));+ yield new Substitution(new Word('chateau'), new Word('chateaux'));+ yield new Substitution(new Word('child'), new Word('children'));+ yield new Substitution(new Word('cookie'), new Word('cookies'));+ yield new Substitution(new Word('corpus'), new Word('corpuses'));+ yield new Substitution(new Word('cow'), new Word('cows'));+ yield new Substitution(new Word('criterion'), new Word('criteria'));+ yield new Substitution(new Word('curriculum'), new Word('curricula'));+ yield new Substitution(new Word('curve'), new Word('curves'));+ yield new Substitution(new Word('demo'), new Word('demos'));+ yield new Substitution(new Word('die'), new Word('dice'));+ yield new Substitution(new Word('domino'), new Word('dominoes'));+ yield new Substitution(new Word('echo'), new Word('echoes'));+ yield new Substitution(new Word('emphasis'), new Word('emphases'));+ yield new Substitution(new Word('epoch'), new Word('epochs'));+ yield new Substitution(new Word('foe'), new Word('foes'));+ yield new Substitution(new Word('foot'), new Word('feet'));+ yield new Substitution(new Word('fungus'), new Word('fungi'));+ yield new Substitution(new Word('ganglion'), new Word('ganglions'));+ yield new Substitution(new Word('gas'), new Word('gases'));+ yield new Substitution(new Word('genie'), new Word('genies'));+ yield new Substitution(new Word('genus'), new Word('genera'));+ yield new Substitution(new Word('goose'), new Word('geese'));+ yield new Substitution(new Word('graffito'), new Word('graffiti'));+ yield new Substitution(new Word('grave'), new Word('graves'));+ yield new Substitution(new Word('hippopotamus'), new Word('hippopotami'));+ yield new Substitution(new Word('hoax'), new Word('hoaxes'));+ yield new Substitution(new Word('hoof'), new Word('hoofs'));+ yield new Substitution(new Word('human'), new Word('humans'));+ yield new Substitution(new Word('iris'), new Word('irises'));+ yield new Substitution(new Word('larva'), new Word('larvae'));+ yield new Substitution(new Word('leaf'), new Word('leaves'));+ yield new Substitution(new Word('lens'), new Word('lenses'));+ yield new Substitution(new Word('loaf'), new Word('loaves'));+ yield new Substitution(new Word('man'), new Word('men'));+ yield new Substitution(new Word('medium'), new Word('media'));+ yield new Substitution(new Word('memorandum'), new Word('memoranda'));+ yield new Substitution(new Word('money'), new Word('monies'));+ yield new Substitution(new Word('mongoose'), new Word('mongooses'));+ yield new Substitution(new Word('motto'), new Word('mottoes'));+ yield new Substitution(new Word('move'), new Word('moves'));+ yield new Substitution(new Word('mythos'), new Word('mythoi'));+ yield new Substitution(new Word('neurosis'), new Word('neuroses'));+ yield new Substitution(new Word('niche'), new Word('niches'));+ yield new Substitution(new Word('niveau'), new Word('niveaux'));+ yield new Substitution(new Word('nucleus'), new Word('nuclei'));+ yield new Substitution(new Word('numen'), new Word('numina'));+ yield new Substitution(new Word('nursery'), new Word('nurseries'));+ yield new Substitution(new Word('oasis'), new Word('oases'));+ yield new Substitution(new Word('occiput'), new Word('occiputs'));+ yield new Substitution(new Word('octopus'), new Word('octopuses'));+ yield new Substitution(new Word('opus'), new Word('opuses'));+ yield new Substitution(new Word('ox'), new Word('oxen'));+ yield new Substitution(new Word('passerby'), new Word('passersby'));+ yield new Substitution(new Word('penis'), new Word('penises'));+ yield new Substitution(new Word('person'), new Word('people'));+ yield new Substitution(new Word('plateau'), new Word('plateaux'));+ yield new Substitution(new Word('runner-up'), new Word('runners-up'));+ yield new Substitution(new Word('safe'), new Word('safes'));+ yield new Substitution(new Word('save'), new Word('saves'));+ yield new Substitution(new Word('sex'), new Word('sexes'));+ yield new Substitution(new Word('sieve'), new Word('sieves'));+ yield new Substitution(new Word('soliloquy'), new Word('soliloquies'));+ yield new Substitution(new Word('son-in-law'), new Word('sons-in-law'));+ yield new Substitution(new Word('stadium'), new Word('stadiums'));+ yield new Substitution(new Word('syllabus'), new Word('syllabi'));+ yield new Substitution(new Word('testis'), new Word('testes'));+ yield new Substitution(new Word('thief'), new Word('thieves'));+ yield new Substitution(new Word('tooth'), new Word('teeth'));+ yield new Substitution(new Word('tornado'), new Word('tornadoes'));+ yield new Substitution(new Word('trilby'), new Word('trilbys'));+ yield new Substitution(new Word('turf'), new Word('turfs'));+ yield new Substitution(new Word('valve'), new Word('valves'));+ yield new Substitution(new Word('volcano'), new Word('volcanoes'));+ yield new Substitution(new Word('wave'), new Word('waves'));+ yield new Substitution(new Word('zombie'), new Word('zombies'));+ }+}
Vulnerability Existed: no No vulnerabilities detected - File is a new addition Explanation: This is a new file addition containing the Doctrine Inflector library's English language inflection rules. The file defines three static methods that return iterables of transformation and substitution rules for converting English words between singular and plural forms. Analysis: - **No input validation concerns**: This is a library configuration file with hardcoded regex patterns and word mappings. There is no user input processing. - **No code execution risks**: The file only instantiates Pattern, Transformation, Substitution, and Word objects with static string values. No dynamic code execution or eval-like operations. - **No injection vulnerabilities**: The regex patterns are defined as string literals and used within the Pattern class constructor. Without seeing the Pattern implementation, standard regex usage would not introduce injection risks. - **No data exposure**: The file contains only public static methods returning linguistic transformation rules - no sensitive data handling. - **No authentication/authorization issues**: This is a utility library file with no authentication logic. This appears to be a legitimate vendor library file (Doctrine Inflector) with standard inflection rule definitions. No security vulnerabilities are present in the added code itself.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/English/InflectorFactory.php@@ -0,0 +1,21 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\English;++use Doctrine\Inflector\GenericLanguageInflectorFactory;+use Doctrine\Inflector\Rules\Ruleset;++final class InflectorFactory extends GenericLanguageInflectorFactory+{+ protected function getSingularRuleset(): Ruleset+ {+ return Rules::getSingularRuleset();+ }++ protected function getPluralRuleset(): Ruleset+ {+ return Rules::getPluralRuleset();+ }+}
Vulnerability Existed: no
No Vulnerabilities Detected - [N/A] - vendor/doctrine/inflector/src/Rules/English/InflectorFactory.php [1-21]
Old Code:
[File did not exist - this is a new file addition]
Fixed Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\English;
use Doctrine\Inflector\GenericLanguageInflectorFactory;
use Doctrine\Inflector\Rules\Ruleset;
final class InflectorFactory extends GenericLanguageInflectorFactory
{
protected function getSingularRuleset(): Ruleset
{
return Rules::getSingularRuleset();
}
protected function getPluralRuleset(): Ruleset
{
return Rules::getPluralRuleset();
}
}
```
Explanation:
This is a new file addition containing a legitimate PHP class from the Doctrine Inflector library. The code is a factory class that extends `GenericLanguageInflectorFactory` and implements two protected methods to retrieve singular and plural rulesets. There are no security vulnerabilities present:
- No user input is processed
- No external data sources are accessed
- No SQL queries or command execution
- No file operations with unsanitized paths
- No authentication/authorization logic with flaws
- Proper use of namespaces and type hints
- Standard factory pattern implementation
This is a library component that poses no security risk.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/English/Rules.php@@ -0,0 +1,31 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\English;++use Doctrine\Inflector\Rules\Patterns;+use Doctrine\Inflector\Rules\Ruleset;+use Doctrine\Inflector\Rules\Substitutions;+use Doctrine\Inflector\Rules\Transformations;++final class Rules+{+ public static function getSingularRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getSingular()),+ new Patterns(...Uninflected::getSingular()),+ (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()+ );+ }++ public static function getPluralRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getPlural()),+ new Patterns(...Uninflected::getPlural()),+ new Substitutions(...Inflectible::getIrregular())+ );+ }+}
Vulnerability Existed: no Explanation: This is a new file being added to the codebase (vendor/doctrine/inflector/src/Rules/English/Rules.php), containing a simple PHP class that provides English language inflection rules. The code is a straightforward utility class with two public static methods that return Ruleset objects. There are no security vulnerabilities present: 1. **No Input Validation Issues**: The class doesn't accept any user input - it only instantiates and returns predefined rule objects. 2. **No Code Injection**: There's no dynamic code execution, eval(), or similar dangerous functions. 3. **No SQL Injection**: No database queries or SQL operations. 4. **No XSS Risks**: No user data being output or echoed. 5. **No Access Control Issues**: Standard class structure with appropriate public/static modifiers for utility methods. 6. **No Dependency Concerns**: Dependencies are properly imported via use statements and instantiated safely. This is a legitimate library file (Doctrine Inflector) that provides text transformation utilities for language inflection and poses no security risks.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/English/Uninflected.php@@ -0,0 +1,189 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\English;++use Doctrine\Inflector\Rules\Pattern;++final class Uninflected+{+ /** @return Pattern[] */+ public static function getSingular(): iterable+ {+ yield from self::getDefault();++ yield new Pattern('.*ss');+ yield new Pattern('clothes');+ yield new Pattern('data');+ yield new Pattern('fascia');+ yield new Pattern('fuchsia');+ yield new Pattern('galleria');+ yield new Pattern('mafia');+ yield new Pattern('militia');+ yield new Pattern('pants');+ yield new Pattern('petunia');+ yield new Pattern('sepia');+ yield new Pattern('trivia');+ yield new Pattern('utopia');+ }++ /** @return Pattern[] */+ public static function getPlural(): iterable+ {+ yield from self::getDefault();++ yield new Pattern('people');+ yield new Pattern('trivia');+ yield new Pattern('\w+ware$');+ yield new Pattern('media');+ }++ /** @return Pattern[] */+ private static function getDefault(): iterable+ {+ yield new Pattern('\w+media');+ yield new Pattern('advice');+ yield new Pattern('aircraft');+ yield new Pattern('amoyese');+ yield new Pattern('art');+ yield new Pattern('audio');+ yield new Pattern('baggage');+ yield new Pattern('bison');+ yield new Pattern('borghese');+ yield new Pattern('bream');+ yield new Pattern('breeches');+ yield new Pattern('britches');+ yield new Pattern('buffalo');+ yield new Pattern('butter');+ yield new Pattern('cantus');+ yield new Pattern('carp');+ yield new Pattern('cattle');+ yield new Pattern('chassis');+ yield new Pattern('clippers');+ yield new Pattern('clothing');+ yield new Pattern('coal');+ yield new Pattern('cod');+ yield new Pattern('coitus');+ yield new Pattern('compensation');+ yield new Pattern('congoese');+ yield new Pattern('contretemps');+ yield new Pattern('coreopsis');+ yield new Pattern('corps');+ yield new Pattern('cotton');+ yield new Pattern('data');+ yield new Pattern('debris');+ yield new Pattern('deer');+ yield new Pattern('diabetes');+ yield new Pattern('djinn');+ yield new Pattern('education');+ yield new Pattern('eland');+ yield new Pattern('elk');+ yield new Pattern('emoji');+ yield new Pattern('equipment');+ yield new Pattern('evidence');+ yield new Pattern('faroese');+ yield new Pattern('feedback');+ yield new Pattern('fish');+ yield new Pattern('flounder');+ yield new Pattern('flour');+ yield new Pattern('foochowese');+ yield new Pattern('food');+ yield new Pattern('furniture');+ yield new Pattern('gallows');+ yield new Pattern('genevese');+ yield new Pattern('genoese');+ yield new Pattern('gilbertese');+ yield new Pattern('gold');+ yield new Pattern('headquarters');+ yield new Pattern('herpes');+ yield new Pattern('hijinks');+ yield new Pattern('homework');+ yield new Pattern('hottentotese');+ yield new Pattern('impatience');+ yield new Pattern('information');+ yield new Pattern('innings');+ yield new Pattern('jackanapes');+ yield new Pattern('jeans');+ yield new Pattern('jedi');+ yield new Pattern('kin');+ yield new Pattern('kiplingese');+ yield new Pattern('knowledge');+ yield new Pattern('kongoese');+ yield new Pattern('leather');+ yield new Pattern('love');+ yield new Pattern('lucchese');+ yield new Pattern('luggage');+ yield new Pattern('mackerel');+ yield new Pattern('Maltese');+ yield new Pattern('management');+ yield new Pattern('metadata');+ yield new Pattern('mews');+ yield new Pattern('money');+ yield new Pattern('moose');+ yield new Pattern('mumps');+ yield new Pattern('music');+ yield new Pattern('nankingese');+ yield new Pattern('news');+ yield new Pattern('nexus');+ yield new Pattern('niasese');+ yield new Pattern('nutrition');+ yield new Pattern('offspring');+ yield new Pattern('oil');+ yield new Pattern('patience');+ yield new Pattern('pekingese');+ yield new Pattern('piedmontese');+ yield new Pattern('pincers');+ yield new Pattern('pistoiese');+ yield new Pattern('plankton');+ yield new Pattern('pliers');+ yield new Pattern('pokemon');+ yield new Pattern('police');+ yield new Pattern('polish');+ yield new Pattern('portuguese');+ yield new Pattern('proceedings');+ yield new Pattern('progress');+ yield new Pattern('rabies');+ yield new Pattern('rain');+ yield new Pattern('research');+ yield new Pattern('rhinoceros');+ yield new Pattern('rice');+ yield new Pattern('salmon');+ yield new Pattern('sand');+ yield new Pattern('sarawakese');+ yield new Pattern('scissors');+ yield new Pattern('sea[- ]bass');+ yield new Pattern('series');+ yield new Pattern('shavese');+ yield new Pattern('shears');+ yield new Pattern('sheep');+ yield new Pattern('siemens');+ yield new Pattern('silk');+ yield new Pattern('sms');+ yield new Pattern('soap');+ yield new Pattern('social media');+ yield new Pattern('spam');+ yield new Pattern('species');+ yield new Pattern('staff');+ yield new Pattern('sugar');+ yield new Pattern('swine');+ yield new Pattern('talent');+ yield new Pattern('toothpaste');+ yield new Pattern('traffic');+ yield new Pattern('travel');+ yield new Pattern('trousers');+ yield new Pattern('trout');+ yield new Pattern('tuna');+ yield new Pattern('us');+ yield new Pattern('vermontese');+ yield new Pattern('vinegar');+ yield new Pattern('weather');+ yield new Pattern('wenchowese');+ yield new Pattern('wheat');+ yield new Pattern('whiting');+ yield new Pattern('wildebeest');+ yield new Pattern('wood');+ yield new Pattern('wool');+ yield new Pattern('yengeese');+ }+}
Vulnerability Existed: no
Pattern Matching - No CWE - vendor/doctrine/inflector/src/Rules/English/Uninflected.php - Lines 1-189
Old Code:
N/A (new file)
Fixed Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\English;
use Doctrine\Inflector\Rules\Pattern;
final class Uninflected
{
// Pattern matching rules for English language inflection
// No user input is processed or evaluated
}
```
Explanation:
This is a new file addition containing a static utility class for English language word inflection rules. The file consists entirely of static method definitions that yield predefined `Pattern` objects with hardcoded string literals. There are no security vulnerabilities present:
1. **No Input Validation Issues**: The patterns are all hardcoded constants with no user input processing.
2. **No Code Injection**: The `Pattern` class appears to be a simple data container for regex patterns used for text processing, not a code execution mechanism.
3. **No SQL Injection**: No database operations are performed.
4. **No Command Injection**: No external commands are executed.
5. **No XXE/Deserialization**: No serialization or external data parsing occurs.
6. **No Path Traversal**: No file system operations are performed.
This is a library utility class for text transformation and contains no security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Esperanto/Inflectible.php@@ -0,0 +1,31 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Esperanto;++use Doctrine\Inflector\Rules\Pattern;+use Doctrine\Inflector\Rules\Substitution;+use Doctrine\Inflector\Rules\Transformation;+use Doctrine\Inflector\Rules\Word;++class Inflectible+{+ /** @return Transformation[] */+ public static function getSingular(): iterable+ {+ yield new Transformation(new Pattern('oj$'), 'o');+ }++ /** @return Transformation[] */+ public static function getPlural(): iterable+ {+ yield new Transformation(new Pattern('o$'), 'oj');+ }++ /** @return Substitution[] */+ public static function getIrregular(): iterable+ {+ yield new Substitution(new Word(''), new Word(''));+ }+}
Vulnerability Existed: no Analysis of the provided diff: This is a new file addition containing a PHP class for Esperanto language inflection rules in the Doctrine Inflector library. The code is straightforward utility logic with no security vulnerabilities. **Security Assessment:** 1. **No Input Validation Issues** - The class only defines static methods that return hardcoded transformation and substitution rules. There is no user input processing. 2. **No Code Injection Risks** - The Pattern, Substitution, Transformation, and Word classes are instantiated with literal string values only. No dynamic code execution or string interpolation that could lead to injection attacks. 3. **No Access Control Issues** - All methods are public static, which is appropriate for a utility class providing language rules. 4. **No Data Exposure** - The class only returns transformation rules; no sensitive data is stored or exposed. 5. **Proper Type Declarations** - The code uses `declare(strict_types=1)` and proper return type hints (`iterable`), following PHP best practices. **Conclusion:** This is a benign addition of language inflection rules. The diff shows no security fixes because there were no vulnerabilities to fix. The code is safe and follows secure coding practices.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Esperanto/InflectorFactory.php@@ -0,0 +1,21 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Esperanto;++use Doctrine\Inflector\GenericLanguageInflectorFactory;+use Doctrine\Inflector\Rules\Ruleset;++final class InflectorFactory extends GenericLanguageInflectorFactory+{+ protected function getSingularRuleset(): Ruleset+ {+ return Rules::getSingularRuleset();+ }++ protected function getPluralRuleset(): Ruleset+ {+ return Rules::getPluralRuleset();+ }+}
Vulnerability Existed: no This is a new file addition (vendor/doctrine/inflector/src/Rules/Esperanto/InflectorFactory.php) containing a straightforward factory class implementation with no security vulnerabilities. Explanation: The code is a simple factory class that extends GenericLanguageInflectorFactory and provides language-specific ruleset implementations for Esperanto. The code: - Contains no external input handling - Performs no data processing or validation - Makes no database queries or system calls - Contains no hardcoded credentials or sensitive data - Uses proper namespace declarations and type hints - Follows standard PHP factory pattern conventions This is a benign addition of vendor library code with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Esperanto/Rules.php@@ -0,0 +1,31 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Esperanto;++use Doctrine\Inflector\Rules\Patterns;+use Doctrine\Inflector\Rules\Ruleset;+use Doctrine\Inflector\Rules\Substitutions;+use Doctrine\Inflector\Rules\Transformations;++final class Rules+{+ public static function getSingularRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getSingular()),+ new Patterns(...Uninflected::getSingular()),+ (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()+ );+ }++ public static function getPluralRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getPlural()),+ new Patterns(...Uninflected::getPlural()),+ new Substitutions(...Inflectible::getIrregular())+ );+ }+}
Vulnerability Existed: no No Security Vulnerabilities Detected Explanation: This is a new file being added that contains a PHP class for the Doctrine Inflector library's Esperanto language rules. The code is a straightforward implementation with no apparent security vulnerabilities: 1. **No User Input**: The file contains only static method definitions that instantiate and return Ruleset objects. There is no user input being processed. 2. **No Injection Risks**: The code uses typed class instantiation with hardcoded method calls (`Inflectible::getSingular()`, `Uninflected::getSingular()`, etc.). These are internal method calls with no external data injection. 3. **No Resource Access**: There are no file operations, database queries, network calls, or other resource access patterns that could be exploited. 4. **Proper Namespace and Declaration**: The file properly declares strict types and uses appropriate namespacing, following PHP best practices. 5. **No Unsafe Functions**: No use of `eval()`, `exec()`, `system()`, dynamic variable access (`$$var`), or other inherently dangerous PHP functions. This is a legitimate library file from the Doctrine Inflector project and contains no security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Esperanto/Uninflected.php@@ -0,0 +1,28 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Esperanto;++use Doctrine\Inflector\Rules\Pattern;++final class Uninflected+{+ /** @return Pattern[] */+ public static function getSingular(): iterable+ {+ yield from self::getDefault();+ }++ /** @return Pattern[] */+ public static function getPlural(): iterable+ {+ yield from self::getDefault();+ }++ /** @return Pattern[] */+ private static function getDefault(): iterable+ {+ yield new Pattern('');+ }+}
Vulnerability Existed: no
**No vulnerabilities identified** - [File] vendor/doctrine/inflector/src/Rules/Esperanto/Uninflected.php [Lines 1-28]
Old Code:
N/A (new file)
Fixed Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\Esperanto;
use Doctrine\Inflector\Rules\Pattern;
final class Uninflected
{
/** @return Pattern[] */
public static function getSingular(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
public static function getPlural(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
private static function getDefault(): iterable
{
yield new Pattern('');
}
}
```
Explanation:
This is a new file containing a simple PHP class for Esperanto language inflection rules. The code is part of the Doctrine Inflector library and follows secure coding practices:
- Proper namespace declaration
- Type hints with `declare(strict_types=1)`
- Access modifiers correctly specified (public/private)
- No user input processing
- No external dependencies beyond safe Doctrine Pattern class usage
- No dynamic code execution, SQL queries, or file operations
- Standard object instantiation with no injection vulnerabilities
This is a legitimate library addition with no security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/French/Inflectible.php@@ -0,0 +1,44 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\French;++use Doctrine\Inflector\Rules\Pattern;+use Doctrine\Inflector\Rules\Substitution;+use Doctrine\Inflector\Rules\Transformation;+use Doctrine\Inflector\Rules\Word;++class Inflectible+{+ /** @return Transformation[] */+ public static function getSingular(): iterable+ {+ yield new Transformation(new Pattern('/(b|cor|ém|gemm|soupir|trav|vant|vitr)aux$/'), '\1ail');+ yield new Transformation(new Pattern('/ails$/'), 'ail');+ yield new Transformation(new Pattern('/(journ|chev|loc)aux$/'), '\1al');+ yield new Transformation(new Pattern('/(bijou|caillou|chou|genou|hibou|joujou|pou|au|eu|eau)x$/'), '\1');+ yield new Transformation(new Pattern('/s$/'), '');+ }++ /** @return Transformation[] */+ public static function getPlural(): iterable+ {+ yield new Transformation(new Pattern('/(s|x|z)$/'), '\1');+ yield new Transformation(new Pattern('/(b|cor|ém|gemm|soupir|trav|vant|vitr)ail$/'), '\1aux');+ yield new Transformation(new Pattern('/ail$/'), 'ails');+ yield new Transformation(new Pattern('/(chacal|carnaval|festival|récital)$/'), '\1s');+ yield new Transformation(new Pattern('/al$/'), 'aux');+ yield new Transformation(new Pattern('/(bleu|émeu|landau|pneu|sarrau)$/'), '\1s');+ yield new Transformation(new Pattern('/(bijou|caillou|chou|genou|hibou|joujou|lieu|pou|au|eu|eau)$/'), '\1x');+ yield new Transformation(new Pattern('/$/'), 's');+ }++ /** @return Substitution[] */+ public static function getIrregular(): iterable+ {+ yield new Substitution(new Word('monsieur'), new Word('messieurs'));+ yield new Substitution(new Word('madame'), new Word('mesdames'));+ yield new Substitution(new Word('mademoiselle'), new Word('mesdemoiselles'));+ }+}
Vulnerability Existed: no This is a new file addition containing French language inflection rules for the Doctrine Inflector library. The code is a straightforward data/configuration class with no security vulnerabilities. The file contains: - Static methods returning transformation and substitution rules for French word pluralization/singularization - Regular expressions used for pattern matching on French words - No user input handling - No external data processing - No database queries - No file operations - No privilege escalation vectors This is a library utility class with hardcoded linguistic transformation rules, which is a safe pattern with no identifiable security risks.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/French/InflectorFactory.php@@ -0,0 +1,21 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\French;++use Doctrine\Inflector\GenericLanguageInflectorFactory;+use Doctrine\Inflector\Rules\Ruleset;++final class InflectorFactory extends GenericLanguageInflectorFactory+{+ protected function getSingularRuleset(): Ruleset+ {+ return Rules::getSingularRuleset();+ }++ protected function getPluralRuleset(): Ruleset+ {+ return Rules::getPluralRuleset();+ }+}
Vulnerability Existed: no **No Vulnerabilities Detected** This is a new file addition containing a PHP class that extends `GenericLanguageInflectorFactory` for French language inflection rules. The code: - Uses proper namespace declaration - Declares strict types - Implements only two simple getter methods that delegate to a `Rules` class - Contains no user input handling, file operations, database queries, or other security-sensitive operations - Follows standard OOP patterns with appropriate access modifiers There are no security vulnerabilities in this code. This is a straightforward factory class implementation for the Doctrine Inflector library's French language support.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/French/Rules.php@@ -0,0 +1,31 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\French;++use Doctrine\Inflector\Rules\Patterns;+use Doctrine\Inflector\Rules\Ruleset;+use Doctrine\Inflector\Rules\Substitutions;+use Doctrine\Inflector\Rules\Transformations;++final class Rules+{+ public static function getSingularRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getSingular()),+ new Patterns(...Uninflected::getSingular()),+ (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()+ );+ }++ public static function getPluralRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getPlural()),+ new Patterns(...Uninflected::getPlural()),+ new Substitutions(...Inflectible::getIrregular())+ );+ }+}
Analyzing the provided code diff for security vulnerabilities... --- **Vulnerability Existed:** no **Analysis Summary:** This diff introduces a new PHP file containing a `Rules` class for French language inflection rules in the Doctrine Inflector library. This is a straightforward utility class with no security vulnerabilities. **Details:** The code: - Declares strict types for type safety - Uses proper namespace organization - Contains only two static factory methods that instantiate and return `Ruleset` objects - Has no external input, no file operations, no database queries, no command execution, or other security-sensitive operations - Uses dependency injection via constructor parameters (Transformations, Patterns, Substitutions) - Does not handle user input or perform any validation that could fail insecurely **Explanation:** This is a new file addition with no prior version to compare against. The code itself is a safe, read-only utility class that provides linguistic rules for French word inflection. There are no: - SQL injection risks (no database operations) - Command injection risks (no shell execution) - Path traversal risks (no file operations) - XSS risks (no HTML generation) - Authentication/authorization issues (no access control logic) - Cryptographic weaknesses - Information disclosure risks The code follows secure coding practices with strict type declarations and immutable-style factory methods.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/French/Uninflected.php@@ -0,0 +1,31 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\French;++use Doctrine\Inflector\Rules\Pattern;++final class Uninflected+{+ /** @return Pattern[] */+ public static function getSingular(): iterable+ {+ yield from self::getDefault();++ yield new Pattern('bois');+ yield new Pattern('mas');+ }++ /** @return Pattern[] */+ public static function getPlural(): iterable+ {+ yield from self::getDefault();+ }++ /** @return Pattern[] */+ private static function getDefault(): iterable+ {+ yield new Pattern('');+ }+}
Vulnerability Existed: no
**Analysis Summary:**
This diff shows the addition of a new PHP file containing a class for French language inflection rules. The code is a straightforward implementation of the Doctrine Inflector library's pattern matching for uninflected words in French.
**Security Assessment:**
No vulnerabilities are present in this code. The analysis follows:
1. **No Input Validation Issues**: The class only yields hardcoded `Pattern` objects with literal string values ('bois', 'mas', ''). There is no user input, external data processing, or dynamic code execution.
2. **No Injection Risks**: No SQL, command, or code injection vulnerabilities exist since the code contains only static pattern definitions with no dynamic evaluation.
3. **No Access Control Issues**: The class uses appropriate visibility modifiers (private for internal helper, public for API methods).
4. **No Information Disclosure**: No sensitive data, credentials, or internal system information is exposed.
5. **No Resource Exhaustion**: The implementation is efficient and yields patterns without creating large data structures or infinite loops.
6. **Type Safety**: The code uses proper type declarations (`iterable` return types, `declare(strict_types=1)`), reducing runtime errors.
This is a safe, well-structured utility class for language inflection rules.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Italian/Inflectible.php@@ -0,0 +1,218 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Italian;++use Doctrine\Inflector\Rules\Pattern;+use Doctrine\Inflector\Rules\Substitution;+use Doctrine\Inflector\Rules\Transformation;+use Doctrine\Inflector\Rules\Word;++class Inflectible+{+ /** @return iterable<Transformation> */+ public static function getSingular(): iterable+ {+ // Reverse of -sce → -scia (fasce → fascia)+ yield new Transformation(new Pattern('([aeiou])sce$'), '\\1scia');++ // Reverse of -cie → -cia (farmacia → farmacie)+ yield new Transformation(new Pattern('cie$'), 'cia');++ // Reverse of -gie → -gia (bugia → bugie)+ yield new Transformation(new Pattern('gie$'), 'gia');++ // Reverse of -ce → -cia (arance → arancia)+ yield new Transformation(new Pattern('([^aeiou])ce$'), '\1cia');++ // Reverse of -ge → -gia (valige → valigia)+ yield new Transformation(new Pattern('([^aeiou])ge$'), '\1gia');++ // Reverse of -chi → -co (bachi → baco)+ yield new Transformation(new Pattern('([bcdfghjklmnpqrstvwxyz][aeiou])chi$'), '\1co');++ // Reverse of -ghi → -go (laghi → lago)+ yield new Transformation(new Pattern('([bcdfghjklmnpqrstvwxyz][aeiou])ghi$'), '\1go');++ // Reverse of -ci → -co (medici → medico)+ yield new Transformation(new Pattern('([aeiou][bcdfghjklmnpqrstvwxyz])ci$'), '\1co');++ // Reverse of -gi → -go (psicologi → psicologo)+ yield new Transformation(new Pattern('([aeiou][bcdfghjklmnpqrstvwxyz])gi$'), '\1go');++ // Reverse of -i → -io (zii → zio, negozi → negozio)+ // This is more complex due to Italian's stress patterns, but we'll handle the basic case+ yield new Transformation(new Pattern('([^aeiou])i$'), '\1io');++ // Handle words that end with -i but should go to -co/-go (amici → amico, not amice)+ yield new Transformation(new Pattern('([^aeiou])ci$'), '\1co');+ yield new Transformation(new Pattern('([^aeiou])gi$'), '\1go');++ // Reverse of -a → -e+ yield new Transformation(new Pattern('e$'), 'a');++ // Reverse of -e → -i+ yield new Transformation(new Pattern('i$'), 'e');++ // Reverse of -o → -i+ yield new Transformation(new Pattern('i$'), 'o');+ }++ /** @return iterable<Transformation> */+ public static function getPlural(): iterable+ {+ // Words ending in -scia without stress on 'i' become -sce (e.g. fascia → fasce)+ yield new Transformation(new Pattern('([aeiou])scia$'), '\\1sce');++ // Words ending in -cia/gia with stress on 'i' keep the 'i' in plural+ yield new Transformation(new Pattern('cia$'), 'cie'); // e.g. farmacia → farmacie+ yield new Transformation(new Pattern('gia$'), 'gie'); // e.g. bugia → bugie++ // Words ending in -cia/gia without stress on 'i' lose the 'i' in plural+ yield new Transformation(new Pattern('([^aeiou])cia$'), '\\1ce'); // e.g. arancia → arance+ yield new Transformation(new Pattern('([^aeiou])gia$'), '\\1ge'); // e.g. valigia → valige++ // Words ending in -co/-go with stress on 'o' become -chi/-ghi+ yield new Transformation(new Pattern('([bcdfghjklmnpqrstvwxyz][aeiou])co$'), '\\1chi'); // e.g. baco → bachi+ yield new Transformation(new Pattern('([bcdfghjklmnpqrstvwxyz][aeiou])go$'), '\\1ghi'); // e.g. lago → laghi++ // Words ending in -co/-go with stress on the penultimate syllable become -ci/-gi+ yield new Transformation(new Pattern('([aeiou][bcdfghjklmnpqrstvwxyz])co$'), '\\1ci'); // e.g. medico → medici+ yield new Transformation(new Pattern('([aeiou][bcdfghjklmnpqrstvwxyz])go$'), '\\1gi'); // e.g. psicologo → psicologi++ // Words ending in -io with stress on 'i' keep the 'i' in plural+ yield new Transformation(new Pattern('([^aeiou])io$'), '\\1i'); // e.g. zio → zii++ // Words ending in -io with stress on 'o' lose the 'i' in plural+ yield new Transformation(new Pattern('([aeiou])io$'), '\\1i'); // e.g. negozio → negozi++ // Standard ending rules+ yield new Transformation(new Pattern('a$'), 'e'); // -a → -e+ yield new Transformation(new Pattern('e$'), 'i'); // -e → -i+ yield new Transformation(new Pattern('o$'), 'i'); // -o → -i+ }++ /** @return iterable<Substitution> */+ public static function getIrregular(): iterable+ {+ // Irregular substitutions (singular => plural)+ $irregulars = [+ 'ala' => 'ali',+ 'albergo' => 'alberghi',+ 'amica' => 'amiche',+ 'amico' => 'amici',+ 'ampio' => 'ampi',+ 'arancia' => 'arance',+ 'arma' => 'armi',+ 'asparago' => 'asparagi',+ 'banca' => 'banche',+ 'belga' => 'belgi',+ 'braccio' => 'braccia',+ 'budello' => 'budella',+ 'bue' => 'buoi',+ 'caccia' => 'cacce',+ 'calcagno' => 'calcagna',+ 'camicia' => 'camicie',+ 'cane' => 'cani',+ 'capitale' => 'capitali',+ 'carcere' => 'carceri',+ 'casa' => 'case',+ 'cavaliere' => 'cavalieri',+ 'centinaio' => 'centinaia',+ 'cerchio' => 'cerchia',+ 'cervello' => 'cervella',+ 'chiave' => 'chiavi',+ 'chirurgo' => 'chirurgi',+ 'ciglio' => 'ciglia',+ 'città' => 'città',+ 'corno' => 'corna',+ 'corpo' => 'corpi',+ 'crisi' => 'crisi',+ 'dente' => 'denti',+ 'dio' => 'dei',+ 'dito' => 'dita',+ 'dottore' => 'dottori',+ 'fiore' => 'fiori',+ 'fratello' => 'fratelli',+ 'fuoco' => 'fuochi',+ 'gamba' => 'gambe',+ 'ginocchio' => 'ginocchia',+ 'gioco' => 'giochi',+ 'giornale' => 'giornali',+ 'giraffa' => 'giraffe',+ 'labbro' => 'labbra',+ 'lenzuolo' => 'lenzuola',+ 'libro' => 'libri',+ 'madre' => 'madri',+ 'maestro' => 'maestri',+ 'magico' => 'magici',+ 'mago' => 'maghi',+ 'maniaco' => 'maniaci',+ 'manico' => 'manici',+ 'mano' => 'mani',+ 'medico' => 'medici',+ 'membro' => 'membri',+ 'metropoli' => 'metropoli',+ 'migliaio' => 'migliaia',+ 'miglio' => 'miglia',+ 'mille' => 'mila',+ 'mio' => 'miei',+ 'moglie' => 'mogli',+ 'mosaico' => 'mosaici',+ 'muro' => 'muri',+ 'nemico' => 'nemici',+ 'nome' => 'nomi',+ 'occhio' => 'occhi',+ 'orecchio' => 'orecchi',+ 'osso' => 'ossa',+ 'paio' => 'paia',+ 'pane' => 'pani',+ 'papa' => 'papi',+ 'pasta' => 'paste',+ 'penna' => 'penne',+ 'pesce' => 'pesci',+ 'piede' => 'piedi',+ 'pittore' => 'pittori',+ 'poeta' => 'poeti',+ 'porco' => 'porci',+ 'porto' => 'porti',+ 'problema' => 'problemi',+ 'ragazzo' => 'ragazzi',+ 're' => 're',+ 'rene' => 'reni',+ 'riso' => 'risa',+ 'rosa' => 'rosa',+ 'sale' => 'sali',+ 'sarto' => 'sarti',+ 'scuola' => 'scuole',+ 'serie' => 'serie',+ 'serramento' => 'serramenta',+ 'sorella' => 'sorelle',+ 'specie' => 'specie',+ 'staio' => 'staia',+ 'stazione' => 'stazioni',+ 'strido' => 'strida',+ 'strillo' => 'strilla',+ 'studio' => 'studi',+ 'suo' => 'suoi',+ 'superficie' => 'superfici',+ 'tavolo' => 'tavoli',+ 'tempio' => 'templi',+ 'treno' => 'treni',+ 'tuo' => 'tuoi',+ 'uomo' => 'uomini',+ 'uovo' => 'uova',+ 'urlo' => 'urla',+ 'valigia' => 'valigie',+ 'vestigio' => 'vestigia',+ 'vino' => 'vini',+ 'viola' => 'viola',+ 'zio' => 'zii',+ ];++ foreach ($irregulars as $singular => $plural) {+ yield new Substitution(new Word($singular), new Word($plural));+ }+ }+}
Vulnerability Existed: no No Security Vulnerabilities Found Explanation: This is a new file containing Italian language inflection rules for the Doctrine Inflector library. The code is a data-driven configuration class that defines grammatical transformation patterns for Italian word pluralization and singularization. Analysis: 1. **No Input Validation Issues**: The file contains only hardcoded regex patterns and static data structures. There is no user input processing, database queries, or external data handling. 2. **No Injection Vulnerabilities**: The regex patterns are defined as string literals in the source code. They are not constructed from user input or external sources, eliminating regex injection risks. 3. **No Data Exposure**: The class only contains public static methods that return transformation rules and irregular substitutions. No sensitive data is stored or exposed. 4. **No Logic Vulnerabilities**: The transformation patterns follow standard regex syntax for Italian language rules and are used by the Inflector library for legitimate linguistic transformations. 5. **No Resource Issues**: The code does not perform heavy computations, allocate large resources, or create potential DoS vectors. This appears to be a legitimate library addition with no security concerns in the implementation itself.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Italian/InflectorFactory.php@@ -0,0 +1,21 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Italian;++use Doctrine\Inflector\GenericLanguageInflectorFactory;+use Doctrine\Inflector\Rules\Ruleset;++final class InflectorFactory extends GenericLanguageInflectorFactory+{+ protected function getSingularRuleset(): Ruleset+ {+ return Rules::getSingularRuleset();+ }++ protected function getPluralRuleset(): Ruleset+ {+ return Rules::getPluralRuleset();+ }+}
I'll analyze this code diff for security vulnerabilities. **Vulnerability Existed: no** This is a new file addition (vendor library code) containing a simple factory class for Italian language inflection rules. The code follows standard PHP practices and design patterns without introducing security vulnerabilities. **Analysis:** - **Code Structure**: The class extends `GenericLanguageInflectorFactory` and implements two protected methods that return ruleset objects. - **No Input Handling**: The code doesn't accept any user input, perform file operations, execute commands, or interact with external systems. - **No Data Exposure**: No sensitive data is hardcoded or exposed. - **No Injection Risks**: No string concatenation, dynamic code execution, or SQL queries. - **Proper Namespace**: Uses appropriate namespace declaration and strict types. **Conclusion**: This is straightforward vendor library code with no apparent security vulnerabilities. It's a legitimate language inflector factory implementation that poses no security risk.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Italian/Rules.php@@ -0,0 +1,31 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Italian;++use Doctrine\Inflector\Rules\Patterns;+use Doctrine\Inflector\Rules\Ruleset;+use Doctrine\Inflector\Rules\Substitutions;+use Doctrine\Inflector\Rules\Transformations;++final class Rules+{+ public static function getSingularRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getSingular()),+ new Patterns(...Uninflected::getSingular()),+ (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()+ );+ }++ public static function getPluralRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getPlural()),+ new Patterns(...Uninflected::getPlural()),+ new Substitutions(...Inflectible::getIrregular())+ );+ }+}
``` Vulnerability Existed: no No Vulnerabilities Detected Explanation: This is a new file (vendor library code) containing a simple PHP class for Italian language inflection rules. The code: 1. Uses proper namespace declaration and type hints (declare(strict_types=1)) 2. Only instantiates and returns standard objects from the Doctrine Inflector library 3. Contains no user input handling, database queries, file operations, or external data processing 4. Is part of a vendor library (Doctrine Inflector) which is a well-established, maintained dependency 5. Follows standard factory pattern with static methods returning properly typed objects There are no security vulnerabilities in this code. It is a straightforward configuration/rules class that does not introduce any OWASP top 10 vulnerabilities or other common security issues. ```
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Italian/Uninflected.php@@ -0,0 +1,80 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Italian;++use Doctrine\Inflector\Rules\Pattern;++final class Uninflected+{+ /** @return iterable<Pattern> */+ public static function getSingular(): iterable+ {+ yield from self::getDefault();+ }++ /** @return iterable<Pattern> */+ public static function getPlural(): iterable+ {+ yield from self::getDefault();+ }++ /** @return iterable<Pattern> */+ private static function getDefault(): iterable+ {+ // Invariable words (same form in singular and plural)+ $invariables = [+ 'alpaca',+ 'auto',+ 'bar',+ 'blu',+ 'boia',+ 'boomerang',+ 'brindisi',+ 'campus',+ 'computer',+ 'crisi',+ 'crocevia',+ 'dopocena',+ 'film',+ 'foto',+ 'fuchsia',+ 'gnu',+ 'gorilla',+ 'gru',+ 'iguana',+ 'kamikaze',+ 'karaoke',+ 'koala',+ 'lama',+ 'menu',+ 'metropoli',+ 'moto',+ 'opossum',+ 'panda',+ 'quiz',+ 'radio',+ 're',+ 'scacciapensieri',+ 'serie',+ 'smartphone',+ 'sosia',+ 'sottoscala',+ 'specie',+ 'sport',+ 'tablet',+ 'taxi',+ 'vaglia',+ 'virtù',+ 'virus',+ 'yogurt',+ 'foto',+ 'fuchsia',+ ];++ foreach ($invariables as $word) {+ yield new Pattern($word);+ }+ }+}
Vulnerability Existed: no
This is a new file addition containing Italian language inflection rules for the Doctrine Inflector library. The code does not introduce any security vulnerabilities.
Analysis:
The file contains:
- A properly declared PHP namespace and use statement
- Type-safe method declarations with return type hints (`iterable<Pattern>`)
- A static array of Italian invariable words (words with identical singular/plural forms)
- Safe iteration over the array to yield Pattern objects
There are no security issues present:
- No user input handling or injection vectors
- No database queries or external API calls
- No file operations or system commands
- No cryptographic or authentication logic
- No sensitive data exposure
- Proper use of type declarations
Minor code quality note (not a security issue): The array contains duplicate entries ('foto' and 'fuchsia' appear twice on lines 73-74), but this is a logic/quality issue, not a security vulnerability.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/NorwegianBokmal/Inflectible.php@@ -0,0 +1,34 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\NorwegianBokmal;++use Doctrine\Inflector\Rules\Pattern;+use Doctrine\Inflector\Rules\Substitution;+use Doctrine\Inflector\Rules\Transformation;+use Doctrine\Inflector\Rules\Word;++class Inflectible+{+ /** @return Transformation[] */+ public static function getSingular(): iterable+ {+ yield new Transformation(new Pattern('/re$/i'), 'r');+ yield new Transformation(new Pattern('/er$/i'), '');+ }++ /** @return Transformation[] */+ public static function getPlural(): iterable+ {+ yield new Transformation(new Pattern('/e$/i'), 'er');+ yield new Transformation(new Pattern('/r$/i'), 're');+ yield new Transformation(new Pattern('/$/'), 'er');+ }++ /** @return Substitution[] */+ public static function getIrregular(): iterable+ {+ yield new Substitution(new Word('konto'), new Word('konti'));+ }+}
Vulnerability Existed: no No vulnerabilities detected in this code diff. Explanation: This is a new file containing a PHP class for Norwegian Bokmål language inflection rules in the Doctrine Inflector library. The code: 1. Uses proper namespace declaration and type hints 2. Contains only static methods that yield transformation and substitution pattern objects 3. Uses the library's Pattern, Substitution, Transformation, and Word classes as intended 4. Does not perform any user input processing, database operations, file I/O, or dynamic code execution 5. Regular expressions are hardcoded literals (not user-controlled), so there is no regex injection risk 6. The class is purely declarative, defining linguistic rules for text transformation This is a legitimate configuration/rules file with no security vulnerabilities. It's part of vendor code for a language inflection library and poses no security risk.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/NorwegianBokmal/InflectorFactory.php@@ -0,0 +1,21 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\NorwegianBokmal;++use Doctrine\Inflector\GenericLanguageInflectorFactory;+use Doctrine\Inflector\Rules\Ruleset;++final class InflectorFactory extends GenericLanguageInflectorFactory+{+ protected function getSingularRuleset(): Ruleset+ {+ return Rules::getSingularRuleset();+ }++ protected function getPluralRuleset(): Ruleset+ {+ return Rules::getPluralRuleset();+ }+}
Vulnerability Existed: no
No CWE Violations Detected
Old Code:
[File did not exist - new file creation]
Fixed Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\NorwegianBokmal;
use Doctrine\Inflector\GenericLanguageInflectorFactory;
use Doctrine\Inflector\Rules\Ruleset;
final class InflectorFactory extends GenericLanguageInflectorFactory
{
protected function getSingularRuleset(): Ruleset
{
return Rules::getSingularRuleset();
}
protected function getPluralRuleset(): Ruleset
{
return Rules::getPluralRuleset();
}
}
```
Explanation:
This is a new file addition containing a simple factory class for Norwegian Bokmål language inflection rules. The code follows secure practices:
1. **No User Input**: The class does not accept or process any user input, eliminating injection attack vectors.
2. **Type Declarations**: Uses `declare(strict_types=1)` and explicit return type hints (`Ruleset`), enforcing type safety.
3. **Encapsulation**: The class properly extends `GenericLanguageInflectorFactory` and delegates to the `Rules` class methods, maintaining clean separation of concerns.
4. **No External Calls**: No external API calls, file operations, or database interactions that could introduce vulnerabilities.
5. **Standard Library Usage**: Only uses Doctrine Inflector's own internal classes, which are trusted components.
This is a legitimate library addition with no security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/NorwegianBokmal/Rules.php@@ -0,0 +1,31 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\NorwegianBokmal;++use Doctrine\Inflector\Rules\Patterns;+use Doctrine\Inflector\Rules\Ruleset;+use Doctrine\Inflector\Rules\Substitutions;+use Doctrine\Inflector\Rules\Transformations;++final class Rules+{+ public static function getSingularRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getSingular()),+ new Patterns(...Uninflected::getSingular()),+ (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()+ );+ }++ public static function getPluralRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getPlural()),+ new Patterns(...Uninflected::getPlural()),+ new Substitutions(...Inflectible::getIrregular())+ );+ }+}
Vulnerability Existed: no File: vendor/doctrine/inflector/src/Rules/NorwegianBokmal/Rules.php Explanation: This is a new file addition (vendor library code) containing a simple PHP class that provides static methods for retrieving singular and plural inflection rulesets. The code: 1. Uses proper namespace declaration with strict types enabled 2. Only instantiates and returns Ruleset objects with configuration data 3. Contains no user input handling, database queries, file operations, or external data access 4. Is part of a well-known PHP library (Doctrine Inflector) following standard patterns 5. Has no dynamic code execution, eval, or variable function calls 6. Demonstrates no SQL injection, XSS, command injection, or other OWASP Top 10 vulnerabilities The code is a standard utility class for language-specific inflection rules and presents no identified security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/NorwegianBokmal/Uninflected.php@@ -0,0 +1,30 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\NorwegianBokmal;++use Doctrine\Inflector\Rules\Pattern;++final class Uninflected+{+ /** @return Pattern[] */+ public static function getSingular(): iterable+ {+ yield from self::getDefault();+ }++ /** @return Pattern[] */+ public static function getPlural(): iterable+ {+ yield from self::getDefault();+ }++ /** @return Pattern[] */+ private static function getDefault(): iterable+ {+ yield new Pattern('barn');+ yield new Pattern('fjell');+ yield new Pattern('hus');+ }+}
Vulnerability Existed: no No Vulnerabilities Detected - File: vendor/doctrine/inflector/src/Rules/NorwegianBokmal/Uninflected.php Explanation: This is a new file addition containing a PHP class definition for Norwegian Bokmål language inflection rules. The code: 1. **No Injection Vulnerabilities**: The file only defines static methods that yield Pattern objects with hardcoded string literals (Norwegian words: 'barn', 'fjell', 'hus'). There is no user input, no dynamic code execution, and no data that could be manipulated. 2. **No Authentication/Authorization Issues**: This is a utility class with no security-sensitive operations, credentials, or access control requirements. 3. **No Information Disclosure**: No sensitive data is exposed, logged, or transmitted. 4. **Proper Namespace and Type Declaration**: The file correctly uses `declare(strict_types=1)` and proper namespace declarations, following PHP best practices. 5. **Legitimate Library Code**: This appears to be part of the Doctrine Inflector library (vendor package), which is a standard, well-established PHP library for word inflection. This is legitimate library code with no security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Pattern.php@@ -0,0 +1,42 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules;++use function preg_match;++final class Pattern+{+ /** @var string */+ private $pattern;++ /** @var string */+ private $regex;++ public function __construct(string $pattern)+ {+ $this->pattern = $pattern;++ if (isset($this->pattern[0]) && $this->pattern[0] === '/') {+ $this->regex = $this->pattern;+ } else {+ $this->regex = '/' . $this->pattern . '/i';+ }+ }++ public function getPattern(): string+ {+ return $this->pattern;+ }++ public function getRegex(): string+ {+ return $this->regex;+ }++ public function matches(string $word): bool+ {+ return preg_match($this->getRegex(), $word) === 1;+ }+}
Vulnerability Existed: yes
FALSE POSITIVE
Regex Injection / Unvalidated Regular Expression - CWE-1025 - vendor/doctrine/inflector/src/Rules/Pattern.php (Lines 20-26)
Old Code:
```php
public function __construct(string $pattern)
{
$this->pattern = $pattern;
if (isset($this->pattern[0]) && $this->pattern[0] === '/') {
$this->regex = $this->pattern;
} else {
$this->regex = '/' . $this->pattern . '/i';
}
}
```
Fixed Code:
(No fix present in this diff - this is a new file)
Explanation:
This code is vulnerable to regex injection. The constructor accepts an arbitrary `$pattern` parameter and either uses it directly as a regex (if it starts with '/') or wraps it with regex delimiters. The critical vulnerability is that there is no validation or escaping of the pattern string. If an attacker controls the pattern input, they can inject arbitrary regex metacharacters to:
1. Break out of the intended regex matching behavior
2. Cause catastrophic backtracking (ReDoS attacks) via malicious regex patterns
3. Perform unintended pattern matching operations
For example, a pattern like `(a+)+$` or `(a|a)*$` could cause severe performance degradation. Additionally, if the pattern starts with '/', an attacker could inject an unvalidated regex directly.
The `matches()` method at line 40 uses this potentially malicious regex in `preg_match()`, executing the attacker-controlled pattern against user input.
Recommended fix would be to use `preg_quote()` on the pattern before using it in regex operations, unless patterns are expected to be raw regex expressions with strict validation rules.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Patterns.php@@ -0,0 +1,29 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules;++use function array_map;+use function implode;+use function preg_match;++class Patterns+{+ /** @var string */+ private $regex;++ public function __construct(Pattern ...$patterns)+ {+ $patterns = array_map(static function (Pattern $pattern): string {+ return $pattern->getPattern();+ }, $patterns);++ $this->regex = '/^(?:' . implode('|', $patterns) . ')$/i';+ }++ public function matches(string $word): bool+ {+ return preg_match($this->regex, $word, $regs) === 1;+ }+}
Vulnerability Existed: not sure
Regex Injection / Unvalidated Regex Construction - CWE-1025 - vendor/doctrine/inflector/src/Rules/Patterns.php - Lines 18-22
Old Code:
N/A (new file)
Fixed Code:
```php
$patterns = array_map(static function (Pattern $pattern): string {
return $pattern->getPattern();
}, $patterns);
$this->regex = '/^(?:' . implode('|', $patterns) . ')$/i';
```
Explanation:
This code constructs a regex pattern by concatenating user-supplied patterns without escaping them. If `Pattern::getPattern()` returns uncontrolled input, an attacker could inject regex metacharacters to alter the regex behavior (e.g., `(?:foo)|.*` would match anything). However, this is mitigated if `Pattern` is an internal class that validates/escapes patterns at instantiation. The vulnerability severity depends on whether Pattern objects are created from untrusted sources. Without seeing the Pattern class implementation, this cannot be definitively determined, hence "not sure." If Pattern inputs come from user-controllable sources without proper escaping, this is a regex injection vulnerability (CWE-1025).
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Portuguese/Inflectible.php@@ -0,0 +1,98 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Portuguese;++use Doctrine\Inflector\Rules\Pattern;+use Doctrine\Inflector\Rules\Substitution;+use Doctrine\Inflector\Rules\Transformation;+use Doctrine\Inflector\Rules\Word;++class Inflectible+{+ /** @return Transformation[] */+ public static function getSingular(): iterable+ {+ yield new Transformation(new Pattern('/^(g|)ases$/i'), '\1ás');+ yield new Transformation(new Pattern('/(japon|escoc|ingl|dinamarqu|fregu|portugu)eses$/i'), '\1ês');+ yield new Transformation(new Pattern('/(ae|ao|oe)s$/'), 'ao');+ yield new Transformation(new Pattern('/(ãe|ão|õe)s$/'), 'ão');+ yield new Transformation(new Pattern('/^(.*[^s]s)es$/i'), '\1');+ yield new Transformation(new Pattern('/sses$/i'), 'sse');+ yield new Transformation(new Pattern('/ns$/i'), 'm');+ yield new Transformation(new Pattern('/(r|t|f|v)is$/i'), '\1il');+ yield new Transformation(new Pattern('/uis$/i'), 'ul');+ yield new Transformation(new Pattern('/ois$/i'), 'ol');+ yield new Transformation(new Pattern('/eis$/i'), 'ei');+ yield new Transformation(new Pattern('/éis$/i'), 'el');+ yield new Transformation(new Pattern('/([^p])ais$/i'), '\1al');+ yield new Transformation(new Pattern('/(r|z)es$/i'), '\1');+ yield new Transformation(new Pattern('/^(á|gá)s$/i'), '\1s');+ yield new Transformation(new Pattern('/([^ê])s$/i'), '\1');+ }++ /** @return Transformation[] */+ public static function getPlural(): iterable+ {+ yield new Transformation(new Pattern('/^(alem|c|p)ao$/i'), '\1aes');+ yield new Transformation(new Pattern('/^(irm|m)ao$/i'), '\1aos');+ yield new Transformation(new Pattern('/ao$/i'), 'oes');+ yield new Transformation(new Pattern('/^(alem|c|p)ão$/i'), '\1ães');+ yield new Transformation(new Pattern('/^(irm|m)ão$/i'), '\1ãos');+ yield new Transformation(new Pattern('/ão$/i'), 'ões');+ yield new Transformation(new Pattern('/^(|g)ás$/i'), '\1ases');+ yield new Transformation(new Pattern('/^(japon|escoc|ingl|dinamarqu|fregu|portugu)ês$/i'), '\1eses');+ yield new Transformation(new Pattern('/m$/i'), 'ns');+ yield new Transformation(new Pattern('/([^aeou])il$/i'), '\1is');+ yield new Transformation(new Pattern('/ul$/i'), 'uis');+ yield new Transformation(new Pattern('/ol$/i'), 'ois');+ yield new Transformation(new Pattern('/el$/i'), 'eis');+ yield new Transformation(new Pattern('/al$/i'), 'ais');+ yield new Transformation(new Pattern('/(z|r)$/i'), '\1es');+ yield new Transformation(new Pattern('/(s)$/i'), '\1');+ yield new Transformation(new Pattern('/$/'), 's');+ }++ /** @return Substitution[] */+ public static function getIrregular(): iterable+ {+ yield new Substitution(new Word('abdomen'), new Word('abdomens'));+ yield new Substitution(new Word('alemão'), new Word('alemães'));+ yield new Substitution(new Word('artesã'), new Word('artesãos'));+ yield new Substitution(new Word('álcool'), new Word('álcoois'));+ yield new Substitution(new Word('árvore'), new Word('árvores'));+ yield new Substitution(new Word('bencão'), new Word('bencãos'));+ yield new Substitution(new Word('cão'), new Word('cães'));+ yield new Substitution(new Word('campus'), new Word('campi'));+ yield new Substitution(new Word('cadáver'), new Word('cadáveres'));+ yield new Substitution(new Word('capelão'), new Word('capelães'));+ yield new Substitution(new Word('capitão'), new Word('capitães'));+ yield new Substitution(new Word('chão'), new Word('chãos'));+ yield new Substitution(new Word('charlatão'), new Word('charlatães'));+ yield new Substitution(new Word('cidadão'), new Word('cidadãos'));+ yield new Substitution(new Word('consul'), new Word('consules'));+ yield new Substitution(new Word('cristão'), new Word('cristãos'));+ yield new Substitution(new Word('difícil'), new Word('difíceis'));+ yield new Substitution(new Word('email'), new Word('emails'));+ yield new Substitution(new Word('escrivão'), new Word('escrivães'));+ yield new Substitution(new Word('fóssil'), new Word('fósseis'));+ yield new Substitution(new Word('gás'), new Word('gases'));+ yield new Substitution(new Word('germens'), new Word('germen'));+ yield new Substitution(new Word('grão'), new Word('grãos'));+ yield new Substitution(new Word('hífen'), new Word('hífens'));+ yield new Substitution(new Word('irmão'), new Word('irmãos'));+ yield new Substitution(new Word('liquens'), new Word('liquen'));+ yield new Substitution(new Word('mal'), new Word('males'));+ yield new Substitution(new Word('mão'), new Word('mãos'));+ yield new Substitution(new Word('orfão'), new Word('orfãos'));+ yield new Substitution(new Word('país'), new Word('países'));+ yield new Substitution(new Word('pai'), new Word('pais'));+ yield new Substitution(new Word('pão'), new Word('pães'));+ yield new Substitution(new Word('projétil'), new Word('projéteis'));+ yield new Substitution(new Word('réptil'), new Word('répteis'));+ yield new Substitution(new Word('sacristão'), new Word('sacristães'));+ yield new Substitution(new Word('sotão'), new Word('sotãos'));+ yield new Substitution(new Word('tabelião'), new Word('tabeliães'));+ }+}
Vulnerability Existed: no No security vulnerabilities detected in this code diff. Explanation: This diff introduces a new PHP file containing the `Inflectible` class for Portuguese language inflection rules in the Doctrine Inflector library. The file contains: 1. **Regular expression patterns** - All regex patterns are used for string transformation only (singular/plural conversion) and are not applied to user input. They operate on predefined language rules. 2. **No user input processing** - The class defines static methods that return iterables of transformation rules and substitutions. These rules are configuration data, not processed user input. 3. **No dangerous functions** - No use of `eval()`, `exec()`, `system()`, `preg_replace()` with the `/e` modifier, or other dangerous functions. 4. **Type-safe construction** - All transformations use the `Transformation` and `Substitution` classes with proper `Pattern` and `Word` wrapper objects, preventing direct regex interpretation of arbitrary strings. 5. **No external data handling** - This is purely a configuration/rules class with hardcoded Portuguese language inflection patterns. This is a legitimate library addition with no security concerns.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Portuguese/InflectorFactory.php@@ -0,0 +1,21 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Portuguese;++use Doctrine\Inflector\GenericLanguageInflectorFactory;+use Doctrine\Inflector\Rules\Ruleset;++final class InflectorFactory extends GenericLanguageInflectorFactory+{+ protected function getSingularRuleset(): Ruleset+ {+ return Rules::getSingularRuleset();+ }++ protected function getPluralRuleset(): Ruleset+ {+ return Rules::getPluralRuleset();+ }+}
I'll analyze this code diff for security vulnerabilities. **Vulnerability Analysis:** Vulnerability Existed: no **Explanation:** This is a new file being added that contains a simple factory class for Portuguese language inflection rules in the Doctrine Inflector library. The code: 1. **No input validation issues** - The class doesn't accept user input or process external data 2. **No injection vulnerabilities** - It's a straightforward factory pattern that returns predefined ruleset objects 3. **No authentication/authorization issues** - Not handling sensitive operations 4. **No path traversal** - No file operations or path manipulation 5. **No information disclosure** - No sensitive data exposure 6. **No unsafe deserialization** - No serialization operations 7. **Proper namespace usage** - Uses appropriate PHP namespace declaration 8. **Type hints present** - Uses `declare(strict_types=1)` for type safety 9. **Final class declaration** - The class is marked as `final`, preventing unintended extension 10. **Protected methods** - Appropriate visibility modifiers used This is a standard, safe implementation of a factory pattern for language-specific inflection rules. No security vulnerabilities are present in this code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Portuguese/Rules.php@@ -0,0 +1,31 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Portuguese;++use Doctrine\Inflector\Rules\Patterns;+use Doctrine\Inflector\Rules\Ruleset;+use Doctrine\Inflector\Rules\Substitutions;+use Doctrine\Inflector\Rules\Transformations;++final class Rules+{+ public static function getSingularRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getSingular()),+ new Patterns(...Uninflected::getSingular()),+ (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()+ );+ }++ public static function getPluralRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getPlural()),+ new Patterns(...Uninflected::getPlural()),+ new Substitutions(...Inflectible::getIrregular())+ );+ }+}
Vulnerability Existed: no No vulnerabilities detected - This file is a new addition containing class definitions and method implementations for Portuguese language inflection rules in the Doctrine Inflector library. Explanation: This is a legitimate library file with standard PHP code structure. The file: - Uses proper namespace declaration with full qualification - Imports required dependencies explicitly - Contains only static factory methods that instantiate and return rule objects - Has no dynamic code execution, user input handling, or external data processing - Uses type declarations (`Ruleset` return types) - Follows standard OOP patterns without security concerns There are no injection vulnerabilities, authentication issues, access control problems, or other OWASP top-10 security concerns present in this code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Portuguese/Uninflected.php@@ -0,0 +1,32 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Portuguese;++use Doctrine\Inflector\Rules\Pattern;++final class Uninflected+{+ /** @return Pattern[] */+ public static function getSingular(): iterable+ {+ yield from self::getDefault();+ }++ /** @return Pattern[] */+ public static function getPlural(): iterable+ {+ yield from self::getDefault();+ }++ /** @return Pattern[] */+ private static function getDefault(): iterable+ {+ yield new Pattern('tórax');+ yield new Pattern('tênis');+ yield new Pattern('ônibus');+ yield new Pattern('lápis');+ yield new Pattern('fênix');+ }+}
Vulnerability Existed: no Analysis of the provided code diff: This is a new file being added to the codebase containing a PHP class for Portuguese language inflection rules. The file is part of the Doctrine Inflector library and follows standard patterns for defining uninflected words. **Security Assessment:** The code does not contain any security vulnerabilities. This is a simple data class that: 1. Follows proper namespace conventions 2. Uses type declarations (`declare(strict_types=1)`) 3. Contains only static methods that yield `Pattern` objects with hardcoded string literals 4. Has no user input processing, no database queries, no file operations, or external data handling 5. Uses proper access modifiers (private/public) 6. Contains no dynamic code execution, string evaluation, or reflection The pattern used (yielding Pattern objects with Portuguese words) is a safe, intentional design pattern for language inflection rules and presents no OWASP Top 10 vulnerabilities such as injection, XSS, authentication issues, or sensitive data exposure.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Ruleset.php@@ -0,0 +1,39 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules;++class Ruleset+{+ /** @var Transformations */+ private $regular;++ /** @var Patterns */+ private $uninflected;++ /** @var Substitutions */+ private $irregular;++ public function __construct(Transformations $regular, Patterns $uninflected, Substitutions $irregular)+ {+ $this->regular = $regular;+ $this->uninflected = $uninflected;+ $this->irregular = $irregular;+ }++ public function getRegular(): Transformations+ {+ return $this->regular;+ }++ public function getUninflected(): Patterns+ {+ return $this->uninflected;+ }++ public function getIrregular(): Substitutions+ {+ return $this->irregular;+ }+}
Vulnerability Existed: no No Vulnerabilities Detected - File [vendor/doctrine/inflector/src/Rules/Ruleset.php] Explanation: This is a new file containing a simple PHP class definition for `Ruleset` in the Doctrine Inflector library. The file implements a straightforward data container pattern with: 1. **Private properties** - Proper encapsulation with private visibility modifiers 2. **Type declarations** - Uses PHP 7.1+ type hints for constructor parameters and return types 3. **Simple getters** - No complex logic, filtering, or data transformation that could introduce vulnerabilities 4. **No external input handling** - The class merely stores and retrieves dependency-injected objects 5. **No database queries** - No SQL injection vectors 6. **No output rendering** - No XSS vectors 7. **No file operations** - No path traversal or file inclusion risks 8. **No deserialization** - No object injection risks This is a standard dependency container class with no identifiable security vulnerabilities. The strict type declarations (`declare(strict_types=1)`) even enhance security by preventing type juggling attacks.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Spanish/Inflectible.php@@ -0,0 +1,47 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Spanish;++use Doctrine\Inflector\Rules\Pattern;+use Doctrine\Inflector\Rules\Substitution;+use Doctrine\Inflector\Rules\Transformation;+use Doctrine\Inflector\Rules\Word;++class Inflectible+{+ /** @return Transformation[] */+ public static function getSingular(): iterable+ {+ yield new Transformation(new Pattern('/ereses$/'), 'erés');+ yield new Transformation(new Pattern('/iones$/'), 'ión');+ yield new Transformation(new Pattern('/ces$/'), 'z');+ yield new Transformation(new Pattern('/es$/'), '');+ yield new Transformation(new Pattern('/s$/'), '');+ }++ /** @return Transformation[] */+ public static function getPlural(): iterable+ {+ yield new Transformation(new Pattern('/ú([sn])$/i'), 'u\1es');+ yield new Transformation(new Pattern('/ó([sn])$/i'), 'o\1es');+ yield new Transformation(new Pattern('/í([sn])$/i'), 'i\1es');+ yield new Transformation(new Pattern('/é([sn])$/i'), 'e\1es');+ yield new Transformation(new Pattern('/á([sn])$/i'), 'a\1es');+ yield new Transformation(new Pattern('/z$/i'), 'ces');+ yield new Transformation(new Pattern('/([aeiou]s)$/i'), '\1');+ yield new Transformation(new Pattern('/([^aeéiou])$/i'), '\1es');+ yield new Transformation(new Pattern('/$/'), 's');+ }++ /** @return Substitution[] */+ public static function getIrregular(): iterable+ {+ yield new Substitution(new Word('el'), new Word('los'));+ yield new Substitution(new Word('papá'), new Word('papás'));+ yield new Substitution(new Word('mamá'), new Word('mamás'));+ yield new Substitution(new Word('sofá'), new Word('sofás'));+ yield new Substitution(new Word('mes'), new Word('meses'));+ }+}
Vulnerability Existed: no This is a new file addition containing Spanish language inflection rules for the Doctrine Inflector library. The code consists of: 1. Static methods returning iterables of `Transformation` and `Substitution` objects 2. Regular expressions for singular/plural word transformations 3. Irregular word mappings **Security Analysis:** - **No Input Validation Issues**: The regular expression patterns are hardcoded string literals, not constructed from user input - **No Code Injection**: The patterns are used within the Doctrine Inflector framework which properly escapes and validates regex patterns - **No SQL Injection**: No database operations present - **No Path Traversal**: No file system operations - **No Authentication/Authorization Issues**: This is a utility class with no security-sensitive operations - **No Information Disclosure**: No sensitive data exposure The code follows safe practices by: - Using `declare(strict_types=1)` for type safety - Using immutable objects (`Pattern`, `Word`, `Substitution`, `Transformation`) - Containing only static, deterministic transformations - Having no external dependencies or side effects **Conclusion**: This is a straightforward library addition with no security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Spanish/InflectorFactory.php@@ -0,0 +1,21 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Spanish;++use Doctrine\Inflector\GenericLanguageInflectorFactory;+use Doctrine\Inflector\Rules\Ruleset;++final class InflectorFactory extends GenericLanguageInflectorFactory+{+ protected function getSingularRuleset(): Ruleset+ {+ return Rules::getSingularRuleset();+ }++ protected function getPluralRuleset(): Ruleset+ {+ return Rules::getPluralRuleset();+ }+}
Vulnerability Existed: no No vulnerabilities detected. Explanation: This is a new file addition containing a Spanish language inflector factory class for the Doctrine Inflector library. The code: 1. **Properly uses namespacing** - Follows PSR-4 standards with declared namespace 2. **Uses type declarations** - `declare(strict_types=1)` enforces strict typing 3. **Inherits from a secure parent class** - Extends `GenericLanguageInflectorFactory` which handles the core logic 4. **No user input handling** - This is a factory class that only returns ruleset objects; it doesn't process any external input 5. **No vulnerable functions** - No use of eval(), exec(), file operations without validation, or other dangerous functions 6. **Proper visibility modifiers** - Methods are correctly marked as `protected` 7. **No SQL/command injection vectors** - The class only calls static methods on the Rules class This is a straightforward, safe utility class with no security vulnerabilities. It's part of a standard translation/inflection library used for language-specific text processing.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Spanish/Rules.php@@ -0,0 +1,31 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Spanish;++use Doctrine\Inflector\Rules\Patterns;+use Doctrine\Inflector\Rules\Ruleset;+use Doctrine\Inflector\Rules\Substitutions;+use Doctrine\Inflector\Rules\Transformations;++final class Rules+{+ public static function getSingularRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getSingular()),+ new Patterns(...Uninflected::getSingular()),+ (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()+ );+ }++ public static function getPluralRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getPlural()),+ new Patterns(...Uninflected::getPlural()),+ new Substitutions(...Inflectible::getIrregular())+ );+ }+}
Vulnerability Existed: no This is a new file addition containing a simple PHP class for Spanish language inflection rules. It does not introduce any security vulnerabilities. Explanation: The code is a straightforward utility class that provides static methods to return Ruleset objects for singular and plural form transformations. There are no security issues present: 1. **No input validation concerns** - The class doesn't accept user input; it only returns pre-defined Ruleset objects. 2. **No injection vulnerabilities** - No dynamic code execution, SQL queries, or command invocations. 3. **No access control issues** - This is a simple utility class with static factory methods. 4. **No sensitive data exposure** - The class only handles linguistic transformation rules. 5. **Type safety** - The code uses `declare(strict_types=1)` which is a security best practice. 6. **No deserialization risks** - No serialization or deserialization of untrusted data. This is a benign addition to a legitimate Doctrine Inflector library component and presents no security risks.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Spanish/Uninflected.php@@ -0,0 +1,30 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Spanish;++use Doctrine\Inflector\Rules\Pattern;++final class Uninflected+{+ /** @return Pattern[] */+ public static function getSingular(): iterable+ {+ yield from self::getDefault();+ }++ /** @return Pattern[] */+ public static function getPlural(): iterable+ {+ yield from self::getDefault();+ }++ /** @return Pattern[] */+ private static function getDefault(): iterable+ {+ yield new Pattern('lunes');+ yield new Pattern('rompecabezas');+ yield new Pattern('crisis');+ }+}
Vulnerability Existed: no
No CWE Vulnerability Detected - vendor/doctrine/inflector/src/Rules/Spanish/Uninflected.php (Lines 1-30)
Old Code:
[File did not exist - new file creation]
Fixed Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\Spanish;
use Doctrine\Inflector\Rules\Pattern;
final class Uninflected
{
/** @return Pattern[] */
public static function getSingular(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
public static function getPlural(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
private static function getDefault(): iterable
{
yield new Pattern('lunes');
yield new Pattern('rompecabezas');
yield new Pattern('crisis');
}
}
```
Explanation:
This is a new file addition containing a PHP class that defines Spanish language inflection rules for uninflected words. The code:
1. Uses proper type declarations (`declare(strict_types=1)`)
2. Defines a final class with private constructor prevention (implicit through final class)
3. Uses typed return hints (`iterable`)
4. Yields Pattern objects safely without any user input
5. Has no dynamic code execution, SQL queries, or external input handling
6. Follows PSR-12 coding standards
There are no security vulnerabilities in this code. It is a static configuration class for the Doctrine Inflector library with no attack surface.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Substitution.php@@ -0,0 +1,30 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules;++final class Substitution+{+ /** @var Word */+ private $from;++ /** @var Word */+ private $to;++ public function __construct(Word $from, Word $to)+ {+ $this->from = $from;+ $this->to = $to;+ }++ public function getFrom(): Word+ {+ return $this->from;+ }++ public function getTo(): Word+ {+ return $this->to;+ }+}
Vulnerability Existed: no This is a new file addition containing a simple PHP class with no security vulnerabilities. Explanation: The `Substitution` class is a basic data transfer object (DTO) that stores two `Word` objects and provides getter methods. The code exhibits no security issues: 1. **No user input processing**: The class simply stores and retrieves objects passed to its constructor. There is no direct user input handling. 2. **Type safety**: Strict type declarations (`declare(strict_types=1)`) and type hints (`Word $from, Word $to`) are properly used, preventing type confusion attacks. 3. **No data exposure**: The class uses private properties with public getters, providing proper encapsulation. 4. **No dangerous operations**: No file operations, database queries, deserialization, or other potentially dangerous operations are present. 5. **No injection vectors**: There are no string concatenations, template operations, or dynamic code execution. This is a benign utility class from the Doctrine Inflector library with no security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Substitutions.php@@ -0,0 +1,57 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules;++use Doctrine\Inflector\WordInflector;++use function strtolower;+use function strtoupper;+use function substr;++class Substitutions implements WordInflector+{+ /** @var Substitution[] */+ private $substitutions;++ public function __construct(Substitution ...$substitutions)+ {+ foreach ($substitutions as $substitution) {+ $this->substitutions[$substitution->getFrom()->getWord()] = $substitution;+ }+ }++ public function getFlippedSubstitutions(): Substitutions+ {+ $substitutions = [];++ foreach ($this->substitutions as $substitution) {+ $substitutions[] = new Substitution(+ $substitution->getTo(),+ $substitution->getFrom()+ );+ }++ return new Substitutions(...$substitutions);+ }++ public function inflect(string $word): string+ {+ $lowerWord = strtolower($word);++ if (isset($this->substitutions[$lowerWord])) {+ $firstLetterUppercase = $lowerWord[0] !== $word[0];++ $toWord = $this->substitutions[$lowerWord]->getTo()->getWord();++ if ($firstLetterUppercase) {+ return strtoupper($toWord[0]) . substr($toWord, 1);+ }++ return $toWord;+ }++ return $word;+ }+}
Vulnerability Existed: no No Security Vulnerabilities Identified - vendor/doctrine/inflector/src/Rules/Substitutions.php [Lines 1-57] Old Code: N/A (New file) Fixed Code: N/A (New file) Explanation: This is a newly added file containing a word inflection utility class from the Doctrine Inflector library. The code implements a substitution-based word inflector with the following characteristics: 1. **Input Handling**: The `inflect()` method accepts a string parameter and performs case-insensitive lookups using `strtolower()`. String operations (`substr()`, `strtoupper()`) are used safely on the input without concatenation with external data. 2. **No User Input Injection Points**: The class operates on string substitutions defined in its constructor. All substitutions come from internal instantiation, not from external/user input sources. 3. **No Direct SQL/Command Injection**: There are no database queries, system command executions, or shell operations. 4. **No Unsafe Deserialization**: No serialization/deserialization of untrusted data. 5. **Proper Array Access**: String indexing (`$lowerWord[0]`, `$toWord[0]`) is safe in PHP for non-empty strings. The code checks string existence with `isset()` before access. 6. **No Path Traversal**: No file operations or path manipulation. This is a standard library utility file with no apparent security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Transformation.php@@ -0,0 +1,39 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules;++use Doctrine\Inflector\WordInflector;++use function preg_replace;++final class Transformation implements WordInflector+{+ /** @var Pattern */+ private $pattern;++ /** @var string */+ private $replacement;++ public function __construct(Pattern $pattern, string $replacement)+ {+ $this->pattern = $pattern;+ $this->replacement = $replacement;+ }++ public function getPattern(): Pattern+ {+ return $this->pattern;+ }++ public function getReplacement(): string+ {+ return $this->replacement;+ }++ public function inflect(string $word): string+ {+ return (string) preg_replace($this->pattern->getRegex(), $this->replacement, $word);+ }+}
Vulnerability Existed: not sure
Regex Injection / Improper Input Validation - CWE-1025 / CWE-94 - vendor/doctrine/inflector/src/Rules/Transformation.php Lines 36-37
Old Code:
[File is new, no old code to compare]
Fixed Code:
```php
public function inflect(string $word): string
{
return (string) preg_replace($this->pattern->getRegex(), $this->replacement, $word);
}
```
Explanation:
This is a new file addition (not a fix), so vulnerability classification as "existed" doesn't apply. However, there is a potential security concern: the `preg_replace()` function on line 37 uses `$this->replacement` directly without validation. If the replacement string contains special regex backreferences (like `$1`, `${1}`, or `\1`), it could cause unintended behavior. Additionally, if `$this->pattern->getRegex()` is not properly validated elsewhere, it could accept arbitrary regex patterns. The code assumes both `getRegex()` and the replacement string are safe, but without seeing the Pattern class implementation and how the Transformation object is instantiated, it's uncertain whether adequate input validation occurs upstream. This is a dependency-based concern rather than a direct vulnerability in this file.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Transformations.php@@ -0,0 +1,29 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules;++use Doctrine\Inflector\WordInflector;++class Transformations implements WordInflector+{+ /** @var Transformation[] */+ private $transformations;++ public function __construct(Transformation ...$transformations)+ {+ $this->transformations = $transformations;+ }++ public function inflect(string $word): string+ {+ foreach ($this->transformations as $transformation) {+ if ($transformation->getPattern()->matches($word)) {+ return $transformation->inflect($word);+ }+ }++ return $word;+ }+}
Vulnerability Existed: no No Security Vulnerabilities Detected Explanation: This is a new PHP file containing a class implementation for word inflection using the Doctrine Inflector library. The code follows standard object-oriented design patterns with: 1. **Type Safety**: Uses strict types declaration and type hints (string return type, Transformation[] type hint) 2. **Encapsulation**: Private property with controlled access through constructor 3. **Safe Logic Flow**: Simple iteration through transformations with pattern matching - no user input directly processed 4. **No External Input Handling**: The inflection logic operates on passed-in objects, not raw user input 5. **No Dynamic Code Execution**: No eval(), dynamic function calls, or unsafe string interpolation This is a well-structured library class with no apparent security vulnerabilities. The code is part of the Doctrine Inflector dependency and implements a straightforward word transformation pattern without any risky operations.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Turkish/Inflectible.php@@ -0,0 +1,34 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Turkish;++use Doctrine\Inflector\Rules\Pattern;+use Doctrine\Inflector\Rules\Substitution;+use Doctrine\Inflector\Rules\Transformation;+use Doctrine\Inflector\Rules\Word;++class Inflectible+{+ /** @return Transformation[] */+ public static function getSingular(): iterable+ {+ yield new Transformation(new Pattern('/l[ae]r$/i'), '');+ }++ /** @return Transformation[] */+ public static function getPlural(): iterable+ {+ yield new Transformation(new Pattern('/([eöiü][^aoıueöiü]{0,6})$/u'), '\1ler');+ yield new Transformation(new Pattern('/([aoıu][^aoıueöiü]{0,6})$/u'), '\1lar');+ }++ /** @return Substitution[] */+ public static function getIrregular(): iterable+ {+ yield new Substitution(new Word('ben'), new Word('biz'));+ yield new Substitution(new Word('sen'), new Word('siz'));+ yield new Substitution(new Word('o'), new Word('onlar'));+ }+}
Vulnerability Existed: no No vulnerabilities detected in this code diff. Explanation: This is a new file addition containing a PHP class that defines Turkish language inflection rules for the Doctrine Inflector library. The code: 1. **Proper namespace and class structure** - Uses appropriate PHP namespacing and class declaration 2. **Type declarations** - Includes proper type hints (`iterable` return types) for better type safety 3. **Safe regex patterns** - The regex patterns are used for linguistic transformations (pluralization/singularization) and are not user-controlled or dynamically constructed from untrusted input 4. **No external input** - The class only uses hardcoded patterns and strings; there is no processing of user input that could lead to injection vulnerabilities 5. **Immutable data structures** - Uses immutable objects (Pattern, Substitution, Transformation, Word) which are instantiated with static values 6. **No dynamic code execution** - No use of `eval()`, `assert()`, or similar dangerous functions 7. **Appropriate visibility** - All methods are public static, which is intentional for a utility class providing language rules The code is a standard library component with no security concerns.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Turkish/InflectorFactory.php@@ -0,0 +1,21 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Turkish;++use Doctrine\Inflector\GenericLanguageInflectorFactory;+use Doctrine\Inflector\Rules\Ruleset;++final class InflectorFactory extends GenericLanguageInflectorFactory+{+ protected function getSingularRuleset(): Ruleset+ {+ return Rules::getSingularRuleset();+ }++ protected function getPluralRuleset(): Ruleset+ {+ return Rules::getPluralRuleset();+ }+}
``` Vulnerability Existed: no Analysis: This is a new file addition (not a modification of existing code) containing a factory class for Turkish language inflection rules in the Doctrine Inflector library. The code follows standard object-oriented design patterns: - Proper namespace declaration - Extends GenericLanguageInflectorFactory - Implements required abstract methods (getSingularRuleset, getPluralRuleset) - Delegates to Rules class for ruleset retrieval - Uses proper PHP type declarations No security vulnerabilities are present in this code: - No user input is processed - No file operations or system calls - No SQL queries or database interactions - No external data handling - No authentication/authorization logic - Standard factory pattern implementation with no injection points This is a benign library addition with no security implications. ```
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Turkish/Rules.php@@ -0,0 +1,31 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Turkish;++use Doctrine\Inflector\Rules\Patterns;+use Doctrine\Inflector\Rules\Ruleset;+use Doctrine\Inflector\Rules\Substitutions;+use Doctrine\Inflector\Rules\Transformations;++final class Rules+{+ public static function getSingularRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getSingular()),+ new Patterns(...Uninflected::getSingular()),+ (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()+ );+ }++ public static function getPluralRuleset(): Ruleset+ {+ return new Ruleset(+ new Transformations(...Inflectible::getPlural()),+ new Patterns(...Uninflected::getPlural()),+ new Substitutions(...Inflectible::getIrregular())+ );+ }+}
Vulnerability Existed: no
No Vulnerabilities Detected - [N/A] - vendor/doctrine/inflector/src/Rules/Turkish/Rules.php [1-31]
Old Code: N/A (file creation)
Fixed Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules\Turkish;
use Doctrine\Inflector\Rules\Patterns;
use Doctrine\Inflector\Rules\Ruleset;
use Doctrine\Inflector\Rules\Substitutions;
use Doctrine\Inflector\Rules\Transformations;
final class Rules
{
public static function getSingularRuleset(): Ruleset
{
return new Ruleset(
new Transformations(...Inflectible::getSingular()),
new Patterns(...Uninflected::getSingular()),
(new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()
);
}
public static function getPluralRuleset(): Ruleset
{
return new Ruleset(
new Transformations(...Inflectible::getPlural()),
new Patterns(...Uninflected::getPlural()),
new Substitutions(...Inflectible::getIrregular())
);
}
}
```
Explanation:
This is a new file addition (not a fix) containing a utility class for Turkish language inflection rules. The code is straightforward library functionality with no security vulnerabilities. It uses type declarations, proper namespacing, dependency injection through constructor parameters, and follows standard PHP practices. There are no input validation issues, injection vulnerabilities, or other security concerns present in this code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Turkish/Uninflected.php@@ -0,0 +1,30 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules\Turkish;++use Doctrine\Inflector\Rules\Pattern;++final class Uninflected+{+ /** @return Pattern[] */+ public static function getSingular(): iterable+ {+ yield from self::getDefault();+ }++ /** @return Pattern[] */+ public static function getPlural(): iterable+ {+ yield from self::getDefault();+ }++ /** @return Pattern[] */+ private static function getDefault(): iterable+ {+ yield new Pattern('lunes');+ yield new Pattern('rompecabezas');+ yield new Pattern('crisis');+ }+}
Vulnerability Existed: no No Security Vulnerabilities Detected Explanation: This is a new PHP file being added to the codebase containing a class definition for Turkish language inflection rules in the Doctrine Inflector library. The code: 1. Uses proper namespace declaration following PSR standards 2. Implements type declarations (`declare(strict_types=1)`) 3. Contains only static methods that yield Pattern objects 4. Has no user input handling, database queries, file operations, or external API calls 5. Contains no dynamic code execution, command injection vectors, or unsafe serialization 6. Uses immutable Pattern objects with hardcoded string values 7. Follows defensive programming practices with proper access modifiers (private for internal methods) This is a data-only configuration file with no executable logic that could be exploited. There are no OWASP Top 10 vulnerabilities, injection attacks, authentication/authorization issues, or other security concerns present in this code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/Rules/Word.php@@ -0,0 +1,21 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector\Rules;++class Word+{+ /** @var string */+ private $word;++ public function __construct(string $word)+ {+ $this->word = $word;+ }++ public function getWord(): string+ {+ return $this->word;+ }+}
Vulnerability Existed: no
**No Vulnerabilities Detected** - File: vendor/doctrine/inflector/src/Rules/Word.php [Lines 1-21]
Old Code:
N/A (new file)
Fixed Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector\Rules;
class Word
{
/** @var string */
private $word;
public function __construct(string $word)
{
$this->word = $word;
}
public function getWord(): string
{
return $this->word;
}
}
```
Explanation:
This is a new file addition containing a simple, well-designed PHP class from the Doctrine Inflector library. The code implements a basic value object pattern with:
- Proper type declarations (`declare(strict_types=1)`)
- Type-hinted constructor parameter (`string $word`)
- Type-hinted return value (`string`)
- Private property with controlled access through a getter method
- No user input handling, external dependencies, or unsafe operations
There are no security vulnerabilities in this code. It follows PHP best practices and represents secure, defensive coding patterns.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/RulesetInflector.php@@ -0,0 +1,56 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector;++use Doctrine\Inflector\Rules\Ruleset;++use function array_merge;++/**+ * Inflects based on multiple rulesets.+ *+ * Rules:+ * - If the word matches any uninflected word pattern, it is not inflected+ * - The first ruleset that returns a different value for an irregular word wins+ * - The first ruleset that returns a different value for a regular word wins+ * - If none of the above match, the word is left as-is+ */+class RulesetInflector implements WordInflector+{+ /** @var Ruleset[] */+ private $rulesets;++ public function __construct(Ruleset $ruleset, Ruleset ...$rulesets)+ {+ $this->rulesets = array_merge([$ruleset], $rulesets);+ }++ public function inflect(string $word): string+ {+ if ($word === '') {+ return '';+ }++ foreach ($this->rulesets as $ruleset) {+ if ($ruleset->getUninflected()->matches($word)) {+ return $word;+ }++ $inflected = $ruleset->getIrregular()->inflect($word);++ if ($inflected !== $word) {+ return $inflected;+ }++ $inflected = $ruleset->getRegular()->inflect($word);++ if ($inflected !== $word) {+ return $inflected;+ }+ }++ return $word;+ }+}
Vulnerability Existed: no No CWE Vulnerabilities Identified Explanation: This is a new file containing a straightforward utility class for word inflection based on multiple rulesets. The code follows standard PHP practices with: 1. **Type Safety**: Uses strict types declaration and proper type hints (string return, Ruleset parameters, array operations) 2. **Input Validation**: Checks for empty string input early and returns safely 3. **No External Input Processing**: The inflect() method only processes internal word strings through predefined ruleset operations 4. **No Dangerous Functions**: Uses only safe array operations (array_merge) and method calls on controlled objects 5. **No SQL/Command Injection Vectors**: No database queries, shell commands, or dynamic code execution 6. **Encapsulation**: Proper access modifiers and immutable state after construction 7. **Safe Iteration**: Simple foreach loop over stored ruleset objects with no external data sources The code is a clean implementation of the WordInflector interface with no apparent security vulnerabilities. It's a supporting utility class for linguistic word transformation that poses no security risk.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/doctrine/inflector/src/WordInflector.php@@ -0,0 +1,10 @@+<?php++declare(strict_types=1);++namespace Doctrine\Inflector;++interface WordInflector+{+ public function inflect(string $word): string;+}
Vulnerability Existed: no
No Vulnerabilities Detected - [N/A] - vendor/doctrine/inflector/src/WordInflector.php [1-10]
Old Code: N/A (new file)
Fixed Code:
```php
<?php
declare(strict_types=1);
namespace Doctrine\Inflector;
interface WordInflector
{
public function inflect(string $word): string;
}
```
Explanation:
This is a new file containing a simple PHP interface definition for the Doctrine Inflector library. The code is straightforward and secure:
- It declares a simple interface with a single method signature
- The method has proper type hints (string input and return type)
- There are no dynamic code execution, unsanitized inputs, SQL queries, file operations, or other common vulnerability vectors
- The code follows PHP best practices with strict types declaration
- This is vendor code (Doctrine library) which is a well-maintained third-party dependency
No security vulnerabilities are present in this code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/BodySummarizer.php 2025-12-21 09:35:59.453067558 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/BodySummarizer.php 2025-12-21 09:36:35.271293771 +0000@@ -11,7 +11,7 @@ */ private $truncateAt; - public function __construct(int $truncateAt = null)+ public function __construct(?int $truncateAt = null) { $this->truncateAt = $truncateAt; }@@ -22,7 +22,7 @@ public function summarize(MessageInterface $message): ?string { return $this->truncateAt === null- ? \GuzzleHttp\Psr7\Message::bodySummary($message)- : \GuzzleHttp\Psr7\Message::bodySummary($message, $this->truncateAt);+ ? Psr7\Message::bodySummary($message)+ : Psr7\Message::bodySummary($message, $this->truncateAt); } }
Vulnerability Existed: no Type Hint Declaration - Not a Security Vulnerability - vendor/guzzlehttp/guzzle/src/BodySummarizer.php Lines 14 [Old Code] public function __construct(int $truncateAt = null) [Fixed Code] public function __construct(?int $truncateAt = null) Explanation: This change updates the type hint syntax from PHP 7.0 style (int with null default) to PHP 7.1+ nullable type hint syntax (?int). This is a code quality improvement for proper type declaration, not a security fix. The change ensures the type hint accurately reflects that null is an accepted value, improving IDE support and static analysis tools. This does not address any security vulnerability. --- Vulnerability Existed: no Namespace Import Simplification - Not a Security Vulnerability - vendor/guzzlehttp/guzzle/src/BodySummarizer.php Lines 25-26 [Old Code] ? \GuzzleHttp\Psr7\Message::bodySummary($message) : \GuzzleHttp\Psr7\Message::bodySummary($message, $this->truncateAt); [Fixed Code] ? Psr7\Message::bodySummary($message) : Psr7\Message::bodySummary($message, $this->truncateAt); Explanation: This change replaces fully qualified namespace paths (\GuzzleHttp\Psr7\Message) with a shorter namespace reference (Psr7\Message), indicating an import statement was likely added at the top of the file. This is a code maintainability improvement, not a security fix. The functionality remains identical and no security vulnerability is addressed or introduced.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Client.php 2025-12-21 09:35:59.453067558 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Client.php 2025-12-21 09:36:35.271293771 +0000@@ -52,7 +52,7 @@ * * @param array $config Client configuration settings. *- * @see \GuzzleHttp\RequestOptions for a list of available request options.+ * @see RequestOptions for a list of available request options. */ public function __construct(array $config = []) {
Vulnerability Existed: no
**No Security Vulnerability** - File: vendor/guzzlehttp/guzzle/src/Client.php [Line 55]
Old Code:
```php
* @see \GuzzleHttp\RequestOptions for a list of available request options.
```
Fixed Code:
```php
* @see RequestOptions for a list of available request options.
```
Explanation:
This change is a documentation/comment-only modification that removes the fully-qualified namespace from a PHPDoc `@see` annotation. This is not a security fix and does not address any vulnerability. It is simply a stylistic change to the inline documentation that removes the explicit namespace prefix `\GuzzleHttp\` from the class reference. This type of change has no security implications, as it only affects how the documentation is formatted and displayed, not the actual code logic or behavior.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php 2025-12-21 09:35:59.453067558 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php 2025-12-21 09:36:35.271293771 +0000@@ -96,9 +96,6 @@ return null; } - /**- * {@inheritDoc}- */ public function toArray(): array { return \array_map(static function (SetCookie $cookie): array {@@ -106,9 +103,6 @@ }, $this->getIterator()->getArrayCopy()); } - /**- * {@inheritDoc}- */ public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void { if (!$domain) {@@ -126,25 +120,22 @@ $this->cookies = \array_filter( $this->cookies, static function (SetCookie $cookie) use ($path, $domain): bool {- return !($cookie->matchesPath($path) &&- $cookie->matchesDomain($domain));+ return !($cookie->matchesPath($path)+ && $cookie->matchesDomain($domain)); } ); } else { $this->cookies = \array_filter( $this->cookies, static function (SetCookie $cookie) use ($path, $domain, $name) {- return !($cookie->getName() == $name &&- $cookie->matchesPath($path) &&- $cookie->matchesDomain($domain));+ return !($cookie->getName() == $name+ && $cookie->matchesPath($path)+ && $cookie->matchesDomain($domain)); } ); } } - /**- * {@inheritDoc}- */ public function clearSessionCookies(): void { $this->cookies = \array_filter(@@ -155,9 +146,6 @@ ); } - /**- * {@inheritDoc}- */ public function setCookie(SetCookie $cookie): bool { // If the name string is empty (but not 0), ignore the set-cookie@@ -182,9 +170,9 @@ foreach ($this->cookies as $i => $c) { // Two cookies are identical, when their path, and domain are // identical.- if ($c->getPath() != $cookie->getPath() ||- $c->getDomain() != $cookie->getDomain() ||- $c->getName() != $cookie->getName()+ if ($c->getPath() != $cookie->getPath()+ || $c->getDomain() != $cookie->getDomain()+ || $c->getName() != $cookie->getName() ) { continue; }@@ -255,7 +243,7 @@ /** * Computes cookie path following RFC 6265 section 5.1.4 *- * @see https://tools.ietf.org/html/rfc6265#section-5.1.4+ * @see https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4 */ private function getCookiePathFromRequest(RequestInterface $request): string {@@ -286,10 +274,10 @@ $path = $uri->getPath() ?: '/'; foreach ($this->cookies as $cookie) {- if ($cookie->matchesPath($path) &&- $cookie->matchesDomain($host) &&- !$cookie->isExpired() &&- (!$cookie->getSecure() || $scheme === 'https')+ if ($cookie->matchesPath($path)+ && $cookie->matchesDomain($host)+ && !$cookie->isExpired()+ && (!$cookie->getSecure() || $scheme === 'https') ) { $values[] = $cookie->getName().'=' .$cookie->getValue();
Vulnerability Existed: no
No Security Vulnerabilities Detected - Code Style Changes Only
This diff contains only non-security-related changes to the CookieJar.php file:
1. **Removed PHPDoc comments** - Deletion of `{@inheritDoc}` documentation blocks (lines 99-101, 106-108, 129-131, 149-151, 158-160) - purely documentation cleanup with no security impact.
2. **Code formatting/style changes** - Reformatting of logical operators and conditions for improved readability:
- Line 123-124: Moved `&&` operator from end of line to start of next line
- Line 132-134: Same formatting adjustment for multi-line condition
- Line 173-175: Reformatted `||` operators similarly
- Line 277-280: Reformatted `&&` operators similarly
3. **Documentation URL update** - Line 246: Updated RFC 6265 reference URL from deprecated `tools.ietf.org` to current `datatracker.ietf.org` format - this is a documentation improvement, not a security fix.
**Explanation:**
These changes are purely stylistic and documentation updates. The logical conditions remain functionally identical - only their formatting on multiple lines has changed. No security vulnerabilities were fixed or introduced. The code's cookie filtering, domain/path matching, and security checks remain unchanged in their logic and behavior.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php 2025-12-21 09:35:59.453067558 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php 2025-12-21 09:36:35.271293771 +0000@@ -14,6 +14,7 @@ * cookies from a file, database, etc. * * @see https://docs.python.org/2/library/cookielib.html Inspiration+ * * @extends \IteratorAggregate<SetCookie> */ interface CookieJarInterface extends \Countable, \IteratorAggregate
Vulnerability Existed: no No Security Vulnerability Detected - [N/A] - vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php [17] Old Code: ```php * @see https://docs.python.org/2/library/cookielib.html Inspiration * @extends \IteratorAggregate<SetCookie> ``` Fixed Code: ```php * @see https://docs.python.org/2/library/cookielib.html Inspiration * * @extends \IteratorAggregate<SetCookie> ``` Explanation: This diff shows a purely cosmetic change to the PHPDoc comment block - adding a blank line between the `@see` tag and the `@extends` tag. This is a documentation/formatting improvement with no security implications. No vulnerability exists in the old code, and none is being fixed. This change has no impact on code behavior, security posture, or vulnerability remediation.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php 2025-12-21 09:35:59.453067558 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php 2025-12-21 09:36:35.271293771 +0000@@ -62,6 +62,10 @@ if (is_numeric($value)) { $data[$search] = (int) $value; }+ } elseif ($search === 'Secure' || $search === 'Discard' || $search === 'HttpOnly') {+ if ($value) {+ $data[$search] = true;+ } } else { $data[$search] = $value; }@@ -420,7 +424,7 @@ } // Remove the leading '.' as per spec in RFC 6265.- // https://tools.ietf.org/html/rfc6265#section-5.2.3+ // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3 $cookieDomain = \ltrim(\strtolower($cookieDomain), '.'); $domain = \strtolower($domain);@@ -431,7 +435,7 @@ } // Matching the subdomain according to RFC 6265.- // https://tools.ietf.org/html/rfc6265#section-5.1.3+ // https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.3 if (\filter_var($domain, \FILTER_VALIDATE_IP)) { return false; }
Vulnerability Existed: no
CWE Name: Improper Restriction of Rendered UI Layers or Frames - CWE-1021 (related to cookie security attributes)
File: vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
Lines: 65-68
Old Code:
```
} else {
$data[$search] = $value;
}
```
Fixed Code:
```
} elseif ($search === 'Secure' || $search === 'Discard' || $search === 'HttpOnly') {
if ($value) {
$data[$search] = true;
}
} else {
$data[$search] = $value;
}
```
Explanation:
This change enhances security handling of critical HTTP cookie attributes (Secure, HttpOnly, Discard). Previously, these boolean flags were assigned string values directly from parsing, which could lead to truthy/falsy evaluation issues. The fix ensures these security-critical attributes are explicitly set to boolean `true` only when the value is truthy, preventing potential cookie security bypass scenarios where these flags might be incorrectly evaluated. This is a security hardening improvement rather than fixing an existing vulnerability, as it prevents potential mishandling of these critical attributes.
---
Vulnerability Existed: no
CWE Name: Use of Broken or Risky Cryptographic Algorithm - CWE-327 (indirectly related to RFC compliance)
File: vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
Lines: 427, 438
Old Code:
```
// https://tools.ietf.org/html/rfc6265#section-5.2.3
// https://tools.ietf.org/html/rfc6265#section-5.1.3
```
Fixed Code:
```
// https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3
// https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.3
```
Explanation:
This is a documentation/reference update only, not a security vulnerability fix. The URLs are being updated to point to the current IETF datatracker canonical location instead of the legacy tools.ietf.org domain. This maintains RFC 6265 compliance references but does not fix any actual security vulnerability in the code logic itself. It is a maintenance improvement for documentation accuracy.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php 2025-12-21 09:35:59.453067558 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php 2025-12-21 09:36:35.271293771 +0000@@ -14,7 +14,7 @@ string $message, RequestInterface $request, ResponseInterface $response,- \Throwable $previous = null,+ ?\Throwable $previous = null, array $handlerContext = [] ) { parent::__construct($message, $request, $response, $previous, $handlerContext);
``` Vulnerability Existed: no Type Mismatch / Type Declaration - No CWE - vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php [Line 17] Old Code: \Throwable $previous = null, Fixed Code: ?\Throwable $previous = null, Explanation: This change is not a security fix but rather a PHP type declaration improvement. The modification changes the parameter type from `\Throwable $previous = null` to `?\Throwable $previous = null` (nullable type). This is a type safety improvement that properly declares the parameter as nullable using PHP 7.1+ syntax, making the type declaration match the default value of `null`. This prevents potential type checking issues and improves code clarity, but it is not addressing a security vulnerability. ```
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php 2025-12-21 09:35:59.453067558 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php 2025-12-21 09:36:35.271293771 +0000@@ -25,7 +25,7 @@ public function __construct( string $message, RequestInterface $request,- \Throwable $previous = null,+ ?\Throwable $previous = null, array $handlerContext = [] ) { parent::__construct($message, 0, $previous);
Vulnerability Existed: no [Type Declaration Enhancement] - [No CWE] - [vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php] [Line 28] Old Code: ```php \Throwable $previous = null, ``` Fixed Code: ```php ?\Throwable $previous = null, ``` Explanation: This change adds nullable type declaration (`?`) to the `$previous` parameter, which is a type safety improvement rather than a security fix. The parameter already had a default value of `null`, but now the type declaration explicitly reflects this nullable possibility using PHP 7.1+ nullable type syntax. This is not fixing a vulnerability but rather improving type safety and code clarity. The change makes the code more type-safe and helps IDEs and static analysis tools better understand the intended types, reducing potential type-related bugs, but no security vulnerability existed in the original code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php 2025-12-21 09:35:59.453067558 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php 2025-12-21 09:36:35.271293771 +0000@@ -7,7 +7,6 @@ use Psr\Http\Client\RequestExceptionInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface;-use Psr\Http\Message\UriInterface; /** * HTTP Request exception@@ -32,8 +31,8 @@ public function __construct( string $message, RequestInterface $request,- ResponseInterface $response = null,- \Throwable $previous = null,+ ?ResponseInterface $response = null,+ ?\Throwable $previous = null, array $handlerContext = [] ) { // Set the code of the exception if the response is set and not future.@@ -63,10 +62,10 @@ */ public static function create( RequestInterface $request,- ResponseInterface $response = null,- \Throwable $previous = null,+ ?ResponseInterface $response = null,+ ?\Throwable $previous = null, array $handlerContext = [],- BodySummarizerInterface $bodySummarizer = null+ ?BodySummarizerInterface $bodySummarizer = null ): self { if (!$response) { return new self(@@ -90,8 +89,7 @@ $className = __CLASS__; } - $uri = $request->getUri();- $uri = static::obfuscateUri($uri);+ $uri = \GuzzleHttp\Psr7\Utils::redactUserInfo($request->getUri()); // Client Error: `GET /` resulted in a `404 Not Found` response: // <html> ... (truncated)@@ -114,20 +112,6 @@ } /**- * Obfuscates URI if there is a username and a password present- */- private static function obfuscateUri(UriInterface $uri): UriInterface- {- $userInfo = $uri->getUserInfo();-- if (false !== ($pos = \strpos($userInfo, ':'))) {- return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');- }-- return $uri;- }-- /** * Get the request that caused the exception */ public function getRequest(): RequestInterface
Vulnerability Existed: yes
FALSE POSITIVE
Potential Information Disclosure through URI Obfuscation - CWE-532 - vendor/guzzlehttp/guzzle/src/Exception/RequestException.php - Lines 92-127
[Old Code]
```php
$uri = $request->getUri();
$uri = static::obfuscateUri($uri);
...
private static function obfuscateUri(UriInterface $uri): UriInterface
{
$userInfo = $uri->getUserInfo();
if (false !== ($pos = \strpos($userInfo, ':'))) {
return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');
}
return $uri;
}
```
[Fixed Code]
```php
$uri = \GuzzleHttp\Psr7\Utils::redactUserInfo($request->getUri());
```
Explanation:
The old code used a custom `obfuscateUri()` method that attempted to redact credentials from URIs by replacing passwords with '***'. However, this implementation had a critical flaw: it only obfuscated the password part if a username:password combination was detected, but it did NOT remove the username itself. This meant usernames (which could be sensitive identifiers or API keys) were still exposed in error messages and logs. Additionally, the custom implementation could have edge cases or inconsistencies in how it handled various URI formats.
The fix replaces the custom obfuscation logic with `\GuzzleHttp\Psr7\Utils::redactUserInfo()`, which is a more robust, standardized method that properly redacts both usernames and passwords (or other sensitive user info) from URIs. This prevents sensitive authentication credentials from being exposed in exception messages and logs - a critical security concern since exception messages are often logged and may be visible in error tracking systems.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php 2025-12-21 09:36:35.275294020 +0000@@ -11,6 +11,7 @@ use GuzzleHttp\TransferStats; use GuzzleHttp\Utils; use Psr\Http\Message\RequestInterface;+use Psr\Http\Message\UriInterface; /** * Creates curl resources from a request@@ -46,6 +47,16 @@ public function create(RequestInterface $request, array $options): EasyHandle {+ $protocolVersion = $request->getProtocolVersion();++ if ('2' === $protocolVersion || '2.0' === $protocolVersion) {+ if (!self::supportsHttp2()) {+ throw new ConnectException('HTTP/2 is supported by the cURL handler, however libcurl is built without HTTP/2 support.', $request);+ }+ } elseif ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {+ throw new ConnectException(sprintf('HTTP/%s is not supported by the cURL handler.', $protocolVersion), $request);+ }+ if (isset($options['curl']['body_as_string'])) { $options['_body_as_string'] = $options['curl']['body_as_string']; unset($options['curl']['body_as_string']);@@ -72,13 +83,51 @@ return $easy; } + private static function supportsHttp2(): bool+ {+ static $supportsHttp2 = null;++ if (null === $supportsHttp2) {+ $supportsHttp2 = self::supportsTls12()+ && defined('CURL_VERSION_HTTP2')+ && (\CURL_VERSION_HTTP2 & \curl_version()['features']);+ }++ return $supportsHttp2;+ }++ private static function supportsTls12(): bool+ {+ static $supportsTls12 = null;++ if (null === $supportsTls12) {+ $supportsTls12 = \CURL_SSLVERSION_TLSv1_2 & \curl_version()['features'];+ }++ return $supportsTls12;+ }++ private static function supportsTls13(): bool+ {+ static $supportsTls13 = null;++ if (null === $supportsTls13) {+ $supportsTls13 = defined('CURL_SSLVERSION_TLSv1_3')+ && (\CURL_SSLVERSION_TLSv1_3 & \curl_version()['features']);+ }++ return $supportsTls13;+ }+ public function release(EasyHandle $easy): void { $resource = $easy->handle; unset($easy->handle); if (\count($this->handles) >= $this->maxHandles) {- \curl_close($resource);+ if (PHP_VERSION_ID < 80000) {+ \curl_close($resource);+ } } else { // Remove all callback functions as they can hold onto references // and are not cleaned up by curl_reset. Using curl_setopt_array@@ -147,7 +196,7 @@ 'error' => \curl_error($easy->handle), 'appconnect_time' => \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME), ] + \curl_getinfo($easy->handle);- $ctx[self::CURL_VERSION_STR] = \curl_version()['version'];+ $ctx[self::CURL_VERSION_STR] = self::getCurlVersion(); $factory->release($easy); // Retry when nothing is present or when curl failed to rewind.@@ -158,6 +207,17 @@ return self::createRejection($easy, $ctx); } + private static function getCurlVersion(): string+ {+ static $curlVersion = null;++ if (null === $curlVersion) {+ $curlVersion = \curl_version()['version'];+ }++ return $curlVersion;+ }+ private static function createRejection(EasyHandle $easy, array $ctx): PromiseInterface { static $connectionErrors = [@@ -194,15 +254,22 @@ ); } + $uri = $easy->request->getUri();++ $sanitizedError = self::sanitizeCurlError($ctx['error'] ?? '', $uri);+ $message = \sprintf( 'cURL error %s: %s (%s)', $ctx['errno'],- $ctx['error'],+ $sanitizedError, 'see https://curl.haxx.se/libcurl/c/libcurl-errors.html' );- $uriString = (string) $easy->request->getUri();- if ($uriString !== '' && false === \strpos($ctx['error'], $uriString)) {- $message .= \sprintf(' for %s', $uriString);++ if ('' !== $sanitizedError) {+ $redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($uri)->__toString();+ if ($redactedUriString !== '' && false === \strpos($sanitizedError, $redactedUriString)) {+ $message .= \sprintf(' for %s', $redactedUriString);+ } } // Create a connection exception if it was a specific error code.@@ -213,6 +280,24 @@ return P\Create::rejectionFor($error); } + private static function sanitizeCurlError(string $error, UriInterface $uri): string+ {+ if ('' === $error) {+ return $error;+ }++ $baseUri = $uri->withQuery('')->withFragment('');+ $baseUriString = $baseUri->__toString();++ if ('' === $baseUriString) {+ return $error;+ }++ $redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($baseUri)->__toString();++ return str_replace($baseUriString, $redactedUriString, $error);+ }+ /** * @return array<int|string, mixed> */@@ -232,10 +317,11 @@ } $version = $easy->request->getProtocolVersion();- if ($version == 1.1) {- $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1;- } elseif ($version == 2.0) {++ if ('2' === $version || '2.0' === $version) { $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0;+ } elseif ('1.1' === $version) {+ $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1; } else { $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0; }@@ -256,7 +342,7 @@ $method = $easy->request->getMethod(); if ($method === 'PUT' || $method === 'POST') {- // See https://tools.ietf.org/html/rfc7230#section-3.3.2+ // See https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2 if (!$easy->request->hasHeader('Content-Length')) { $conf[\CURLOPT_HTTPHEADER][] = 'Content-Length: 0'; }@@ -367,11 +453,11 @@ // If it's a directory or a link to a directory use CURLOPT_CAPATH. // If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO. if (- \is_dir($options['verify']) ||- (- \is_link($options['verify']) === true &&- ($verifyLink = \readlink($options['verify'])) !== false &&- \is_dir($verifyLink)+ \is_dir($options['verify'])+ || (+ \is_link($options['verify']) === true+ && ($verifyLink = \readlink($options['verify'])) !== false+ && \is_dir($verifyLink) ) ) { $conf[\CURLOPT_CAPATH] = $options['verify'];@@ -390,8 +476,10 @@ // The empty string enables all available decoders and implicitly // sets a matching 'Accept-Encoding' header. $conf[\CURLOPT_ENCODING] = '';- // But as the user did not specify any acceptable encodings we need- // to overwrite this implicit header with an empty one.+ // But as the user did not specify any encoding preference,+ // let's leave it up to server by preventing curl from sending+ // the header, which will be interpreted as 'Accept-Encoding: *'.+ // https://www.rfc-editor.org/rfc/rfc9110#field.accept-encoding $conf[\CURLOPT_HTTPHEADER][] = 'Accept-Encoding:'; } }@@ -455,23 +543,35 @@ } if (isset($options['crypto_method'])) {- if (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) {- if (!defined('CURL_SSLVERSION_TLSv1_0')) {- throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.0 not supported by your version of cURL');+ $protocolVersion = $easy->request->getProtocolVersion();++ // If HTTP/2, upgrade TLS 1.0 and 1.1 to 1.2+ if ('2' === $protocolVersion || '2.0' === $protocolVersion) {+ if (+ \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']+ || \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']+ || \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']+ ) {+ $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2;+ } elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) {+ if (!self::supportsTls13()) {+ throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL');+ }+ $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3;+ } else {+ throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided'); }+ } elseif (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) { $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_0; } elseif (\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']) {- if (!defined('CURL_SSLVERSION_TLSv1_1')) {- throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.1 not supported by your version of cURL');- } $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_1; } elseif (\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']) {- if (!defined('CURL_SSLVERSION_TLSv1_2')) {+ if (!self::supportsTls12()) { throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.2 not supported by your version of cURL'); } $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2; } elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) {- if (!defined('CURL_SSLVERSION_TLSv1_3')) {+ if (!self::supportsTls13()) { throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL'); } $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3;@@ -627,4 +727,15 @@ return \strlen($h); }; }++ public function __destruct()+ {+ foreach ($this->handles as $id => $handle) {+ if (PHP_VERSION_ID < 80000) {+ \curl_close($handle);+ }++ unset($this->handles[$id]);+ }+ } }
Analyzing the security-related changes in this GuzzleHTTP cURL factory diff:
---
**Vulnerability 1:**
Vulnerability Existed: yes
TRUE POSITIVE
Information Disclosure via Error Messages - CWE-209 - vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php Lines 254-273
**Old Code:**
```php
$message = \sprintf(
'cURL error %s: %s (%s)',
$ctx['errno'],
$ctx['error'],
'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
);
$uriString = (string) $easy->request->getUri();
if ($uriString !== '' && false === \strpos($ctx['error'], $uriString)) {
$message .= \sprintf(' for %s', $uriString);
}
```
**Fixed Code:**
```php
$uri = $easy->request->getUri();
$sanitizedError = self::sanitizeCurlError($ctx['error'] ?? '', $uri);
$message = \sprintf(
'cURL error %s: %s (%s)',
$ctx['errno'],
$sanitizedError,
'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
);
if ('' !== $sanitizedError) {
$redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($uri)->__toString();
if ($redactedUriString !== '' && false === \strpos($sanitizedError, $redactedUriString)) {
$message .= \sprintf(' for %s', $redactedUriString);
}
}
```
**Explanation:**
Error messages could leak sensitive information from URIs including usernames, passwords, and query parameters. The old code appended raw URI strings and raw cURL errors to exception messages. The fix introduces `sanitizeCurlError()` to redact credentials from error messages and uses `redactUserInfo()` to remove authentication details from URIs before including them in error messages.
---
**Vulnerability 2:**
Vulnerability Existed: yes
TRUE POSITIVE
Information Disclosure via HTTP Protocol Negotiation - CWE-754 (Improper Check for Unusual or Exceptional Conditions) - vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php Lines 50-61
**Old Code:**
```php
$version = $easy->request->getProtocolVersion();
if ($version == 1.1) {
$conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1;
} elseif ($version == 2.0) {
$conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0;
} else {
$conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0;
}
```
**Fixed Code:**
```php
$protocolVersion = $request->getProtocolVersion();
if ('2' === $protocolVersion || '2.0' === $protocolVersion) {
if (!self::supportsHttp2()) {
throw new ConnectException('HTTP/2 is supported by the cURL handler, however libcurl is built without HTTP/2 support.', $request);
}
} elseif ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {
throw new ConnectException(sprintf('HTTP/%s is not supported by the cURL handler.', $protocolVersion), $request);
}
```
**Explanation:**
The old code used loose comparison (==) which could allow invalid protocol versions to be silently accepted and default to HTTP/1.0. The fix adds explicit validation at the request creation phase to reject unsupported HTTP protocol versions and verify HTTP/2 support before attempting to use it, preventing downgrade attacks or unexpected protocol behavior.
---
**Vulnerability 3:**
Vulnerability Existed: yes
TRUE POSITIVE
Resource Management / Memory Leak - CWE-401 - vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php Lines 127-130 and Lines 731-741
**Old Code:**
```php
if (\count($this->handles) >= $this->maxHandles) {
\curl_close($resource);
}
```
**Fixed Code:**
```php
if (PHP_VERSION_ID < 80000) {
\curl_close($resource);
}
```
And added destructor:
```php
public function __destruct()
{
foreach ($this->handles as $id => $handle) {
if (PHP_VERSION_ID < 80000) {
\curl_close($handle);
}
unset($this->handles[$id]);
}
}
```
**Explanation:**
In PHP 8.0+, cURL handles are automatically closed when dereferenced. Explicitly calling `curl_close()` on PHP 8.0+ can cause issues. The fix adds version checks to only call `curl_close()` on PHP < 8.0, and adds a destructor to ensure proper cleanup on older PHP versions. This prevents resource leaks on PHP 7.x while maintaining compatibility with PHP 8.0+.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php 2025-12-21 09:36:35.275294020 +0000@@ -2,6 +2,7 @@ namespace GuzzleHttp\Handler; +use Closure; use GuzzleHttp\Promise as P; use GuzzleHttp\Promise\Promise; use GuzzleHttp\Promise\PromiseInterface;@@ -15,11 +16,8 @@ * associative array of curl option constants mapping to values in the * **curl** key of the provided request options. *- * @property resource|\CurlMultiHandle $_mh Internal use only. Lazy loaded multi-handle.- * * @final */-#[\AllowDynamicProperties] class CurlMultiHandler { /**@@ -56,6 +54,9 @@ */ private $options = []; + /** @var resource|\CurlMultiHandle */+ private $_mh;+ /** * This handler accepts the following options: *@@ -79,6 +80,10 @@ } $this->options = $options['options'] ?? [];++ // unsetting the property forces the first access to go through+ // __get().+ unset($this->_mh); } /**@@ -155,6 +160,9 @@ } } + // Run curl_multi_exec in the queue to enable other async tasks to run+ P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));+ // Step through the task queue which may add additional requests. P\Utils::queue()->run(); @@ -165,12 +173,25 @@ } while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {+ // Prevent busy looping for slow HTTP requests.+ \curl_multi_select($this->_mh, $this->selectTimeout); } $this->processMessages(); } /**+ * Runs \curl_multi_exec() inside the event loop, to prevent busy looping+ */+ private function tickInQueue(): void+ {+ if (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {+ \curl_multi_select($this->_mh, 0);+ P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));+ }+ }++ /** * Runs until all outstanding connections have completed. */ public function execute(): void@@ -219,7 +240,10 @@ $handle = $this->handles[$id]['easy']->handle; unset($this->delays[$id], $this->handles[$id]); \curl_multi_remove_handle($this->_mh, $handle);- \curl_close($handle);++ if (PHP_VERSION_ID < 80000) {+ \curl_close($handle);+ } return true; }
Vulnerability Existed: not sure
Improper Resource Management - CWE-404 - vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php - Line 244-246
Old Code:
```
\curl_close($handle);
```
Fixed Code:
```
if (PHP_VERSION_ID < 80000) {
\curl_close($handle);
}
```
Explanation:
The change conditionally calls `curl_close()` only for PHP versions below 8.0.0. In PHP 8.0+, curl handles are automatically cleaned up when they go out of scope due to resource-to-object conversion. This prevents potential double-free or resource leaks in PHP 8.0+ where explicit `curl_close()` may cause issues. However, without additional context about reported bugs or CVEs, it's uncertain whether this addresses an actual vulnerability or is merely a compatibility improvement. The change appears defensive and version-aware, which suggests it may address a known issue in PHP 8.0+.
---
Vulnerability Existed: no
Dynamic Property Assignment - CWE-1025 - vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php - Line 22, 57-58
Old Code:
```
#[\AllowDynamicProperties]
class CurlMultiHandler
{
```
Fixed Code:
```
class CurlMultiHandler
{
...
/** @var resource|\CurlMultiHandle */
private $_mh;
}
```
Explanation:
The `#[\AllowDynamicProperties]` attribute was removed and `$_mh` is now properly declared as an explicit typed property. This is a code quality improvement that makes property declaration explicit and type-safe, reducing reliance on dynamic properties. This is not fixing a vulnerability but rather improving code robustness and maintainability by following proper PHP 8.0+ practices. The property is explicitly initialized via `unset($this->_mh)` in the constructor to trigger lazy loading through `__get()`.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php 2025-12-21 09:36:35.275294020 +0000@@ -52,21 +52,21 @@ * @param callable|null $onFulfilled Callback to invoke when the return value is fulfilled. * @param callable|null $onRejected Callback to invoke when the return value is rejected. */- public static function createWithMiddleware(array $queue = null, callable $onFulfilled = null, callable $onRejected = null): HandlerStack+ public static function createWithMiddleware(?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null): HandlerStack { return HandlerStack::create(new self($queue, $onFulfilled, $onRejected)); } /** * The passed in value must be an array of- * {@see \Psr\Http\Message\ResponseInterface} objects, Exceptions,+ * {@see ResponseInterface} objects, Exceptions, * callables, or Promises. * * @param array<int, mixed>|null $queue The parameters to be passed to the append function, as an indexed array. * @param callable|null $onFulfilled Callback to invoke when the return value is fulfilled. * @param callable|null $onRejected Callback to invoke when the return value is rejected. */- public function __construct(array $queue = null, callable $onFulfilled = null, callable $onRejected = null)+ public function __construct(?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null) { $this->onFulfilled = $onFulfilled; $this->onRejected = $onRejected;@@ -200,7 +200,7 @@ private function invokeStats( RequestInterface $request, array $options,- ResponseInterface $response = null,+ ?ResponseInterface $response = null, $reason = null ): void { if (isset($options['on_stats'])) {
Vulnerability Existed: no No Security Vulnerabilities Detected - Type Declaration Updates File: vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php Lines: 55, 69, 203 Explanation: This diff contains type system improvements (PHP 7.1+ nullable type syntax) rather than security fixes. The changes convert function parameters from optional typed parameters (`type $param = null`) to explicitly nullable parameters (`?type $param = null`). These modifications: 1. **Line 55 (`createWithMiddleware`)**: Changes `array $queue = null` to `?array $queue = null`, and similarly for `$onFulfilled` and `$onRejected` parameters. This improves type safety by explicitly declaring nullable types. 2. **Line 69 (`__construct`)**: Same nullable type improvements as above. 3. **Line 203 (`invokeStats`)**: Changes `ResponseInterface $response = null` to `?ResponseInterface $response = null`, explicitly marking the parameter as nullable. 4. **Line 61**: Documentation reference update from `\Psr\Http\Message\ResponseInterface` to `ResponseInterface` - a documentation clarification, not a security change. These are code quality improvements that enhance type checking and IDE support, but do not address, fix, or introduce any security vulnerabilities. The behavior and security posture of the code remain unchanged.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php 2025-12-21 09:36:35.275294020 +0000@@ -17,10 +17,10 @@ * Sends synchronous requests to a specific handler while sending all other * requests to another handler. *- * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for normal responses- * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $sync Handler used for synchronous responses.+ * @param callable(RequestInterface, array): PromiseInterface $default Handler used for normal responses+ * @param callable(RequestInterface, array): PromiseInterface $sync Handler used for synchronous responses. *- * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.+ * @return callable(RequestInterface, array): PromiseInterface Returns the composed handler. */ public static function wrapSync(callable $default, callable $sync): callable {@@ -37,10 +37,10 @@ * performance benefits of curl while still supporting true streaming * through the StreamHandler. *- * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for non-streaming responses- * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $streaming Handler used for streaming responses+ * @param callable(RequestInterface, array): PromiseInterface $default Handler used for non-streaming responses+ * @param callable(RequestInterface, array): PromiseInterface $streaming Handler used for streaming responses *- * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.+ * @return callable(RequestInterface, array): PromiseInterface Returns the composed handler. */ public static function wrapStreaming(callable $default, callable $streaming): callable {
Vulnerability Existed: no No Security Vulnerabilities Detected Explanation: This diff contains only documentation/PHPDoc comment changes. The modifications simplify the type hint syntax in docblocks from fully-qualified class names (e.g., `\Psr\Http\Message\RequestInterface`) to short class names (e.g., `RequestInterface`). These changes: - Do not alter any executable code logic - Do not modify function signatures or behavior - Do not introduce or fix security vulnerabilities - Represent a documentation style improvement only (likely due to import statements at the top of the file making full qualification unnecessary) The actual handler implementations remain unchanged and unaffected by these cosmetic documentation updates.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php 2025-12-21 09:36:35.275294020 +0000@@ -40,6 +40,12 @@ \usleep($options['delay'] * 1000); } + $protocolVersion = $request->getProtocolVersion();++ if ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {+ throw new ConnectException(sprintf('HTTP/%s is not supported by the stream handler.', $protocolVersion), $request);+ }+ $startTime = isset($options['on_stats']) ? Utils::currentTime() : null; try {@@ -47,8 +53,14 @@ $request = $request->withoutHeader('Expect'); // Append a content-length header if body size is zero to match- // cURL's behavior.- if (0 === $request->getBody()->getSize()) {+ // the behavior of `CurlHandler`+ if (+ (+ 0 === \strcasecmp('PUT', $request->getMethod())+ || 0 === \strcasecmp('POST', $request->getMethod())+ )+ && 0 === $request->getBody()->getSize()+ ) { $request = $request->withHeader('Content-Length', '0'); } @@ -83,8 +95,8 @@ array $options, RequestInterface $request, ?float $startTime,- ResponseInterface $response = null,- \Throwable $error = null+ ?ResponseInterface $response = null,+ ?\Throwable $error = null ): void { if (isset($options['on_stats'])) { $stats = new TransferStats($request, $response, Utils::currentTime() - $startTime, $error, []);@@ -273,7 +285,7 @@ // HTTP/1.1 streams using the PHP stream wrapper require a // Connection: close header- if ($request->getProtocolVersion() == '1.1'+ if ($request->getProtocolVersion() === '1.1' && !$request->hasHeader('Connection') ) { $request = $request->withHeader('Connection', 'close');@@ -321,8 +333,15 @@ ); return $this->createResource(- function () use ($uri, &$http_response_header, $contextResource, $context, $options, $request) {+ function () use ($uri, $contextResource, $context, $options, $request) { $resource = @\fopen((string) $uri, 'r', false, $contextResource);++ // See https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_the_http_response_header_predefined_variable+ if (function_exists('http_get_last_response_headers')) {+ /** @var array|null */+ $http_response_header = \http_get_last_response_headers();+ }+ $this->lastHeaders = $http_response_header ?? []; if (false === $resource) {
# Security Analysis of StreamHandler.php Diff
## Vulnerability 1
**Vulnerability Existed:** no
**HTTP Protocol Version Validation - CWE-20 (Improper Input Validation) - CWE-20 - vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php Lines 43-47**
**Old Code:**
```php
// No validation of protocol version
$startTime = isset($options['on_stats']) ? Utils::currentTime() : null;
```
**Fixed Code:**
```php
$protocolVersion = $request->getProtocolVersion();
if ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {
throw new ConnectException(sprintf('HTTP/%s is not supported by the stream handler.', $protocolVersion), $request);
}
```
**Explanation:**
This is a security hardening fix, not a vulnerability fix. The code now validates that only HTTP/1.0 and HTTP/1.1 protocols are supported by the stream handler. This prevents potential issues from unsupported protocol versions (like HTTP/2 or HTTP/3) that the stream handler cannot properly handle, which could lead to unexpected behavior or security issues.
---
## Vulnerability 2
**Vulnerability Existed:** not sure
**Improper Content-Length Header Assignment - CWE-400 (Uncontrolled Resource Consumption) - CWE-400 - vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php Lines 56-66**
**Old Code:**
```php
// Append a content-length header if body size is zero to match
// cURL's behavior.
if (0 === $request->getBody()->getSize()) {
$request = $request->withHeader('Content-Length', '0');
}
```
**Fixed Code:**
```php
// Append a content-length header if body size is zero to match
// the behavior of `CurlHandler`
if (
(
0 === \strcasecmp('PUT', $request->getMethod())
|| 0 === \strcasecmp('POST', $request->getMethod())
)
&& 0 === $request->getBody()->getSize()
) {
$request = $request->withHeader('Content-Length', '0');
}
```
**Explanation:**
This fix restricts Content-Length: 0 header assignment to only PUT and POST requests with zero-size bodies. Previously, it applied to all request methods, which could cause issues with GET, DELETE, or other requests that shouldn't have Content-Length headers added unconditionally. This prevents potential protocol violations and mismatches with server expectations for different HTTP methods.
---
## Vulnerability 3
**Vulnerability Existed:** no
**Type Safety Improvement - CWE-347 (Improper Verification of Cryptographic Signature) - CWE-347 - vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php Line 288**
**Old Code:**
```php
if ($request->getProtocolVersion() == '1.1'
&& !$request->hasHeader('Connection')
) {
```
**Fixed Code:**
```php
if ($request->getProtocolVersion() === '1.1'
&& !$request->hasHeader('Connection')
) {
```
**Explanation:**
Changed loose comparison (`==`) to strict comparison (`===`). This is a type safety improvement that prevents potential type coercion issues. While unlikely to be a vulnerability in this specific context, strict comparison is a security best practice to avoid unexpected type juggling behavior.
---
## Vulnerability 4
**Vulnerability Existed:** not sure
**Deprecated Global Variable Reference - CWE-665 (Improper Initialization) - CWE-665 - vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php Lines 336-345**
**Old Code:**
```php
return $this->createResource(
function () use ($uri, &$http_response_header, $contextResource, $context, $options, $request) {
$resource = @\fopen((string) $uri, 'r', false, $contextResource);
$this->lastHeaders = $http_response_header ?? [];
```
**Fixed Code:**
```php
return $this->createResource(
function () use ($uri, $contextResource, $context, $options, $request) {
$resource = @\fopen((string) $uri, 'r', false, $contextResource);
// See https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_the_http_response_header_predefined_variable
if (function_exists('http_get_last_response_headers')) {
/** @var array|null */
$http_response_header = \http_get_last_response_headers();
}
$this->lastHeaders = $http_response_header ?? [];
```
**Explanation:**
This fix addresses PHP 8.5 deprecation of the automatic `$http_response_header` superglobal. The old code relied on this predefined variable being automatically populated by `fopen()`, which is being deprecated. The new code uses the safer `http_get_last_response_headers()` function when available, ensuring forward compatibility with PHP 8.5+. This prevents reliance on deprecated behavior that could break in future PHP versions.
---
## Vulnerability 5
**Vulnerability Existed:** no
**Type Declaration Improvement - CWE-400 (Uncontrolled Resource Consumption) - CWE-400 - vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php Lines 98-99**
**Old Code:**
```php
ResponseInterface $response = null,
\Throwable $error = null
```
**Fixed Code:**
```php
?ResponseInterface $response = null,
?\Throwable $error = null
```
**Explanation:**
Added nullable type hints (`?`) to the function parameters. This is a type safety improvement that makes the nullable nature of these parameters explicit in the function signature. This helps prevent null pointer exceptions and improves code clarity and IDE support, though it's not fixing an existing vulnerability but rather improving code quality and maintainability.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/HandlerStack.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/HandlerStack.php 2025-12-21 09:36:35.275294020 +0000@@ -58,7 +58,7 @@ /** * @param (callable(RequestInterface, array): PromiseInterface)|null $handler Underlying HTTP handler. */- public function __construct(callable $handler = null)+ public function __construct(?callable $handler = null) { $this->handler = $handler; }
Vulnerability Existed: no [Type Declaration - Parameter Type Safety] - [CWE-400] - [vendor/guzzlehttp/guzzle/src/HandlerStack.php] [Lines 61] Old Code: ```php public function __construct(callable $handler = null) ``` Fixed Code: ```php public function __construct(?callable $handler = null) ``` Explanation: This change adds nullable type declaration (`?callable`) to the `$handler` parameter. This is a type safety improvement rather than a security vulnerability fix. The old code allowed `null` as a default value but didn't explicitly declare the parameter as nullable in the type hint, which could lead to type checking issues or unexpected behavior. The fix makes the type declaration explicit and correct, ensuring that the parameter can properly accept either a callable or null value. This improves type safety and is consistent with PHP best practices for nullable parameters.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Middleware.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Middleware.php 2025-12-21 09:36:35.275294020 +0000@@ -55,7 +55,7 @@ * * @return callable(callable): callable Returns a function that accepts the next handler. */- public static function httpErrors(BodySummarizerInterface $bodySummarizer = null): callable+ public static function httpErrors(?BodySummarizerInterface $bodySummarizer = null): callable { return static function (callable $handler) use ($bodySummarizer): callable { return static function ($request, array $options) use ($handler, $bodySummarizer) {@@ -132,7 +132,7 @@ * * @return callable Returns a function that accepts the next handler. */- public static function tap(callable $before = null, callable $after = null): callable+ public static function tap(?callable $before = null, ?callable $after = null): callable { return static function (callable $handler) use ($before, $after): callable { return static function (RequestInterface $request, array $options) use ($handler, $before, $after) {@@ -176,7 +176,7 @@ * * @return callable Returns a function that accepts the next handler. */- public static function retry(callable $decider, callable $delay = null): callable+ public static function retry(callable $decider, ?callable $delay = null): callable { return static function (callable $handler) use ($decider, $delay): RetryMiddleware { return new RetryMiddleware($decider, $handler, $delay);@@ -187,12 +187,12 @@ * Middleware that logs requests, responses, and errors using a message * formatter. *- * @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests.- * * @param LoggerInterface $logger Logs messages. * @param MessageFormatterInterface|MessageFormatter $formatter Formatter used to create message strings. * @param string $logLevel Level at which to log requests. *+ * @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests.+ * * @return callable Returns a function that accepts the next handler. */ public static function log(LoggerInterface $logger, $formatter, string $logLevel = 'info'): callable
I'll analyze this code diff for security vulnerabilities. **Vulnerability Existed:** no **Type Annotations Enhancement - No Security Vulnerability - File: vendor/guzzlehttp/guzzle/src/Middleware.php - Lines 58, 135, 179, 190-196** **Old Code:** ```php public static function httpErrors(BodySummarizerInterface $bodySummarizer = null): callable public static function tap(callable $before = null, callable $after = null): callable public static function retry(callable $decider, callable $delay = null): callable ``` **Fixed Code:** ```php public static function httpErrors(?BodySummarizerInterface $bodySummarizer = null): callable public static function tap(?callable $before = null, ?callable $after = null): callable public static function retry(callable $decider, ?callable $delay = null): callable ``` **Explanation:** These changes add nullable type declarations (`?Type`) to optional parameters in three middleware methods and reorganize documentation comments in the `log` method. These are type safety improvements, not security fixes. The addition of nullable type hints (`?BodySummarizerInterface`, `?callable`) is a PHP 7.1+ feature that explicitly declares which parameters can be `null`. This improves type safety and static analysis capabilities but does not address any existing security vulnerabilities. The code already accepted `null` values via default parameters; the change only makes this explicit in the type system. The documentation reordering in the `log` method (moving the `@phpstan-param` annotation) is purely for documentation clarity and has no security implications. These are code quality and type safety improvements, not security vulnerability fixes.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Pool.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Pool.php 2025-12-21 09:36:35.275294020 +0000@@ -86,7 +86,7 @@ * @param ClientInterface $client Client used to send the requests * @param array|\Iterator $requests Requests to send concurrently. * @param array $options Passes through the options available in- * {@see \GuzzleHttp\Pool::__construct}+ * {@see Pool::__construct} * * @return array Returns an array containing the response or an exception * in the same order that the requests were sent.
Vulnerability Existed: no
[No Vulnerability] - [N/A] - [vendor/guzzlehttp/guzzle/src/Pool.php] [Lines 89]
Old Code:
```php
* {@see \GuzzleHttp\Pool::__construct}
```
Fixed Code:
```php
* {@see Pool::__construct}
```
Explanation:
This change is a documentation fix only. The diff modifies a PHPDoc comment by removing the fully qualified namespace prefix `\GuzzleHttp\` from a `@see` reference, changing it from `\GuzzleHttp\Pool::__construct` to `Pool::__construct`. This is a style/documentation improvement that does not introduce, fix, or relate to any security vulnerability. It's simply making the documentation reference more concise while remaining valid within the context of the same file.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php 2025-12-21 09:36:35.279294269 +0000@@ -76,8 +76,8 @@ $expect = $options['expect'] ?? null; - // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0- if ($expect === false || $request->getProtocolVersion() < 1.1) {+ // Return if disabled or using HTTP/1.0+ if ($expect === false || $request->getProtocolVersion() === '1.0') { return; }
```
Vulnerability Existed: no
Logical Correctness Fix - Not a Security Vulnerability - vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php [Lines 79-80]
[Old Code]
if ($expect === false || $request->getProtocolVersion() < 1.1) {
[Fixed Code]
if ($expect === false || $request->getProtocolVersion() === '1.0') {
Explanation:
This is a logical correctness fix rather than a security vulnerability. The original code had a type comparison issue: `getProtocolVersion()` returns a string (e.g., '1.0', '1.1', '2.0'), not a numeric value. The comparison `< 1.1` was performing a string-to-number type coercion, which could lead to unexpected behavior. The fix correctly compares the protocol version as a string with the specific value '1.0', which is more accurate and reliable. While this improves code correctness and prevents potential edge cases, it does not directly fix a security vulnerability like XSS, injection, authentication bypass, or similar issues. The change ensures the Expect header handling logic works correctly across different HTTP protocol versions.
```
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php 2025-12-21 09:36:35.279294269 +0000@@ -166,8 +166,8 @@ // not forcing RFC compliance, but rather emulating what all browsers // would do. $statusCode = $response->getStatusCode();- if ($statusCode == 303 ||- ($statusCode <= 302 && !$options['allow_redirects']['strict'])+ if ($statusCode == 303+ || ($statusCode <= 302 && !$options['allow_redirects']['strict']) ) { $safeMethods = ['GET', 'HEAD', 'OPTIONS']; $requestMethod = $request->getMethod();
Vulnerability Existed: no This diff contains no security fixes or vulnerabilities. The changes are purely formatting/style adjustments to the conditional statement in the RedirectMiddleware.php file. **Details of the change:** - **Line 169-170**: The logical operator `||` was moved from the end of the first condition line to the beginning of the second line - **Before**: `if ($statusCode == 303 ||` followed by `($statusCode <= 302 && !$options['allow_redirects']['strict'])` - **After**: `if ($statusCode == 303` followed by `|| ($statusCode <= 302 && !$options['allow_redirects']['strict'])` **Explanation:** This is a whitespace/formatting change only. The logical behavior of the code remains identical - the condition still evaluates to true if either the status code is 303 OR (the status code is 302 or less AND strict redirects are not allowed). The relocation of the `||` operator does not alter the logic, precedence, or security properties of the conditional statement. This appears to be a code style normalization, possibly to comply with a linter or coding standard.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/RequestOptions.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/RequestOptions.php 2025-12-21 09:36:35.279294269 +0000@@ -5,9 +5,7 @@ /** * This class contains a list of built-in Guzzle request options. *- * More documentation for each option can be found at http://guzzlephp.org/.- *- * @see http://docs.guzzlephp.org/en/v6/request-options.html+ * @see https://docs.guzzlephp.org/en/latest/request-options.html */ final class RequestOptions {@@ -63,7 +61,7 @@ * Specifies whether or not cookies are used in a request or what cookie * jar to use or what cookies to send. This option only works if your * handler has the `cookie` middleware. Valid values are `false` and- * an instance of {@see \GuzzleHttp\Cookie\CookieJarInterface}.+ * an instance of {@see Cookie\CookieJarInterface}. */ public const COOKIES = 'cookies';
Vulnerability Existed: no
[No Security Vulnerability] - [N/A] - [vendor/guzzlehttp/guzzle/src/RequestOptions.php] [Lines 8-10, 66]
Old Code:
```php
* More documentation for each option can be found at http://guzzlephp.org/.
*
* @see http://docs.guzzlephp.org/en/v6/request-options.html
```
and
```php
* an instance of {@see \GuzzleHttp\Cookie\CookieJarInterface}.
```
Fixed Code:
```php
* @see https://docs.guzzlephp.org/en/latest/request-options.html
```
and
```php
* an instance of {@see Cookie\CookieJarInterface}.
```
Explanation:
These changes are documentation and code reference improvements, not security fixes:
1. **Lines 8-10**: The documentation URL changes from HTTP to HTTPS (http://docs.guzzlephp.org/ → https://docs.guzzlephp.org/) and updates the documentation path from v6 to latest. While using HTTPS is a security best practice, this change is only in a comment/documentation string and does not affect the actual code execution. No vulnerability existed in the original code.
2. **Line 66**: The `@see` annotation changes from a fully qualified class name `\GuzzleHttp\Cookie\CookieJarInterface` to a relative reference `Cookie\CookieJarInterface`. This is a documentation/code readability improvement and does not introduce or fix a security vulnerability. The actual class reference remains the same functionally.
These are maintenance updates that improve documentation and code clarity, but do not address any security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php 2025-12-21 09:36:35.279294269 +0000@@ -40,7 +40,7 @@ * and returns the number of * milliseconds to delay. */- public function __construct(callable $decider, callable $nextHandler, callable $delay = null)+ public function __construct(callable $decider, callable $nextHandler, ?callable $delay = null) { $this->decider = $decider; $this->nextHandler = $nextHandler;@@ -110,7 +110,7 @@ }; } - private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null): PromiseInterface+ private function doRetry(RequestInterface $request, array $options, ?ResponseInterface $response = null): PromiseInterface { $options['delay'] = ($this->delay)(++$options['retries'], $response, $request);
Vulnerability Existed: no Type Safety Enhancement - N/A - vendor/guzzlehttp/guzzle/src/RetryMiddleware.php Lines 43, 113 [Old Code] Line 43: `public function __construct(callable $decider, callable $nextHandler, callable $delay = null)` Line 113: `private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null): PromiseInterface` [Fixed Code] Line 43: `public function __construct(callable $decider, callable $nextHandler, ?callable $delay = null)` Line 113: `private function doRetry(RequestInterface $request, array $options, ?ResponseInterface $response = null): PromiseInterface` Explanation: These changes add PHP 7.1+ nullable type hints (`?callable` and `?ResponseInterface`) to parameters that can be `null`. This is a type safety improvement, not a security vulnerability fix. The code behavior remains identical—these parameters already accepted `null` values with the default parameter syntax. The nullable type hint makes the code more explicit and enables better static analysis, but does not fix or prevent any security vulnerabilities. This is a code quality improvement rather than a security patch.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/Utils.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/Utils.php 2025-12-21 09:36:35.279294269 +0000@@ -71,7 +71,7 @@ return \STDOUT; } - return \GuzzleHttp\Psr7\Utils::tryFopen('php://output', 'w');+ return Psr7\Utils::tryFopen('php://output', 'w'); } /**@@ -79,7 +79,7 @@ * * The returned handler is not wrapped by any default middlewares. *- * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system.+ * @return callable(\Psr\Http\Message\RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system. * * @throws \RuntimeException if no viable Handler is available. */@@ -87,7 +87,7 @@ { $handler = null; - if (\defined('CURLOPT_CUSTOMREQUEST')) {+ if (\defined('CURLOPT_CUSTOMREQUEST') && \function_exists('curl_version') && version_compare(curl_version()['version'], '7.21.2') >= 0) { if (\function_exists('curl_multi_exec') && \function_exists('curl_exec')) { $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler()); } elseif (\function_exists('curl_exec')) {@@ -176,14 +176,13 @@ PHP versions earlier than 5.6 are not properly configured to use the system's CA bundle by default. In order to verify peer certificates, you will need to supply the path on disk to a certificate bundle to the 'verify' request-option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not-need a specific certificate bundle, then Mozilla provides a commonly used CA-bundle which can be downloaded here (provided by the maintainer of cURL):-https://curl.haxx.se/ca/cacert.pem. Once-you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP-ini setting to point to the path to the file, allowing you to omit the 'verify'-request option. See https://curl.haxx.se/docs/sslcerts.html for more-information.+option: https://docs.guzzlephp.org/en/latest/request-options.html#verify. If+you do not need a specific certificate bundle, then Mozilla provides a commonly+used CA bundle which can be downloaded here (provided by the maintainer of+cURL): https://curl.haxx.se/ca/cacert.pem. Once you have a CA bundle available+on disk, you can set the 'openssl.cafile' PHP ini setting to point to the path+to the file, allowing you to omit the 'verify' request option. See+https://curl.haxx.se/docs/sslcerts.html for more information. EOT ); }
Analyzing the provided code diff for security fixes:
---
**Vulnerability 1:**
Vulnerability Existed: yes
FALSE POSITIVE
Improper Input Validation - CWE-1025 - vendor/guzzlehttp/guzzle/src/Utils.php [Line 90]
**Old Code:**
```php
if (\defined('CURLOPT_CUSTOMREQUEST')) {
```
**Fixed Code:**
```php
if (\defined('CURLOPT_CUSTOMREQUEST') && \function_exists('curl_version') && version_compare(curl_version()['version'], '7.21.2') >= 0) {
```
**Explanation:**
The original code only checked if the CURLOPT_CUSTOMREQUEST constant was defined, which is insufficient for ensuring a safe cURL environment. The fix adds two critical validations: (1) verifying that the `curl_version()` function exists before calling it, and (2) ensuring the cURL version is at least 7.21.2, which is when certain important security and stability features were introduced. Without these additional checks, the code could attempt to use cURL features on versions that don't support them or may have known vulnerabilities. This represents an improvement in input validation and version-specific capability checking.
---
**Vulnerability 2:**
Vulnerability Existed: not sure
Insecure Transport - CWE-295 - vendor/guzzlehttp/guzzle/src/Utils.php [Lines 179-186]
**Old Code:**
```
option: http://docs.guzzlephp.org/en/latest/clients.html#verify.
```
**Fixed Code:**
```
option: https://docs.guzzlephp.org/en/latest/request-options.html#verify.
```
**Explanation:**
The documentation URL was updated from HTTP to HTTPS. While this is primarily a documentation fix in a comment/docstring, it does address insecure transport concerns by ensuring users are directed to HTTPS URLs when reading security-related documentation about certificate verification. This is a best practice for security documentation but is not a fix for code-level vulnerabilities in the library itself.
---
**Vulnerability 3:**
Vulnerability Existed: no
Namespace Resolution - vendor/guzzlehttp/guzzle/src/Utils.php [Line 74]
**Old Code:**
```php
return \GuzzleHttp\Psr7\Utils::tryFopen('php://output', 'w');
```
**Fixed Code:**
```php
return Psr7\Utils::tryFopen('php://output', 'w');
```
**Explanation:**
This change is a namespace cleanup/refactoring rather than a security fix. The fully qualified namespace is replaced with a relative namespace reference (assuming proper use statements). This is not a vulnerability fix but rather improves code consistency and potentially reduces namespace resolution overhead.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/guzzle/src/functions.php 2025-12-21 09:35:59.453067558 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/guzzle/src/functions.php 2025-12-21 09:36:35.275294020 +0000@@ -50,7 +50,7 @@ * * The returned handler is not wrapped by any default middlewares. *- * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system.+ * @return callable(\Psr\Http\Message\RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system. * * @throws \RuntimeException if no viable Handler is available. *
``` Vulnerability Existed: no Documentation/Namespace Reference - No CWE - vendor/guzzlehttp/guzzle/src/functions.php [53] [Old Code] @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system. [Fixed Code] @return callable(\Psr\Http\Message\RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system. Explanation: This change is a documentation/comment-only modification that corrects a namespace reference in a PHPDoc return type annotation. The old code uses the fully qualified namespace `\GuzzleHttp\Promise\PromiseInterface` while the fixed code uses the shorter `Promise\PromiseInterface`. This is a stylistic/consistency improvement in documentation and does not represent a security vulnerability being fixed. No security issue existed in the original code - this is simply a namespace notation adjustment in comments. ```
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/promises/src/Coroutine.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/promises/src/Coroutine.php 2025-12-21 09:36:35.279294269 +0000@@ -84,8 +84,8 @@ } public function then(- callable $onFulfilled = null,- callable $onRejected = null+ ?callable $onFulfilled = null,+ ?callable $onRejected = null ): PromiseInterface { return $this->result->then($onFulfilled, $onRejected); }
Vulnerability Existed: no Nullable Type Declaration - No CWE - vendor/guzzlehttp/promises/src/Coroutine.php Lines 87-88 Old Code: ```php callable $onFulfilled = null, callable $onRejected = null ``` Fixed Code: ```php ?callable $onFulfilled = null, ?callable $onRejected = null ``` Explanation: This change adds nullable type declarations (`?callable`) to the method parameters. This is a type safety improvement, not a security vulnerability fix. The old code allowed `null` values without explicit type declaration, which could mask type errors. The new code explicitly declares that these parameters can be `null` using PHP's nullable type syntax. This is a best practice for type safety and code clarity, but it does not address any security vulnerability. The functionality remains identical - the parameters could already be `null` before this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/promises/src/Each.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/promises/src/Each.php 2025-12-21 09:36:35.279294269 +0000@@ -19,14 +19,12 @@ * index, and the aggregate promise. The callback can invoke any necessary * side effects and choose to resolve or reject the aggregate if needed. *- * @param mixed $iterable Iterator or array to iterate over.- * @param callable $onFulfilled- * @param callable $onRejected+ * @param mixed $iterable Iterator or array to iterate over. */ public static function of( $iterable,- callable $onFulfilled = null,- callable $onRejected = null+ ?callable $onFulfilled = null,+ ?callable $onRejected = null ): PromiseInterface { return (new EachPromise($iterable, [ 'fulfilled' => $onFulfilled,@@ -44,14 +42,12 @@ * * @param mixed $iterable * @param int|callable $concurrency- * @param callable $onFulfilled- * @param callable $onRejected */ public static function ofLimit( $iterable, $concurrency,- callable $onFulfilled = null,- callable $onRejected = null+ ?callable $onFulfilled = null,+ ?callable $onRejected = null ): PromiseInterface { return (new EachPromise($iterable, [ 'fulfilled' => $onFulfilled,@@ -67,12 +63,11 @@ * * @param mixed $iterable * @param int|callable $concurrency- * @param callable $onFulfilled */ public static function ofLimitAll( $iterable, $concurrency,- callable $onFulfilled = null+ ?callable $onFulfilled = null ): PromiseInterface { return self::ofLimit( $iterable,
Analyzing the provided diff for security vulnerabilities: --- Vulnerability Existed: no Type Hint Addition - N/A - vendor/guzzlehttp/promises/src/Each.php [28-29, 50-51, 70] Old Code: ```php callable $onFulfilled = null, callable $onRejected = null ``` Fixed Code: ```php ?callable $onFulfilled = null, ?callable $onRejected = null ``` Explanation: This change adds nullable type hints (`?callable`) to function parameters that already had `= null` default values. This is a code quality improvement, not a security fix. The addition of explicit nullable type hints in PHP 7.1+ makes the code more type-safe and helps catch potential type errors at development/analysis time. No security vulnerability existed before or after this change - the parameters were already accepting null values. This is a best practice improvement for type safety. --- Additional Note: The diff also includes documentation cleanup (removing redundant `@param` entries from PHPDoc blocks that correspond to the parameters). This is a documentation improvement with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/promises/src/EachPromise.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/promises/src/EachPromise.php 2025-12-21 09:36:35.279294269 +0000@@ -135,7 +135,7 @@ // Add only up to N pending promises. $concurrency = is_callable($this->concurrency)- ? call_user_func($this->concurrency, count($this->pending))+ ? ($this->concurrency)(count($this->pending)) : $this->concurrency; $concurrency = max($concurrency - count($this->pending), 0); // Concurrency may be set to 0 to disallow new promises.@@ -170,8 +170,7 @@ $this->pending[$idx] = $promise->then( function ($value) use ($idx, $key): void { if ($this->onFulfilled) {- call_user_func(- $this->onFulfilled,+ ($this->onFulfilled)( $value, $key, $this->aggregate@@ -181,8 +180,7 @@ }, function ($reason) use ($idx, $key): void { if ($this->onRejected) {- call_user_func(- $this->onRejected,+ ($this->onRejected)( $reason, $key, $this->aggregate
Vulnerability Existed: no Code Style/Syntax Refactoring - Not a Security Fix - vendor/guzzlehttp/promises/src/EachPromise.php - Lines 138, 173-174, 183-184 [Old Code] ```php call_user_func($this->concurrency, count($this->pending)) call_user_func($this->onFulfilled, $value, $key, $this->aggregate) call_user_func($this->onRejected, $reason, $key, $this->aggregate) ``` [Fixed Code] ```php ($this->concurrency)(count($this->pending)) ($this->onFulfilled)($value, $key, $this->aggregate) ($this->onRejected)($reason, $key, $this->aggregate) ``` Explanation: This diff represents a code style modernization, not a security fix. The changes replace legacy `call_user_func()` function calls with modern PHP callable syntax `(callable)()`. Both approaches are functionally equivalent and equally secure. The refactoring improves code readability and aligns with modern PHP best practices (PHP 7+), but does not address any security vulnerabilities. There are no CWE-related security issues present in either the original or updated code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/promises/src/FulfilledPromise.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/promises/src/FulfilledPromise.php 2025-12-21 09:36:35.279294269 +0000@@ -31,8 +31,8 @@ } public function then(- callable $onFulfilled = null,- callable $onRejected = null+ ?callable $onFulfilled = null,+ ?callable $onRejected = null ): PromiseInterface { // Return itself if there is no onFulfilled function. if (!$onFulfilled) {
Vulnerability Existed: no PHP Nullable Type Declaration - No CWE - vendor/guzzlehttp/promises/src/FulfilledPromise.php Lines 34-35 Old Code: ```php callable $onFulfilled = null, callable $onRejected = null ``` Fixed Code: ```php ?callable $onFulfilled = null, ?callable $onRejected = null ``` Explanation: This is not a security fix but rather a code quality improvement. The change converts implicit nullable type declarations to explicit nullable type declarations using PHP's nullable type syntax (`?callable`). In PHP 7.1+, the nullable type operator `?` makes the type explicitly nullable in the function signature, which is more semantically correct and helps with static analysis. The old code implicitly allows `null` through the default parameter value, but the type hint `callable` alone doesn't indicate that `null` is an acceptable value. This change improves type safety and code clarity but does not fix an existing security vulnerability.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/promises/src/Promise.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/promises/src/Promise.php 2025-12-21 09:36:35.279294269 +0000@@ -25,16 +25,16 @@ * @param callable $cancelFn Fn that when invoked cancels the promise. */ public function __construct(- callable $waitFn = null,- callable $cancelFn = null+ ?callable $waitFn = null,+ ?callable $cancelFn = null ) { $this->waitFn = $waitFn; $this->cancelFn = $cancelFn; } public function then(- callable $onFulfilled = null,- callable $onRejected = null+ ?callable $onFulfilled = null,+ ?callable $onRejected = null ): PromiseInterface { if ($this->state === self::PENDING) { $p = new Promise(null, [$this, 'cancel']);
Vulnerability Existed: no
[Type Hint Modernization] - [No CWE] - [vendor/guzzlehttp/promises/src/Promise.php] [Lines 28-29, 36-37]
Old Code:
```php
public function __construct(
callable $waitFn = null,
callable $cancelFn = null
)
```
and
```php
public function then(
callable $onFulfilled = null,
callable $onRejected = null
): PromiseInterface
```
Fixed Code:
```php
public function __construct(
?callable $waitFn = null,
?callable $cancelFn = null
)
```
and
```php
public function then(
?callable $onFulfilled = null,
?callable $onRejected = null
): PromiseInterface
```
Explanation:
This diff represents a code modernization update, not a security fix. The changes add PHP 7.1+ nullable type hints (`?callable`) to function parameters that already had `= null` default values. This is a best practice improvement that:
1. Makes the code's intent more explicit - parameters can be null
2. Improves static analysis and IDE support
3. Provides stricter type checking at runtime
4. Has no security implications
The code was previously accepting null values and treating them as such; the change simply makes this contract explicit in the type signature. No security vulnerability existed in the original code, and this change does not fix a vulnerability - it's purely a code quality improvement related to PHP version compatibility and type safety standards.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/promises/src/PromiseInterface.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/promises/src/PromiseInterface.php 2025-12-21 09:36:35.279294269 +0000@@ -27,8 +27,8 @@ * @param callable $onRejected Invoked when the promise is rejected. */ public function then(- callable $onFulfilled = null,- callable $onRejected = null+ ?callable $onFulfilled = null,+ ?callable $onRejected = null ): PromiseInterface; /**
Vulnerability Existed: no Nullable Type Declaration - N/A - vendor/guzzlehttp/promises/src/PromiseInterface.php - Lines 30-31 Old Code: ```php callable $onFulfilled = null, callable $onRejected = null ``` Fixed Code: ```php ?callable $onFulfilled = null, ?callable $onRejected = null ``` Explanation: This change adds PHP nullable type declarations (`?callable`) to the method parameters. This is a type safety improvement, not a security fix. The change clarifies that these parameters can be either a callable or null, which is enforced by PHP's type system at runtime. This actually improves code safety by making the intent explicit and allowing PHP to catch type errors earlier. No security vulnerability existed in the old code - this is purely a code quality enhancement that makes the type hints more accurate and consistent with PHP 7.1+ nullable type syntax.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/promises/src/RejectedPromise.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/promises/src/RejectedPromise.php 2025-12-21 09:36:35.279294269 +0000@@ -31,8 +31,8 @@ } public function then(- callable $onFulfilled = null,- callable $onRejected = null+ ?callable $onFulfilled = null,+ ?callable $onRejected = null ): PromiseInterface { // If there's no onRejected callback then just return self. if (!$onRejected) {
Vulnerability Existed: no [Type Declaration Change - No CWE] - N/A - vendor/guzzlehttp/promises/src/RejectedPromise.php Lines 34-35 [Old Code] ```php callable $onFulfilled = null, callable $onRejected = null ``` [Fixed Code] ```php ?callable $onFulfilled = null, ?callable $onRejected = null ``` Explanation: This change adds nullable type declarations (`?callable`) to the function parameters, which is a code quality improvement, not a security fix. The parameters already had default values of `null`, so the code was already accepting `null` values at runtime. This change makes the type declaration explicit and consistent with PHP's type system (PHP 7.1+), allowing static analysis tools to properly verify that `null` is a valid value for these parameters. This is a best practice for type safety but does not address any existing security vulnerability. The original code was not vulnerable; this is merely a modernization of the type hints.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/promises/src/Utils.php 2025-12-21 09:35:59.457067807 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/promises/src/Utils.php 2025-12-21 09:36:35.279294269 +0000@@ -21,7 +21,7 @@ * * @param TaskQueueInterface|null $assign Optionally specify a new queue instance. */- public static function queue(TaskQueueInterface $assign = null): TaskQueueInterface+ public static function queue(?TaskQueueInterface $assign = null): TaskQueueInterface { static $queue; @@ -144,7 +144,9 @@ $results[$idx] = $value; }, function ($reason, $idx, Promise $aggregate): void {- $aggregate->reject($reason);+ if (Is::pending($aggregate)) {+ $aggregate->reject($reason);+ } } )->then(function () use (&$results) { ksort($results);
Based on my analysis of the provided code diff from `vendor/guzzlehttp/promises/src/Utils.php`, here are the security findings:
---
**Vulnerability 1:**
Vulnerability Existed: not sure
Null Type Declaration - CWE-1025 - vendor/guzzlehttp/promises/src/Utils.php [Line 24]
**Old Code:**
```php
public static function queue(TaskQueueInterface $assign = null): TaskQueueInterface
```
**Fixed Code:**
```php
public static function queue(?TaskQueueInterface $assign = null): TaskQueueInterface
```
**Explanation:**
This change adds nullable type hint syntax (`?TaskQueueInterface`) to the parameter. While this is not a security vulnerability per se, it represents better type safety and prevents potential type juggling issues. The nullable type hint makes the intent explicit and allows PHP's type system to catch type errors earlier. From a security perspective, this reduces the risk of unexpected behavior from null values being passed without proper validation.
---
**Vulnerability 2:**
Vulnerability Existed: yes
TRUE POSITIVE
Race Condition / State Management Issue - CWE-362 / Logic Error - CWE-682 - vendor/guzzlehttp/promises/src/Utils.php [Lines 147-150]
**Old Code:**
```php
function ($reason, $idx, Promise $aggregate): void {
$aggregate->reject($reason);
}
```
**Fixed Code:**
```php
function ($reason, $idx, Promise $aggregate): void {
if (Is::pending($aggregate)) {
$aggregate->reject($reason);
}
}
```
**Explanation:**
The original code unconditionally calls `reject()` on a Promise without checking its state. This is vulnerable to a state management issue where a Promise that has already been resolved or rejected could be rejected again, causing an error or unexpected behavior. The fix adds a guard condition `Is::pending($aggregate)` to ensure the Promise is still in a pending state before attempting to reject it. This prevents double-rejection or rejection of already-settled promises, which could lead to unhandled exceptions or undefined behavior in asynchronous operations.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/AppendStream.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/AppendStream.php 2025-12-21 09:36:35.283294517 +0000@@ -140,9 +140,9 @@ public function eof(): bool {- return !$this->streams ||- ($this->current >= count($this->streams) - 1 &&- $this->streams[$this->current]->eof());+ return !$this->streams+ || ($this->current >= count($this->streams) - 1+ && $this->streams[$this->current]->eof()); } public function rewind(): void@@ -239,8 +239,6 @@ } /**- * {@inheritdoc}- * * @return mixed */ public function getMetadata($key = null)
Analyzing the provided code diff for security vulnerabilities:
Vulnerability Existed: no
N/A - N/A - vendor/guzzlehttp/psr7/src/AppendStream.php - Lines 140-146, 242-244
Old Code:
```
return !$this->streams ||
($this->current >= count($this->streams) - 1 &&
$this->streams[$this->current]->eof());
```
and
```
/**
* {@inheritdoc}
*
* @return mixed
*/
```
Fixed Code:
```
return !$this->streams
|| ($this->current >= count($this->streams) - 1
&& $this->streams[$this->current]->eof());
```
and
```
/**
* @return mixed
*/
```
Explanation:
These changes are code formatting and documentation updates with no security implications. The first change reformats the logical operators for improved readability without altering the logic. The second change removes redundant `{@inheritdoc}` documentation tag. Neither modification introduces or fixes a security vulnerability. The code functionality remains identical in both versions.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/BufferStream.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/BufferStream.php 2025-12-21 09:36:35.283294517 +0000@@ -134,8 +134,6 @@ } /**- * {@inheritdoc}- * * @return mixed */ public function getMetadata($key = null)
Vulnerability Existed: no
No CWE Applicable - This is a Documentation/Comment Change
File: vendor/guzzlehttp/psr7/src/BufferStream.php (Lines 136-137)
Old Code:
```
/**
* {@inheritdoc}
*
* @return mixed
*/
```
Fixed Code:
```
/**
* @return mixed
*/
```
Explanation:
This change removes the `{@inheritdoc}` PHPDoc annotation from the `getMetadata()` method's documentation block. This is purely a documentation/comment modification with no security implications. The `{@inheritdoc}` tag is a documentation tool directive that tells documentation generators to inherit documentation from parent classes or interfaces. Removing it does not affect code execution, security posture, or vulnerability remediation. This appears to be a minor documentation cleanup or standardization change in the Guzzle HTTP library's PSR-7 implementation.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/CachingStream.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/CachingStream.php 2025-12-21 09:36:35.283294517 +0000@@ -33,7 +33,7 @@ */ public function __construct( StreamInterface $stream,- StreamInterface $target = null+ ?StreamInterface $target = null ) { $this->remoteStream = $stream; $this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+'));
Vulnerability Existed: no [Type Declaration - Type Juggling] - [CWE-1025] - [vendor/guzzlehttp/psr7/src/CachingStream.php] [Line 36] Old Code: ```php StreamInterface $target = null ``` Fixed Code: ```php ?StreamInterface $target = null ``` Explanation: This is a code quality improvement, not a security fix. The change from `StreamInterface $target = null` to `?StreamInterface $target = null` is a PHP 7.1+ nullable type declaration syntax update. This makes the type hint explicitly nullable rather than relying on the default parameter value of `null`. This change: - Improves type safety by making nullability explicit in the signature - Enables better static analysis and IDE support - Does not address or fix any existing security vulnerability - Is purely a modernization of PHP syntax and type hinting practices No security vulnerability was fixed in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/FnStream.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/FnStream.php 2025-12-21 09:36:35.283294517 +0000@@ -54,7 +54,7 @@ public function __destruct() { if (isset($this->_fn_close)) {- call_user_func($this->_fn_close);+ ($this->_fn_close)(); } } @@ -93,7 +93,8 @@ public function __toString(): string { try {- return call_user_func($this->_fn___toString);+ /** @var string */+ return ($this->_fn___toString)(); } catch (\Throwable $e) { if (\PHP_VERSION_ID >= 70400) { throw $e;@@ -106,76 +107,74 @@ public function close(): void {- call_user_func($this->_fn_close);+ ($this->_fn_close)(); } public function detach() {- return call_user_func($this->_fn_detach);+ return ($this->_fn_detach)(); } public function getSize(): ?int {- return call_user_func($this->_fn_getSize);+ return ($this->_fn_getSize)(); } public function tell(): int {- return call_user_func($this->_fn_tell);+ return ($this->_fn_tell)(); } public function eof(): bool {- return call_user_func($this->_fn_eof);+ return ($this->_fn_eof)(); } public function isSeekable(): bool {- return call_user_func($this->_fn_isSeekable);+ return ($this->_fn_isSeekable)(); } public function rewind(): void {- call_user_func($this->_fn_rewind);+ ($this->_fn_rewind)(); } public function seek($offset, $whence = SEEK_SET): void {- call_user_func($this->_fn_seek, $offset, $whence);+ ($this->_fn_seek)($offset, $whence); } public function isWritable(): bool {- return call_user_func($this->_fn_isWritable);+ return ($this->_fn_isWritable)(); } public function write($string): int {- return call_user_func($this->_fn_write, $string);+ return ($this->_fn_write)($string); } public function isReadable(): bool {- return call_user_func($this->_fn_isReadable);+ return ($this->_fn_isReadable)(); } public function read($length): string {- return call_user_func($this->_fn_read, $length);+ return ($this->_fn_read)($length); } public function getContents(): string {- return call_user_func($this->_fn_getContents);+ return ($this->_fn_getContents)(); } /**- * {@inheritdoc}- * * @return mixed */ public function getMetadata($key = null) {- return call_user_func($this->_fn_getMetadata, $key);+ return ($this->_fn_getMetadata)($key); } }
Vulnerability Existed: no No vulnerabilities identified in this diff. Explanation: This diff represents a refactoring of the `FnStream.php` file that replaces deprecated `call_user_func()` calls with modern PHP callable syntax using arrow function invocation syntax `($callable)()`. Key observations: 1. **Function Call Replacement**: All instances of `call_user_func($this->_fn_*, ...)` have been replaced with `($this->_fn_*)(...)` 2. **Security Impact**: This change actually improves code security by: - Using native PHP callable invocation syntax instead of a reflection-based function - Reducing the attack surface by avoiding the `call_user_func()` function, which has historically been a target for security researchers - Maintaining the same callable validation that PHP's variable function syntax provides 3. **No New Vulnerabilities Introduced**: - The refactored code maintains the same object property access pattern - No new user input processing is introduced - No changes to authentication, validation, or authorization logic - The callable properties (`$this->_fn_*`) are internal to the class and set during object construction 4. **Minor Change**: One docblock comment was removed (`@inheritdoc`), and a type hint comment was added for the `__toString()` method return value, neither of which introduce security issues. This is a safe refactoring that modernizes the code without introducing security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/Header.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/Header.php 2025-12-21 09:36:35.283294517 +0000@@ -22,7 +22,7 @@ foreach ((array) $header as $value) { foreach (self::splitList($value) as $val) { $part = [];- foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {+ foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) ?: [] as $kvp) { if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) { $m = $matches[0]; if (isset($m[1])) {
Vulnerability Existed: no
Improper Null Handling - CWE-252 - vendor/guzzlehttp/psr7/src/Header.php Line 25
Old Code:
```php
foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
```
Fixed Code:
```php
foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) ?: [] as $kvp) {
```
Explanation:
This is a defensive coding improvement rather than a security vulnerability fix. The `preg_split()` function can return `false` on error (though in normal operation it returns an array). The fix adds a null coalescing fallback `?: []` to ensure the foreach loop always receives an array, preventing potential PHP errors if `preg_split()` fails. This prevents possible Denial of Service through uncaught exceptions or warnings, making it a minor hardening measure. However, this is not a critical security vulnerability being fixed—`preg_split()` returning false is extremely rare in normal operation, and PHP 8+ would handle this more gracefully. The change is defensive programming rather than a security patch.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/HttpFactory.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/HttpFactory.php 2025-12-21 09:36:35.283294517 +0000@@ -27,10 +27,10 @@ { public function createUploadedFile( StreamInterface $stream,- int $size = null,+ ?int $size = null, int $error = \UPLOAD_ERR_OK,- string $clientFilename = null,- string $clientMediaType = null+ ?string $clientFilename = null,+ ?string $clientMediaType = null ): UploadedFileInterface { if ($size === null) { $size = $stream->getSize();
Vulnerability Existed: no Type Juggling / Type Declaration Issue - Not a Security Vulnerability - vendor/guzzlehttp/psr7/src/HttpFactory.php [30, 32, 33] Old Code: ```php int $size = null, string $clientFilename = null, string $clientMediaType = null ``` Fixed Code: ```php ?int $size = null, ?string $clientFilename = null, ?string $clientMediaType = null ``` Explanation: This is not a security fix but rather a code quality improvement. The change updates the function parameter type declarations to use PHP 7.1+ nullable type syntax (`?type`), which is semantically equivalent to `type = null` but more explicit and follows modern PHP conventions. The nullable type declarations clarify to developers and static analysis tools that these parameters can accept null values. This improves type safety and IDE support but does not address any security vulnerability. The functionality remains identical before and after this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/InflateStream.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/InflateStream.php 2025-12-21 09:36:35.283294517 +0000@@ -13,9 +13,9 @@ * then appends the zlib.inflate filter. The stream is then converted back * to a Guzzle stream resource to be used as a Guzzle stream. *- * @see http://tools.ietf.org/html/rfc1950- * @see http://tools.ietf.org/html/rfc1952- * @see http://php.net/manual/en/filters.compression.php+ * @see https://datatracker.ietf.org/doc/html/rfc1950+ * @see https://datatracker.ietf.org/doc/html/rfc1952+ * @see https://www.php.net/manual/en/filters.compression.php */ final class InflateStream implements StreamInterface {@@ -28,7 +28,7 @@ { $resource = StreamWrapper::getResource($stream); // Specify window=15+32, so zlib will use header detection to both gzip (with header) and zlib data- // See http://www.zlib.net/manual.html#Advanced definition of inflateInit2+ // See https://www.zlib.net/manual.html#Advanced definition of inflateInit2 // "Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection" // Default window size is 15. stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ, ['window' => 15 + 32]);
Vulnerability Existed: no No CWE - N/A - vendor/guzzlehttp/psr7/src/InflateStream.php (All lines) Old Code: ``` * @see http://tools.ietf.org/html/rfc1950 * @see http://tools.ietf.org/html/rfc1952 * @see http://php.net/manual/en/filters.compression.php ... // See http://www.zlib.net/manual.html#Advanced definition of inflateInit2 ``` Fixed Code: ``` * @see https://datatracker.ietf.org/doc/html/rfc1950 * @see https://datatracker.ietf.org/doc/html/rfc1952 * @see https://www.php.net/manual/en/filters.compression.php ... // See https://www.zlib.net/manual.html#Advanced definition of inflateInit2 ``` Explanation: This diff contains no security vulnerability fixes. The changes are purely cosmetic/documentation updates that upgrade HTTP URLs to HTTPS and redirect outdated URL paths to their current equivalents (e.g., `tools.ietf.org` → `datatracker.ietf.org`). These are best practice improvements for URL validity and security (HTTPS over HTTP), but they do not fix any actual vulnerabilities in the code itself. The functional code remains unchanged, and no security issues are being remediated by this patch.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/Message.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/Message.php 2025-12-21 09:36:35.283294517 +0000@@ -33,7 +33,7 @@ } foreach ($message->getHeaders() as $name => $values) {- if (strtolower($name) === 'set-cookie') {+ if (is_string($name) && strtolower($name) === 'set-cookie') { foreach ($values as $value) { $msg .= "\r\n{$name}: ".$value; }@@ -146,7 +146,7 @@ // If these aren't the same, then one line didn't match and there's an invalid header. if ($count !== substr_count($rawHeaders, "\n")) {- // Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4+ // Folding is deprecated, see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4 if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) { throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding'); }@@ -227,9 +227,9 @@ public static function parseResponse(string $message): ResponseInterface { $data = self::parseMessage($message);- // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space- // between status-code and reason-phrase is required. But browsers accept- // responses without space and reason as well.+ // According to https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2+ // the space between status-code and reason-phrase is required. But+ // browsers accept responses without space and reason as well. if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) { throw new \InvalidArgumentException('Invalid response string: '.$data['start-line']); }
Vulnerability Existed: not sure
Type Checking Issue - Not a CWE Security Vulnerability - vendor/guzzlehttp/psr7/src/Message.php, Line 36
Old Code:
```php
if (strtolower($name) === 'set-cookie') {
```
Fixed Code:
```php
if (is_string($name) && strtolower($name) === 'set-cookie') {
```
Explanation:
The added `is_string($name)` check is a defensive programming practice rather than a security fix. It guards against potential type errors if `$name` is not a string, which could cause unexpected behavior or warnings. However, this is not a traditional security vulnerability (CWE). The `foreach` loop iterates over `$message->getHeaders()`, which should return an array where keys are strings by design. The fix prevents potential type juggling issues but doesn't address a concrete security vulnerability like injection, access control, or data exposure.
---
Vulnerability Existed: no
Documentation URL Update - Not a CWE Security Vulnerability - vendor/guzzlehttp/psr7/src/Message.php, Lines 149, 230-232
Old Code:
```php
// Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4
// According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space
```
Fixed Code:
```php
// Folding is deprecated, see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4
// According to https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
```
Explanation:
These changes update RFC documentation URLs from the deprecated `tools.ietf.org` domain to the current `datatracker.ietf.org` domain. This is a documentation maintenance update with no security implications. The URLs point to the same RFC specifications, and no code logic or security behavior has changed.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/MessageTrait.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/MessageTrait.php 2025-12-21 09:36:35.283294517 +0000@@ -12,10 +12,10 @@ */ trait MessageTrait {- /** @var array<string, string[]> Map of all registered headers, as original name => array of values */+ /** @var string[][] Map of all registered headers, as original name => array of values */ private $headers = []; - /** @var array<string, string> Map of lowercase header name => original name at registration */+ /** @var string[] Map of lowercase header name => original name at registration */ private $headerNames = []; /** @var string */@@ -141,7 +141,7 @@ } /**- * @param array<string|int, string|string[]> $headers+ * @param (string|string[])[] $headers */ private function setHeaders(array $headers): void {@@ -174,10 +174,6 @@ return $this->trimAndValidateHeaderValues([$value]); } - if (count($value) === 0) {- throw new \InvalidArgumentException('Header value can not be an empty array.');- }- return $this->trimAndValidateHeaderValues($value); } @@ -193,7 +189,7 @@ * * @return string[] Trimmed header values *- * @see https://tools.ietf.org/html/rfc7230#section-3.2.4+ * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4 */ private function trimAndValidateHeaderValues(array $values): array {@@ -213,7 +209,7 @@ } /**- * @see https://tools.ietf.org/html/rfc7230#section-3.2+ * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2 * * @param mixed $header */@@ -234,7 +230,7 @@ } /**- * @see https://tools.ietf.org/html/rfc7230#section-3.2+ * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2 * * field-value = *( field-content / obs-fold ) * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
Analyzing the provided code diff for security fixes:
---
**Vulnerability 1:**
Vulnerability Existed: yes
FALSE POSITIVE
Improper Input Validation - CWE-20 - vendor/guzzlehttp/psr7/src/MessageTrait.php - Lines 177-180
Old Code:
```php
if (count($value) === 0) {
throw new \InvalidArgumentException('Header value can not be an empty array.');
}
```
Fixed Code:
```php
(Code removed - validation check deleted)
```
Explanation:
The removal of the empty array validation is a security regression. The check `if (count($value) === 0)` was preventing empty header values from being set. By removing this validation, the code now allows empty header arrays to be passed to `trimAndValidateHeaderValues()`, which could lead to invalid HTTP headers being generated. This violates RFC 7230 requirements for header field values and could allow malformed HTTP messages to be constructed, potentially enabling HTTP response splitting or header injection attacks.
---
**Vulnerability 2:**
Vulnerability Existed: not sure
Improper Resource Validation - CWE-20 - vendor/guzzlehttp/psr7/src/MessageTrait.php - Lines 144
Old Code:
```php
@param array<string|int, string|string[]> $headers
```
Fixed Code:
```php
@param (string|string[])[] $headers
```
Explanation:
The type hint change from `array<string|int, string|string[]>` to `(string|string[])[]` removes support for integer keys in the headers array. This is primarily a type safety improvement rather than a security fix. However, if code relied on integer keys being accepted, this change could affect behavior. The security implication is unclear without understanding how integer keys were previously handled and whether they could have been exploited for type confusion or bypass attacks.
---
**Additional Changes (Non-Security):**
The remaining changes (type hint documentation updates and RFC URL updates from tools.ietf.org to datatracker.ietf.org) are non-security related and represent documentation improvements and maintenance updates.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/MultipartStream.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/MultipartStream.php 2025-12-21 09:36:35.283294517 +0000@@ -32,7 +32,7 @@ * * @throws \InvalidArgumentException */- public function __construct(array $elements = [], string $boundary = null)+ public function __construct(array $elements = [], ?string $boundary = null) { $this->boundary = $boundary ?: bin2hex(random_bytes(20)); $this->stream = $this->createStream($elements);@@ -51,7 +51,7 @@ /** * Get the headers needed before transferring the content of a POST file *- * @param array<string, string> $headers+ * @param string[] $headers */ private function getHeaders(array $headers): string {@@ -112,10 +112,15 @@ $stream->addStream(Utils::streamFor("\r\n")); } + /**+ * @param string[] $headers+ *+ * @return array{0: StreamInterface, 1: string[]}+ */ private function createElement(string $name, StreamInterface $stream, ?string $filename, array $headers): array { // Set a default content-disposition header if one was no provided- $disposition = $this->getHeader($headers, 'content-disposition');+ $disposition = self::getHeader($headers, 'content-disposition'); if (!$disposition) { $headers['Content-Disposition'] = ($filename === '0' || $filename) ? sprintf(@@ -127,7 +132,7 @@ } // Set a default content-length header if one was no provided- $length = $this->getHeader($headers, 'content-length');+ $length = self::getHeader($headers, 'content-length'); if (!$length) { if ($length = $stream->getSize()) { $headers['Content-Length'] = (string) $length;@@ -135,7 +140,7 @@ } // Set a default Content-Type if one was not supplied- $type = $this->getHeader($headers, 'content-type');+ $type = self::getHeader($headers, 'content-type'); if (!$type && ($filename === '0' || $filename)) { $headers['Content-Type'] = MimeType::fromFilename($filename) ?? 'application/octet-stream'; }@@ -143,11 +148,14 @@ return [$stream, $headers]; } - private function getHeader(array $headers, string $key)+ /**+ * @param string[] $headers+ */+ private static function getHeader(array $headers, string $key): ?string { $lowercaseHeader = strtolower($key); foreach ($headers as $k => $v) {- if (strtolower($k) === $lowercaseHeader) {+ if (strtolower((string) $k) === $lowercaseHeader) { return $v; } }
Vulnerability Existed: no
[Type Juggling / Weak Comparison] - [CWE-1025] - [vendor/guzzlehttp/psr7/src/MultipartStream.php] [Lines 157-158]
[Old Code]
```php
if (strtolower($k) === $lowercaseHeader) {
return $v;
}
```
[Fixed Code]
```php
if (strtolower((string) $k) === $lowercaseHeader) {
return $v;
}
```
Explanation:
This is a defensive code improvement rather than a vulnerability fix. The original code was already safe because `$k` comes from array keys in the `$headers` array parameter, which are always strings in PHP. The explicit `(string)` cast added in the fix is a defensive programming practice to ensure type safety and prevent potential issues if the array structure were to change unexpectedly. However, this is not fixing an actual vulnerability in the original code.
---
Vulnerability Existed: no
[Code Quality - Documentation] - [N/A] - [vendor/guzzlehttp/psr7/src/MultipartStream.php] [Lines 32, 54, 115-118, 151-153]
[Old Code]
```php
public function __construct(array $elements = [], string $boundary = null)
// Missing return type documentation
private function getHeader(array $headers, string $key)
```
[Fixed Code]
```php
public function __construct(array $elements = [], ?string $boundary = null)
/**
* @param string[] $headers
*
* @return array{0: StreamInterface, 1: string[]}
*/
private static function getHeader(array $headers, string $key): ?string
```
Explanation:
These changes represent improvements in code documentation and type safety through better PHP 7.1+ nullable type syntax and PHPDoc annotations. The addition of nullable type hints (`?string` instead of `string = null`) and return type declarations (`?string`) improve type safety and IDE support. The method was also changed from instance to static (`self::getHeader()` calls), which is appropriate since it doesn't use any instance state. These are refactoring improvements, not security vulnerability fixes.
---
**Summary:** No security vulnerabilities were fixed in this diff. The changes represent code quality improvements including better type declarations, improved documentation, and defensive programming practices.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/PumpStream.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/PumpStream.php 2025-12-21 09:36:35.283294517 +0000@@ -18,7 +18,7 @@ */ final class PumpStream implements StreamInterface {- /** @var callable|null */+ /** @var callable(int): (string|false|null)|null */ private $source; /** @var int|null */@@ -34,7 +34,7 @@ private $buffer; /**- * @param callable(int): (string|null|false) $source Source of the stream data. The callable MAY+ * @param callable(int): (string|false|null) $source Source of the stream data. The callable MAY * accept an integer argument used to control the * amount of data to return. The callable MUST * return a string when called, or false|null on error@@ -150,8 +150,6 @@ } /**- * {@inheritdoc}- * * @return mixed */ public function getMetadata($key = null)@@ -165,9 +163,9 @@ private function pump(int $length): void {- if ($this->source) {+ if ($this->source !== null) { do {- $data = call_user_func($this->source, $length);+ $data = ($this->source)($length); if ($data === false || $data === null) { $this->source = null;
I'll analyze this code diff for security vulnerabilities.
Vulnerability Existed: no
CWE-476 (NULL Pointer Dereference) - CWE-476 - vendor/guzzlehttp/psr7/src/PumpStream.php Lines 166-167
[Old Code]
```
if ($this->source) {
do {
$data = call_user_func($this->source, $length);
```
[Fixed Code]
```
if ($this->source !== null) {
do {
$data = ($this->source)($length);
```
Explanation:
This change improves null-safety checking. The old code used a loose truthiness check `if ($this->source)` which could be problematic if `$this->source` is set to a callable that evaluates to falsy. The new code uses explicit null comparison `if ($this->source !== null)` to only proceed if the source is actually set. Additionally, `call_user_func()` is replaced with direct callable invocation `($this->source)($length)`, which is more type-safe and performant. While this is a legitimate improvement, it does not appear to fix an existing vulnerability but rather prevents a potential issue. The original code was not vulnerable in practice due to the type declaration ensuring `$source` is callable when set.
---
Vulnerability Existed: no
Code Quality Issue - No CWE - vendor/guzzlehttp/psr7/src/PumpStream.php Lines 21, 37
[Old Code]
```
/** @var callable|null */
private $source;
/**
* @param callable(int): (string|null|false) $source
```
[Fixed Code]
```
/** @var callable(int): (string|false|null)|null */
private $source;
/**
* @param callable(int): (string|false|null) $source
```
Explanation:
This is a documentation/type annotation improvement, not a security fix. The PHPDoc comments are made more precise and consistent. The parameter type now explicitly documents that the callable returns `string|false|null` (reordered as `string|false|null` for consistency). This improves code clarity and IDE type-checking but does not address a security vulnerability.
---
Vulnerability Existed: no
Code Quality Issue - No CWE - vendor/guzzlehttp/psr7/src/PumpStream.php Lines 152-154
[Old Code]
```
/**
* {@inheritdoc}
*
* @return mixed
*/
```
[Fixed Code]
```
/**
* @return mixed
*/
```
Explanation:
This removes the `{@inheritdoc}` tag from the PHPDoc comment for the `getMetadata()` method. This is a documentation cleanup, not a security fix. It reduces redundant documentation markup but does not address any security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/Query.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/Query.php 2025-12-21 09:36:35.283294517 +0000@@ -63,12 +63,15 @@ * string. This function does not modify the provided keys when an array is * encountered (like `http_build_query()` would). *- * @param array $params Query string parameters.- * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986- * to encode using RFC3986, or PHP_QUERY_RFC1738- * to encode using RFC1738.+ * @param array $params Query string parameters.+ * @param int|false $encoding Set to false to not encode,+ * PHP_QUERY_RFC3986 to encode using+ * RFC3986, or PHP_QUERY_RFC1738 to+ * encode using RFC1738.+ * @param bool $treatBoolsAsInts Set to true to encode as 0/1, and+ * false as false/true. */- public static function build(array $params, $encoding = PHP_QUERY_RFC3986): string+ public static function build(array $params, $encoding = PHP_QUERY_RFC3986, bool $treatBoolsAsInts = true): string { if (!$params) { return '';@@ -86,12 +89,14 @@ throw new \InvalidArgumentException('Invalid type'); } + $castBool = $treatBoolsAsInts ? static function ($v) { return (int) $v; } : static function ($v) { return $v ? 'true' : 'false'; };+ $qs = ''; foreach ($params as $k => $v) { $k = $encoder((string) $k); if (!is_array($v)) { $qs .= $k;- $v = is_bool($v) ? (int) $v : $v;+ $v = is_bool($v) ? $castBool($v) : $v; if ($v !== null) { $qs .= '='.$encoder((string) $v); }@@ -99,7 +104,7 @@ } else { foreach ($v as $vv) { $qs .= $k;- $vv = is_bool($vv) ? (int) $vv : $vv;+ $vv = is_bool($vv) ? $castBool($vv) : $vv; if ($vv !== null) { $qs .= '='.$encoder((string) $vv); }
Analyzing the provided code diff for security vulnerabilities...
Vulnerability Existed: no
[No Security Vulnerability Detected] - [N/A] - [vendor/guzzlehttp/psr7/src/Query.php] [63-107]
Old Code:
```php
public static function build(array $params, $encoding = PHP_QUERY_RFC3986): string
{
// ... encoder setup ...
foreach ($params as $k => $v) {
$k = $encoder((string) $k);
if (!is_array($v)) {
$qs .= $k;
$v = is_bool($v) ? (int) $v : $v;
if ($v !== null) {
$qs .= '='.$encoder((string) $v);
}
} else {
foreach ($v as $vv) {
$qs .= $k;
$vv = is_bool($vv) ? (int) $vv : $vv;
if ($vv !== null) {
$qs .= '='.$encoder((string) $vv);
}
}
}
}
}
```
Fixed Code:
```php
public static function build(array $params, $encoding = PHP_QUERY_RFC3986, bool $treatBoolsAsInts = true): string
{
// ... encoder setup ...
$castBool = $treatBoolsAsInts ? static function ($v) { return (int) $v; } : static function ($v) { return $v ? 'true' : 'false'; };
foreach ($params as $k => $v) {
$k = $encoder((string) $k);
if (!is_array($v)) {
$qs .= $k;
$v = is_bool($v) ? $castBool($v) : $v;
if ($v !== null) {
$qs .= '='.$encoder((string) $v);
}
} else {
foreach ($v as $vv) {
$qs .= $k;
$vv = is_bool($vv) ? $castBool($vv) : $vv;
if ($vv !== null) {
$qs .= '='.$encoder((string) $vv);
}
}
}
}
}
```
Explanation:
This change adds a new optional parameter `$treatBoolsAsInts` with a default value of `true` and refactors boolean handling logic. The modification is a feature enhancement that provides backward compatibility while allowing flexible boolean representation in query strings. There is no security vulnerability being fixed or introduced. The change only affects how boolean values are cast to strings in URL query parameters, and the implementation properly encodes all values using the existing `$encoder` function, which prevents injection attacks. The encoding step remains unchanged and continues to protect against XSS and injection vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/Request.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/Request.php 2025-12-21 09:36:35.283294517 +0000@@ -28,7 +28,7 @@ /** * @param string $method HTTP method * @param string|UriInterface $uri URI- * @param array<string, string|string[]> $headers Request headers+ * @param (string|string[])[] $headers Request headers * @param string|resource|StreamInterface|null $body Request body * @param string $version Protocol version */@@ -143,7 +143,7 @@ $this->headerNames['host'] = 'Host'; } // Ensure Host is the first header.- // See: http://tools.ietf.org/html/rfc7230#section-5.4+ // See: https://datatracker.ietf.org/doc/html/rfc7230#section-5.4 $this->headers = [$header => [$host]] + $this->headers; }
``` Vulnerability Existed: no [No Vulnerability Identified] Explanation: This diff contains only non-security changes: 1. Line 31: Type hint documentation update from `array<string, string|string[]>` to `(string|string[])[]` - This is a documentation/type annotation clarification with no security impact. 2. Line 146: URL update from `http://` to `https://` in a code comment referencing RFC 7230 - This is a documentation improvement (using secure protocol for reference links) with no security implications for the code functionality. Both changes are benign and do not address, introduce, or relate to any security vulnerabilities. No security fixes are present in this diff. ```
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/Response.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/Response.php 2025-12-21 09:36:35.283294517 +0000@@ -86,7 +86,7 @@ /** * @param int $status Status code- * @param array<string, string|string[]> $headers Response headers+ * @param (string|string[])[] $headers Response headers * @param string|resource|StreamInterface|null $body Response body * @param string $version Protocol version * @param string|null $reason Reason phrase (when empty a default will be used based on the status code)@@ -96,7 +96,7 @@ array $headers = [], $body = null, string $version = '1.1',- string $reason = null+ ?string $reason = null ) { $this->assertStatusCodeRange($status);
Vulnerability Existed: no Nullable Type Declaration - N/A - vendor/guzzlehttp/psr7/src/Response.php Lines 99 [Old Code] string $reason = null [Fixed Code] ?string $reason = null Explanation: This is not a security vulnerability. The change modernizes the PHP type declaration from using a default null value to using proper nullable type syntax (?string). This is a code quality improvement that makes the type declaration more explicit and compliant with modern PHP standards (PHP 7.1+). It does not introduce or fix any security vulnerabilities—it simply clarifies the intended type signature. --- Vulnerability Existed: no Type Annotation Documentation Update - N/A - vendor/guzzlehttp/psr7/src/Response.php Lines 89 [Old Code] @param array<string, string|string[]> $headers Response headers [Fixed Code] @param (string|string[])[] $headers Response headers Explanation: This is not a security vulnerability. The change updates the PHPDoc type annotation to be more precise about the structure of the $headers array. Both annotations describe the same data structure (an array where values can be strings or arrays of strings), but the new syntax is more accurate. This is a documentation improvement with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/ServerRequest.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/ServerRequest.php 2025-12-21 09:36:35.283294517 +0000@@ -59,7 +59,7 @@ /** * @param string $method HTTP method * @param string|UriInterface $uri URI- * @param array<string, string|string[]> $headers Request headers+ * @param (string|string[])[] $headers Request headers * @param string|resource|StreamInterface|null $body Request body * @param string $version Protocol version * @param array $serverParams Typically the $_SERVER superglobal@@ -286,8 +286,6 @@ } /**- * {@inheritdoc}- * * @return array|object|null */ public function getParsedBody()@@ -309,8 +307,6 @@ } /**- * {@inheritdoc}- * * @return mixed */ public function getAttribute($attribute, $default = null)
Vulnerability Existed: no
This diff contains only documentation and type hint improvements with no security implications:
1. **Type hint refinement (line 62)**: Changed from `array<string, string|string[]>` to `(string|string[])[]` - this is a more precise type annotation that doesn't affect runtime behavior or security.
2. **Documentation cleanup (lines 289-290, 312-313)**: Removed `{@inheritdoc}` comments - this is a documentation-only change with no security impact.
These are maintenance improvements with no security vulnerabilities introduced or fixed.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/Stream.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/Stream.php 2025-12-21 09:36:35.283294517 +0000@@ -12,8 +12,8 @@ class Stream implements StreamInterface { /**- * @see http://php.net/manual/function.fopen.php- * @see http://php.net/manual/en/function.gzopen.php+ * @see https://www.php.net/manual/en/function.fopen.php+ * @see https://www.php.net/manual/en/function.gzopen.php */ private const READABLE_MODES = '/r|a\+|ab\+|w\+|wb\+|x\+|xb\+|c\+|cb\+/'; private const WRITABLE_MODES = '/a|w|r\+|rb\+|rw|x|c/';@@ -264,8 +264,6 @@ } /**- * {@inheritdoc}- * * @return mixed */ public function getMetadata($key = null)
Vulnerability Existed: no
No Security Vulnerabilities Detected - [N/A] - vendor/guzzlehttp/psr7/src/Stream.php [Lines 15-16, 267-268]
**Old Code:**
```php
* @see http://php.net/manual/function.fopen.php
* @see http://php.net/manual/en/function.gzopen.php
```
and
```php
* {@inheritdoc}
*
```
**Fixed Code:**
```php
* @see https://www.php.net/manual/en/function.fopen.php
* @see https://www.php.net/manual/en/function.gzopen.php
```
and
```php
* @return mixed
```
**Explanation:**
This diff contains only non-security documentation and comment updates:
1. **Lines 15-16**: URLs are updated from `http://` to `https://` and corrected from `php.net/manual/function.fopen.php` to `php.net/manual/en/function.fopen.php`. This is a documentation improvement (HTTPS upgrade and URL standardization) with no security impact on the actual code.
2. **Lines 267-268**: The `{@inheritdoc}` PHPDoc tag is removed from a comment block. This is purely a documentation change with no functional or security implications.
Neither change introduces, fixes, or relates to any security vulnerability in the code logic. These are maintenance changes to documentation strings.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php 2025-12-21 09:36:35.283294517 +0000@@ -70,7 +70,7 @@ { /** @var callable $callable */ $callable = [$this->stream, $method];- $result = call_user_func_array($callable, $args);+ $result = ($callable)(...$args); // Always return the wrapped object if the result is a return $this return $result === $this->stream ? $this : $result;@@ -82,8 +82,6 @@ } /**- * {@inheritdoc}- * * @return mixed */ public function getMetadata($key = null)
Based on the provided diff analysis:
---
**Vulnerability 1: Code Modernization (No Vulnerability)**
Vulnerability Existed: no
CWE - N/A - vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php [Line 73]
Old Code:
```php
$result = call_user_func_array($callable, $args);
```
Fixed Code:
```php
$result = ($callable)(...$args);
```
Explanation:
This change replaces the deprecated `call_user_func_array()` function with PHP's modern first-class callable syntax (`(...$args)` unpacking). This is a modernization change, not a security fix. Both approaches are functionally equivalent in terms of security. The new syntax is cleaner, more performant, and aligns with modern PHP 8.1+ best practices. No vulnerability existed in the old code, and none is introduced in the new code.
---
**Vulnerability 2: Documentation Removal (No Vulnerability)**
Vulnerability Existed: no
CWE - N/A - vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php [Lines 84-86]
Old Code:
```php
/**
* {@inheritdoc}
*
* @return mixed
*/
```
Fixed Code:
```php
/**
* @return mixed
*/
```
Explanation:
This change removes the `{@inheritdoc}` PHPDoc tag, which is redundant. This is purely a documentation cleanup and has no security implications. The `@return mixed` annotation remains intact to document the return type.
---
**Summary:** This diff contains no security vulnerabilities. It represents routine maintenance: modernizing deprecated function calls and cleaning up redundant documentation comments.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/StreamWrapper.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/StreamWrapper.php 2025-12-21 09:36:35.283294517 +0000@@ -69,7 +69,7 @@ } } - public function stream_open(string $path, string $mode, int $options, string &$opened_path = null): bool+ public function stream_open(string $path, string $mode, int $options, ?string &$opened_path = null): bool { $options = stream_context_get_options($this->context); @@ -122,10 +122,28 @@ } /**- * @return array<int|string, int>+ * @return array{+ * dev: int,+ * ino: int,+ * mode: int,+ * nlink: int,+ * uid: int,+ * gid: int,+ * rdev: int,+ * size: int,+ * atime: int,+ * mtime: int,+ * ctime: int,+ * blksize: int,+ * blocks: int+ * }|false */- public function stream_stat(): array+ public function stream_stat() {+ if ($this->stream->getSize() === null) {+ return false;+ }+ static $modeMap = [ 'r' => 33060, 'rb' => 33060,@@ -152,7 +170,21 @@ } /**- * @return array<int|string, int>+ * @return array{+ * dev: int,+ * ino: int,+ * mode: int,+ * nlink: int,+ * uid: int,+ * gid: int,+ * rdev: int,+ * size: int,+ * atime: int,+ * mtime: int,+ * ctime: int,+ * blksize: int,+ * blocks: int+ * } */ public function url_stat(string $path, int $flags): array {
Analyzing the provided code diff for security vulnerabilities:
---
**Vulnerability 1:**
Vulnerability Existed: yes
TRUE POSITIVE
Improper Input Validation / Missing Return Type Handling - CWE-252 / CWE-754 - vendor/guzzlehttp/psr7/src/StreamWrapper.php lines 125-146
[Old Code]
```php
/**
* @return array<int|string, int>
*/
public function stream_stat(): array
{
static $modeMap = [
'r' => 33060,
'rb' => 33060,
...
];
return [
'dev' => 0, 'ino' => 0, 'mode' => $modeMap[$this->mode] ?? 33060,
'nlink' => 1, 'uid' => 0, 'gid' => 0, 'rdev' => 0,
'size' => $this->stream->getSize() ?? 0,
'atime' => time(), 'mtime' => time(), 'ctime' => time(),
'blksize' => -1, 'blocks' => -1,
];
}
```
[Fixed Code]
```php
/**
* @return array{
* dev: int,
* ino: int,
* mode: int,
* nlink: int,
* uid: int,
* gid: int,
* rdev: int,
* size: int,
* atime: int,
* mtime: int,
* ctime: int,
* blksize: int,
* blocks: int
* }|false
*/
public function stream_stat()
{
if ($this->stream->getSize() === null) {
return false;
}
static $modeMap = [
'r' => 33060,
'rb' => 33060,
...
];
return [
'dev' => 0, 'ino' => 0, 'mode' => $modeMap[$this->mode] ?? 33060,
'nlink' => 1, 'uid' => 0, 'gid' => 0, 'rdev' => 0,
'size' => $this->stream->getSize() ?? 0,
'atime' => time(), 'mtime' => time(), 'ctime' => time(),
'blksize' => -1, 'blocks' => -1,
];
}
```
Explanation:
The original code guaranteed an array return type, but stream_stat() can legitimately fail (when stream size is unavailable) and should return false per PHP stream wrapper protocol. The fix adds a validation check that returns false when the stream size is null, preventing invalid stat data from being returned. The removed return type declaration and updated docblock correctly reflect that the function can return false on failure, which is the proper behavior for stream wrapper stat methods.
---
**Vulnerability 2:**
Vulnerability Existed: not sure
Type Declaration Update - CWE-704 - vendor/guzzlehttp/psr7/src/StreamWrapper.php line 72
[Old Code]
```php
public function stream_open(string $path, string $mode, int $options, string &$opened_path = null): bool
```
[Fixed Code]
```php
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path = null): bool
```
Explanation:
The parameter `$opened_path` is made nullable by adding the `?` type prefix. This is a type safety improvement rather than a security fix. The original signature allowed `null` as a default value but the type hint didn't reflect this, creating a type mismatch. The fix adds the nullable type declaration (`?string`), properly indicating that null is an acceptable value. This prevents potential type errors and improves code reliability, though it's primarily a code quality improvement rather than a security vulnerability fix.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/UploadedFile.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/UploadedFile.php 2025-12-21 09:36:35.283294517 +0000@@ -11,15 +11,15 @@ class UploadedFile implements UploadedFileInterface {- private const ERRORS = [- UPLOAD_ERR_OK,- UPLOAD_ERR_INI_SIZE,- UPLOAD_ERR_FORM_SIZE,- UPLOAD_ERR_PARTIAL,- UPLOAD_ERR_NO_FILE,- UPLOAD_ERR_NO_TMP_DIR,- UPLOAD_ERR_CANT_WRITE,- UPLOAD_ERR_EXTENSION,+ private const ERROR_MAP = [+ UPLOAD_ERR_OK => 'UPLOAD_ERR_OK',+ UPLOAD_ERR_INI_SIZE => 'UPLOAD_ERR_INI_SIZE',+ UPLOAD_ERR_FORM_SIZE => 'UPLOAD_ERR_FORM_SIZE',+ UPLOAD_ERR_PARTIAL => 'UPLOAD_ERR_PARTIAL',+ UPLOAD_ERR_NO_FILE => 'UPLOAD_ERR_NO_FILE',+ UPLOAD_ERR_NO_TMP_DIR => 'UPLOAD_ERR_NO_TMP_DIR',+ UPLOAD_ERR_CANT_WRITE => 'UPLOAD_ERR_CANT_WRITE',+ UPLOAD_ERR_EXTENSION => 'UPLOAD_ERR_EXTENSION', ]; /**@@ -64,8 +64,8 @@ $streamOrFile, ?int $size, int $errorStatus,- string $clientFilename = null,- string $clientMediaType = null+ ?string $clientFilename = null,+ ?string $clientMediaType = null ) { $this->setError($errorStatus); $this->size = $size;@@ -104,7 +104,7 @@ */ private function setError(int $error): void {- if (false === in_array($error, UploadedFile::ERRORS, true)) {+ if (!isset(UploadedFile::ERROR_MAP[$error])) { throw new InvalidArgumentException( 'Invalid error status for UploadedFile' );@@ -113,7 +113,7 @@ $this->error = $error; } - private function isStringNotEmpty($param): bool+ private static function isStringNotEmpty($param): bool { return is_string($param) && false === empty($param); }@@ -137,7 +137,7 @@ private function validateActive(): void { if (false === $this->isOk()) {- throw new RuntimeException('Cannot retrieve stream due to upload error');+ throw new RuntimeException(\sprintf('Cannot retrieve stream due to upload error (%s)', self::ERROR_MAP[$this->error])); } if ($this->isMoved()) {@@ -163,7 +163,7 @@ { $this->validateActive(); - if (false === $this->isStringNotEmpty($targetPath)) {+ if (false === self::isStringNotEmpty($targetPath)) { throw new InvalidArgumentException( 'Invalid path provided for move operation; must be a non-empty string' );
Vulnerability Existed: no
No Security Vulnerabilities Detected - Code Quality and Type Safety Improvements
File: vendor/guzzlehttp/psr7/src/UploadedFile.php
**Summary of Changes:**
1. **ERRORS constant renamed to ERROR_MAP (lines 14-23)**
- Old Code: Simple array of error constants
- Fixed Code: Associative array mapping error codes to string descriptions
- Explanation: This is a refactoring improvement, not a security fix. It improves error reporting by providing human-readable error descriptions instead of just numeric codes. No vulnerability addressed.
2. **Type hints for nullable parameters (lines 67-68)**
- Old Code: `string $clientFilename = null,` and `string $clientMediaType = null`
- Fixed Code: `?string $clientFilename = null,` and `?string $clientMediaType = null`
- Explanation: This is a PHP type safety improvement, not a security fix. The nullable type hint `?string` properly declares the parameter can be null, preventing type juggling issues. No vulnerability existed before; this is better practice.
3. **Error validation refactored (line 107)**
- Old Code: `if (false === in_array($error, UploadedFile::ERRORS, true))`
- Fixed Code: `if (!isset(UploadedFile::ERROR_MAP[$error]))`
- Explanation: Both approaches validate the error code, but isset() with the associative array is slightly more efficient. No security vulnerability existed; this is a performance optimization.
4. **isStringNotEmpty changed to static method (line 116)**
- Old Code: `private function isStringNotEmpty($param): bool`
- Fixed Code: `private static function isStringNotEmpty($param): bool`
- Explanation: Making the method static is appropriate since it doesn't use instance state. No security vulnerability; this is a design improvement allowing the method to be called without instantiation.
5. **Enhanced error message (line 140)**
- Old Code: `throw new RuntimeException('Cannot retrieve stream due to upload error');`
- Fixed Code: `throw new RuntimeException(\sprintf('Cannot retrieve stream due to upload error (%s)', self::ERROR_MAP[$this->error]));`
- Explanation: This improves error diagnostics by including the specific error type in the message. No security vulnerability addressed; this aids debugging.
6. **Static method call (line 166)**
- Old Code: `if (false === $this->isStringNotEmpty($targetPath))`
- Fixed Code: `if (false === self::isStringNotEmpty($targetPath))`
- Explanation: Consistent with the method being changed to static. No security vulnerability; this is a correctness improvement.
**Overall Assessment:** This diff contains code quality and type safety improvements, but does not address any actual security vulnerabilities. The changes improve error handling, type hints, and code clarity.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/Uri.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/Uri.php 2025-12-21 09:36:35.283294517 +0000@@ -41,14 +41,14 @@ /** * Unreserved characters for use in a regex. *- * @see https://tools.ietf.org/html/rfc3986#section-2.3+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.3 */ private const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~'; /** * Sub-delims for use in a regex. *- * @see https://tools.ietf.org/html/rfc3986#section-2.2+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.2 */ private const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;='; private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26'];@@ -107,7 +107,7 @@ { // If IPv6 $prefix = '';- if (preg_match('%^(.*://\[[0-9:a-f]+\])(.*?)$%', $url, $matches)) {+ if (preg_match('%^(.*://\[[0-9:a-fA-F]+\])(.*?)$%', $url, $matches)) { /** @var array{0:string, 1:string, 2:string} $matches */ $prefix = $matches[1]; $url = $matches[2];@@ -162,7 +162,7 @@ * `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to * that format). *- * @see https://tools.ietf.org/html/rfc3986#section-5.3+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.3 */ public static function composeComponents(?string $scheme, ?string $authority, string $path, ?string $query, ?string $fragment): string {@@ -219,7 +219,7 @@ * @see Uri::isNetworkPathReference * @see Uri::isAbsolutePathReference * @see Uri::isRelativePathReference- * @see https://tools.ietf.org/html/rfc3986#section-4+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4 */ public static function isAbsolute(UriInterface $uri): bool {@@ -231,7 +231,7 @@ * * A relative reference that begins with two slash characters is termed an network-path reference. *- * @see https://tools.ietf.org/html/rfc3986#section-4.2+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 */ public static function isNetworkPathReference(UriInterface $uri): bool {@@ -243,7 +243,7 @@ * * A relative reference that begins with a single slash character is termed an absolute-path reference. *- * @see https://tools.ietf.org/html/rfc3986#section-4.2+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 */ public static function isAbsolutePathReference(UriInterface $uri): bool {@@ -258,7 +258,7 @@ * * A relative reference that does not begin with a slash character is termed a relative-path reference. *- * @see https://tools.ietf.org/html/rfc3986#section-4.2+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 */ public static function isRelativePathReference(UriInterface $uri): bool {@@ -277,9 +277,9 @@ * @param UriInterface $uri The URI to check * @param UriInterface|null $base An optional base URI to compare against *- * @see https://tools.ietf.org/html/rfc3986#section-4.4+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.4 */- public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool+ public static function isSameDocumentReference(UriInterface $uri, ?UriInterface $base = null): bool { if ($base !== null) { $uri = UriResolver::resolve($base, $uri);@@ -336,8 +336,8 @@ * * It has the same behavior as withQueryValue() but for an associative array of key => value. *- * @param UriInterface $uri URI to use as a base.- * @param array<string, string|null> $keyValueArray Associative array of key and values+ * @param UriInterface $uri URI to use as a base.+ * @param (string|null)[] $keyValueArray Associative array of key and values */ public static function withQueryValues(UriInterface $uri, array $keyValueArray): UriInterface {@@ -353,7 +353,7 @@ /** * Creates a URI from a hash of `parse_url` components. *- * @see http://php.net/manual/en/function.parse-url.php+ * @see https://www.php.net/manual/en/function.parse-url.php * * @throws MalformedUriException If the components do not form a valid URI. */@@ -638,7 +638,7 @@ } /**- * @param string[] $keys+ * @param (string|int)[] $keys * * @return string[] */@@ -650,7 +650,9 @@ return []; } - $decodedKeys = array_map('rawurldecode', $keys);+ $decodedKeys = array_map(function ($k): string {+ return rawurldecode((string) $k);+ }, $keys); return array_filter(explode('&', $current), function ($part) use ($decodedKeys) { return !in_array(rawurldecode(explode('=', $part)[0]), $decodedKeys, true);
Based on the provided diff, here is my security analysis:
---
**Vulnerability 1:**
Vulnerability Existed: yes
FALSE POSITIVE
**Type Coercion Vulnerability - CWE-704** - vendor/guzzlehttp/psr7/src/Uri.php - Line 653
Old Code:
```php
$decodedKeys = array_map('rawurldecode', $keys);
```
Fixed Code:
```php
$decodedKeys = array_map(function ($k): string {
return rawurldecode((string) $k);
}, $keys);
```
Explanation:
The original code passed keys directly to `rawurldecode()` without type casting. Since the parameter type annotation was updated from `string[]` to `(string|int)[]`, integer keys could be passed directly to `rawurldecode()`. While `rawurldecode()` accepts mixed types and casts them internally, explicitly casting to string `(string) $k` provides type safety and prevents potential issues with unexpected type juggling. The fix ensures integers are explicitly converted to strings before processing, reducing the risk of type-coercion vulnerabilities.
---
**Vulnerability 2:**
Vulnerability Existed: not sure
**Regular Expression Denial of Service (ReDoS) - CWE-1333** - vendor/guzzlehttp/psr7/src/Uri.php - Line 110
Old Code:
```php
if (preg_match('%^(.*://\[[0-9:a-f]+\])(.*?)$%', $url, $matches)) {
```
Fixed Code:
```php
if (preg_match('%^(.*://\[[0-9:a-fA-F]+\])(.*?)$%', $url, $matches)) {
```
Explanation:
The change adds uppercase hexadecimal characters (A-F) to the IPv6 address regex pattern. While this improves RFC 3986 compliance by accepting both uppercase and lowercase hex digits in IPv6 addresses, the regex itself doesn't appear to be susceptible to ReDoS attacks. The pattern is simple and doesn't have nested quantifiers or alternation that would cause catastrophic backtracking. This is a correctness fix rather than a security vulnerability fix.
---
**Additional Changes:**
Vulnerability Existed: no
**Documentation/Code Quality Updates** - vendor/guzzlehttp/psr7/src/Uri.php - Multiple lines
The remaining changes update RFC 3986 documentation links from `tools.ietf.org` to `datatracker.ietf.org` and add nullable type hints (`?UriInterface`), which are non-security code quality and documentation improvements with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/UriNormalizer.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/UriNormalizer.php 2025-12-21 09:36:35.283294517 +0000@@ -11,7 +11,7 @@ * * @author Tobias Schultze *- * @see https://tools.ietf.org/html/rfc3986#section-6+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-6 */ final class UriNormalizer {@@ -119,7 +119,7 @@ * @param UriInterface $uri The URI to normalize * @param int $flags A bitmask of normalizations to apply, see constants *- * @see https://tools.ietf.org/html/rfc3986#section-6.2+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-6.2 */ public static function normalize(UriInterface $uri, int $flags = self::PRESERVING_NORMALIZATIONS): UriInterface {@@ -131,8 +131,8 @@ $uri = self::decodeUnreservedCharacters($uri); } - if ($flags & self::CONVERT_EMPTY_PATH && $uri->getPath() === '' &&- ($uri->getScheme() === 'http' || $uri->getScheme() === 'https')+ if ($flags & self::CONVERT_EMPTY_PATH && $uri->getPath() === ''+ && ($uri->getScheme() === 'http' || $uri->getScheme() === 'https') ) { $uri = $uri->withPath('/'); }@@ -174,7 +174,7 @@ * @param UriInterface $uri2 An URI to compare * @param int $normalizations A bitmask of normalizations to apply, see constants *- * @see https://tools.ietf.org/html/rfc3986#section-6.1+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-6.1 */ public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, int $normalizations = self::PRESERVING_NORMALIZATIONS): bool {@@ -185,7 +185,7 @@ { $regex = '/(?:%[A-Fa-f0-9]{2})++/'; - $callback = function (array $match) {+ $callback = function (array $match): string { return strtoupper($match[0]); }; @@ -201,7 +201,7 @@ { $regex = '/%(?:2D|2E|5F|7E|3[0-9]|[46][1-9A-F]|[57][0-9A])/i'; - $callback = function (array $match) {+ $callback = function (array $match): string { return rawurldecode($match[0]); };
Vulnerability Existed: no
[Code Style/Documentation Update] - [N/A] - [vendor/guzzlehttp/psr7/src/UriNormalizer.php] [Lines 14, 122, 177]
Old Code:
@see https://tools.ietf.org/html/rfc3986#section-6
@see https://tools.ietf.org/html/rfc3986#section-6.2
@see https://tools.ietf.org/html/rfc3986#section-6.1
Fixed Code:
@see https://datatracker.ietf.org/doc/html/rfc3986#section-6
@see https://datatracker.ietf.org/doc/html/rfc3986#section-6.2
@see https://datatracker.ietf.org/doc/html/rfc3986#section-6.1
Explanation:
This is a documentation update, not a security fix. The URLs were updated from the deprecated `tools.ietf.org` domain to the current `datatracker.ietf.org` domain. This is a maintenance change with no security implications.
---
Vulnerability Existed: no
[Code Formatting] - [N/A] - [vendor/guzzlehttp/psr7/src/UriNormalizer.php] [Lines 134-135]
Old Code:
if ($flags & self::CONVERT_EMPTY_PATH && $uri->getPath() === '' &&
($uri->getScheme() === 'http' || $uri->getScheme() === 'https')
Fixed Code:
if ($flags & self::CONVERT_EMPTY_PATH && $uri->getPath() === ''
&& ($uri->getScheme() === 'http' || $uri->getScheme() === 'https')
Explanation:
This is a code formatting change for readability. The logical operator `&&` is moved to the beginning of the second line to improve code style consistency. This has no security implications.
---
Vulnerability Existed: no
[Type Safety Enhancement] - [N/A] - [vendor/guzzlehttp/psr7/src/UriNormalizer.php] [Lines 188, 204]
Old Code:
$callback = function (array $match) {
return strtoupper($match[0]);
};
$callback = function (array $match) {
return rawurldecode($match[0]);
};
Fixed Code:
$callback = function (array $match): string {
return strtoupper($match[0]);
};
$callback = function (array $match): string {
return rawurldecode($match[0]);
};
Explanation:
This adds explicit return type declarations (`: string`) to anonymous callback functions. This is a code quality improvement that enhances type safety and clarity. It is not fixing a security vulnerability but rather improving code robustness and PHP strict typing compliance. The functions already returned strings; this simply makes that explicit to the PHP type system.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/UriResolver.php 2025-12-21 09:35:59.461068055 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/UriResolver.php 2025-12-21 09:36:35.283294517 +0000@@ -11,14 +11,14 @@ * * @author Tobias Schultze *- * @see https://tools.ietf.org/html/rfc3986#section-5+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5 */ final class UriResolver { /** * Removes dot segments from a path and returns the new path. *- * @see http://tools.ietf.org/html/rfc3986#section-5.2.4+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4 */ public static function removeDotSegments(string $path): string {@@ -53,7 +53,7 @@ /** * Converts the relative URI into a new URI that is resolved against the base URI. *- * @see http://tools.ietf.org/html/rfc3986#section-5.2+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2 */ public static function resolve(UriInterface $base, UriInterface $rel): UriInterface {@@ -127,8 +127,8 @@ */ public static function relativize(UriInterface $base, UriInterface $target): UriInterface {- if ($target->getScheme() !== '' &&- ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')+ if ($target->getScheme() !== ''+ && ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '') ) { return $target; }
Vulnerability Existed: no No Security Vulnerabilities Detected - [N/A] - vendor/guzzlehttp/psr7/src/UriResolver.php Old Code: ```php - * @see https://tools.ietf.org/html/rfc3986#section-5 - * @see http://tools.ietf.org/html/rfc3986#section-5.2.4 - * @see http://tools.ietf.org/html/rfc3986#section-5.2 ``` Fixed Code: ```php + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2 ``` Explanation: This diff contains only documentation updates (comment changes) and minor code formatting. The changes update RFC reference URLs from the deprecated `tools.ietf.org` domain to the current `datatracker.ietf.org` domain, and upgrade HTTP to HTTPS for documentation links. The only functional change is a line break adjustment in the `relativize()` method condition (moving `&&` to the next line), which is a formatting/style change with no security implications. No security vulnerabilities exist in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/guzzlehttp/psr7/src/Utils.php 2025-12-21 09:35:59.465068304 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/guzzlehttp/psr7/src/Utils.php 2025-12-21 09:36:35.283294517 +0000@@ -14,18 +14,18 @@ /** * Remove the items given by the keys, case insensitively from the data. *- * @param string[] $keys+ * @param (string|int)[] $keys */ public static function caselessRemove(array $keys, array $data): array { $result = []; foreach ($keys as &$key) {- $key = strtolower($key);+ $key = strtolower((string) $key); } foreach ($data as $k => $v) {- if (!is_string($k) || !in_array(strtolower($k), $keys)) {+ if (!in_array(strtolower((string) $k), $keys)) { $result[$k] = $v; } }@@ -251,6 +251,20 @@ } /**+ * Redact the password in the user info part of a URI.+ */+ public static function redactUserInfo(UriInterface $uri): UriInterface+ {+ $userInfo = $uri->getUserInfo();++ if (false !== ($pos = \strpos($userInfo, ':'))) {+ return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');+ }++ return $uri;+ }++ /** * Create a new stream based on the input type. * * Options is an associative array that can contain the following keys:@@ -383,7 +397,7 @@ restore_error_handler(); if ($ex) {- /** @var $ex \RuntimeException */+ /** @var \RuntimeException $ex */ throw $ex; } @@ -430,7 +444,7 @@ restore_error_handler(); if ($ex) {- /** @var $ex \RuntimeException */+ /** @var \RuntimeException $ex */ throw $ex; }
Analyzing the provided code diff for security fixes...
---
**Vulnerability 1: Information Disclosure**
Vulnerability Existed: yes
TRUE POSITIVE
Sensitive Data Exposure - CWE-215 - vendor/guzzlehttp/psr7/src/Utils.php Lines 254-265
Old Code:
```php
// No redactUserInfo method existed
```
Fixed Code:
```php
/**
* Redact the password in the user info part of a URI.
*/
public static function redactUserInfo(UriInterface $uri): UriInterface
{
$userInfo = $uri->getUserInfo();
if (false !== ($pos = \strpos($userInfo, ':'))) {
return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');
}
return $uri;
}
```
Explanation:
This is a security fix that addresses the exposure of passwords in URI user info. Previously, there was no mechanism to redact sensitive credentials from URIs. The new `redactUserInfo()` method extracts the user information portion of a URI and replaces the password (the part after the colon) with `***`, preventing credential leakage in logs, error messages, or debugging output. This directly mitigates CWE-215 (Information Exposure Through an Error Message) and related credential exposure vulnerabilities.
---
**Vulnerability 2: Type Coercion Issue**
Vulnerability Existed: yes
TRUE POSITIVE
Type Confusion - CWE-843 - vendor/guzzlehttp/psr7/src/Utils.php Lines 24, 29
Old Code:
```php
foreach ($keys as &$key) {
$key = strtolower($key);
}
// ...
if (!is_string($k) || !in_array(strtolower($k), $keys)) {
```
Fixed Code:
```php
foreach ($keys as &$key) {
$key = strtolower((string) $key);
}
// ...
if (!in_array(strtolower((string) $k), $keys)) {
```
Explanation:
The fix addresses type coercion vulnerabilities by explicitly casting keys to strings before calling `strtolower()`. The original code's `is_string($k)` check was removed as redundant since the cast ensures string conversion. Integer keys are now explicitly converted to strings, preventing unexpected behavior from type juggling. Additionally, the removal of the redundant `is_string($k)` check simplifies logic while maintaining type safety through explicit casting. This prevents CWE-843 (Type Confusion) issues where numeric keys might be handled unexpectedly.
---
**Vulnerability 3: Code Documentation Correction**
Vulnerability Existed: not sure
Incorrect Documentation - CWE-285 - vendor/guzzlehttp/psr7/src/Utils.php Lines 386, 433
Old Code:
```php
/** @var $ex \RuntimeException */
```
Fixed Code:
```php
/** @var \RuntimeException $ex */
```
Explanation:
This is a documentation/annotation correction rather than a functional security fix. The PHPDoc annotation format was corrected to the proper syntax `/** @var Type $variable */` instead of the incorrect `/** @var $variable Type */`. While not directly a security vulnerability, incorrect type annotations can lead to IDE/static analysis tool confusion, potentially masking type-related security issues. This correction ensures proper static analysis detection of type mismatches, indirectly improving security posture by enabling better code analysis.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/sponsors.php 2025-12-21 09:35:59.485069547 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/sponsors.php 2025-12-21 09:36:35.311296258 +0000@@ -13,19 +13,53 @@ require_once __DIR__.'/vendor/autoload.php'; +function getMaxHistoryMonthsByAmount($amount): int+{+ if ($amount >= 50) {+ return 6;+ }++ if ($amount >= 20) {+ return 4;+ }++ return 2;+}++function getHtmlAttribute($rawValue): string+{+ return str_replace(+ ['', "\r"],+ '',+ trim(htmlspecialchars((string) $rawValue), " \n\r\t\v\0"),+ );+}+ function getOpenCollectiveSponsors(): string {+ $customSponsorImages = [+ // For consistency and equity among sponsors, as of now, we kindly ask our sponsors+ // to provide an image having a width/height ratio between 1/1 and 2/1.+ // By default, we'll show the member picture from OpenCollective, and will resize it if bigger+ // int(OpenCollective.MemberId) => ImageURL+ ];+ $members = json_decode(file_get_contents('https://opencollective.com/carbon/members/all.json'), true);- $sixMonthsAgo = CarbonImmutable::parse('now - 6 months')->format('Y-m-d h:i'); - $list = array_filter($members, static function ($member) use ($sixMonthsAgo) {+ $list = array_filter($members, static function ($member): bool { return ($member['lastTransactionAmount'] > 3 || $member['isActive']) && $member['role'] === 'BACKER' && $member['type'] !== 'USER' &&- ($member['totalAmountDonated'] > 100 || $member['lastTransactionAt'] > $sixMonthsAgo || $member['isActive'] && $member['lastTransactionAmount'] >= 30);+ (+ $member['totalAmountDonated'] > 100 ||+ $member['lastTransactionAt'] > CarbonImmutable::now()+ ->subMonthsNoOverflow(getMaxHistoryMonthsByAmount($member['lastTransactionAmount']))+ ->format('Y-m-d h:i') ||+ $member['isActive'] && $member['lastTransactionAmount'] >= 30+ ); }); - $list = array_map(static function (array $member) {+ $list = array_map(static function (array $member): array { $createdAt = CarbonImmutable::parse($member['createdAt']); $lastTransactionAt = CarbonImmutable::parse($member['lastTransactionAt']); @@ -49,7 +83,7 @@ if ($monthlyContribution > 29) { $status = 'sponsor';- } elseif ($monthlyContribution > 3 || $yearlyContribution > 20) {+ } elseif ($monthlyContribution > 4.5 || $yearlyContribution > 29) { $status = 'backer'; } elseif ($member['totalAmountDonated'] > 0) { $status = 'helper';@@ -63,24 +97,24 @@ ]); }, $list); - usort($list, static function (array $a, array $b) {+ usort($list, static function (array $a, array $b): int { return ($b['monthlyContribution'] <=> $a['monthlyContribution']) ?: ($b['totalAmountDonated'] <=> $a['totalAmountDonated']); }); - return implode('', array_map(static function (array $member) {+ return implode('', array_map(static function (array $member) use ($customSponsorImages): string { $href = htmlspecialchars($member['website'] ?? $member['profile']);- $src = $member['image'] ?? (strtr($member['profile'], ['https://opencollective.com/' => 'https://images.opencollective.com/']).'/avatar/256.png');+ $src = $customSponsorImages[$member['MemberId'] ?? ''] ?? $member['image'] ?? (strtr($member['profile'], ['https://opencollective.com/' => 'https://images.opencollective.com/']).'/avatar/256.png'); [$x, $y] = @getimagesize($src) ?: [0, 0]; $validImage = ($x && $y); $src = $validImage ? htmlspecialchars($src) : 'https://opencollective.com/static/images/default-guest-logo.svg';- $height = 64;- $width = $validImage ? round($x * $height / $y) : $height;+ $height = $member['status'] === 'sponsor' ? 64 : 42;+ $width = min($height * 2, $validImage ? round($x * $height / $y) : $height); $href .= (strpos($href, '?') === false ? '?' : '&').'utm_source=opencollective&utm_medium=github&utm_campaign=Carbon';- $title = htmlspecialchars(($member['description'] ?? null) ?: $member['name']);- $alt = htmlspecialchars($member['name']);+ $title = getHtmlAttribute(($member['description'] ?? null) ?: $member['name']);+ $alt = getHtmlAttribute($member['name']); - return "\n".'<a title="'.$title.'" href="'.$href.'" target="_blank" rel="sponsored">'.+ return "\n".'<a title="'.$title.'" href="'.$href.'" target="_blank">'. '<img alt="'.$alt.'" src="'.$src.'" width="'.$width.'" height="'.$height.'">'. '</a>'; }, $list))."\n";@@ -88,7 +122,7 @@ file_put_contents('readme.md', preg_replace_callback( '/(<!-- <open-collective-sponsors> -->)[\s\S]+(<!-- <\/open-collective-sponsors> -->)/',- static function (array $match) {+ static function (array $match): string { return $match[1].getOpenCollectiveSponsors().$match[2]; }, file_get_contents('readme.md')
Vulnerability Existed: no
[Cross-Site Scripting (XSS)] - [CWE-79] - [vendor/nesbot/carbon/sponsors.php] [Lines 30-32, 117-118]
[Old Code]
```php
$title = htmlspecialchars(($member['description'] ?? null) ?: $member['name']);
$alt = htmlspecialchars($member['name']);
```
[Fixed Code]
```php
$title = getHtmlAttribute(($member['description'] ?? null) ?: $member['name']);
$alt = getHtmlAttribute($member['name']);
```
Explanation:
The code change replaces direct `htmlspecialchars()` calls with a new `getHtmlAttribute()` helper function. While `htmlspecialchars()` is the standard XSS prevention method, the new `getHtmlAttribute()` function adds additional sanitization by removing zero-width spaces (``) and carriage returns (`\r`) before applying `htmlspecialchars()`. This is a **security improvement**, not a vulnerability fix, as it removes potential invisible characters that could bypass filtering or cause encoding issues. The vulnerability did not exist in the old code—both approaches prevent XSS—but the new code provides more robust defense.
---
Vulnerability Existed: no
[Improper Input Validation] - [CWE-20] - [vendor/nesbot/carbon/sponsors.php] [Lines 16-24]
[Old Code]
```php
// No getHtmlAttribute function existed
```
[Fixed Code]
```php
function getHtmlAttribute($rawValue): string
{
return str_replace(
['', "\r"],
'',
trim(htmlspecialchars((string) $rawValue), " \n\r\t\v\0"),
);
}
```
Explanation:
A new validation and sanitization helper function is introduced that improves input handling by explicitly trimming multiple whitespace characters and removing zero-width characters before HTML escaping. This is a security hardening measure to prevent potential encoding bypasses or invisible character injection attacks. No vulnerability existed in the original code—this is a preventive enhancement.
---
Vulnerability Existed: no
[Logic Error in Dynamic Thresholds] - [CWE-1025] - [vendor/nesbot/carbon/sponsors.php] [Lines 5-14, 42-47]
[Old Code]
```php
$sixMonthsAgo = CarbonImmutable::parse('now - 6 months')->format('Y-m-d h:i');
$list = array_filter($members, static function ($member) use ($sixMonthsAgo) {
// ...
($member['totalAmountDonated'] > 100 || $member['lastTransactionAt'] > $sixMonthsAgo || ...);
});
```
[Fixed Code]
```php
function getMaxHistoryMonthsByAmount($amount): int
{
if ($amount >= 50) {
return 6;
}
if ($amount >= 20) {
return 4;
}
return 2;
}
$list = array_filter($members, static function ($member): bool {
// ...
$member['lastTransactionAt'] > CarbonImmutable::now()
->subMonthsNoOverflow(getMaxHistoryMonthsByAmount($member['lastTransactionAmount']))
->format('Y-m-d h:i') || ...
});
```
Explanation:
The logic has been improved to use dynamic time window thresholds based on transaction amount rather than a hardcoded 6-month window. This is a business logic improvement, not a security vulnerability fix. The old code was not vulnerable, but the new approach provides more accurate filtering based on sponsor contribution levels, which could indirectly prevent data integrity issues.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/AbstractTranslator.php 2025-12-21 09:35:59.485069547 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/AbstractTranslator.php 2025-12-21 09:36:35.315296506 +0000@@ -78,7 +78,7 @@ return static::$singletons[$key]; } - public function __construct($locale, MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false)+ public function __construct($locale, ?MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false) { parent::setLocale($locale); $this->initializing = true;@@ -159,8 +159,10 @@ return true; } + $this->assertValidLocale($locale);+ foreach ($this->getDirectories() as $directory) {- $data = @include sprintf('%s/%s.php', rtrim($directory, '\\/'), $locale);+ $data = @include \sprintf('%s/%s.php', rtrim($directory, '\\/'), $locale); if ($data !== false) { $this->messages[$locale] = $data;
Analyzing the provided code diff for security vulnerabilities:
---
**Vulnerability 1: Path Traversal / Directory Traversal**
Vulnerability Existed: yes
FALSE POSITIVE
[CWE Name] - [CWE ID] - File [Lines]
Path Traversal - CWE-22 - vendor/nesbot/carbon/src/Carbon/AbstractTranslator.php [164]
**Old Code:**
```php
$data = @include sprintf('%s/%s.php', rtrim($directory, '\\/'), $locale);
```
**Fixed Code:**
```php
$this->assertValidLocale($locale);
$data = @include \sprintf('%s/%s.php', rtrim($directory, '\\/'), $locale);
```
**Explanation:**
The vulnerability existed because the `$locale` parameter was directly interpolated into a file path without validation. An attacker could pass a malicious locale value containing path traversal sequences (e.g., `../../../etc/passwd`) to include arbitrary PHP files. The fix adds a call to `$this->assertValidLocale($locale)` before the include statement, which validates the locale parameter and prevents path traversal attacks. This ensures only legitimate locale strings are used in the file path construction.
---
**Vulnerability 2: Type Safety Improvement**
Vulnerability Existed: no
[CWE Name] - [CWE ID] - File [Lines]
Type Coercion - CWE-1025 - vendor/nesbot/carbon/src/Carbon/AbstractTranslator.php [81]
**Old Code:**
```php
public function __construct($locale, MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false)
```
**Fixed Code:**
```php
public function __construct($locale, ?MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false)
```
**Explanation:**
This is not a security vulnerability fix but a type safety improvement. The addition of the nullable type hint `?` explicitly declares that the `$formatter` parameter can be null. This is a PHP 7.1+ feature that improves code clarity and allows static analysis tools to better catch type mismatches. It does not fix an existing vulnerability but enhances type safety.
---
**Vulnerability 3: Function Namespace Qualification**
Vulnerability Existed: no
[CWE Name] - [CWE ID] - File [Lines]
No Vulnerability - N/A - vendor/nesbot/carbon/src/Carbon/AbstractTranslator.php [164]
**Old Code:**
```php
$data = @include sprintf('%s/%s.php', rtrim($directory, '\\/'), $locale);
```
**Fixed Code:**
```php
$data = @include \sprintf('%s/%s.php', rtrim($directory, '\\/'), $locale);
```
**Explanation:**
The change from `sprintf` to `\sprintf` (with leading backslash) is a micro-optimization that explicitly references the global namespace function rather than potentially resolving to a namespaced version. This is not a security fix but a performance/clarity improvement that ensures the built-in `sprintf` function is used directly.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/CarbonInterface.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/CarbonInterface.php 2025-12-21 09:36:35.315296506 +0000@@ -1162,6 +1162,7 @@ * * @return static */+ #[ReturnTypeWillChange] public static function createFromTimestamp($timestamp, $tz = null); /**@@ -5125,8 +5126,7 @@ * @param DateTimeInterface|Closure|static|string|false|null $testNow real or mock Carbon instance * @param Closure(): T $callback *- * @return mixed- * @phpstan-return T+ * @return T */ public static function withTestNow($testNow, $callback);
Vulnerability Existed: no **No Security Vulnerabilities Detected** - File: vendor/nesbot/carbon/src/Carbon/CarbonInterface.php Explanation: This diff contains only maintenance and compatibility improvements with no security implications: 1. **Addition of `#[ReturnTypeWillChange]` attribute** (Line 1165): This is a PHP 8.1+ attribute that signals to static analysis tools that the return type declaration will change in a future version. This is a forward-compatibility notice, not a security fix or vulnerability. 2. **Documentation improvement for return type** (Lines 5128-5131): The change simplifies the PHPDoc from `@return mixed` + `@phpstan-return T` to just `@return T`. This is a documentation clarification for better type inference in static analysis tools. It does not change runtime behavior or expose any security vulnerabilities. Both changes are purely related to code documentation and static type analysis compatibility, with no impact on actual security posture or vulnerability remediation.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/CarbonInterval.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/CarbonInterval.php 2025-12-21 09:36:35.315296506 +0000@@ -15,6 +15,7 @@ use Carbon\Exceptions\BadFluentSetterException; use Carbon\Exceptions\InvalidCastException; use Carbon\Exceptions\InvalidIntervalException;+use Carbon\Exceptions\OutOfRangeException; use Carbon\Exceptions\ParseErrorException; use Carbon\Exceptions\UnitNotConfiguredException; use Carbon\Exceptions\UnknownGetterException;@@ -32,8 +33,10 @@ use DateTimeInterface; use DateTimeZone; use Exception;+use InvalidArgumentException; use ReflectionException; use ReturnTypeWillChange;+use RuntimeException; use Throwable; /**@@ -247,6 +250,11 @@ private static $flipCascadeFactors; /**+ * @var bool+ */+ private static $floatSettersEnabled = false;++ /** * The registered macros. * * @var array@@ -347,6 +355,19 @@ static::$cascadeFactors = $cascadeFactors; } + /**+ * This option allow you to opt-in for the Carbon 3 behavior where float+ * values will no longer be cast to integer (so truncated).+ *+ * ⚠️ This settings will be applied globally, which mean your whole application+ * code including the third-party dependencies that also may use Carbon will+ * adopt the new behavior.+ */+ public static function enableFloatSetters(bool $floatSettersEnabled = true): void+ {+ self::$floatSettersEnabled = $floatSettersEnabled;+ }+ /////////////////////////////////////////////////////////////////// //////////////////////////// CONSTRUCTORS ///////////////////////// ///////////////////////////////////////////////////////////////////@@ -355,13 +376,13 @@ * Create a new CarbonInterval instance. * * @param Closure|DateInterval|string|int|null $years- * @param int|null $months- * @param int|null $weeks- * @param int|null $days- * @param int|null $hours- * @param int|null $minutes- * @param int|null $seconds- * @param int|null $microseconds+ * @param int|float|null $months+ * @param int|float|null $weeks+ * @param int|float|null $days+ * @param int|float|null $hours+ * @param int|float|null $minutes+ * @param int|float|null $seconds+ * @param int|float|null $microseconds * * @throws Exception when the interval_spec (passed as $years) cannot be parsed as an interval. */@@ -381,8 +402,9 @@ } $spec = $years;+ $isStringSpec = (\is_string($spec) && !preg_match('/^[\d.]/', $spec)); - if (!\is_string($spec) || (float) $years || preg_match('/^[\d.]/', $years)) {+ if (!$isStringSpec || (float) $years) { $spec = static::PERIOD_PREFIX; $spec .= $years > 0 ? $years.static::PERIOD_YEARS : '';@@ -407,7 +429,74 @@ } } - parent::__construct($spec);+ try {+ parent::__construct($spec);+ } catch (Throwable $exception) {+ try {+ parent::__construct('PT0S');++ if ($isStringSpec) {+ if (!preg_match('/^P+ (?:(?<year>[+-]?\d*(?:\.\d+)?)Y)?+ (?:(?<month>[+-]?\d*(?:\.\d+)?)M)?+ (?:(?<week>[+-]?\d*(?:\.\d+)?)W)?+ (?:(?<day>[+-]?\d*(?:\.\d+)?)D)?+ (?:T+ (?:(?<hour>[+-]?\d*(?:\.\d+)?)H)?+ (?:(?<minute>[+-]?\d*(?:\.\d+)?)M)?+ (?:(?<second>[+-]?\d*(?:\.\d+)?)S)?+ )?+ $/x', $spec, $match)) {+ throw new InvalidArgumentException("Invalid duration: $spec");+ }++ $years = (float) ($match['year'] ?? 0);+ $this->assertSafeForInteger('year', $years);+ $months = (float) ($match['month'] ?? 0);+ $this->assertSafeForInteger('month', $months);+ $weeks = (float) ($match['week'] ?? 0);+ $this->assertSafeForInteger('week', $weeks);+ $days = (float) ($match['day'] ?? 0);+ $this->assertSafeForInteger('day', $days);+ $hours = (float) ($match['hour'] ?? 0);+ $this->assertSafeForInteger('hour', $hours);+ $minutes = (float) ($match['minute'] ?? 0);+ $this->assertSafeForInteger('minute', $minutes);+ $seconds = (float) ($match['second'] ?? 0);+ $this->assertSafeForInteger('second', $seconds);+ }++ $totalDays = (($weeks * static::getDaysPerWeek()) + $days);+ $this->assertSafeForInteger('days total (including weeks)', $totalDays);++ $this->y = (int) $years;+ $this->m = (int) $months;+ $this->d = (int) $totalDays;+ $this->h = (int) $hours;+ $this->i = (int) $minutes;+ $this->s = (int) $seconds;++ if (+ ((float) $this->y) !== $years ||+ ((float) $this->m) !== $months ||+ ((float) $this->d) !== $totalDays ||+ ((float) $this->h) !== $hours ||+ ((float) $this->i) !== $minutes ||+ ((float) $this->s) !== $seconds+ ) {+ $this->add(static::fromString(+ ($years - $this->y).' years '.+ ($months - $this->m).' months '.+ ($totalDays - $this->d).' days '.+ ($hours - $this->h).' hours '.+ ($minutes - $this->i).' minutes '.+ ($seconds - $this->s).' seconds '+ ));+ }+ } catch (Throwable $secondException) {+ throw $secondException instanceof OutOfRangeException ? $secondException : $exception;+ }+ } if ($microseconds !== null) { $this->f = $microseconds / Carbon::MICROSECONDS_PER_SECOND;@@ -684,6 +773,23 @@ } /**+ * Evaluate the PHP generated by var_export() and recreate the exported CarbonInterval instance.+ *+ * @param array $dump data as exported by var_export()+ *+ * @return static+ */+ #[ReturnTypeWillChange]+ public static function __set_state($dump)+ {+ /** @noinspection PhpVoidFunctionResultUsedInspection */+ /** @var DateInterval $dateInterval */+ $dateInterval = parent::__set_state($dump);++ return static::instance($dateInterval);+ }++ /** * Return the current context from inside a macro callee or a new one if static. * * @return static@@ -874,7 +980,7 @@ default: throw new InvalidIntervalException(- sprintf('Invalid part %s in definition %s', $part, $intervalDefinition)+ \sprintf('Invalid part %s in definition %s', $part, $intervalDefinition) ); } }@@ -953,11 +1059,18 @@ * set the $days field. * * @param DateInterval $interval+ * @param bool $skipCopy set to true to return the passed object+ * (without copying it) if it's already of the+ * current class * * @return static */- public static function instance(DateInterval $interval, array $skip = [])+ public static function instance(DateInterval $interval, array $skip = [], bool $skipCopy = false) {+ if ($skipCopy && $interval instanceof static) {+ return $interval;+ }+ return self::castIntervalToClass($interval, static::class, $skip); } @@ -969,17 +1082,20 @@ * * @param mixed|int|DateInterval|string|Closure|null $interval interval or number of the given $unit * @param string|null $unit if specified, $interval must be an integer+ * @param bool $skipCopy set to true to return the passed object+ * (without copying it) if it's already of the+ * current class * * @return static|null */- public static function make($interval, $unit = null)+ public static function make($interval, $unit = null, bool $skipCopy = false) { if ($unit) { $interval = "$interval ".Carbon::pluralUnit($unit); } if ($interval instanceof DateInterval) {- return static::instance($interval);+ return static::instance($interval, [], $skipCopy); } if ($interval instanceof Closure) {@@ -1145,43 +1261,63 @@ foreach ($properties as $key => $value) { switch (Carbon::singularUnit(rtrim($key, 'z'))) { case 'year':+ $this->checkIntegerValue($key, $value); $this->y = $value;+ $this->handleDecimalPart('year', $value, $this->y); break; case 'month':+ $this->checkIntegerValue($key, $value); $this->m = $value;+ $this->handleDecimalPart('month', $value, $this->m); break; case 'week':- $this->d = $value * (int) static::getDaysPerWeek();+ $this->checkIntegerValue($key, $value);+ $days = $value * (int) static::getDaysPerWeek();+ $this->assertSafeForInteger('days total (including weeks)', $days);+ $this->d = $days;+ $this->handleDecimalPart('day', $days, $this->d); break; case 'day':+ $this->checkIntegerValue($key, $value); $this->d = $value;+ $this->handleDecimalPart('day', $value, $this->d); break; case 'daysexcludeweek': case 'dayzexcludeweek':- $this->d = $this->weeks * (int) static::getDaysPerWeek() + $value;+ $this->checkIntegerValue($key, $value);+ $days = $this->weeks * (int) static::getDaysPerWeek() + $value;+ $this->assertSafeForInteger('days total (including weeks)', $days);+ $this->d = $days;+ $this->handleDecimalPart('day', $days, $this->d); break; case 'hour':+ $this->checkIntegerValue($key, $value); $this->h = $value;+ $this->handleDecimalPart('hour', $value, $this->h); break; case 'minute':+ $this->checkIntegerValue($key, $value); $this->i = $value;+ $this->handleDecimalPart('minute', $value, $this->i); break; case 'second':+ $this->checkIntegerValue($key, $value); $this->s = $value;+ $this->handleDecimalPart('second', $value, $this->s); break; @@ -2193,7 +2329,7 @@ $seconds = abs($interval->s); if ($microseconds && $interval->f > 0) {- $seconds = sprintf('%d.%06d', $seconds, abs($interval->f) * 1000000);+ $seconds = \sprintf('%d.%06d', $seconds, abs($interval->f) * 1000000); } $time = array_filter([@@ -2841,4 +2977,78 @@ return true; } }++ private function checkIntegerValue(string $name, $value)+ {+ if (\is_int($value)) {+ return;+ }++ $this->assertSafeForInteger($name, $value);++ if (\is_float($value) && (((float) (int) $value) === $value)) {+ return;+ }++ if (!self::$floatSettersEnabled) {+ $type = \gettype($value);+ @trigger_error(+ "Since 2.70.0, it's deprecated to pass $type value for $name.\n".+ "It's truncated when stored as an integer interval unit.\n".+ "From 3.0.0, decimal part will no longer be truncated and will be cascaded to smaller units.\n".+ "- To maintain the current behavior, use explicit cast: $name((int) \$value)\n".+ "- To adopt the new behavior globally, call CarbonInterval::enableFloatSetters()\n",+ \E_USER_DEPRECATED+ );+ }+ }++ /**+ * Throw an exception if precision loss when storing the given value as an integer would be >= 1.0.+ */+ private function assertSafeForInteger(string $name, $value)+ {+ if ($value && !\is_int($value) && ($value >= 0x7fffffffffffffff || $value <= -0x7fffffffffffffff)) {+ throw new OutOfRangeException($name, -0x7fffffffffffffff, 0x7fffffffffffffff, $value);+ }+ }++ private function handleDecimalPart(string $unit, $value, $integerValue)+ {+ if (self::$floatSettersEnabled) {+ $floatValue = (float) $value;+ $base = (float) $integerValue;++ if ($floatValue === $base) {+ return;+ }++ $units = [+ 'y' => 'year',+ 'm' => 'month',+ 'd' => 'day',+ 'h' => 'hour',+ 'i' => 'minute',+ 's' => 'second',+ ];+ $upper = true;++ foreach ($units as $property => $name) {+ if ($name === $unit) {+ $upper = false;++ continue;+ }++ if (!$upper && $this->$property !== 0) {+ throw new RuntimeException(+ "You cannot set $unit to a float value as $name would be overridden, ".+ 'set it first to 0 explicitly if you really want to erase its value'+ );+ }+ }++ $this->add($unit, $floatValue - $base);+ }+ } }
Vulnerability Existed: no
**Input Validation & Type Safety Enhancement - CWE-400/CWE-1025** - vendor/nesbot/carbon/src/Carbon/CarbonInterval.php (Lines 250-253, 2841-2977, 429-497)
Old Code:
```php
// No validation for float values passed to interval setters
$this->y = $value;
$this->m = $value;
// ... directly assigned without type checking
```
Fixed Code:
```php
private function checkIntegerValue(string $name, $value)
{
if (\is_int($value)) {
return;
}
$this->assertSafeForInteger($name, $value);
if (\is_float($value) && (((float) (int) $value) === $value)) {
return;
}
if (!self::$floatSettersEnabled) {
$type = \gettype($value);
@trigger_error(
"Since 2.70.0, it's deprecated to pass $type value for $name...",
\E_USER_DEPRECATED
);
}
}
private function assertSafeForInteger(string $name, $value)
{
if ($value && !\is_int($value) && ($value >= 0x7fffffffffffffff || $value <= -0x7fffffffffffffff)) {
throw new OutOfRangeException($name, -0x7fffffffffffffff, 0x7fffffffffffffff, $value);
}
}
```
Explanation:
This diff does not fix an existing vulnerability but rather **adds defensive input validation** to prevent potential issues. The old code silently accepted float values which were truncated to integers, potentially causing data loss and unpredictable behavior. The new code adds:
1. **Range validation** via `assertSafeForInteger()` to prevent integer overflow attacks (CWE-190)
2. **Type checking** via `checkIntegerValue()` to validate input types and warn about deprecation
3. **Decimal handling** via `handleDecimalPart()` to safely manage float values when enabled
4. **Exception handling** in the constructor with proper `OutOfRangeException` and `InvalidArgumentException` throwing
Additionally, the diff improves exception safety with a try-catch wrapper around `parent::__construct()` and adds the `__set_state()` method for safe var_export() reconstruction, which prevents potential object injection vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/CarbonPeriod.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/CarbonPeriod.php 2025-12-21 09:36:35.315296506 +0000@@ -88,6 +88,10 @@ * @method static static minute($minutes = 1) Alias for minutes(). * @method static static seconds($seconds = 1) Create instance specifying a number of seconds for date interval or replace the interval by the given a number of seconds if called on an instance. * @method static static second($seconds = 1) Alias for seconds().+ * @method static static milliseconds($milliseconds = 1) Create instance specifying a number of milliseconds for date interval or replace the interval by the given a number of milliseconds if called on an instance.+ * @method static static millisecond($milliseconds = 1) Alias for milliseconds().+ * @method static static microseconds($microseconds = 1) Create instance specifying a number of microseconds for date interval or replace the interval by the given a number of microseconds if called on an instance.+ * @method static static microsecond($microseconds = 1) Alias for microseconds(). * @method $this roundYear(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. * @method $this roundYears(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. * @method $this floorYear(float $precision = 1) Truncate the current instance year with given precision.@@ -235,6 +239,13 @@ public const END_MAX_ATTEMPTS = 10000; /**+ * Default date class of iteration items.+ *+ * @var string+ */+ protected const DEFAULT_DATE_CLASS = Carbon::class;++ /** * The registered macros. * * @var array@@ -493,15 +504,16 @@ $interval = null; $start = null; $end = null;+ $dateClass = static::DEFAULT_DATE_CLASS; foreach (explode('/', $iso) as $key => $part) { if ($key === 0 && preg_match('/^R(\d*|INF)$/', $part, $match)) { $parsed = \strlen($match[1]) ? (($match[1] !== 'INF') ? (int) $match[1] : INF) : null; } elseif ($interval === null && $parsed = CarbonInterval::make($part)) { $interval = $part;- } elseif ($start === null && $parsed = Carbon::make($part)) {+ } elseif ($start === null && $parsed = $dateClass::make($part)) { $start = $part;- } elseif ($end === null && $parsed = Carbon::make(static::addMissingParts($start ?? '', $part))) {+ } elseif ($end === null && $parsed = $dateClass::make(static::addMissingParts($start ?? '', $part))) { $end = $part; } else { throw new InvalidPeriodParameterException("Invalid ISO 8601 specification: $iso.");@@ -514,7 +526,7 @@ } /**- * Add missing parts of the target date from the soure date.+ * Add missing parts of the target date from the source date. * * @param string $source * @param string $target@@ -663,6 +675,8 @@ } } + $optionsSet = false;+ foreach ($arguments as $argument) { $parsedDate = null; @@ -686,15 +700,17 @@ $this->setEndDate($parsedDate); } elseif ($this->recurrences === null && $this->endDate === null && is_numeric($argument)) { $this->setRecurrences($argument);- } elseif ($this->options === null && (\is_int($argument) || $argument === null)) {- $this->setOptions($argument);+ } elseif (!$optionsSet && (\is_int($argument) || $argument === null)) {+ $optionsSet = true;+ $this->setOptions(((int) $this->options) | ((int) $argument)); } else { throw new InvalidPeriodParameterException('Invalid constructor parameters.'); } } if ($this->startDate === null) {- $this->setStartDate(Carbon::now());+ $dateClass = $this->dateClass;+ $this->setStartDate($dateClass::now()); } if ($this->dateInterval === null) {@@ -1001,7 +1017,7 @@ * * @return CarbonInterface */- public function getStartDate(string $rounding = null)+ public function getStartDate(?string $rounding = null) { $date = $this->startDate->avoidMutation(); @@ -1015,7 +1031,7 @@ * * @return CarbonInterface|null */- public function getEndDate(string $rounding = null)+ public function getEndDate(?string $rounding = null) { if (!$this->endDate) { return null;@@ -1809,13 +1825,19 @@ case 'minute': case 'seconds': case 'second':+ case 'milliseconds':+ case 'millisecond':+ case 'microseconds':+ case 'microsecond': return $this->setDateInterval(( // Override default P1D when instantiating via fluent setters. [$this->isDefaultInterval ? new CarbonInterval('PT0S') : $this->dateInterval, $method] )(...$parameters)); } - if ($this->localStrictModeEnabled ?? Carbon::isStrictModeEnabled()) {+ $dateClass = $this->dateClass;++ if ($this->localStrictModeEnabled ?? $dateClass::isStrictModeEnabled()) { throw new UnknownMethodException($method); } @@ -1877,7 +1899,7 @@ * * @return CarbonInterface */- public function calculateEnd(string $rounding = null)+ public function calculateEnd(?string $rounding = null) { if ($end = $this->getEndDate($rounding)) { return $end;@@ -2012,7 +2034,7 @@ /** * Determines if the instance is equal to another.- * Warning: if options differ, instances wil never be equal.+ * Warning: if options differ, instances will never be equal. * * @param mixed $period *@@ -2027,7 +2049,7 @@ /** * Determines if the instance is equal to another.- * Warning: if options differ, instances wil never be equal.+ * Warning: if options differ, instances will never be equal. * * @param mixed $period *@@ -2050,7 +2072,7 @@ /** * Determines if the instance is not equal to another.- * Warning: if options differ, instances wil never be equal.+ * Warning: if options differ, instances will never be equal. * * @param mixed $period *@@ -2065,7 +2087,7 @@ /** * Determines if the instance is not equal to another.- * Warning: if options differ, instances wil never be equal.+ * Warning: if options differ, instances will never be equal. * * @param mixed $period *@@ -2674,7 +2696,9 @@ !preg_match('/^R\d/', $value) && preg_match('/[a-z\d]/i', $value) ) {- return Carbon::parse($value, $this->tzName);+ $dateClass = $this->dateClass;++ return $dateClass::parse($value, $this->tzName); } }
Analyzing the provided code diff from `vendor/nesbot/carbon/src/Carbon/CarbonPeriod.php`:
---
**Vulnerability 1:**
Vulnerability Existed: no
Use After Free / Null Pointer Dereference - CWE-416 / CWE-476 - CarbonPeriod.php - Lines 505-516
Old Code:
```php
} elseif ($start === null && $parsed = Carbon::make($part)) {
$start = $part;
} elseif ($end === null && $parsed = Carbon::make(static::addMissingParts($start ?? '', $part))) {
$end = $part;
```
Fixed Code:
```php
$dateClass = static::DEFAULT_DATE_CLASS;
...
} elseif ($start === null && $parsed = $dateClass::make($part)) {
$start = $part;
} elseif ($end === null && $parsed = $dateClass::make(static::addMissingParts($start ?? '', $part))) {
$end = $part;
```
Explanation:
The fix improves code maintainability and extensibility by using a configurable `DEFAULT_DATE_CLASS` constant instead of hard-coding `Carbon`. This prevents potential issues if subclasses need to use a different date class. The hard-coded approach was not technically vulnerable, but the fix prevents future coupling issues and makes the code more flexible for inheritance patterns.
---
**Vulnerability 2:**
Vulnerability Existed: not sure
Improper Input Validation / Type Confusion - CWE-20 - CarbonPeriod.php - Lines 700-705
Old Code:
```php
} elseif ($this->options === null && (\is_int($argument) || $argument === null)) {
$this->setOptions($argument);
```
Fixed Code:
```php
} elseif (!$optionsSet && (\is_int($argument) || $argument === null)) {
$optionsSet = true;
$this->setOptions(((int) $this->options) | ((int) $argument));
```
Explanation:
The original code could allow options to be set multiple times if multiple integer arguments or null values are passed, potentially causing unexpected behavior. The fix introduces an `$optionsSet` flag to ensure options are only processed once, and uses bitwise OR to merge options correctly. This prevents option overwriting and enforces proper option accumulation semantics. The vulnerability is marked as "not sure" because while the original behavior could be unintended, whether it constitutes a security vulnerability depends on the context of how options are used downstream.
---
**Vulnerability 3:**
Vulnerability Existed: no
Logic Error / Typo - CWE-397 - CarbonPeriod.php - Lines 2034, 2052, 2074, 2088
Old Code:
```php
* Warning: if options differ, instances wil never be equal.
```
Fixed Code:
```php
* Warning: if options differ, instances will never be equal.
```
Explanation:
This is a documentation/comment typo fix ("wil" → "will"). No security vulnerability exists, but the correction improves documentation clarity.
---
**Summary:**
The diff primarily contains maintenance improvements, API extensions (milliseconds/microseconds methods), and one notable fix to the options handling logic that prevents potential unintended behavior in option accumulation. No critical security vulnerabilities are fixed by these changes.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/CarbonPeriodImmutable.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/CarbonPeriodImmutable.php 2025-12-21 09:36:35.315296506 +0000@@ -14,6 +14,13 @@ class CarbonPeriodImmutable extends CarbonPeriod { /**+ * Default date class of iteration items.+ *+ * @var string+ */+ protected const DEFAULT_DATE_CLASS = CarbonImmutable::class;++ /** * Date class of iteration items. * * @var string
Based on my analysis of the provided diff, I find no security vulnerabilities in this code change. **Analysis Result:** Vulnerability Existed: **no** **Explanation:** This diff introduces a new protected constant `DEFAULT_DATE_CLASS` in the `CarbonPeriodImmutable` class that points to `CarbonImmutable::class`. This is a straightforward addition of a class constant with no security implications: 1. **No Input Handling**: The change does not involve user input, external data sources, or dynamic code execution. 2. **Type Safety**: The constant is assigned a class reference (`CarbonImmutable::class`), which is resolved at compile-time and cannot be manipulated. 3. **Access Control**: The constant is marked as `protected`, limiting access to the class and its subclasses appropriately. 4. **No New Attack Vectors**: This addition does not introduce any new functionality that could be exploited, nor does it modify existing security controls. 5. **Documentation**: The change includes proper docblock comments explaining the constant's purpose. This appears to be a refactoring change to establish a default date class constant for the immutable period implementation, with no security risks.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/CarbonTimeZone.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/CarbonTimeZone.php 2025-12-21 09:36:35.319296755 +0000@@ -155,7 +155,7 @@ * * @return string */- public function toOffsetName(DateTimeInterface $date = null)+ public function toOffsetName(?DateTimeInterface $date = null) { return static::getOffsetNameFromMinuteOffset( $this->getOffset($date ?: Carbon::now($this)) / 60@@ -169,7 +169,7 @@ * * @return CarbonTimeZone */- public function toOffsetTimeZone(DateTimeInterface $date = null)+ public function toOffsetTimeZone(?DateTimeInterface $date = null) { return new static($this->toOffsetName($date)); }@@ -185,7 +185,7 @@ * * @return string|false */- public function toRegionName(DateTimeInterface $date = null, $isDst = 1)+ public function toRegionName(?DateTimeInterface $date = null, $isDst = 1) { $name = $this->getName(); $firstChar = substr($name, 0, 1);@@ -227,7 +227,7 @@ * * @return CarbonTimeZone|false */- public function toRegionTimeZone(DateTimeInterface $date = null)+ public function toRegionTimeZone(?DateTimeInterface $date = null) { $tz = $this->toRegionName($date);
Vulnerability Existed: no Nullable Type Declaration - CWE-1025 - vendor/nesbot/carbon/src/Carbon/CarbonTimeZone.php lines 158, 172, 188, 230 Old Code: ```php public function toOffsetName(DateTimeInterface $date = null) public function toOffsetTimeZone(DateTimeInterface $date = null) public function toRegionName(DateTimeInterface $date = null, $isDst = 1) public function toRegionTimeZone(DateTimeInterface $date = null) ``` Fixed Code: ```php public function toOffsetName(?DateTimeInterface $date = null) public function toOffsetTimeZone(?DateTimeInterface $date = null) public function toRegionName(?DateTimeInterface $date = null, $isDst = 1) public function toRegionTimeZone(?DateTimeInterface $date = null) ``` Explanation: This diff does not represent a security fix addressing a vulnerability. Instead, it applies PHP 7.1+ nullable type declaration syntax (`?DateTimeInterface`) to method parameters that already had default `null` values. This is a code quality improvement that makes type declarations more explicit and semantically correct. The old code was not vulnerable—it simply used an older style of indicating optional parameters. The change improves code clarity and enables better static analysis tools, but does not fix any security vulnerability.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Doctrine/CarbonDoctrineType.php+++ /dev/null@@ -1,23 +0,0 @@-<?php--/**- * This file is part of the Carbon package.- *- * (c) Brian Nesbitt <[email protected]>- *- * For the full copyright and license information, please view the LICENSE- * file that was distributed with this source code.- */--namespace Carbon\Doctrine;--use Doctrine\DBAL\Platforms\AbstractPlatform;--interface CarbonDoctrineType-{- public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform);-- public function convertToPHPValue($value, AbstractPlatform $platform);-- public function convertToDatabaseValue($value, AbstractPlatform $platform);-}
Vulnerability Existed: no No vulnerabilities detected in this diff. Explanation: This diff shows the deletion of a file (`vendor/nesbot/carbon/src/Carbon/Doctrine/CarbonDoctrineType.php`). The file being deleted is an interface definition with no implementation code. It defines three method signatures for Doctrine type conversion: - `getSQLDeclaration()` - `convertToPHPValue()` - `convertToDatabaseValue()` Since this is merely an interface contract with no actual executable code, no security vulnerabilities exist within it. The removal of this file does not represent a security fix—it appears to be a vendor dependency cleanup or version update. Interface definitions themselves cannot introduce vulnerabilities; only their implementations can contain security flaws.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Doctrine/CarbonImmutableType.php+++ /dev/null@@ -1,37 +0,0 @@-<?php--/**- * This file is part of the Carbon package.- *- * (c) Brian Nesbitt <[email protected]>- *- * For the full copyright and license information, please view the LICENSE- * file that was distributed with this source code.- */--namespace Carbon\Doctrine;--use Doctrine\DBAL\Platforms\AbstractPlatform;--class CarbonImmutableType extends DateTimeImmutableType implements CarbonDoctrineType-{- /**- * {@inheritdoc}- *- * @return string- */- public function getName()- {- return 'carbon_immutable';- }-- /**- * {@inheritdoc}- *- * @return bool- */- public function requiresSQLCommentHint(AbstractPlatform $platform)- {- return true;- }-}
Vulnerability Existed: no **File Removal - No Active Vulnerability** - N/A - vendor/nesbot/carbon/src/Carbon/Doctrine/CarbonImmutableType.php (Lines 1-37) Old Code: ```php <?php /** * This file is part of the Carbon package. * * (c) Brian Nesbitt <[email protected]> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Carbon\Doctrine; use Doctrine\DBAL\Platforms\AbstractPlatform; class CarbonImmutableType extends DateTimeImmutableType implements CarbonDoctrineType { /** * {@inheritdoc} * * @return string */ public function getName() { return 'carbon_immutable'; } /** * {@inheritdoc} * * @return bool */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } } ``` Fixed Code: ``` [File deleted] ``` Explanation: This diff represents the deletion of a vendor library file (CarbonImmutableType.php from the nesbot/carbon package). The file itself contains no security vulnerabilities - it is a standard Doctrine type class for handling immutable Carbon datetime objects. The removal of this file does not fix an existing vulnerability in the code; rather, it appears to be a cleanup or refactoring of vendor dependencies. Vendor files are typically excluded from security analysis as they are third-party code managed through package managers.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Doctrine/CarbonType.php+++ /dev/null@@ -1,37 +0,0 @@-<?php--/**- * This file is part of the Carbon package.- *- * (c) Brian Nesbitt <[email protected]>- *- * For the full copyright and license information, please view the LICENSE- * file that was distributed with this source code.- */--namespace Carbon\Doctrine;--use Doctrine\DBAL\Platforms\AbstractPlatform;--class CarbonType extends DateTimeType implements CarbonDoctrineType-{- /**- * {@inheritdoc}- *- * @return string- */- public function getName()- {- return 'carbon';- }-- /**- * {@inheritdoc}- *- * @return bool- */- public function requiresSQLCommentHint(AbstractPlatform $platform)- {- return true;- }-}
Vulnerability Existed: no No CWE Identified - File Deletion Old Code: ```php <?php /** * This file is part of the Carbon package. * * (c) Brian Nesbitt <[email protected]> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Carbon\Doctrine; use Doctrine\DBAL\Platforms\AbstractPlatform; class CarbonType extends DateTimeType implements CarbonDoctrineType { /** * {@inheritdoc} * * @return string */ public function getName() { return 'carbon'; } /** * {@inheritdoc} * * @return bool */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } } ``` Fixed Code: File deleted (no longer present) Explanation: This diff shows the deletion of the CarbonType.php file. The file itself contains no security vulnerabilities. It is a legitimate Doctrine type class that extends DateTimeType and implements CarbonDoctrineType. The class provides two simple methods: `getName()` which returns the type name 'carbon', and `requiresSQLCommentHint()` which returns a boolean flag. There are no code injection risks, authentication issues, authorization bypasses, or other security flaws present in this code. The deletion appears to be a dependency management or file cleanup operation rather than a security fix.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Doctrine/CarbonTypeConverter.php+++ /dev/null@@ -1,123 +0,0 @@-<?php--/**- * This file is part of the Carbon package.- *- * (c) Brian Nesbitt <[email protected]>- *- * For the full copyright and license information, please view the LICENSE- * file that was distributed with this source code.- */--namespace Carbon\Doctrine;--use Carbon\Carbon;-use Carbon\CarbonInterface;-use DateTimeInterface;-use Doctrine\DBAL\Platforms\AbstractPlatform;-use Doctrine\DBAL\Types\ConversionException;-use Exception;--/**- * @template T of CarbonInterface- */-trait CarbonTypeConverter-{- /**- * @return class-string<T>- */- protected function getCarbonClassName(): string- {- return Carbon::class;- }-- /**- * @return string- */- public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)- {- $precision = $fieldDeclaration['precision'] ?: 10;-- if ($fieldDeclaration['secondPrecision'] ?? false) {- $precision = 0;- }-- if ($precision === 10) {- $precision = DateTimeDefaultPrecision::get();- }-- $type = parent::getSQLDeclaration($fieldDeclaration, $platform);-- if (!$precision) {- return $type;- }-- if (str_contains($type, '(')) {- return preg_replace('/\(\d+\)/', "($precision)", $type);- }-- [$before, $after] = explode(' ', "$type ");-- return trim("$before($precision) $after");- }-- /**- * @SuppressWarnings(PHPMD.UnusedFormalParameter)- *- * @return T|null- */- public function convertToPHPValue($value, AbstractPlatform $platform)- {- $class = $this->getCarbonClassName();-- if ($value === null || is_a($value, $class)) {- return $value;- }-- if ($value instanceof DateTimeInterface) {- return $class::instance($value);- }-- $date = null;- $error = null;-- try {- $date = $class::parse($value);- } catch (Exception $exception) {- $error = $exception;- }-- if (!$date) {- throw ConversionException::conversionFailedFormat(- $value,- $this->getName(),- 'Y-m-d H:i:s.u or any format supported by '.$class.'::parse()',- $error- );- }-- return $date;- }-- /**- * @SuppressWarnings(PHPMD.UnusedFormalParameter)- *- * @return string|null- */- public function convertToDatabaseValue($value, AbstractPlatform $platform)- {- if ($value === null) {- return $value;- }-- if ($value instanceof DateTimeInterface) {- return $value->format('Y-m-d H:i:s.u');- }-- throw ConversionException::conversionFailedInvalidType(- $value,- $this->getName(),- ['null', 'DateTime', 'Carbon']- );- }-}
Vulnerability Existed: no This diff shows the **removal** of a file (vendor/nesbot/carbon/src/Carbon/Doctrine/CarbonTypeConverter.php), not a security fix to existing code. **Analysis:** The file being deleted is a trait that provides Doctrine DBAL type conversion for Carbon date objects. The code itself does not contain exploitable vulnerabilities: - **convertToPHPValue()**: Safely handles date parsing with proper exception handling and validation - **convertToDatabaseValue()**: Safely formats dates and validates input types - **getSQLDeclaration()**: Uses `preg_replace()` with a fixed pattern (not user-controlled regex), safe from injection The removal of this file appears to be a dependency cleanup or version update, not a security patch addressing a vulnerability in this specific code. If there were security concerns, they would likely be in the Carbon or Doctrine libraries themselves, not in this straightforward converter trait. **Conclusion:** No vulnerability was present in the removed code. This is a file deletion/cleanup operation, not a security fix.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Doctrine/DateTimeDefaultPrecision.php+++ /dev/null@@ -1,37 +0,0 @@-<?php--/**- * This file is part of the Carbon package.- *- * (c) Brian Nesbitt <[email protected]>- *- * For the full copyright and license information, please view the LICENSE- * file that was distributed with this source code.- */--namespace Carbon\Doctrine;--class DateTimeDefaultPrecision-{- private static $precision = 6;-- /**- * Change the default Doctrine datetime and datetime_immutable precision.- *- * @param int $precision- */- public static function set(int $precision): void- {- self::$precision = $precision;- }-- /**- * Get the default Doctrine datetime and datetime_immutable precision.- *- * @return int- */- public static function get(): int- {- return self::$precision;- }-}
Vulnerability Existed: no No Vulnerability - File Deletion File: vendor/nesbot/carbon/src/Carbon/Doctrine/DateTimeDefaultPrecision.php Lines: 1-37 (entire file deleted) Old Code: ```php <?php /** * This file is part of the Carbon package. * * (c) Brian Nesbitt <[email protected]> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Carbon\Doctrine; class DateTimeDefaultPrecision { private static $precision = 6; /** * Change the default Doctrine datetime and datetime_immutable precision. * * @param int $precision */ public static function set(int $precision): void { self::$precision = $precision; } /** * Get the default Doctrine datetime and datetime_immutable precision. * * @return int */ public static function get(): int { return self::$precision; } } ``` Fixed Code: (File deleted - no longer present) Explanation: This diff shows the complete removal of the DateTimeDefaultPrecision.php file from the vendor directory. The deleted code itself contains no security vulnerabilities. It is a simple utility class providing static methods to get and set a precision value for Doctrine datetime handling. The deletion likely indicates either a vendor update, cleanup of unused code, or removal of a deprecated utility. There are no injection risks, authentication issues, or other security concerns in the original code. File deletion is a maintenance action, not a security fix.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Doctrine/DateTimeImmutableType.php+++ /dev/null@@ -1,24 +0,0 @@-<?php--/**- * Thanks to https://github.com/flaushi for his suggestion:- * https://github.com/doctrine/dbal/issues/2873#issuecomment-534956358- */-namespace Carbon\Doctrine;--use Carbon\CarbonImmutable;-use Doctrine\DBAL\Types\VarDateTimeImmutableType;--class DateTimeImmutableType extends VarDateTimeImmutableType implements CarbonDoctrineType-{- /** @use CarbonTypeConverter<CarbonImmutable> */- use CarbonTypeConverter;-- /**- * @return class-string<CarbonImmutable>- */- protected function getCarbonClassName(): string- {- return CarbonImmutable::class;- }-}
Vulnerability Existed: no
File Deletion - No Security Vulnerability - vendor/nesbot/carbon/src/Carbon/Doctrine/DateTimeImmutableType.php [Lines 1-24]
Old Code:
```php
<?php
/**
* Thanks to https://github.com/flaushi for his suggestion:
* https://github.com/doctrine/dbal/issues/2873#issuecomment-534956358
*/
namespace Carbon\Doctrine;
use Carbon\CarbonImmutable;
use Doctrine\DBAL\Types\VarDateTimeImmutableType;
class DateTimeImmutableType extends VarDateTimeImmutableType implements CarbonDoctrineType
{
/** @use CarbonTypeConverter<CarbonImmutable> */
use CarbonTypeConverter;
/**
* @return class-string<CarbonImmutable>
*/
protected function getCarbonClassName(): string
{
return CarbonImmutable::class;
}
}
```
Fixed Code:
[File deleted]
Explanation:
This diff shows the deletion of a vendor file (Carbon's DateTimeImmutableType class). This is not a security fix but rather a dependency cleanup or version update. The file itself contains no security vulnerabilities - it is a straightforward Doctrine type class that converts database values to CarbonImmutable instances. The deletion does not address or remove any vulnerable code patterns such as injection vulnerabilities, authentication issues, or cryptographic weaknesses. This is routine dependency management, not a security fix.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Doctrine/DateTimeType.php+++ /dev/null@@ -1,16 +0,0 @@-<?php--/**- * Thanks to https://github.com/flaushi for his suggestion:- * https://github.com/doctrine/dbal/issues/2873#issuecomment-534956358- */-namespace Carbon\Doctrine;--use Carbon\Carbon;-use Doctrine\DBAL\Types\VarDateTimeType;--class DateTimeType extends VarDateTimeType implements CarbonDoctrineType-{- /** @use CarbonTypeConverter<Carbon> */- use CarbonTypeConverter;-}
Vulnerability Existed: no
File Deletion - No CWE - vendor/nesbot/carbon/src/Carbon/Doctrine/DateTimeType.php (Lines 1-16)
Old Code:
```php
<?php
/**
* Thanks to https://github.com/flaushi for his suggestion:
* https://github.com/doctrine/dbal/issues/2873#issuecomment-534956358
*/
namespace Carbon\Doctrine;
use Carbon\Carbon;
use Doctrine\DBAL\Types\VarDateTimeType;
class DateTimeType extends VarDateTimeType implements CarbonDoctrineType
{
/** @use CarbonTypeConverter<Carbon> */
use CarbonTypeConverter;
}
```
Fixed Code:
File deleted (no replacement code)
Explanation:
This diff shows the complete removal of the DateTimeType.php file. The file itself contains no security vulnerabilities. It is a legitimate Doctrine type class that extends VarDateTimeType and uses the CarbonTypeConverter trait for type conversion. The deletion appears to be a refactoring or dependency management change, not a security fix. No vulnerability was present in the deleted code, and the removal does not address any security issue.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/BadComparisonUnitException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/BadComparisonUnitException.php 2025-12-21 09:36:35.319296755 +0000@@ -29,7 +29,7 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($unit, $code = 0, Throwable $previous = null)+ public function __construct($unit, $code = 0, ?Throwable $previous = null) { $this->unit = $unit;
Vulnerability Existed: no Type Hint Addition - Not a Security Vulnerability - vendor/nesbot/carbon/src/Carbon/Exceptions/BadComparisonUnitException.php [Line 32] Old Code: ```php public function __construct($unit, $code = 0, Throwable $previous = null) ``` Fixed Code: ```php public function __construct($unit, $code = 0, ?Throwable $previous = null) ``` Explanation: This change adds a nullable type hint (`?Throwable`) to the `$previous` parameter. This is a PHP type system improvement (PHP 7.1+ nullable types syntax), not a security fix. The code was functionally equivalent before - the parameter accepted null values regardless - but this change makes the type contract explicit. This is a code quality and maintainability improvement that does not address any security vulnerability. There is no security issue in either the old or new code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/BadFluentConstructorException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/BadFluentConstructorException.php 2025-12-21 09:36:35.319296755 +0000@@ -30,11 +30,11 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($method, $code = 0, Throwable $previous = null)+ public function __construct($method, $code = 0, ?Throwable $previous = null) { $this->method = $method; - parent::__construct(sprintf("Unknown fluent constructor '%s'.", $method), $code, $previous);+ parent::__construct(\sprintf("Unknown fluent constructor '%s'.", $method), $code, $previous); } /**
Analyzing the provided code diff for security vulnerabilities:
Vulnerability Existed: no
[No Vulnerability Identified] - [N/A] - vendor/nesbot/carbon/src/Carbon/Exceptions/BadFluentConstructorException.php [33, 37]
[Old Code]
public function __construct($method, $code = 0, Throwable $previous = null)
{
$this->method = $method;
parent::__construct(sprintf("Unknown fluent constructor '%s'.", $method), $code, $previous);
}
[Fixed Code]
public function __construct($method, $code = 0, ?Throwable $previous = null)
{
$this->method = $method;
parent::__construct(\sprintf("Unknown fluent constructor '%s'.", $method), $code, $previous);
}
Explanation:
This diff contains two changes, neither of which address security vulnerabilities:
1. **Line 33**: The parameter type hint for `$previous` was changed from `Throwable $previous = null` to `?Throwable $previous = null`. This is a modernization to PHP 7.1+ nullable type syntax, providing better type safety and clarity, but it does not fix a security vulnerability.
2. **Line 37**: The function call `sprintf()` was changed to `\sprintf()` with a fully-qualified namespace prefix. This is a code style change to ensure the global namespace function is called explicitly, avoiding potential namespace collisions. This is a best practice but not a security fix.
Both changes represent code quality improvements and modernization rather than security fixes.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/BadFluentSetterException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/BadFluentSetterException.php 2025-12-21 09:36:35.319296755 +0000@@ -30,11 +30,11 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($setter, $code = 0, Throwable $previous = null)+ public function __construct($setter, $code = 0, ?Throwable $previous = null) { $this->setter = $setter; - parent::__construct(sprintf("Unknown fluent setter '%s'", $setter), $code, $previous);+ parent::__construct(\sprintf("Unknown fluent setter '%s'", $setter), $code, $previous); } /**
I'll analyze this code diff for security vulnerabilities.
Vulnerability Existed: no
Type Parameter Nullability - Not a Security Vulnerability - vendor/nesbot/carbon/src/Carbon/Exceptions/BadFluentSetterException.php - Line 33
**Old Code:**
```php
public function __construct($setter, $code = 0, Throwable $previous = null)
```
**Fixed Code:**
```php
public function __construct($setter, $code = 0, ?Throwable $previous = null)
```
**Explanation:**
This change adds explicit nullable type declaration (`?Throwable`) to the `$previous` parameter. This is a code quality improvement that makes the type system more explicit and allows proper static analysis. It is not a security fix—it's a type safety enhancement that clarifies intent. The parameter already accepted `null` values in the old code (default value was `null`), so there was no underlying vulnerability being fixed here.
---
Vulnerability Existed: no
Function Call Namespace Qualification - Not a Security Vulnerability - vendor/nesbot/carbon/src/Carbon/Exceptions/BadFluentSetterException.php - Line 37
**Old Code:**
```php
parent::__construct(sprintf("Unknown fluent setter '%s'", $setter), $code, $previous);
```
**Fixed Code:**
```php
parent::__construct(\sprintf("Unknown fluent setter '%s'", $setter), $code, $previous);
```
**Explanation:**
This change adds a backslash prefix to `sprintf()`, converting it to `\sprintf()` to explicitly reference the global namespace function. This is a code style/performance optimization, not a security fix. It ensures the global `sprintf()` function is called directly rather than potentially being resolved through the current namespace. There was no vulnerability in the original code—this is merely a best practice for clarity and potential performance in PHP.
---
**Summary:** This diff contains no security vulnerabilities. Both changes are code quality improvements related to type declarations and namespace resolution.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/ImmutableException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/ImmutableException.php 2025-12-21 09:36:35.323297003 +0000@@ -30,7 +30,7 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($value, $code = 0, Throwable $previous = null)+ public function __construct($value, $code = 0, ?Throwable $previous = null) { $this->value = $value; parent::__construct("$value is immutable.", $code, $previous);
Vulnerability Existed: no [No Vulnerability - Type Declaration Update] - N/A - vendor/nesbot/carbon/src/Carbon/Exceptions/ImmutableException.php [33] Old Code: ```php public function __construct($value, $code = 0, Throwable $previous = null) ``` Fixed Code: ```php public function __construct($value, $code = 0, ?Throwable $previous = null) ``` Explanation: This change adds nullable type declaration (`?Throwable`) to the `$previous` parameter. This is a code quality improvement, not a security fix. The change makes the type system more explicit by using PHP 7.1+ nullable type syntax (`?Throwable` instead of relying on `= null` to indicate optionality). This improves type safety and IDE support but does not address any security vulnerability. The functionality remains identical - the parameter was already accepting `null` values before, and the change simply makes this explicit in the type declaration.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidDateException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidDateException.php 2025-12-21 09:36:35.323297003 +0000@@ -38,7 +38,7 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($field, $value, $code = 0, Throwable $previous = null)+ public function __construct($field, $value, $code = 0, ?Throwable $previous = null) { $this->field = $field; $this->value = $value;
Vulnerability Existed: no Nullable Type Declaration - CWE-1025 - vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidDateException.php Line 41 Old Code: ```php public function __construct($field, $value, $code = 0, Throwable $previous = null) ``` Fixed Code: ```php public function __construct($field, $value, $code = 0, ?Throwable $previous = null) ``` Explanation: This change is not a security fix for a vulnerability, but rather a code quality improvement. The modification adds explicit nullable type declaration (`?Throwable`) to the `$previous` parameter. In PHP 7.1+, this is the proper way to declare that a parameter can accept either a `Throwable` object or `null`. Previously, the code relied on implicit nullability through the default value assignment, which is less explicit and doesn't enforce type checking as strongly. This change improves type safety and code clarity but does not address or fix an existing security vulnerability.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/NotACarbonClassException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/NotACarbonClassException.php 2025-12-21 09:36:35.323297003 +0000@@ -31,11 +31,11 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($className, $code = 0, Throwable $previous = null)+ public function __construct($className, $code = 0, ?Throwable $previous = null) { $this->className = $className; - parent::__construct(sprintf('Given class does not implement %s: %s', CarbonInterface::class, $className), $code, $previous);+ parent::__construct(\sprintf('Given class does not implement %s: %s', CarbonInterface::class, $className), $code, $previous); } /**
Vulnerability Existed: no
PHP Type Declaration Update - No CWE - vendor/nesbot/carbon/src/Carbon/Exceptions/NotACarbonClassException.php [34, 38]
Old Code:
```php
public function __construct($className, $code = 0, Throwable $previous = null)
{
$this->className = $className;
parent::__construct(sprintf('Given class does not implement %s: %s', CarbonInterface::class, $className), $code, $previous);
}
```
Fixed Code:
```php
public function __construct($className, $code = 0, ?Throwable $previous = null)
{
$this->className = $className;
parent::__construct(\sprintf('Given class does not implement %s: %s', CarbonInterface::class, $className), $code, $previous);
}
```
Explanation:
This diff contains two non-security related changes:
1. **Line 34**: Addition of nullable type hint `?Throwable` instead of `Throwable $previous = null` - This is a PHP 7.1+ nullable type declaration improvement for code clarity and type safety. It does not fix a security vulnerability.
2. **Line 38**: Fully qualified function name `\sprintf()` instead of `sprintf()` - This is a best practice to use fully qualified function names to avoid namespace collisions and improve performance slightly. It does not address a security vulnerability.
Both changes are code quality and maintainability improvements, not security fixes. No security vulnerabilities were identified in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/NotLocaleAwareException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/NotLocaleAwareException.php 2025-12-21 09:36:35.323297003 +0000@@ -23,7 +23,7 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($object, $code = 0, Throwable $previous = null)+ public function __construct($object, $code = 0, ?Throwable $previous = null) { $dump = \is_object($object) ? \get_class($object) : \gettype($object);
Vulnerability Existed: no [PHP Type Hinting - No CWE] - N/A - vendor/nesbot/carbon/src/Carbon/Exceptions/NotLocaleAwareException.php - Line 26 Old Code: ```php public function __construct($object, $code = 0, Throwable $previous = null) ``` Fixed Code: ```php public function __construct($object, $code = 0, ?Throwable $previous = null) ``` Explanation: This is not a security vulnerability fix, but rather a code quality improvement. The change adds explicit nullable type declaration (`?Throwable`) to the `$previous` parameter, which is a PHP 7.1+ feature. This change makes the code more explicit about accepting `null` values and improves type safety by having the type hint match the default value. This is a best practice in modern PHP development but does not address any security vulnerability. The parameter behavior remains identical - it still accepts `null` as a default value and a `Throwable` object when provided.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/OutOfRangeException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/OutOfRangeException.php 2025-12-21 09:36:35.323297003 +0000@@ -57,7 +57,7 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($unit, $min, $max, $value, $code = 0, Throwable $previous = null)+ public function __construct($unit, $min, $max, $value, $code = 0, ?Throwable $previous = null) { $this->unit = $unit; $this->min = $min;
Vulnerability Existed: no Parameter Type Declaration - Not a Security Vulnerability - vendor/nesbot/carbon/src/Carbon/Exceptions/OutOfRangeException.php [Line 60] [Old Code] public function __construct($unit, $min, $max, $value, $code = 0, Throwable $previous = null) [Fixed Code] public function __construct($unit, $min, $max, $value, $code = 0, ?Throwable $previous = null) Explanation: This change is a code quality improvement, not a security fix. The modification adds nullable type declaration syntax (`?Throwable`) to the `$previous` parameter, which is a PHP 7.1+ feature. This makes the code more type-safe by explicitly declaring that the parameter can be either a `Throwable` object or `null`. This is a best practice for type hints but does not fix any security vulnerability. The parameter was already functioning as nullable before this change (default value of `null`), so this is purely a syntax/declaration improvement for better code clarity and static analysis support.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/ParseErrorException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/ParseErrorException.php 2025-12-21 09:36:35.323297003 +0000@@ -45,7 +45,7 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($expected, $actual, $help = '', $code = 0, Throwable $previous = null)+ public function __construct($expected, $actual, $help = '', $code = 0, ?Throwable $previous = null) { $this->expected = $expected; $this->actual = $actual;
Vulnerability Existed: no Nullable Type Declaration - Not a Security Vulnerability - vendor/nesbot/carbon/src/Carbon/Exceptions/ParseErrorException.php - Line 48 Old Code: ```php public function __construct($expected, $actual, $help = '', $code = 0, Throwable $previous = null) ``` Fixed Code: ```php public function __construct($expected, $actual, $help = '', $code = 0, ?Throwable $previous = null) ``` Explanation: This change adds explicit nullable type declaration (`?Throwable`) to the `$previous` parameter. This is a code quality improvement, not a security fix. The parameter was already functionally nullable (with a default value of `null`), but the explicit nullable type hint makes the intent clearer and enables better static analysis. This change does not address or fix any security vulnerability—it's a modernization of PHP type declarations to PHP 7.1+ syntax. No CWE applies to this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/UnitNotConfiguredException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/UnitNotConfiguredException.php 2025-12-21 09:36:35.323297003 +0000@@ -29,7 +29,7 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($unit, $code = 0, Throwable $previous = null)+ public function __construct($unit, $code = 0, ?Throwable $previous = null) { $this->unit = $unit;
Vulnerability Existed: no Nullable Type Declaration - Type Safety Enhancement - vendor/nesbot/carbon/src/Carbon/Exceptions/UnitNotConfiguredException.php - Line 32 Old Code: ```php public function __construct($unit, $code = 0, Throwable $previous = null) ``` Fixed Code: ```php public function __construct($unit, $code = 0, ?Throwable $previous = null) ``` Explanation: This change is a type safety improvement, not a security fix for a vulnerability. The modification adds explicit nullable type declaration (`?Throwable`) to the `$previous` parameter, which already had a default value of `null`. This change: 1. **Improves type safety** - Makes it explicit in the type signature that `null` is an acceptable value 2. **Enables stricter static analysis** - Tools like PHPStan and Psalm can now properly enforce that the parameter can be `null` 3. **Does not fix a vulnerability** - The code was already functionally safe; `null` was already being passed as the default value This is a modernization of PHP code to use PHP 7.1+ nullable type syntax, enhancing code clarity and enabling better static analysis, but it does not address or fix any existing security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownGetterException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownGetterException.php 2025-12-21 09:36:35.323297003 +0000@@ -30,7 +30,7 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($getter, $code = 0, Throwable $previous = null)+ public function __construct($getter, $code = 0, ?Throwable $previous = null) { $this->getter = $getter;
Vulnerability Existed: no [No Vulnerability] - UnknownGetterException Constructor Parameter Type Update - vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownGetterException.php - Line 33 Old Code: ```php public function __construct($getter, $code = 0, Throwable $previous = null) ``` Fixed Code: ```php public function __construct($getter, $code = 0, ?Throwable $previous = null) ``` Explanation: This change adds explicit nullable type hint (`?Throwable`) to the `$previous` parameter. This is a type safety improvement, not a security fix. The parameter already accepted `null` as a default value in the original code, but the new syntax makes the nullable type explicit and enforces it at the type-checking level. This is a PHP best practice improvement that increases code clarity and enables better static analysis, but does not address or remediate any security vulnerability. The change is purely a code quality enhancement for type consistency.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownMethodException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownMethodException.php 2025-12-21 09:36:35.323297003 +0000@@ -30,7 +30,7 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($method, $code = 0, Throwable $previous = null)+ public function __construct($method, $code = 0, ?Throwable $previous = null) { $this->method = $method;
Vulnerability Existed: no PHP Type System - No CWE - vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownMethodException.php line 33 Old Code: ```php public function __construct($method, $code = 0, Throwable $previous = null) ``` Fixed Code: ```php public function __construct($method, $code = 0, ?Throwable $previous = null) ``` Explanation: This change adds nullable type declaration (`?Throwable`) to the `$previous` parameter, which is a type system improvement rather than a security fix. The code allows `null` to be passed to this parameter (as indicated by the default value `= null`), but the old declaration didn't explicitly document this. Adding the `?` nullable indicator makes the type signature match PHP 7.1+ nullable type syntax and clarifies that `null` is an acceptable value. This is a code quality improvement that helps prevent type errors and improves IDE autocompletion, but there was no actual security vulnerability in the original code. The parameter was already safely handling `null` values as expected by the Exception base class constructor.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownSetterException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownSetterException.php 2025-12-21 09:36:35.323297003 +0000@@ -30,7 +30,7 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($setter, $code = 0, Throwable $previous = null)+ public function __construct($setter, $code = 0, ?Throwable $previous = null) { $this->setter = $setter;
Vulnerability Existed: no [No Vulnerability Detected] - N/A - vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownSetterException.php [Line 33] Old Code: ```php public function __construct($setter, $code = 0, Throwable $previous = null) ``` Fixed Code: ```php public function __construct($setter, $code = 0, ?Throwable $previous = null) ``` Explanation: This change is a type system improvement, not a security fix. The modification adds proper nullable type declaration (`?Throwable`) to the `$previous` parameter, which was previously using the older PHP style of allowing `null` as a default value without explicit nullable typing. This is a modern PHP best practice (PHP 7.1+ nullable types) that improves code clarity and type safety but does not address or fix any security vulnerability. The code was already functionally safe before this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownUnitException.php 2025-12-21 09:35:59.489069796 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownUnitException.php 2025-12-21 09:36:35.323297003 +0000@@ -29,7 +29,7 @@ * @param int $code * @param Throwable|null $previous */- public function __construct($unit, $code = 0, Throwable $previous = null)+ public function __construct($unit, $code = 0, ?Throwable $previous = null) { $this->unit = $unit;
Vulnerability Existed: no [No vulnerability] - [N/A] - [vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownUnitException.php] [Lines 32] Old Code: ```php public function __construct($unit, $code = 0, Throwable $previous = null) ``` Fixed Code: ```php public function __construct($unit, $code = 0, ?Throwable $previous = null) ``` Explanation: This change adds nullable type declaration (`?Throwable`) to the `$previous` parameter instead of relying on implicit nullable assignment. This is a code quality improvement that makes the type hint explicit and compatible with modern PHP practices (PHP 7.1+), but it does not fix an existing security vulnerability. The functionality remains identical—the parameter was already accepting null values before this change. This is a type safety enhancement rather than a security fix.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Factory.php 2025-12-21 09:35:59.493070045 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Factory.php 2025-12-21 09:36:35.323297003 +0000@@ -266,7 +266,7 @@ return $this; } - public function className(string $className = null)+ public function className(?string $className = null) { return $className === null ? $this->getClassName() : $this->setClassName($className); }@@ -283,7 +283,7 @@ return $this; } - public function settings(array $settings = null)+ public function settings(?array $settings = null) { return $settings === null ? $this->getSettings() : $this->setSettings($settings); }
Vulnerability Existed: no Type Hint Improvement - No CWE - vendor/nesbot/carbon/src/Carbon/Factory.php Lines 269, 286 [Old Code] public function className(string $className = null) public function settings(array $settings = null) [Fixed Code] public function className(?string $className = null) public function settings(?array $settings = null) Explanation: This is a code quality improvement, not a security fix. The changes add explicit nullable type declarations using PHP 7.1+ nullable type syntax (`?string` and `?array`). The original code allowed `null` as a default value but didn't declare the parameter as nullable in the type hint, which could cause type checking warnings or issues with strict typing. The fix makes the code more explicit and type-safe by properly declaring that these parameters can accept `null` values. No security vulnerability existed in either version - this is purely a PHP best practice improvement for type safety.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/FactoryImmutable.php 2025-12-21 09:35:59.493070045 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/FactoryImmutable.php 2025-12-21 09:36:35.323297003 +0000@@ -12,6 +12,9 @@ namespace Carbon; use Closure;+use DateTimeImmutable;+use DateTimeZone;+use Psr\Clock\ClockInterface; /** * A factory to generate CarbonImmutable instances with common settings.@@ -111,7 +114,6 @@ * @method CarbonImmutable maxValue() Create a Carbon instance for the greatest supported date. * @method CarbonImmutable minValue() Create a Carbon instance for the lowest supported date. * @method void mixin($mixin) Mix another object into the class.- * @method CarbonImmutable now($tz = null) Get a Carbon instance for the current date and time. * @method CarbonImmutable parse($time = null, $tz = null) Create a carbon instance from a string. * This is an alias for the constructor that allows better fluent syntax * as it allows you to do Carbon::parse('Monday next week')->fn() rather@@ -237,7 +239,21 @@ * * </autodoc> */-class FactoryImmutable extends Factory+class FactoryImmutable extends Factory implements ClockInterface { protected $className = CarbonImmutable::class;++ /**+ * Get a Carbon instance for the current date and time.+ *+ * @param DateTimeZone|string|int|null $tz+ *+ * @return CarbonImmutable+ */+ public function now($tz = null): DateTimeImmutable+ {+ $className = $this->className;++ return new $className(null, $tz);+ } }
Analyzing the provided code diff for security vulnerabilities:
Vulnerability Existed: no
[No CWE Name] - [N/A] - vendor/nesbot/carbon/src/Carbon/FactoryImmutable.php [all changes]
Old Code:
```php
use Closure;
class FactoryImmutable extends Factory
{
protected $className = CarbonImmutable::class;
}
```
Fixed Code:
```php
use Closure;
use DateTimeImmutable;
use DateTimeZone;
use Psr\Clock\ClockInterface;
class FactoryImmutable extends Factory implements ClockInterface
{
protected $className = CarbonImmutable::class;
/**
* Get a Carbon instance for the current date and time.
*
* @param DateTimeZone|string|int|null $tz
*
* @return CarbonImmutable
*/
public function now($tz = null): DateTimeImmutable
{
$className = $this->className;
return new $className(null, $tz);
}
}
```
Explanation:
This diff represents a refactoring and API enhancement rather than a security fix. The changes include:
1. **Added imports** for `DateTimeImmutable`, `DateTimeZone`, and `Psr\Clock\ClockInterface` - standard PHP library classes with no security implications.
2. **Implemented `ClockInterface`** - adds PSR-20 Clock compliance, which is a standard interface with no security vulnerabilities.
3. **Moved `now()` method** from docblock to actual implementation - this is a refactoring for better API design and type safety.
4. **Added return type hint** `DateTimeImmutable` - improves type safety and IDE support.
The implementation is secure. The method creates a new instance using the `$className` property with null timestamp and optional timezone, which matches the expected behavior. There are no input validation issues, injection vulnerabilities, or other security concerns introduced or addressed by this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Lang/hu.php 2025-12-21 09:35:59.513071288 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Lang/hu.php 2025-12-21 09:36:35.371299986 +0000@@ -82,7 +82,7 @@ 'second_before' => ':count másodperccel', 's_before' => ':count másodperccel', 'months' => ['január', 'február', 'március', 'április', 'május', 'június', 'július', 'augusztus', 'szeptember', 'október', 'november', 'december'],- 'months_short' => ['jan.', 'feb.', 'márc.', 'ápr.', 'máj.', 'jún.', 'júl.', 'aug.', 'szept.', 'okt.', 'nov.', 'dec.'],+ 'months_short' => ['jan.', 'febr.', 'márc.', 'ápr.', 'máj.', 'jún.', 'júl.', 'aug.', 'szept.', 'okt.', 'nov.', 'dec.'], 'weekdays' => ['vasárnap', 'hétfő', 'kedd', 'szerda', 'csütörtök', 'péntek', 'szombat'], 'weekdays_short' => ['vas', 'hét', 'kedd', 'sze', 'csüt', 'pén', 'szo'], 'weekdays_min' => ['v', 'h', 'k', 'sze', 'cs', 'p', 'sz'],
Vulnerability Existed: no [No Security Vulnerability] - [N/A] - [vendor/nesbot/carbon/src/Carbon/Lang/hu.php] [Line 85] Old Code: ``` 'months_short' => ['jan.', 'feb.', 'márc.', 'ápr.', 'máj.', 'jún.', 'júl.', 'aug.', 'szept.', 'okt.', 'nov.', 'dec.'], ``` Fixed Code: ``` 'months_short' => ['jan.', 'febr.', 'márc.', 'ápr.', 'máj.', 'jún.', 'júl.', 'aug.', 'szept.', 'okt.', 'nov.', 'dec.'], ``` Explanation: This change corrects a localization string in the Hungarian language file for the Carbon date library. The abbreviation for February (februarie) has been changed from 'feb.' to 'febr.' to match the proper Hungarian abbreviation. This is a data/content fix with no security implications. No injection, authentication, authorization, encryption, or other security-related vulnerabilities are present in this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Lang/ms.php 2025-12-21 09:35:59.521071785 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Lang/ms.php 2025-12-21 09:36:35.395301478 +0000@@ -48,7 +48,7 @@ 'ago' => ':time yang lepas', 'from_now' => ':time dari sekarang', 'after' => ':time kemudian',- 'before' => ':time lepas',+ 'before' => ':time sebelum', 'diff_now' => 'sekarang', 'diff_today' => 'Hari', 'diff_today_regexp' => 'Hari(?:\\s+ini)?(?:\\s+pukul)?',
Vulnerability Existed: no No CWE Vulnerability Detected Old Code: ``` 'before' => ':time lepas', ``` Fixed Code: ``` 'before' => ':time sebelum', ``` Explanation: This is a localization/translation update for the Malay language file in the Carbon date library. The change updates the translation of the 'before' key from ':time lepas' (which means "time past/ago") to ':time sebelum' (which means "time before"). This is a linguistic correction to improve translation accuracy, not a security fix. There is no vulnerability in either the old or new code—this is purely a language string correction that does not involve any code execution, input validation, data handling, or security-sensitive operations.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Lang/sk.php 2025-12-21 09:35:59.525072034 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Lang/sk.php 2025-12-21 09:36:35.407302223 +0000@@ -33,33 +33,87 @@ * - Marek Adamický * - AlterwebStudio */++use Carbon\CarbonInterface;++$fromNow = function ($time) {+ return 'o '.strtr($time, [+ 'hodina' => 'hodinu',+ 'minúta' => 'minútu',+ 'sekunda' => 'sekundu',+ ]);+};++$ago = function ($time) {+ $replacements = [+ '/\bhodina\b/' => 'hodinou',+ '/\bminúta\b/' => 'minútou',+ '/\bsekunda\b/' => 'sekundou',+ '/\bdeň\b/u' => 'dňom',+ '/\btýždeň\b/u' => 'týždňom',+ '/\bmesiac\b/' => 'mesiacom',+ '/\brok\b/' => 'rokom',+ ];++ $replacementsPlural = [+ '/\bhodiny\b/' => 'hodinami',+ '/\bminúty\b/' => 'minútami',+ '/\bsekundy\b/' => 'sekundami',+ '/\bdni\b/' => 'dňami',+ '/\btýždne\b/' => 'týždňami',+ '/\bmesiace\b/' => 'mesiacmi',+ '/\broky\b/' => 'rokmi',+ ];++ foreach ($replacements + $replacementsPlural as $pattern => $replacement) {+ $time = preg_replace($pattern, $replacement, $time);+ }++ return "pred $time";+};+ return [- 'year' => 'rok|:count roky|:count rokov',+ 'year' => ':count rok|:count roky|:count rokov',+ 'a_year' => 'rok|:count roky|:count rokov', 'y' => ':count r',- 'month' => 'mesiac|:count mesiace|:count mesiacov',+ 'month' => ':count mesiac|:count mesiace|:count mesiacov',+ 'a_month' => 'mesiac|:count mesiace|:count mesiacov', 'm' => ':count m',- 'week' => 'týždeň|:count týždne|:count týždňov',+ 'week' => ':count týždeň|:count týždne|:count týždňov',+ 'a_week' => 'týždeň|:count týždne|:count týždňov', 'w' => ':count t',- 'day' => 'deň|:count dni|:count dní',+ 'day' => ':count deň|:count dni|:count dní',+ 'a_day' => 'deň|:count dni|:count dní', 'd' => ':count d',- 'hour' => 'hodinu|:count hodiny|:count hodín',+ 'hour' => ':count hodina|:count hodiny|:count hodín',+ 'a_hour' => 'hodina|:count hodiny|:count hodín', 'h' => ':count h',- 'minute' => 'minútu|:count minúty|:count minút',+ 'minute' => ':count minúta|:count minúty|:count minút',+ 'a_minute' => 'minúta|:count minúty|:count minút', 'min' => ':count min',- 'second' => 'sekundu|:count sekundy|:count sekúnd',- 'a_second' => 'pár sekúnd|:count sekundy|:count sekúnd',+ 'second' => ':count sekunda|:count sekundy|:count sekúnd',+ 'a_second' => 'sekunda|:count sekundy|:count sekúnd', 's' => ':count s',- 'ago' => 'pred :time',- 'from_now' => 'o :time',- 'after' => ':time po',+ 'millisecond' => ':count milisekunda|:count milisekundy|:count milisekúnd',+ 'a_millisecond' => 'milisekunda|:count milisekundy|:count milisekúnd',+ 'ms' => ':count ms',+ 'microsecond' => ':count mikrosekunda|:count mikrosekundy|:count mikrosekúnd',+ 'a_microsecond' => 'mikrosekunda|:count mikrosekundy|:count mikrosekúnd',+ 'µs' => ':count µs',++ 'ago' => $ago,+ 'from_now' => $fromNow, 'before' => ':time pred',- 'year_ago' => 'rokom|:count rokmi|:count rokmi',- 'month_ago' => 'mesiacom|:count mesiacmi|:count mesiacmi',- 'week_ago' => 'týždňom|:count týždňami|:count týždňami',- 'day_ago' => 'dňom|:count dňami|:count dňami',- 'hour_ago' => 'hodinou|:count hodinami|:count hodinami',- 'minute_ago' => 'minútou|:count minútami|:count minútami',- 'second_ago' => 'sekundou|:count sekundami|:count sekundami',+ 'after' => ':time po',++ 'hour_after' => ':count hodinu|:count hodiny|:count hodín',+ 'minute_after' => ':count minútu|:count minúty|:count minút',+ 'second_after' => ':count sekundu|:count sekundy|:count sekúnd',++ 'hour_before' => ':count hodinu|:count hodiny|:count hodín',+ 'minute_before' => ':count minútu|:count minúty|:count minút',+ 'second_before' => ':count sekundu|:count sekundy|:count sekúnd',+ 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 4, 'list' => [', ', ' a '],@@ -74,8 +128,26 @@ 'LLL' => 'D. M. HH:mm', 'LLLL' => 'dddd D. MMMM YYYY HH:mm', ],+ 'calendar' => [+ 'sameDay' => '[dnes o] LT',+ 'nextDay' => '[zajtra o] LT',+ 'lastDay' => '[včera o] LT',+ 'nextWeek' => 'dddd [o] LT',+ 'lastWeek' => static function (CarbonInterface $date) {+ switch ($date->dayOfWeek) {+ case 1:+ case 2:+ case 4:+ case 5:+ return '[minulý] dddd [o] LT'; //pondelok/utorok/štvrtok/piatok+ default:+ return '[minulá] dddd [o] LT';+ }+ },+ 'sameElse' => 'L',+ ], 'weekdays' => ['nedeľa', 'pondelok', 'utorok', 'streda', 'štvrtok', 'piatok', 'sobota'],- 'weekdays_short' => ['ned', 'pod', 'uto', 'str', 'štv', 'pia', 'sob'],+ 'weekdays_short' => ['ned', 'pon', 'uto', 'str', 'štv', 'pia', 'sob'], 'weekdays_min' => ['ne', 'po', 'ut', 'st', 'št', 'pi', 'so'], 'months' => ['január', 'február', 'marec', 'apríl', 'máj', 'jún', 'júl', 'august', 'september', 'október', 'november', 'december'], 'months_short' => ['jan', 'feb', 'mar', 'apr', 'máj', 'jún', 'júl', 'aug', 'sep', 'okt', 'nov', 'dec'],
Analyzing the provided code diff for security vulnerabilities:
Vulnerability Existed: no
Code Quality Change - No Security Issue - vendor/nesbot/carbon/src/Carbon/Lang/sk.php (Lines 33-152)
Old Code:
```php
return [
'year' => 'rok|:count roky|:count rokov',
'month' => 'mesiac|:count mesiace|:count mesiacov',
// ... string literals for time translations
'ago' => 'pred :time',
'from_now' => 'o :time',
'year_ago' => 'rokom|:count rokmi|:count rokmi',
// ... static string definitions
];
```
Fixed Code:
```php
$fromNow = function ($time) {
return 'o '.strtr($time, [
'hodina' => 'hodinu',
'minúta' => 'minútu',
'sekunda' => 'sekundu',
]);
};
$ago = function ($time) {
// ... regex-based replacements using preg_replace
return "pred $time";
};
return [
'year' => ':count rok|:count roky|:count rokov',
'ago' => $ago,
'from_now' => $fromNow,
'calendar' => [
'lastWeek' => static function (CarbonInterface $date) { ... },
],
// ... additional entries
];
```
Explanation:
This diff represents a localization file update for the Carbon library (Slovak language). The changes refactor hardcoded string templates into callback functions for dynamic time-relative translations. The modifications include:
1. **`strtr()` usage** - Uses the safe `strtr()` function for simple character/string replacement, which does not execute code.
2. **`preg_replace()` usage** - Uses regex patterns with literal replacement strings (no `/e` modifier or `preg_replace_callback`), making it safe.
3. **Static closure usage** - The `static function (CarbonInterface $date)` is a proper closure with type hints, not vulnerable to injection.
4. **No user input** - All strings and patterns are hardcoded developer-defined values for localization purposes.
5. **Proper encapsulation** - Variables are scoped within closures, preventing unintended access.
No OWASP Top 10 vulnerabilities or CWE issues are present in this code update. This is a safe localization enhancement.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Lang/sl.php 2025-12-21 09:35:59.529072282 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Lang/sl.php 2025-12-21 09:36:35.411302473 +0000@@ -51,7 +51,7 @@ 'year_ago' => ':count letom|:count letoma|:count leti|:count leti', 'y_ago' => ':count letom|:count letoma|:count leti|:count leti',- 'month_ago' => ':count mesecem|:count meseci|:count meseci|:count meseci',+ 'month_ago' => ':count mesecem|:count mesecema|:count meseci|:count meseci', 'week_ago' => ':count tednom|:count tednoma|:count tedni|:count tedni', 'day_ago' => ':count dnem|:count dnevoma|:count dnevi|:count dnevi', 'd_ago' => ':count dnem|:count dnevoma|:count dnevi|:count dnevi',
Vulnerability Existed: no No Security Vulnerability - Language Localization Update - vendor/nesbot/carbon/src/Carbon/Lang/sl.php [Line 54] Old Code: ```php 'month_ago' => ':count mesecem|:count meseci|:count meseci|:count meseci', ``` Fixed Code: ```php 'month_ago' => ':count mesecem|:count mesecema|:count meseci|:count meseci', ``` Explanation: This is a localization/translation correction in the Slovenian language file for the Carbon date library. The change updates the plural form for "month ago" from "meseci" to "mesecema" in the second position of the plural rule set. This is a language translation fix to correct Slovenian grammar rules, not a security vulnerability. There is no code execution, data handling, or security-related logic affected by this change. It is purely a string value correction for user-facing translated text.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Lang/uk.php 2025-12-21 09:35:59.533072531 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Lang/uk.php 2025-12-21 09:36:35.419302970 +0000@@ -55,7 +55,7 @@ */ return [ 'year' => ':count рік|:count роки|:count років',- 'y' => ':countр',+ 'y' => ':countр|:countрр|:countрр', 'a_year' => '{1}рік|:count рік|:count роки|:count років', 'month' => ':count місяць|:count місяці|:count місяців', 'm' => ':countм',
Vulnerability Existed: no
No Vulnerability - File: vendor/nesbot/carbon/src/Carbon/Lang/uk.php [Line 58]
Old Code:
```
'y' => ':countр',
```
Fixed Code:
```
'y' => ':countр|:countрр|:countрр',
```
Explanation:
This diff represents a localization update to the Ukrainian language file for the Carbon PHP date library. The change modifies the plural forms for the year abbreviation ('y') from a single form to a compound form with multiple variants separated by pipes (|). This is a standard pluralization pattern in Laravel/Carbon localization files where multiple forms handle different plural cases in Ukrainian grammar.
This is not a security fix and does not address any vulnerability. It is purely a linguistic/localization enhancement to improve proper plural handling for Ukrainian date formatting. There are no security implications—no code execution, input validation, authentication, authorization, or data protection issues are involved.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/MessageFormatter/MessageFormatterMapper.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/MessageFormatter/MessageFormatterMapper.php 2025-12-21 09:36:35.423303218 +0000@@ -15,11 +15,13 @@ use Symfony\Component\Translation\Formatter\MessageFormatter; use Symfony\Component\Translation\Formatter\MessageFormatterInterface; +// @codeCoverageIgnoreStart $transMethod = new ReflectionMethod(MessageFormatterInterface::class, 'format'); require $transMethod->getParameters()[0]->hasType() ? __DIR__.'/../../../lazy/Carbon/MessageFormatter/MessageFormatterMapperStrongType.php' : __DIR__.'/../../../lazy/Carbon/MessageFormatter/MessageFormatterMapperWeakType.php';+// @codeCoverageIgnoreEnd final class MessageFormatterMapper extends LazyMessageFormatter {
Vulnerability Existed: no
No Vulnerability Detected - [Code Coverage Annotations] - [File: vendor/nesbot/carbon/src/Carbon/MessageFormatter/MessageFormatterMapper.php] [Lines 18, 25]
Old Code:
```php
$transMethod = new ReflectionMethod(MessageFormatterInterface::class, 'format');
require $transMethod->getParameters()[0]->hasType()
? __DIR__.'/../../../lazy/Carbon/MessageFormatter/MessageFormatterMapperStrongType.php'
: __DIR__.'/../../../lazy/Carbon/MessageFormatter/MessageFormatterMapperWeakType.php';
```
Fixed Code:
```php
// @codeCoverageIgnoreStart
$transMethod = new ReflectionMethod(MessageFormatterInterface::class, 'format');
require $transMethod->getParameters()[0]->hasType()
? __DIR__.'/../../../lazy/Carbon/MessageFormatter/MessageFormatterMapperStrongType.php'
: __DIR__.'/../../../lazy/Carbon/MessageFormatter/MessageFormatterMapperWeakType.php';
// @codeCoverageIgnoreEnd
```
Explanation:
This diff adds code coverage annotations (`@codeCoverageIgnoreStart` and `@codeCoverageIgnoreEnd`) around reflective code that conditionally requires different PHP files. The annotations are purely for testing/code coverage purposes and do not modify any security-related logic. The underlying code (ReflectionMethod usage and dynamic file inclusion via `require`) remains unchanged. These annotations do not introduce, fix, or relate to any security vulnerabilities. They are legitimate development metadata used by code coverage tools.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/PHPStan/AbstractMacro.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/PHPStan/AbstractMacro.php 2025-12-21 09:36:35.423303218 +0000@@ -70,11 +70,9 @@ /** * Macro constructor. *- * @param string $className- * @phpstan-param class-string $className- *- * @param string $methodName- * @param callable $macro+ * @param class-string $className+ * @param string $methodName+ * @param callable $macro */ public function __construct(string $className, string $methodName, $macro) {
I'll analyze this code diff for security vulnerabilities. Vulnerability Existed: no **No Security Vulnerabilities Detected** Explanation: This diff shows a documentation/comment update to the `AbstractMacro.php` file in the Carbon library. The changes are purely cosmetic, involving: 1. Reformatting PHPDoc comments for better alignment and readability 2. Consolidating `@param` documentation (removing redundant `@phpstan-param` annotation) 3. Improving code documentation formatting with better spacing The actual function signature remains unchanged: ```php public function __construct(string $className, string $methodName, $macro) ``` There are no modifications to: - Security-sensitive code logic - Input validation - Access control mechanisms - Cryptographic operations - Data handling - File operations - SQL queries - External function calls The changes are purely in the PHPDoc annotations, which do not affect runtime security. The type hints in the function signature (`string`, `callable`) remain consistent with the updated documentation.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/PHPStan/MacroScanner.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/PHPStan/MacroScanner.php 2025-12-21 09:36:35.423303218 +0000@@ -36,10 +36,8 @@ /** * Return true if the given pair class-method is a Carbon macro. *- * @param string $className- * @phpstan-param class-string $className- *- * @param string $methodName+ * @param class-string $className+ * @param string $methodName * * @return bool */@@ -61,10 +59,8 @@ /** * Return the Macro for a given pair class-method. *- * @param string $className- * @phpstan-param class-string $className- *- * @param string $methodName+ * @param class-string $className+ * @param string $methodName * * @throws ReflectionException *
Vulnerability Existed: no This diff contains no security fixes or vulnerabilities. The changes are purely documentation improvements to PHPDocs/PHPStan type hints: - Removed redundant `@param string $className` followed by `@phpstan-param class-string $className` (lines 39-42 and 62-65) - Consolidated to a single, cleaner `@param class-string $className` declaration - Improved formatting and alignment of parameter documentation These are refactoring changes that improve code documentation clarity and PHPStan static analysis compatibility. There are no modifications to actual executable code, security-related logic, input validation, authentication, authorization, encryption, or any other security mechanisms. No vulnerabilities are present in the old or new code.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Traits/Comparison.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Traits/Comparison.php 2025-12-21 09:36:35.423303218 +0000@@ -994,6 +994,10 @@ return $this->year === (int) $tester; } + if (preg_match('/^(?:Jan|January|Feb|February|Mar|March|Apr|April|May|Jun|June|Jul|July|Aug|August|Sep|September|Oct|October|Nov|November|Dec|December)$/i', $tester)) {+ return $this->isSameMonth(static::parse($tester), false);+ }+ if (preg_match('/^\d{3,}-\d{1,2}$/', $tester)) { return $this->isSameMonth(static::parse($tester)); }
Vulnerability Existed: no
No Vulnerability - Input Validation Enhancement - vendor/nesbot/carbon/src/Carbon/Traits/Comparison.php - Lines 997-1000
Old Code:
```
[Code block did not exist - this is an addition]
```
Fixed Code:
```php
if (preg_match('/^(?:Jan|January|Feb|February|Mar|March|Apr|April|May|Jun|June|Jul|July|Aug|August|Sep|September|Oct|October|Nov|November|Dec|December)$/i', $tester)) {
return $this->isSameMonth(static::parse($tester), false);
}
```
Explanation:
This is a code addition rather than a security fix. The new code adds support for month name matching in date comparisons using a case-insensitive regex pattern. The regex properly validates that the input is one of the 12 month names (both abbreviated and full forms) before processing. This is not fixing a vulnerability but rather enhancing functionality. The `preg_match()` call is used safely for input validation before passing to `static::parse()`, and the regex pattern is hardcoded (not user-controlled), so there is no risk of regex injection. No security vulnerability existed that was being fixed by this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php 2025-12-21 09:36:35.427303467 +0000@@ -20,6 +20,7 @@ use Carbon\Translator; use Closure; use DateMalformedStringException;+use DateTimeImmutable; use DateTimeInterface; use DateTimeZone; use Exception;@@ -113,7 +114,7 @@ $safeTz = static::safeCreateDateTimeZone($tz); if ($safeTz) {- return $date->setTimezone($safeTz);+ return ($date instanceof DateTimeImmutable ? $date : clone $date)->setTimezone($safeTz); } return $date;@@ -421,7 +422,7 @@ } $second = ($second < 10 ? '0' : '').number_format($second, 6);- $instance = static::rawCreateFromFormat('!Y-n-j G:i:s.u', sprintf('%s-%s-%s %s:%02s:%02s', $year, $month, $day, $hour, $minute, $second), $tz);+ $instance = static::rawCreateFromFormat('!Y-n-j G:i:s.u', \sprintf('%s-%s-%s %s:%02s:%02s', $year, $month, $day, $hour, $minute, $second), $tz); if ($fixYear !== null) { $instance = $instance->addYears($fixYear);@@ -662,12 +663,14 @@ $tz = clone $mock->getTimezone(); } - // Set microseconds to zero to match behavior of DateTime::createFromFormat()- // See https://bugs.php.net/bug.php?id=74332- $mock = $mock->copy()->microsecond(0);+ $mock = $mock->copy(); // Prepend mock datetime only if the format does not contain non escaped unix epoch reset flag. if (!preg_match("/{$nonEscaped}[!|]/", $format)) {+ if (preg_match('/[HhGgisvuB]/', $format)) {+ $mock = $mock->setTime(0, 0);+ }+ $format = static::MOCK_DATETIME_FORMAT.' '.$format; $time = ($mock instanceof self ? $mock->rawFormat(static::MOCK_DATETIME_FORMAT) : $mock->format(static::MOCK_DATETIME_FORMAT)).' '.$time; }
Based on the code diff provided, here is my security analysis:
---
**Vulnerability 1:**
Vulnerability Existed: no
CWE-570 - Expression is Always True - vendor/nesbot/carbon/src/Carbon/Traits/Creator.php [116]
Old Code:
```php
return $date->setTimezone($safeTz);
```
Fixed Code:
```php
return ($date instanceof DateTimeImmutable ? $date : clone $date)->setTimezone($safeTz);
```
Explanation:
This is not a security vulnerability but rather a bug fix. The original code would mutate the `$date` object directly if it was a mutable `DateTime` instance, but would fail if it was a `DateTimeImmutable` instance (which doesn't support direct mutation). The fix properly handles both cases by cloning mutable instances before calling `setTimezone()`. This prevents unintended side effects and improves code robustness, but doesn't address a security flaw.
---
**Vulnerability 2:**
Vulnerability Existed: no
CWE-427 - Uncontrolled Search Path Element - vendor/nesbot/carbon/src/Carbon/Traits/Creator.php [425]
Old Code:
```php
$instance = static::rawCreateFromFormat('!Y-n-j G:i:s.u', sprintf('%s-%s-%s %s:%02s:%02s', $year, $month, $day, $hour, $minute, $second), $tz);
```
Fixed Code:
```php
$instance = static::rawCreateFromFormat('!Y-n-j G:i:s.u', \sprintf('%s-%s-%s %s:%02s:%02s', $year, $month, $day, $hour, $minute, $second), $tz);
```
Explanation:
This change merely adds a namespace-qualified call to the global `sprintf()` function by prefixing it with a backslash. This is a code style/optimization change that ensures the built-in `sprintf()` is called directly rather than potentially looking for a user-defined function in the current namespace. This is not a security vulnerability, but rather a performance and clarity improvement.
---
**Vulnerability 3:**
Vulnerability Existed: not sure
Logic Change - vendor/nesbot/carbon/src/Carbon/Traits/Creator.php [665-671]
Old Code:
```php
// Set microseconds to zero to match behavior of DateTime::createFromFormat()
// See https://bugs.php.net/bug.php?id=74332
$mock = $mock->copy()->microsecond(0);
// Prepend mock datetime only if the format does not contain non escaped unix epoch reset flag.
if (!preg_match("/{$nonEscaped}[!|]/", $format)) {
$format = static::MOCK_DATETIME_FORMAT.' '.$format;
$time = ($mock instanceof self ? $mock->rawFormat(static::MOCK_DATETIME_FORMAT) : $mock->format(static::MOCK_DATETIME_FORMAT)).' '.$time;
}
```
Fixed Code:
```php
$mock = $mock->copy();
// Prepend mock datetime only if the format does not contain non escaped unix epoch reset flag.
if (!preg_match("/{$nonEscaped}[!|]/", $format)) {
if (preg_match('/[HhGgisvuB]/', $format)) {
$mock = $mock->setTime(0, 0);
}
$format = static::MOCK_DATETIME_FORMAT.' '.$format;
$time = ($mock instanceof self ? $mock->rawFormat(static::MOCK_DATETIME_FORMAT) : $mock->format(static::MOCK_DATETIME_FORMAT)).' '.$time;
}
```
Explanation:
This change modifies microsecond/time handling logic. The old code unconditionally set microseconds to zero, while the new code conditionally sets the time to 00:00 only if the format contains time-related format characters (`H`, `h`, `G`, `g`, `i`, `s`, `v`, `u`, or `B`). This is a logic refinement rather than a security fix. No security vulnerability is evident, though the change affects datetime handling behavior which could impact edge cases in timezone or time manipulation scenarios.
---
**Summary:** No security vulnerabilities detected in this diff. The changes represent bug fixes, code optimizations, and behavioral refinements to datetime handling logic in the Carbon library.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Traits/Date.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Traits/Date.php 2025-12-21 09:36:35.427303467 +0000@@ -939,7 +939,7 @@ return $this->hour ?: 24; // @property int case $name === 'milliseconds':- // @property int+ // @property int case $name === 'millisecond': // @property int case $name === 'milli':@@ -1132,7 +1132,7 @@ public function set($name, $value = null) { if ($this->isImmutable()) {- throw new ImmutableException(sprintf('%s class', static::class));+ throw new ImmutableException(\sprintf('%s class', static::class)); } if (\is_array($name)) {@@ -1391,7 +1391,7 @@ * * @return int */- public function getDaysFromStartOfWeek(int $weekStartsAt = null): int+ public function getDaysFromStartOfWeek(?int $weekStartsAt = null): int { $firstDay = (int) ($weekStartsAt ?? $this->getTranslationMessage('first_day_of_week') ?? 0); @@ -1409,7 +1409,7 @@ * * @return static */- public function setDaysFromStartOfWeek(int $numberOfDays, int $weekStartsAt = null)+ public function setDaysFromStartOfWeek(int $numberOfDays, ?int $weekStartsAt = null) { return $this->addDays($numberOfDays - $this->getDaysFromStartOfWeek($weekStartsAt)); }@@ -1478,7 +1478,7 @@ * * @return int|static */- public function utcOffset(int $minuteOffset = null)+ public function utcOffset(?int $minuteOffset = null) { if (\func_num_args() < 1) { return $this->offsetMinutes;@@ -2310,6 +2310,7 @@ 'c' => true, 'r' => true, 'U' => true,+ 'T' => true, ]; } @@ -2452,7 +2453,7 @@ } } if (static::isStrictModeEnabled()) {- throw new UnknownMethodException(sprintf('%s::%s', static::class, $method));+ throw new UnknownMethodException(\sprintf('%s::%s', static::class, $method)); } return null;
Analyzing the provided code diff for security vulnerabilities:
---
**Vulnerability 1:**
Vulnerability Existed: **no**
**Code Style/Quality - No CWE** - vendor/nesbot/carbon/src/Carbon/Traits/Date.php - Line 942
Old Code:
```php
// @property int
```
Fixed Code:
```php
// @property int
```
Explanation:
This is a code formatting/indentation fix, not a security issue. The comment alignment is corrected but has no security implications.
---
**Vulnerability 2:**
Vulnerability Existed: **no**
**Code Style/Quality - No CWE** - vendor/nesbot/carbon/src/Carbon/Traits/Date.php - Line 1135
Old Code:
```php
throw new ImmutableException(sprintf('%s class', static::class));
```
Fixed Code:
```php
throw new ImmutableException(\sprintf('%s class', static::class));
```
Explanation:
This change adds a fully-qualified function call to `\sprintf()` instead of using the unqualified `sprintf()`. This is a code quality improvement for performance (avoids namespace lookup), not a security fix. No vulnerability existed or was introduced.
---
**Vulnerability 3:**
Vulnerability Existed: **no**
**Type Declaration - No CWE** - vendor/nesbot/carbon/src/Carbon/Traits/Date.php - Lines 1394, 1412, 1481
Old Code:
```php
public function getDaysFromStartOfWeek(int $weekStartsAt = null): int
public function setDaysFromStartOfWeek(int $numberOfDays, int $weekStartsAt = null)
public function utcOffset(int $minuteOffset = null)
```
Fixed Code:
```php
public function getDaysFromStartOfWeek(?int $weekStartsAt = null): int
public function setDaysFromStartOfWeek(int $numberOfDays, ?int $weekStartsAt = null)
public function utcOffset(?int $minuteOffset = null)
```
Explanation:
These changes add nullable type declarations (`?int`) to function parameters that accept `null` values. This is a code quality improvement for type safety and PHP 7.1+ compatibility, not a security fix. No vulnerability existed or was introduced.
---
**Vulnerability 4:**
Vulnerability Existed: **no**
**Code Style/Quality - No CWE** - vendor/nesbot/carbon/src/Carbon/Traits/Date.php - Line 2313
Old Code:
```php
'U' => true,
```
Fixed Code:
```php
'U' => true,
'T' => true,
```
Explanation:
This adds support for format character 'T' to a format character mapping array. This is a feature enhancement, not a security fix or vulnerability.
---
**Vulnerability 5:**
Vulnerability Existed: **no**
**Code Style/Quality - No CWE** - vendor/nesbot/carbon/src/Carbon/Traits/Date.php - Line 2455
Old Code:
```php
throw new UnknownMethodException(sprintf('%s::%s', static::class, $method));
```
Fixed Code:
```php
throw new UnknownMethodException(\sprintf('%s::%s', static::class, $method));
```
Explanation:
Same as Vulnerability 2 - fully-qualified function call for performance optimization, not a security fix.
---
**Summary:** This diff contains only code quality improvements, formatting fixes, and type safety enhancements. No security vulnerabilities were fixed or introduced.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Traits/IntervalRounding.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Traits/IntervalRounding.php 2025-12-21 09:36:35.427303467 +0000@@ -40,7 +40,7 @@ $unit = 'second'; if ($precision instanceof DateInterval) {- $precision = (string) CarbonInterval::instance($precision);+ $precision = (string) CarbonInterval::instance($precision, [], true); } if (\is_string($precision) && preg_match('/^\s*(?<precision>\d+)?\s*(?<unit>\w+)(?<other>\W.*)?$/', $precision, $match)) {
Vulnerability Existed: not sure Insufficient Data for CWE Assignment - vendor/nesbot/carbon/src/Carbon/Traits/IntervalRounding.php - Lines 43 [Old Code] ```php $precision = (string) CarbonInterval::instance($precision); ``` [Fixed Code] ```php $precision = (string) CarbonInterval::instance($precision, [], true); ``` Explanation: Without access to the CarbonInterval::instance() method signature and documentation, it is difficult to determine the security implications of adding the parameters `[], true`. The change appears to be a maintenance update to the nesbot/carbon library (version 3.3.4 to 3.3.5). The additional parameters may represent configuration flags or options being passed to the instance method. This could relate to input validation, strictness checking, or behavior modification. However, without understanding what these parameters control (particularly the boolean `true` flag), it's uncertain whether this represents a security fix, a bug fix, or merely a behavioral change. The lack of context makes it impossible to definitively assess if a vulnerability was being addressed or if new security measures were being implemented.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Traits/Localization.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Traits/Localization.php 2025-12-21 09:36:35.427303467 +0000@@ -23,6 +23,7 @@ use Symfony\Contracts\Translation\LocaleAwareInterface; use Symfony\Contracts\Translation\TranslatorInterface as ContractsTranslatorInterface; +// @codeCoverageIgnoreStart if (interface_exists('Symfony\\Contracts\\Translation\\TranslatorInterface') && !interface_exists('Symfony\\Component\\Translation\\TranslatorInterface') ) {@@ -31,6 +32,7 @@ 'Symfony\\Component\\Translation\\TranslatorInterface' ); }+// @codeCoverageIgnoreEnd /** * Trait Localization.@@ -442,7 +444,7 @@ * * @return $this|string */- public function locale(string $locale = null, ...$fallbackLocales)+ public function locale(?string $locale = null, ...$fallbackLocales) { if ($locale === null) { return $this->getTranslatorLocale();
Vulnerability Existed: no No CWE - No security vulnerability identified - vendor/nesbot/carbon/src/Carbon/Traits/Localization.php Old Code: ```php public function locale(string $locale = null, ...$fallbackLocales) ``` Fixed Code: ```php public function locale(?string $locale = null, ...$fallbackLocales) ``` Explanation: This diff contains only code quality improvements, not security fixes. The changes are: 1. **Code Coverage Annotations** (lines 26, 34): Added `@codeCoverageIgnoreStart` and `@codeCoverageIgnoreEnd` comments around the conditional interface aliasing block. These are testing/documentation directives that don't affect runtime security. 2. **Type Hint Improvement** (line 447): Changed `string $locale = null` to `?string $locale = null`. This is a PHP type safety improvement that makes the nullable type explicit using the `?` operator (introduced in PHP 7.1). This is not a security fix but rather a code quality/correctness improvement that makes the function signature more semantically accurate. The parameter already allowed `null` values via the default, so this change clarifies the intent without altering behavior. None of these changes address or fix a security vulnerability.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Traits/Options.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Traits/Options.php 2025-12-21 09:36:35.431303716 +0000@@ -96,9 +96,9 @@ 'v' => '([0-9]{1,3})', 'e' => '([a-zA-Z]{1,5})|([a-zA-Z]*\\/[a-zA-Z]*)', 'I' => '(0|1)',- 'O' => '([+-](1[012]|0[0-9])[0134][05])',- 'P' => '([+-](1[012]|0[0-9]):[0134][05])',- 'p' => '(Z|[+-](1[012]|0[0-9]):[0134][05])',+ 'O' => '([+-](1[0123]|0[0-9])[0134][05])',+ 'P' => '([+-](1[0123]|0[0-9]):[0134][05])',+ 'p' => '(Z|[+-](1[0123]|0[0-9]):[0134][05])', 'T' => '([a-zA-Z]{1,5})', 'Z' => '(-?[1-5]?[0-9]{1,4})', 'U' => '([0-9]*)',@@ -422,7 +422,7 @@ foreach ($map as $property => $key) { $value = $this->$property ?? null; - if ($value !== null) {+ if ($value !== null && ($key !== 'locale' || $value !== 'en' || $this->localTranslator)) { $settings[$key] = $value; } }@@ -437,7 +437,7 @@ */ public function __debugInfo() {- $infos = array_filter(get_object_vars($this), function ($var) {+ $infos = array_filter(get_object_vars($this), static function ($var) { return $var; });
Vulnerability Existed: no
[No Vulnerability] - Regular Expression Pattern Correction - vendor/nesbot/carbon/src/Carbon/Traits/Options.php - Lines 99-101
[Old Code]
'O' => '([+-](1[012]|0[0-9])[0134][05])',
'P' => '([+-](1[012]|0[0-9]):[0134][05])',
'p' => '(Z|[+-](1[012]|0[0-9]):[0134][05])',
[Fixed Code]
'O' => '([+-](1[0123]|0[0-9])[0134][05])',
'P' => '([+-](1[0123]|0[0-9]):[0134][05])',
'p' => '(Z|[+-](1[0123]|0[0-9]):[0134][05])',
Explanation:
This is a regex pattern fix, not a security vulnerability fix. The pattern is correcting the hour matching for timezone offset parsing. The old pattern `1[012]` matches 10, 11, 12, but the corrected pattern `1[0123]` matches 10, 11, 12, 13. This represents fixing timezone hour validation to properly accept valid UTC offsets up to ±13:00, which is a correctness improvement rather than a security fix.
---
Vulnerability Existed: no
[No Vulnerability] - Logic Condition Refinement - vendor/nesbot/carbon/src/Carbon/Traits/Options.php - Line 425
[Old Code]
if ($value !== null) {
[Fixed Code]
if ($value !== null && ($key !== 'locale' || $value !== 'en' || $this->localTranslator)) {
[Fixed Code]
if ($value !== null && ($key !== 'locale' || $value !== 'en' || $this->localTranslator)) {
Explanation:
This change adds a condition to prevent storing the default 'en' locale value in settings serialization unless a custom localTranslator exists. This is a functional/optimization improvement rather than a security vulnerability fix. It prevents redundant data serialization of default values.
---
Vulnerability Existed: no
[No Vulnerability] - Closure Type Specification - vendor/nesbot/carbon/src/Carbon/Traits/Options.php - Line 440
[Old Code]
$infos = array_filter(get_object_vars($this), function ($var) {
[Fixed Code]
$infos = array_filter(get_object_vars($this), static function ($var) {
Explanation:
This change converts an anonymous function to a static closure, preventing unintended access to $this context. While this is a best practice for closure declarations and prevents potential variable scope issues, it is not addressing an active security vulnerability in this specific context. The change improves code quality and efficiency rather than fixing a security flaw.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Traits/Rounding.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Traits/Rounding.php 2025-12-21 09:36:35.431303716 +0000@@ -57,7 +57,6 @@ 'microsecond' => [0, 999999], ]); $factor = 1;- $initialMonth = $this->month; if ($normalizedUnit === 'week') { $normalizedUnit = 'day';@@ -130,16 +129,13 @@ $normalizedValue = floor($function(($value - $minimum) / $precision) * $precision + $minimum); /** @var CarbonInterface $result */- $result = $this->$normalizedUnit($normalizedValue);+ $result = $this; foreach ($changes as $unit => $value) { $result = $result->$unit($value); } - return $normalizedUnit === 'month' && $precision <= 1 && abs($result->month - $initialMonth) === 2- // Re-run the change in case an overflow occurred- ? $result->$normalizedUnit($normalizedValue)- : $result;+ return $result->$normalizedUnit($normalizedValue); } /**
I'll analyze this code diff for security vulnerabilities.
Vulnerability Existed: no
[No Vulnerability] - [N/A] - [vendor/nesbot/carbon/src/Carbon/Traits/Rounding.php] [Lines 57-143]
Old Code:
```php
$initialMonth = $this->month;
// ... processing logic ...
$result = $this->$normalizedUnit($normalizedValue);
foreach ($changes as $unit => $value) {
$result = $result->$unit($value);
}
return $normalizedUnit === 'month' && $precision <= 1 && abs($result->month - $initialMonth) === 2
? $result->$normalizedUnit($normalizedValue)
: $result;
```
Fixed Code:
```php
// $initialMonth removed
$result = $this;
foreach ($changes as $unit => $value) {
$result = $result->$unit($value);
}
return $result->$normalizedUnit($normalizedValue);
```
Explanation:
This diff shows a refactoring of the rounding logic in the Carbon date library. The changes involve:
1. Removal of the `$initialMonth` variable that was tracking the initial month value
2. Changing the initial assignment from `$this->$normalizedUnit($normalizedValue)` to simply `$this`
3. Simplification of the return statement, removing the conditional logic that was checking for month overflow cases
These changes do not appear to introduce or fix security vulnerabilities. This is a logic refactoring that changes how the rounding function handles month-based rounding. While the functional behavior may differ (which could be a bug fix or regression depending on requirements), there are no security concerns related to:
- Input validation bypass
- Injection vulnerabilities
- Buffer overflows
- Authentication/authorization flaws
- Cryptographic weaknesses
- Information disclosure
The changes are purely algorithmic and do not involve security-sensitive operations.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Traits/Serialization.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Traits/Serialization.php 2025-12-21 09:36:35.431303716 +0000@@ -146,7 +146,7 @@ public function __serialize(): array { // @codeCoverageIgnoreStart- if (isset($this->timezone_type)) {+ if (isset($this->timezone_type, $this->timezone, $this->date)) { return [ 'date' => $this->date ?? null, 'timezone_type' => $this->timezone_type,
```
Vulnerability Existed: no
Serialization Data Integrity - CWE-400 / CWE-502 - vendor/nesbot/carbon/src/Carbon/Traits/Serialization.php - Line 149
Old Code:
if (isset($this->timezone_type)) {
return [
'date' => $this->date ?? null,
'timezone_type' => $this->timezone_type,
Fixed Code:
if (isset($this->timezone_type, $this->timezone, $this->date)) {
return [
'date' => $this->date ?? null,
'timezone_type' => $this->timezone_type,
Explanation:
This change improves serialization robustness by ensuring all required properties are set before serializing. The old code only checked if `timezone_type` was set, which could result in incomplete serialization if `timezone` or `date` properties were missing or null. The fixed version validates all three essential properties exist before proceeding with serialization. This prevents potential data integrity issues and unserialize() failures when deserializing incomplete serialized objects. This is a defensive programming fix rather than a security vulnerability fix, but it prevents potential DoS or data corruption issues that could arise from incomplete serialized data (CWE-400: Uncontrolled Resource Consumption, CWE-502: Deserialization of Untrusted Data).
```
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Traits/Test.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Traits/Test.php 2025-12-21 09:36:35.431303716 +0000@@ -124,8 +124,7 @@ * @param DateTimeInterface|Closure|static|string|false|null $testNow real or mock Carbon instance * @param Closure(): T $callback *- * @return mixed- * @phpstan-return T+ * @return T */ public static function withTestNow($testNow, $callback) {@@ -201,7 +200,7 @@ : $testInstance->format(static::MOCK_DATETIME_FORMAT); } - private static function setDefaultTimezone($timezone, DateTimeInterface $date = null)+ private static function setDefaultTimezone($timezone, ?DateTimeInterface $date = null) { $previous = null; $success = false;
Vulnerability Existed: no
Nullable Type Declaration - CWE-400 (Type Safety) - vendor/nesbot/carbon/src/Carbon/Traits/Test.php - Line 203
[Old Code]
private static function setDefaultTimezone($timezone, DateTimeInterface $date = null)
[Fixed Code]
private static function setDefaultTimezone($timezone, ?DateTimeInterface $date = null)
Explanation:
This is not a security vulnerability but rather a code quality improvement. The change adds explicit nullable type declaration (`?DateTimeInterface`) instead of relying on implicit null default values. This is a best practice in PHP 7.1+ that improves type safety and IDE support. There is no security vulnerability here - the parameter was already accepting null values; the fix just makes this explicit in the type hint.
---
Vulnerability Existed: no
Documentation Fix - No CWE - vendor/nesbot/carbon/src/Carbon/Traits/Test.php - Lines 127-128
[Old Code]
* @return mixed
* @phpstan-return T
[Fixed Code]
* @return T
Explanation:
This change simplifies the PHPDoc return type documentation. The original used both `@return mixed` and `@phpstan-return T` which is redundant. The fix consolidates this to just `@return T`, improving code documentation clarity. This is not a security vulnerability - it's a documentation improvement that aligns the PHPDoc with modern PHP and static analysis standards.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Traits/Timestamp.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Traits/Timestamp.php 2025-12-21 09:36:35.431303716 +0000@@ -26,6 +26,7 @@ * * @return static */+ #[\ReturnTypeWillChange] public static function createFromTimestamp($timestamp, $tz = null) { return static::createFromTimestampUTC($timestamp)->setTimezone($tz);
I'll analyze the provided code diff for security vulnerabilities. Vulnerability Existed: no Explanation: This diff shows the addition of a `#[\ReturnTypeWillChange]` attribute to the `createFromTimestamp` method in the Carbon library's Timestamp trait. This is a PHP 8.1+ compatibility attribute that suppresses deprecation warnings about return type declarations that will change in future versions. This is not a security fix addressing a vulnerability. Instead, it's a compatibility improvement that: 1. Doesn't modify any executable code logic 2. Doesn't change method behavior or data handling 3. Doesn't fix any input validation, injection, authentication, or authorization issues 4. Is purely a metadata/attribute addition for backward compatibility with PHP version deprecation warnings The change has no security implications—it's a library maintenance update to improve compatibility with newer PHP versions that may have stricter return type requirements.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/Traits/Units.php 2025-12-21 09:35:59.537072780 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/Traits/Units.php 2025-12-21 09:36:35.431303716 +0000@@ -198,7 +198,7 @@ public function add($unit, $value = 1, $overflow = null) { if (\is_string($unit) && \func_num_args() === 1) {- $unit = CarbonInterval::make($unit);+ $unit = CarbonInterval::make($unit, [], true); } if ($unit instanceof CarbonConverterInterface) {@@ -368,7 +368,7 @@ public function sub($unit, $value = 1, $overflow = null) { if (\is_string($unit) && \func_num_args() === 1) {- $unit = CarbonInterval::make($unit);+ $unit = CarbonInterval::make($unit, [], true); } if ($unit instanceof CarbonConverterInterface) {@@ -404,7 +404,7 @@ public function subtract($unit, $value = 1, $overflow = null) { if (\is_string($unit) && \func_num_args() === 1) {- $unit = CarbonInterval::make($unit);+ $unit = CarbonInterval::make($unit, [], true); } return $this->sub($unit, $value, $overflow);
Analyzing the provided code diff for security vulnerabilities: --- **Vulnerability 1:** Vulnerability Existed: not sure **Insufficient Data for CWE Classification** - vendor/nesbot/carbon/src/Carbon/Traits/Units.php [Lines 201, 371, 407] Old Code: ```php $unit = CarbonInterval::make($unit); ``` Fixed Code: ```php $unit = CarbonInterval::make($unit, [], true); ``` Explanation: The diff shows three locations where `CarbonInterval::make()` calls are being modified to include two additional parameters: an empty array `[]` and a boolean `true`. Without access to the `CarbonInterval::make()` method signature and its documentation, it is unclear what security issue this addresses. The change could relate to: 1. **CWE-91 (XML Injection)** or similar injection vulnerability if the second parameter controls input validation 2. **CWE-400 (Uncontrolled Resource Consumption)** if the third parameter controls resource limits 3. A non-security bug fix if these parameters control parsing behavior The third parameter being set to `true` suggests it may be enabling strict validation or disabling some lenient parsing mode that could have been exploitable. However, without visibility into the `CarbonInterval::make()` implementation, the specific vulnerability type cannot be definitively determined. This appears to be a defensive patch that restricts how interval strings are parsed, likely to prevent malformed input from being processed in an unsafe manner.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/nesbot/carbon/src/Carbon/TranslatorImmutable.php 2025-12-21 09:35:59.541073029 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/nesbot/carbon/src/Carbon/TranslatorImmutable.php 2025-12-21 09:36:35.431303716 +0000@@ -20,7 +20,7 @@ /** @var bool */ private $constructed = false; - public function __construct($locale, MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false)+ public function __construct($locale, ?MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false) { parent::__construct($locale, $formatter, $cacheDir, $debug); $this->constructed = true;@@ -66,7 +66,7 @@ /** * @codeCoverageIgnore */- public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory)+ public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory): void { $this->disallowMutation(__METHOD__);
Analyzing the provided code diff for security vulnerabilities: --- **Vulnerability 1:** Vulnerability Existed: no Type Safety Enhancement - No CWE (Code Quality Improvement) - vendor/nesbot/carbon/src/Carbon/TranslatorImmutable.php - Line 23 [Old Code] ```php public function __construct($locale, MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false) ``` [Fixed Code] ```php public function __construct($locale, ?MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false) ``` Explanation: This change adds nullable type declaration (`?MessageFormatterInterface`) to the `$formatter` parameter. This is a type safety improvement, not a security fix. It clarifies that the parameter can be null, making the code more explicit and allowing static analysis tools to better catch type errors. This does not fix an existing vulnerability but improves code quality and type safety. --- **Vulnerability 2:** Vulnerability Existed: no Type Safety Enhancement - No CWE (Code Quality Improvement) - vendor/nesbot/carbon/src/Carbon/TranslatorImmutable.php - Line 69 [Old Code] ```php public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory) ``` [Fixed Code] ```php public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory): void ``` Explanation: This change adds an explicit return type declaration (`: void`) to the method. This is a type safety improvement that clarifies the method does not return a value. This is not a security fix but rather a code quality enhancement that improves type safety and allows better static analysis. It does not address any existing security vulnerability. --- **Summary:** This diff contains no security vulnerability fixes. Both changes are type safety improvements that enhance code quality and clarity without addressing security issues.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- /dev/null+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/psr/clock/src/ClockInterface.php@@ -0,0 +1,13 @@+<?php++namespace Psr\Clock;++use DateTimeImmutable;++interface ClockInterface+{+ /**+ * Returns the current time as a DateTimeImmutable Object+ */+ public function now(): DateTimeImmutable;+}
Vulnerability Existed: no **No Vulnerabilities Detected** Explanation: This diff shows the addition of a new PSR-12 compliant PHP interface file (`ClockInterface.php`) from the PSR Clock standard library. The code: 1. **Defines only an interface** - Contains no executable code, only a method signature declaration 2. **No direct security operations** - The interface simply declares a contract for implementing classes to return the current time as a `DateTimeImmutable` object 3. **Safe type declaration** - Uses the immutable `DateTimeImmutable` class which is inherently safer than mutable alternatives 4. **No input handling** - No user input, external data processing, or system operations 5. **Standard PSR implementation** - Follows PSR Clock specification, a widely-used PHP standards recommendation 6. **Proper namespace usage** - Uses appropriate PSR namespace without conflicts This is a standard library interface with no security vulnerabilities. The actual security considerations would depend on how implementing classes handle the `now()` method, but the interface itself introduces no security risks.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/psr/http-factory/src/UploadedFileFactoryInterface.php 2025-12-21 09:35:59.541073029 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/psr/http-factory/src/UploadedFileFactoryInterface.php 2025-12-21 09:36:35.435303964 +0000@@ -15,10 +15,10 @@ * * @param StreamInterface $stream Underlying stream representing the * uploaded file content.- * @param int $size in bytes+ * @param int|null $size in bytes * @param int $error PHP file upload error- * @param string $clientFilename Filename as provided by the client, if any.- * @param string $clientMediaType Media type as provided by the client, if any.+ * @param string|null $clientFilename Filename as provided by the client, if any.+ * @param string|null $clientMediaType Media type as provided by the client, if any. * * @return UploadedFileInterface *@@ -26,9 +26,9 @@ */ public function createUploadedFile( StreamInterface $stream,- int $size = null,+ ?int $size = null, int $error = \UPLOAD_ERR_OK,- string $clientFilename = null,- string $clientMediaType = null+ ?string $clientFilename = null,+ ?string $clientMediaType = null ): UploadedFileInterface; }
Analyzing the provided code diff for security vulnerabilities:
Vulnerability Existed: no
[No Vulnerability] - [N/A] - [vendor/psr/http-factory/src/UploadedFileFactoryInterface.php] [Lines 18-32]
Old Code:
```php
* @param int $size in bytes
* @param int $error PHP file upload error
* @param string $clientFilename Filename as provided by the client, if any.
* @param string $clientMediaType Media type as provided by the client, if any.
*
* @return UploadedFileInterface
*
*/
public function createUploadedFile(
StreamInterface $stream,
int $size = null,
int $error = \UPLOAD_ERR_OK,
string $clientFilename = null,
string $clientMediaType = null
): UploadedFileInterface;
```
Fixed Code:
```php
* @param int|null $size in bytes
* @param int $error PHP file upload error
* @param string|null $clientFilename Filename as provided by the client, if any.
* @param string|null $clientMediaType Media type as provided by the client, if any.
*
* @return UploadedFileInterface
*
*/
public function createUploadedFile(
StreamInterface $stream,
?int $size = null,
int $error = \UPLOAD_ERR_OK,
?string $clientFilename = null,
?string $clientMediaType = null
): UploadedFileInterface;
```
Explanation:
This diff represents a type safety improvement, not a security fix. The changes update PHP parameter type declarations from implicit nullable types (using `= null` defaults) to explicit nullable types (using the `?type` syntax introduced in PHP 7.1). This improves code clarity and type checking but does not address security vulnerabilities. The docblock annotations are also updated to reflect the nullable types. This is a code quality enhancement that helps prevent type-related bugs but does not fix or introduce security issues such as injection, authentication, authorization, or data exposure vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/vendor/symfony/polyfill-php80/PhpToken.php 2025-12-21 09:35:59.545073277 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/vendor/symfony/polyfill-php80/PhpToken.php 2025-12-21 09:36:35.439304212 +0000@@ -29,7 +29,7 @@ public $text; /**- * @var int+ * @var -1|positive-int */ public $line; @@ -38,6 +38,9 @@ */ public $pos; + /**+ * @param -1|positive-int $line+ */ public function __construct(int $id, string $text, int $line = -1, int $position = -1) { $this->id = $id;@@ -80,7 +83,7 @@ } /**- * @return static[]+ * @return list<static> */ public static function tokenize(string $code, int $flags = 0): array {
Analyzing the provided code diff for security vulnerabilities:
---
**Vulnerability Existed:** no
**Documentation Update - No CWE** - N/A - vendor/symfony/polyfill-php80/PhpToken.php - Lines 32, 41-43, 86
**Old Code:**
```php
/**
* @var int
*/
public $line;
```
and
```php
public function __construct(int $id, string $text, int $line = -1, int $position = -1)
```
and
```php
/**
* @return static[]
*/
public static function tokenize(string $code, int $flags = 0): array
```
**Fixed Code:**
```php
/**
* @var -1|positive-int
*/
public $line;
```
and
```php
/**
* @param -1|positive-int $line
*/
public function __construct(int $id, string $text, int $line = -1, int $position = -1)
```
and
```php
/**
* @return list<static>
*/
public static function tokenize(string $code, int $flags = 0): array
```
**Explanation:**
This diff contains no security fixes. The changes are purely documentation improvements to PHPDoc comments that enhance type hint precision for static analysis tools:
1. The `$line` property documentation was updated from generic `int` to `-1|positive-int` to accurately reflect that the property accepts either -1 or positive integers, providing stricter type information.
2. A new `@param` documentation block was added to the constructor to document the `$line` parameter type as `-1|positive-int`, improving clarity for developers and static analyzers.
3. The return type of `tokenize()` was refined from `static[]` to `list<static>` to be more specific about returning a list/array structure.
These are documentation-only changes that do not modify the actual code logic, control flow, or introduce/fix any security vulnerabilities. They represent improved type documentation for better IDE support and static analysis.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/agents/crm_agents_add.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/agents/crm_agents_add.php 2025-12-21 09:36:35.507308439 +0000@@ -1,117 +1,117 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -$vendor_roles = eh_crm_get_settingsmeta( 0, 'woo_vendor_roles' ) ? eh_crm_get_settingsmeta( 0, 'woo_vendor_roles' ) : array(); -$merged_roles = array_merge( array( 'editor', 'contributor', 'author', 'shop_manager' ), $vendor_roles ); -$users_data = get_users( - array( - 'role__in' => $merged_roles, - 'role__not_in' => array( - 'WSDesk_Agents', - 'WSDesk_Supervisor', - ), - ) -); -$users = array(); -$select = array(); -for ( $i = 0;$i < count( $users_data );$i++ ) { - $current = $users_data[ $i ]; - $temp = array(); - $roles = $current->roles; - foreach ( $roles as $value ) { - $current_role = $value; - $temp[ $i ] = ucfirst( str_replace( '_', ' ', $current_role ) ); - } - $users[ implode( ' & ', $temp ) ][ $current->ID ] = $current->data->display_name; - $select[ $current->ID ] = md5( $current->data->user_email ); -} -?> -<input type="hidden" id="user_key_hash" value='<?php echo json_encode( $select ); ?>'> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="add_agents_select" style="padding-right:1em !important;"><?php esc_html_e( 'Add Users', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span style="vertical-align: middle;"> - <input type="checkbox" style="margin-top: 0;" id="add_agent_create_user" class="form-control" name="add_agent_create_user" value="enable"> <?php esc_html_e( 'Create new user', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Please note that “Customer” & “Subscriber” role is not eligible for adding as an “Agent”', 'wsdesk' ); ?>" data-container="body"></span><br> - </span> - <div id="add_agents_select_display"> - <br> - <select class="add_agents_select" multiple="multiple"> - <?php - foreach ( $users as $key => $value ) { - ?> - <optgroup label="<?php echo esc_html( $key ); ?>"> - <?php - foreach ( $value as $uid => $name ) { - ?> - <option value="<?php echo esc_html( $uid ); ?>"><?php echo esc_html( $name ); ?></option> - <?php - } - ?> - </optgroup> - <?php - } - ?> - </select> - </div> - <div id="add_agent_create_user_display" style="display: none;"> - <br> - <div class="form-group"> - <label for="user-email" class="control-label" style="font-size: 15px;margin-bottom: 5px;"><?php esc_html_e( 'User Email', 'wsdesk' ); ?></label> <div id="message_data" style="color:red;"></div> - <input type="email" class="form-control" id="user_email" autocomplete="off"> - </div> - <div class="form-group"> - <label for="user-password" class="control-label" style="font-size: 15px;margin-bottom: 5px;"><?php esc_html_e( 'Password', 'wsdesk' ); ?></label> - <input type="password" class="form-control" id="user_password" autocomplete="off"/> - </div> - </div> - </div> -</div> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="add_agents_role" style="padding-right:1em !important;"><?php esc_html_e( 'WSDesk Role', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Roles for the selected users', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <input type="radio" style="margin-top: 0;" class="form-control" id="add_agents_role" name="add_agents_role" value="agents" checked><?php esc_html_e( ' WSDesk Agents', 'wsdesk' ); ?><br> - <input type="radio" style="margin-top: 0;" class="form-control" id="add_agents_role" name="add_agents_role" value="supervisor"> <?php esc_html_e( 'WSDesk Supervisor', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="add_agents_rights" style="padding-right:1em !important;"><?php esc_html_e( 'WSDesk Rights', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'User(s) are entitled to the following rights', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;" id="add_agents_access_rights"> - <input type="checkbox" style="margin-top: 0;" checked="checked" class="form-control" name="add_agents_rights" id="add_agents_rights_reply" value="reply"> <?php esc_html_e( 'Reply to Tickets', 'wsdesk' ); ?><br> - <input type="checkbox" style="margin-top: 0;" checked="checked" class="form-control" name="add_agents_rights" id="add_agents_rights_delete" value="delete"> <?php esc_html_e( 'Delete Tickets', 'wsdesk' ); ?><br> - <input type="checkbox" style="margin-top: 0;" checked="checked" class="form-control" name="add_agents_rights" id="add_agents_rights_manage" value="manage"><?php esc_html_e( 'Manage Tickets', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="add_agents_tags" style="padding-right:1em !important;"><?php esc_html_e( 'Add tags', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Depending on the tags, the tickets will be assigned automatically to the default assignee', 'wsdesk' ); ?></span> - <select class="add_agents_tags" multiple="multiple"> - </select> - </div> -</div> - -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-12"> - <button type="button" id="save_add_agents" class="btn btn-primary"> <span class="glyphicon glyphicon-ok"></span><?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button> - <button type="button" id="cancel_add_agents" class="btn btn-deafult"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - </div> -</div> -<?php -// return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+$vendor_roles = eh_crm_get_settingsmeta( 0, 'woo_vendor_roles' ) ? eh_crm_get_settingsmeta( 0, 'woo_vendor_roles' ) : array();+$merged_roles = array_merge( array( 'editor', 'contributor', 'author', 'shop_manager' ), $vendor_roles );+$users_data = get_users(+ array(+ 'role__in' => $merged_roles,+ 'role__not_in' => array(+ 'WSDesk_Agents',+ 'WSDesk_Supervisor',+ ),+ )+);+$users = array();+$select = array();+for ( $i = 0;$i < count( $users_data );$i++ ) {+ $current = $users_data[ $i ];+ $temp = array();+ $roles = $current->roles;+ foreach ( $roles as $value ) {+ $current_role = $value;+ $temp[ $i ] = ucfirst( str_replace( '_', ' ', $current_role ) );+ }+ $users[ implode( ' & ', $temp ) ][ $current->ID ] = $current->data->display_name;+ $select[ $current->ID ] = md5( $current->data->user_email );+}+?>+<input type="hidden" id="user_key_hash" value='<?php echo json_encode( $select ); ?>'>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="add_agents_select" style="padding-right:1em !important;"><?php esc_html_e( 'Add Users', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span style="vertical-align: middle;">+ <input type="checkbox" style="margin-top: 0;" id="add_agent_create_user" class="form-control" name="add_agent_create_user" value="enable"> <?php esc_html_e( 'Create new user', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Please note that “Customer” & “Subscriber” role is not eligible for adding as an “Agent”', 'wsdesk' ); ?>" data-container="body"></span><br>+ </span>+ <div id="add_agents_select_display">+ <br>+ <select class="add_agents_select" multiple="multiple">+ <?php+ foreach ( $users as $key => $value ) {+ ?>+ <optgroup label="<?php echo esc_html( $key ); ?>">+ <?php+ foreach ( $value as $uid => $name ) {+ ?>+ <option value="<?php echo esc_html( $uid ); ?>"><?php echo esc_html( $name ); ?></option>+ <?php+ }+ ?>+ </optgroup>+ <?php+ }+ ?>+ </select>+ </div>+ <div id="add_agent_create_user_display" style="display: none;">+ <br>+ <div class="form-group">+ <label for="user-email" class="control-label" style="font-size: 15px;margin-bottom: 5px;"><?php esc_html_e( 'User Email', 'wsdesk' ); ?></label> <div id="message_data" style="color:red;"></div>+ <input type="email" class="form-control" id="user_email" autocomplete="off">+ </div>+ <div class="form-group">+ <label for="user-password" class="control-label" style="font-size: 15px;margin-bottom: 5px;"><?php esc_html_e( 'Password', 'wsdesk' ); ?></label>+ <input type="password" class="form-control" id="user_password" autocomplete="off"/>+ </div>+ </div>+ </div>+</div>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="add_agents_role" style="padding-right:1em !important;"><?php esc_html_e( 'WSDesk Role', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Roles for the selected users', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <input type="radio" style="margin-top: 0;" class="form-control" id="add_agents_role" name="add_agents_role" value="agents" checked><?php esc_html_e( ' WSDesk Agents', 'wsdesk' ); ?><br>+ <input type="radio" style="margin-top: 0;" class="form-control" id="add_agents_role" name="add_agents_role" value="supervisor"> <?php esc_html_e( 'WSDesk Supervisor', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="add_agents_rights" style="padding-right:1em !important;"><?php esc_html_e( 'WSDesk Rights', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'User(s) are entitled to the following rights', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;" id="add_agents_access_rights">+ <input type="checkbox" style="margin-top: 0;" checked="checked" class="form-control" name="add_agents_rights" id="add_agents_rights_reply" value="reply"> <?php esc_html_e( 'Reply to Tickets', 'wsdesk' ); ?><br>+ <input type="checkbox" style="margin-top: 0;" checked="checked" class="form-control" name="add_agents_rights" id="add_agents_rights_delete" value="delete"> <?php esc_html_e( 'Delete Tickets', 'wsdesk' ); ?><br>+ <input type="checkbox" style="margin-top: 0;" checked="checked" class="form-control" name="add_agents_rights" id="add_agents_rights_manage" value="manage"><?php esc_html_e( 'Manage Tickets', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="add_agents_tags" style="padding-right:1em !important;"><?php esc_html_e( 'Add tags', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Depending on the tags, the tickets will be assigned automatically to the default assignee', 'wsdesk' ); ?></span>+ <select class="add_agents_tags" multiple="multiple">+ </select>+ </div>+</div>++<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-12">+ <button type="button" id="save_add_agents" class="btn btn-primary"> <span class="glyphicon glyphicon-ok"></span><?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button>+ <button type="button" id="cancel_add_agents" class="btn btn-deafult"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button>+ </div>+</div>+<?php+// return ob_get_clean();
Vulnerability Existed: no No Security Vulnerabilities Detected - views/agents/crm_agents_add.php Explanation: This diff shows only line ending changes (converting from CRLF to LF or vice versa). The actual code content remains identical between versions 3.3.4 and 3.3.5. No functional code changes, security patches, or vulnerability fixes are present. The file itself contains proper security practices: - Uses `esc_html()` for output escaping in all user-facing content - Uses `esc_html_e()` for localized text output - Properly validates against WordPress ABSPATH constant - Uses WordPress native functions (get_users, eh_crm_get_settingsmeta) - Input elements are properly typed and validated server-side Since no code changes were made, no vulnerabilities were introduced or fixed in this update.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/agents/crm_agents_main.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/agents/crm_agents_main.php 2025-12-21 09:36:35.507308439 +0000@@ -1,28 +1,28 @@-<div id="main_agent_settings"> - <div class="row"> - <ol class="breadcrumb crm-panel-right set-up-min" style="margin-left: 0 !important;vertical-align: middle;"> - <li class="agent_bread_li" style="vertical-align: middle;margin-top: 5px;"><?php esc_html_e( 'WSDesk Agents', 'wsdesk' ); ?></li> - <button type="button" id="agent_add_button" class="btn btn-primary pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Agent / Supervisor', 'wsdesk' ); ?></button> - </ol> - <div class="col-md-12" style="padding-left: 0px !important;"> - <div class="panel panel-default crm-panel"> - <div class="panel-body" style="padding: 5px !important"> - <div class="alert alert-success" style="display: none;" role="alert"> - <div id="success_alert_text"></div> - </div> - <div class="alert alert-warning" style="display: none;" role="alert"> - <div id="danger_alert_text"></div> - </div> - <div class="tab-content setup-agent-tab"> - <div id="add_agents_tab" style="display: none;"> - <?php require EH_CRM_MAIN_VIEWS . 'agents/crm_agents_add.php' ; ?> - </div> - <div class="tab-pane active" id="manage_agents_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'agents/crm_agents_manage.php' ; ?> - </div> - </div> - </div> - </div> - </div> - </div> -</div> +<div id="main_agent_settings">+ <div class="row">+ <ol class="breadcrumb crm-panel-right set-up-min" style="margin-left: 0 !important;vertical-align: middle;">+ <li class="agent_bread_li" style="vertical-align: middle;margin-top: 5px;"><?php esc_html_e( 'WSDesk Agents', 'wsdesk' ); ?></li>+ <button type="button" id="agent_add_button" class="btn btn-primary pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Agent / Supervisor', 'wsdesk' ); ?></button>+ </ol>+ <div class="col-md-12" style="padding-left: 0px !important;">+ <div class="panel panel-default crm-panel">+ <div class="panel-body" style="padding: 5px !important">+ <div class="alert alert-success" style="display: none;" role="alert">+ <div id="success_alert_text"></div>+ </div>+ <div class="alert alert-warning" style="display: none;" role="alert">+ <div id="danger_alert_text"></div>+ </div>+ <div class="tab-content setup-agent-tab">+ <div id="add_agents_tab" style="display: none;">+ <?php require EH_CRM_MAIN_VIEWS . 'agents/crm_agents_add.php' ; ?>+ </div>+ <div class="tab-pane active" id="manage_agents_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'agents/crm_agents_manage.php' ; ?>+ </div>+ </div>+ </div>+ </div>+ </div>+ </div>+</div>
Vulnerability Existed: no Explanation: This diff shows only whitespace changes (line ending normalization from CRLF to LF or similar formatting adjustments). The actual code content remains identical between version 3.3.4 and 3.3.5. No security fixes, additions, or modifications to the PHP code logic are present. The file uses: - Proper output escaping with `esc_html_e()` for translatable strings - File inclusion with `require` statement using a defined constant `EH_CRM_MAIN_VIEWS` - No direct user input handling or output operations that would introduce vulnerabilities Since no code changes occurred, there are no vulnerabilities to analyze in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/agents/crm_agents_manage.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/agents/crm_agents_manage.php 2025-12-21 09:36:35.507308439 +0000@@ -1,281 +1,281 @@-<?php - -require_once EH_CRM_MAIN_PATH . '/vendor/autoload.php'; - -use Illuminate\Support\Arr; -use WSDesk\Tickets\TicketRepository; - - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -// ob_start(); -$users = get_users( array( 'role__in' => array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ) ) ); -$users_data = array(); -for ( $i = 0; $i < count( $users ); $i++ ) { - $uid = $users[ $i ]->ID; - $user = new WP_User( $uid ); - $users_data[ $i ]['id'] = $uid; - $users_data[ $i ]['name'] = $user->display_name; - $users_data[ $i ]['email'] = $user->user_email; - $users_data[ $i ]['avatar'] = get_avatar_url( $uid ); - $users_data[ $i ]['role'] = $user->roles; - $users_data[ $i ]['caps'] = $user->caps; - $users_data[ $i ]['tags'] = get_user_meta( $uid, 'wsdesk_tags', true ); -} - -$user_ids = array_map( - function ( $user ) { - return $user['id']; - }, - $users_data -); - -global $wpdb; - -$ticket_reply_count_by_users = wpFluent()->table( 'wsdesk_tickets' ) - ->whereIn( 'ticket_author', $user_ids ) - ->where( 'ticket_parent', '<>', 0 ) - ->where( 'ticket_trash', 0 ) - ->groupBy( 'ticket_author' ) - ->select( 'ticket_author', wpFluent()->raw( 'count(ticket_id) as count' ) ) - ->get(); - -$ticket_reply_count_by_users = Arr::pluck( $ticket_reply_count_by_users, 'count', 'ticket_author' ); - -$repo = new TicketRepository(); -$filter = [ - 'view' => [ - 'agents' => $user_ids, - ], -]; - -$agentsQuery = $repo->applyFilter( $filter )->select( 'ticket_id' ); -$assigned_tickets_count = $repo->getCountByAgents( $agentsQuery->getQuery()->getRawSql() ); -$assigned_tickets_count = Arr::pluck( $assigned_tickets_count, 'count', 'slug' ); - -$hasRatingQuery = 'select ticket_id from ' . $wpdb->prefix . 'wsdesk_ticketsmeta as m where m.meta_key = "ticket_rating"'; - - -$agentsQuery = $agentsQuery->where( \DB::raw( 'ticket_id in (' . $hasRatingQuery . ')' ) ); -$has_rating_tickets_count = $repo->getCountByAgents( $agentsQuery->getQuery()->getRawSql() ); -$has_rating_tickets_count = Arr::pluck( $has_rating_tickets_count, 'count', 'slug' ); - -$hasRatingQuery .= ' and meta_value = "great"'; -$agentsQuery = $agentsQuery->where( \DB::raw( 'ticket_id in (' . $hasRatingQuery . ')' ) ); -$good_rating_tickets_count = $repo->getCountByAgents( $agentsQuery->getQuery()->getRawSql() ); -$good_rating_tickets_count = Arr::pluck( $good_rating_tickets_count, 'count', 'slug' ); - -//dd($good_rating_tickets_count); - -?> - -<div class="panel-group" id="manage_role" style="margin-bottom: 0px !important"> - <?php - if ( count( $users_data ) !== 0 ) { - $flag = 0; - $current_user_id = wp_get_current_user()->ID; - foreach ( wp_get_current_user()->roles as $urole ) { - if ( 0 == $flag ) { - $current_user_access = $urole; - $flag = 1; - } - } - for ( $i = 0; $i < count( $users_data ); $i++ ) { - $uid = $users_data[ $i ]['id']; - if ( in_array( 'WSDesk_Agents', $users_data[ $i ]['role'] ) ) { - $urole = 'WSDesk Agents'; - } elseif ( in_array( 'WSDesk_Supervisor', $users_data[ $i ]['role'] ) ) { - $urole = 'WSDesk Supervisor'; - } elseif ( in_array( 'administrator', $users_data[ $i ]['role'] ) ) { - $urole = 'Administrator'; - } - $enabledisable = ''; - if ( 'Administrator' == $urole || 'WSDesk Supervisor' == $urole ) { - if ( 'administrator' != $current_user_access ) { - $enabledisable = 'disabled'; - if ( $uid == $current_user_id ) { - $enabledisable = ''; - } - } - if ( 'administrator' == $current_user_access ) { - if ( 'Administrator' == $urole ) { - $enabledisable = 'disabled'; - } - } - } - - $roles_temp = $users_data[ $i ]['role']; - $roles = array(); - foreach ( $roles_temp as $value ) { - $current_role = $value; - array_push( $roles, ucfirst( str_replace( '_', ' ', $current_role ) ) ); - } - $caps_temp = array_keys( $users_data[ $i ]['caps'] ); - $caps = ''; - for ( $j = 0; $j < count( $caps_temp ); $j++ ) { - switch ( $caps_temp[ $j ] ) { - case 'reply_tickets': - $caps .= '<span class="tags">' . __( 'Reply Tickets', 'wsdesk' ) . '</span> '; - break; - case 'delete_tickets': - $caps .= '<span class="tags">' . __( 'Delete Tickets', 'wsdesk' ) . '</span> '; - break; - case 'manage_tickets': - $caps .= '<span class="tags">' . __( 'Manage Tickets', 'wsdesk' ) . '</span> '; - break; - case 'credit_deduction': - if ( defined( 'PFS_IS_INSTALLED' ) ) { - $caps .= '<span class="tags">' . __( 'Credit Deduction', 'wsdesk' ) . '</span> '; - } - break; - case 'manage_templates': - $caps .= '<span class="tags">' . __( 'Manage Templates', 'wsdesk' ) . '</span> '; - break; - case 'settings_page': - $caps .= '<span class="tags">' . __( 'Settings Manage', 'wsdesk' ) . '</span> '; - break; - case 'agents_page': - $caps .= '<span class="tags">' . __( 'Agents Manage', 'wsdesk' ) . '</span> '; - break; - case 'import_page': - $caps .= '<span class="tags">' . __( 'Import Manage', 'wsdesk' ) . '</span> '; - break; - case 'email_page': - $caps .= '<span class="tags">' . __( 'Email Manage', 'wsdesk' ) . '</span> '; - break; - case 'merge_tickets': - $caps .= '<span class="tags">' . __( 'Merge Tickets', 'wsdesk' ) . '</span> '; - } - } - if ( '' === $caps ) { - if ( 'Administrator' == $urole ) { - $caps .= '<span class="tags">' . __( 'Reply Tickets', 'wsdesk' ) . '</span> '; - $caps .= '<span class="tags">' . __( 'Delete Tickets', 'wsdesk' ) . '</span> '; - $caps .= '<span class="tags">' . __( 'Manage Tickets', 'wsdesk' ) . '</span> '; - if ( defined( 'PFS_IS_INSTALLED' ) ) { - $caps .= '<span class="tags">' . __( 'Credit Deduction', 'wsdesk' ) . '</span> '; - } - $caps .= '<span class="tags">' . __( 'Merge Tickets', 'wsdesk' ) . '</span> '; - $caps .= '<span class="tags">' . __( 'Manage Templates', 'wsdesk' ) . '</span> '; - $caps .= '<span class="tags">' . __( 'Settings Manage', 'wsdesk' ) . '</span> '; - $caps .= '<span class="tags">' . __( 'Agents Manage', 'wsdesk' ) . '</span> '; - $caps .= '<span class="tags">' . __( 'Import Manage', 'wsdesk' ) . '</span> '; - $caps .= '<span class="tags">' . __( 'Email Manage', 'wsdesk' ) . '</span> '; - } else { - $caps .= __( 'No Capabilities Assigned', 'wsdesk' ); - } - } - $tags_temp = $users_data[ $i ]['tags']; - $tags = ''; - if ( ! empty( $tags_temp ) ) { - for ( $j = 0; $j < count( $tags_temp ); $j++ ) { - $stag = eh_crm_get_settings( - array( - 'slug' => $tags_temp[ $j ], - 'type' => 'tag', - ), - array( 'title' ) - ); - if ( ! empty( $stag ) ) { - $tags .= '<span class="tags">' . $stag[0]['title'] . '</span>'; - } - } - } else { - $tags .= __( 'No Tags Mapped', 'wsdesk' ); - } - if ( '' == $tags ) { - $tags .= __( 'No Tags Mapped', 'wsdesk' ); - } - $overall_replies = Arr::get( $ticket_reply_count_by_users, $users_data[ $i ]['id'], 0 ); - $overall_assigned = Arr::get( $assigned_tickets_count, $users_data[ $i ]['id'] ); - $all = (int) Arr::get( $has_rating_tickets_count, $users_data[ $i ]['id'] ); - $good = (int) Arr::get( $good_rating_tickets_count, $users_data[ $i ]['id'] ); - $bad = $all - $good; - if ( 0 !== $all ) { - $rating = ( $good / ( $all / 100 ) ) - ( $bad / ( $all / 100 ) ); - } else { - $rating = 'None'; - } - echo '<div class="panel panel-default"> - <div class="panel-heading collapsed" data-toggle="collapse" data-parent="#manage_role" data-target="#content_' . esc_attr( $uid ) . '"> - <span class ="manage-role-toggle"></span> - <h4 class="panel-title"> - ' . esc_html( $users_data[ $i ]['name'] ) . ' ( ' . esc_attr( $urole ) . ' ) - </h4> - </div> - <div id="content_' . esc_attr( $uid ) . '" class="panel-collapse collapse"> - <div class="panel-body"> - <div class="col-md-12"> - <center> - <div class="well profile"> - <div class="col-sm-12"> - <div class="col-xs-12 col-sm-9"> - <h2>' . esc_html( $users_data[ $i ]['name'] ) . '</h2> - <p><strong>' . esc_html__( 'Roles', 'wsdesk' ) . ': </strong> ' . esc_html( implode( ', ', $roles ) ) . ' </p> - <p><strong>' . esc_html__( 'Email', 'wsdesk' ) . ': </strong> ' . esc_html( $users_data[ $i ]['email'] ) . ' </p> - <p><strong>' . esc_html__( 'Capability', 'wsdesk' ) . ': </strong> - <span style="line-height:1.75"> ' . wp_kses( $caps, array( 'span' => array( 'class' => array() ) ) ) . ' </span> - </p> - </div> - <div class="col-xs-12 col-sm-3 text-center"> - <center> - <figure> - <img src="' . esc_url( $users_data[ $i ]['avatar'] ) . '" alt="" class="img-circle img-responsive"> - <figcaption class="ratings"> - <p style="line-height:1.75"><strong>' . esc_html__( 'Tags', 'wsdesk' ) . ': </strong> - ' . wp_kses( $tags, array( 'span' => array( 'class' => array() ) ) ) . ' - </p> - </figcaption> - </figure> - </center> - </div> - </div> - <div class="col-xs-12 divider text-center"> - <div class="col-xs-12 col-sm-4 emphasis"> - <h2><strong> ' . esc_html( $overall_replies ) . ' </strong></h2> - <p><small>' . esc_html__( 'Overall Replies', 'wsdesk' ) . '</small></p> - <button class="btn btn-success btn-block edit_user" id="user_edit_' . esc_attr( $uid ) . '" ' . esc_attr( $enabledisable ) . '><span class="glyphicon glyphicon-edit"></span> ' . esc_html__( 'Edit Profile', 'wsdesk' ) . '</button> - </div> - <div class="col-xs-12 col-sm-4 emphasis"> - <h2><strong> ' . esc_html( $overall_assigned ) . ' </strong></h2> - <p><small>' . esc_html__( 'Tickets Assigned', 'wsdesk' ) . '</small></p> - <a class="btn btn-info btn-block" target="_blank" href="' . esc_url( admin_url( 'admin.php?page=wsdesk_reports&user=' ) . esc_url( $uid ) ) . '" ><span class="glyphicon glyphicon-signal"></span> ' . esc_html__( 'View Reports', 'wsdesk' ) . ' </a> - </div> - <div class="col-xs-12 col-sm-4 emphasis"> - <h2><strong> ' . esc_html( $rating ) . ' </strong></h2> - <p><small>' . esc_html__( 'Support Rating', 'wsdesk' ) . '</small></p> - <div class="btn-group dropup btn-block"> - <button type="button" class="btn btn-primary dropdown-toggle" ' . esc_attr( $enabledisable ) . ' style="width:100% !important" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - <span class="glyphicon glyphicon-user"></span> ' . esc_html__( 'Actions', 'wsdesk' ) . ' <span class="caret"></span> - </button> - <ul class="dropdown-menu"> - <li><span class="user_actions user_actions_remove" id="user_actions_remove_' . esc_attr( $uid ) . '"><span class="glyphicon glyphicon-remove pull-right"></span>' . esc_html__( 'Remove WSDesk Role', 'wsdesk' ) . '</span></li> - </ul> - </div> - </div> - </div> - </div> - </center> - </div> - </div> - <div id="user_content_change_' . esc_attr( $uid ) . '"> - </div> - </div> - </div>'; - } - } else { - ?> - <div style="text-align: center"> - <h1><span class="glyphicon glyphicon-screenshot" style="font-size: 2em;color: lightgrey;"></span></h1><br> - <?php - esc_html_e( 'No WSDesk role assigned to any users / No Agents added', 'wsdesk' ); - ?> - </div> - <?php - } - ?> -</div> -<?php -// return ob_get_clean(); +<?php++require_once EH_CRM_MAIN_PATH . '/vendor/autoload.php';++use Illuminate\Support\Arr;+use WSDesk\Tickets\TicketRepository;+++if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++// ob_start();+$users = get_users( array( 'role__in' => array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ) ) );+$users_data = array();+for ( $i = 0; $i < count( $users ); $i++ ) {+ $uid = $users[ $i ]->ID;+ $user = new WP_User( $uid );+ $users_data[ $i ]['id'] = $uid;+ $users_data[ $i ]['name'] = $user->display_name;+ $users_data[ $i ]['email'] = $user->user_email;+ $users_data[ $i ]['avatar'] = get_avatar_url( $uid );+ $users_data[ $i ]['role'] = $user->roles;+ $users_data[ $i ]['caps'] = $user->caps;+ $users_data[ $i ]['tags'] = get_user_meta( $uid, 'wsdesk_tags', true );+}++$user_ids = array_map(+ function ( $user ) {+ return $user['id'];+ },+ $users_data+);++global $wpdb;++$ticket_reply_count_by_users = wpFluent()->table( 'wsdesk_tickets' )+ ->whereIn( 'ticket_author', $user_ids )+ ->where( 'ticket_parent', '<>', 0 )+ ->where( 'ticket_trash', 0 )+ ->groupBy( 'ticket_author' )+ ->select( 'ticket_author', wpFluent()->raw( 'count(ticket_id) as count' ) )+ ->get();++$ticket_reply_count_by_users = Arr::pluck( $ticket_reply_count_by_users, 'count', 'ticket_author' );++$repo = new TicketRepository();+$filter = [+ 'view' => [+ 'agents' => $user_ids,+ ],+];++$agentsQuery = $repo->applyFilter( $filter )->select( 'ticket_id' );+$assigned_tickets_count = $repo->getCountByAgents( $agentsQuery->getQuery()->getRawSql() );+$assigned_tickets_count = Arr::pluck( $assigned_tickets_count, 'count', 'slug' );++$hasRatingQuery = 'select ticket_id from ' . $wpdb->prefix . 'wsdesk_ticketsmeta as m where m.meta_key = "ticket_rating"';+++$agentsQuery = $agentsQuery->where( \DB::raw( 'ticket_id in (' . $hasRatingQuery . ')' ) );+$has_rating_tickets_count = $repo->getCountByAgents( $agentsQuery->getQuery()->getRawSql() );+$has_rating_tickets_count = Arr::pluck( $has_rating_tickets_count, 'count', 'slug' );++$hasRatingQuery .= ' and meta_value = "great"';+$agentsQuery = $agentsQuery->where( \DB::raw( 'ticket_id in (' . $hasRatingQuery . ')' ) );+$good_rating_tickets_count = $repo->getCountByAgents( $agentsQuery->getQuery()->getRawSql() );+$good_rating_tickets_count = Arr::pluck( $good_rating_tickets_count, 'count', 'slug' );++//dd($good_rating_tickets_count);++?>++<div class="panel-group" id="manage_role" style="margin-bottom: 0px !important">+ <?php+ if ( count( $users_data ) !== 0 ) {+ $flag = 0;+ $current_user_id = wp_get_current_user()->ID;+ foreach ( wp_get_current_user()->roles as $urole ) {+ if ( 0 == $flag ) {+ $current_user_access = $urole;+ $flag = 1;+ }+ }+ for ( $i = 0; $i < count( $users_data ); $i++ ) {+ $uid = $users_data[ $i ]['id'];+ if ( in_array( 'WSDesk_Agents', $users_data[ $i ]['role'] ) ) {+ $urole = 'WSDesk Agents';+ } elseif ( in_array( 'WSDesk_Supervisor', $users_data[ $i ]['role'] ) ) {+ $urole = 'WSDesk Supervisor';+ } elseif ( in_array( 'administrator', $users_data[ $i ]['role'] ) ) {+ $urole = 'Administrator';+ }+ $enabledisable = '';+ if ( 'Administrator' == $urole || 'WSDesk Supervisor' == $urole ) {+ if ( 'administrator' != $current_user_access ) {+ $enabledisable = 'disabled';+ if ( $uid == $current_user_id ) {+ $enabledisable = '';+ }+ }+ if ( 'administrator' == $current_user_access ) {+ if ( 'Administrator' == $urole ) {+ $enabledisable = 'disabled';+ }+ }+ }++ $roles_temp = $users_data[ $i ]['role'];+ $roles = array();+ foreach ( $roles_temp as $value ) {+ $current_role = $value;+ array_push( $roles, ucfirst( str_replace( '_', ' ', $current_role ) ) );+ }+ $caps_temp = array_keys( $users_data[ $i ]['caps'] );+ $caps = '';+ for ( $j = 0; $j < count( $caps_temp ); $j++ ) {+ switch ( $caps_temp[ $j ] ) {+ case 'reply_tickets':+ $caps .= '<span class="tags">' . __( 'Reply Tickets', 'wsdesk' ) . '</span> ';+ break;+ case 'delete_tickets':+ $caps .= '<span class="tags">' . __( 'Delete Tickets', 'wsdesk' ) . '</span> ';+ break;+ case 'manage_tickets':+ $caps .= '<span class="tags">' . __( 'Manage Tickets', 'wsdesk' ) . '</span> ';+ break;+ case 'credit_deduction':+ if ( defined( 'PFS_IS_INSTALLED' ) ) {+ $caps .= '<span class="tags">' . __( 'Credit Deduction', 'wsdesk' ) . '</span> ';+ }+ break;+ case 'manage_templates':+ $caps .= '<span class="tags">' . __( 'Manage Templates', 'wsdesk' ) . '</span> ';+ break;+ case 'settings_page':+ $caps .= '<span class="tags">' . __( 'Settings Manage', 'wsdesk' ) . '</span> ';+ break;+ case 'agents_page':+ $caps .= '<span class="tags">' . __( 'Agents Manage', 'wsdesk' ) . '</span> ';+ break;+ case 'import_page':+ $caps .= '<span class="tags">' . __( 'Import Manage', 'wsdesk' ) . '</span> ';+ break;+ case 'email_page':+ $caps .= '<span class="tags">' . __( 'Email Manage', 'wsdesk' ) . '</span> ';+ break;+ case 'merge_tickets':+ $caps .= '<span class="tags">' . __( 'Merge Tickets', 'wsdesk' ) . '</span> ';+ }+ }+ if ( '' === $caps ) {+ if ( 'Administrator' == $urole ) {+ $caps .= '<span class="tags">' . __( 'Reply Tickets', 'wsdesk' ) . '</span> ';+ $caps .= '<span class="tags">' . __( 'Delete Tickets', 'wsdesk' ) . '</span> ';+ $caps .= '<span class="tags">' . __( 'Manage Tickets', 'wsdesk' ) . '</span> ';+ if ( defined( 'PFS_IS_INSTALLED' ) ) {+ $caps .= '<span class="tags">' . __( 'Credit Deduction', 'wsdesk' ) . '</span> ';+ }+ $caps .= '<span class="tags">' . __( 'Merge Tickets', 'wsdesk' ) . '</span> ';+ $caps .= '<span class="tags">' . __( 'Manage Templates', 'wsdesk' ) . '</span> ';+ $caps .= '<span class="tags">' . __( 'Settings Manage', 'wsdesk' ) . '</span> ';+ $caps .= '<span class="tags">' . __( 'Agents Manage', 'wsdesk' ) . '</span> ';+ $caps .= '<span class="tags">' . __( 'Import Manage', 'wsdesk' ) . '</span> ';+ $caps .= '<span class="tags">' . __( 'Email Manage', 'wsdesk' ) . '</span> ';+ } else {+ $caps .= __( 'No Capabilities Assigned', 'wsdesk' );+ }+ }+ $tags_temp = $users_data[ $i ]['tags'];+ $tags = '';+ if ( ! empty( $tags_temp ) ) {+ for ( $j = 0; $j < count( $tags_temp ); $j++ ) {+ $stag = eh_crm_get_settings(+ array(+ 'slug' => $tags_temp[ $j ],+ 'type' => 'tag',+ ),+ array( 'title' )+ );+ if ( ! empty( $stag ) ) {+ $tags .= '<span class="tags">' . $stag[0]['title'] . '</span>';+ }+ }+ } else {+ $tags .= __( 'No Tags Mapped', 'wsdesk' );+ }+ if ( '' == $tags ) {+ $tags .= __( 'No Tags Mapped', 'wsdesk' );+ }+ $overall_replies = Arr::get( $ticket_reply_count_by_users, $users_data[ $i ]['id'], 0 );+ $overall_assigned = Arr::get( $assigned_tickets_count, $users_data[ $i ]['id'] );+ $all = (int) Arr::get( $has_rating_tickets_count, $users_data[ $i ]['id'] );+ $good = (int) Arr::get( $good_rating_tickets_count, $users_data[ $i ]['id'] );+ $bad = $all - $good;+ if ( 0 !== $all ) {+ $rating = ( $good / ( $all / 100 ) ) - ( $bad / ( $all / 100 ) );+ } else {+ $rating = 'None';+ }+ echo '<div class="panel panel-default">+ <div class="panel-heading collapsed" data-toggle="collapse" data-parent="#manage_role" data-target="#content_' . esc_attr( $uid ) . '">+ <span class ="manage-role-toggle"></span>+ <h4 class="panel-title">+ ' . esc_html( $users_data[ $i ]['name'] ) . ' ( ' . esc_attr( $urole ) . ' )+ </h4>+ </div>+ <div id="content_' . esc_attr( $uid ) . '" class="panel-collapse collapse">+ <div class="panel-body">+ <div class="col-md-12">+ <center>+ <div class="well profile">+ <div class="col-sm-12">+ <div class="col-xs-12 col-sm-9">+ <h2>' . esc_html( $users_data[ $i ]['name'] ) . '</h2>+ <p><strong>' . esc_html__( 'Roles', 'wsdesk' ) . ': </strong> ' . esc_html( implode( ', ', $roles ) ) . ' </p>+ <p><strong>' . esc_html__( 'Email', 'wsdesk' ) . ': </strong> ' . esc_html( $users_data[ $i ]['email'] ) . ' </p>+ <p><strong>' . esc_html__( 'Capability', 'wsdesk' ) . ': </strong>+ <span style="line-height:1.75"> ' . wp_kses( $caps, array( 'span' => array( 'class' => array() ) ) ) . ' </span>+ </p>+ </div>+ <div class="col-xs-12 col-sm-3 text-center">+ <center>+ <figure>+ <img src="' . esc_url( $users_data[ $i ]['avatar'] ) . '" alt="" class="img-circle img-responsive">+ <figcaption class="ratings">+ <p style="line-height:1.75!important"><strong>' . esc_html__( 'Tags', 'wsdesk' ) . ': </strong>+ ' . wp_kses( $tags, array( 'span' => array( 'class' => array() ) ) ) . '+ </p>+ </figcaption>+ </figure>+ </center>+ </div>+ </div>+ <div class="col-xs-12 divider text-center">+ <div class="col-xs-12 col-sm-4 emphasis">+ <h2><strong> ' . esc_html( $overall_replies ) . ' </strong></h2>+ <p><small>' . esc_html__( 'Overall Replies', 'wsdesk' ) . '</small></p>+ <button class="btn btn-success btn-block edit_user" id="user_edit_' . esc_attr( $uid ) . '" ' . esc_attr( $enabledisable ) . '><span class="glyphicon glyphicon-edit"></span> ' . esc_html__( 'Edit Profile', 'wsdesk' ) . '</button>+ </div>+ <div class="col-xs-12 col-sm-4 emphasis">+ <h2><strong> ' . esc_html( $overall_assigned ) . ' </strong></h2>+ <p><small>' . esc_html__( 'Tickets Assigned', 'wsdesk' ) . '</small></p>+ <a class="btn btn-info btn-block" target="_blank" href="' . esc_url( admin_url( 'admin.php?page=wsdesk_reports&user=' ) . esc_url( $uid ) ) . '" ><span class="glyphicon glyphicon-signal"></span> ' . esc_html__( 'View Reports', 'wsdesk' ) . ' </a>+ </div>+ <div class="col-xs-12 col-sm-4 emphasis">+ <h2><strong> ' . esc_html( $rating ) . ' </strong></h2>+ <p><small>' . esc_html__( 'Support Rating', 'wsdesk' ) . '</small></p>+ <div class="btn-group dropup btn-block">+ <button type="button" class="btn btn-primary dropdown-toggle" ' . esc_attr( $enabledisable ) . ' style="width:100% !important" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">+ <span class="glyphicon glyphicon-user"></span> ' . esc_html__( 'Actions', 'wsdesk' ) . ' <span class="caret"></span>+ </button>+ <ul class="dropdown-menu">+ <li><span class="user_actions user_actions_remove" id="user_actions_remove_' . esc_attr( $uid ) . '"><span class="glyphicon glyphicon-remove pull-right"></span>' . esc_html__( 'Remove WSDesk Role', 'wsdesk' ) . '</span></li>+ </ul>+ </div>+ </div>+ </div>+ </div>+ </center>+ </div>+ </div>+ <div id="user_content_change_' . esc_attr( $uid ) . '">+ </div>+ </div>+ </div>';+ }+ } else {+ ?>+ <div style="text-align: center">+ <h1><span class="glyphicon glyphicon-screenshot" style="font-size: 2em;color: lightgrey;"></span></h1><br>+ <?php+ esc_html_e( 'No WSDesk role assigned to any users / No Agents added', 'wsdesk' );+ ?>+ </div>+ <?php+ }+ ?>+</div>+<?php+// return ob_get_clean();
Vulnerability Existed: no Explanation: This diff shows only a line ending change (LF to CRLF or vice versa) throughout the entire file. The actual code content remains identical between versions 3.3.4 and 3.3.5. No security fixes have been applied. The code itself contains several potential security issues (SQL injection in raw queries, lack of input validation, potential XSS in concatenated HTML), but these issues exist in both versions and are not addressed by this update. Since no code changes were made—only whitespace/line ending normalization—there are no security vulnerabilities fixed in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/crm_agents_view.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/crm_agents_view.php 2025-12-21 09:36:35.507308439 +0000@@ -1,6 +1,6 @@-<?php -echo '<div class="wsdesk_wrapper">'; - -echo '<div class="loader"></div>'; -require EH_CRM_MAIN_VIEWS . 'agents/crm_agents_main.php' ; -echo '</div>'; +<?php+echo '<div class="wsdesk_wrapper">';++echo '<div class="loader"></div>';+require EH_CRM_MAIN_VIEWS . 'agents/crm_agents_main.php' ;+echo '</div>';
Vulnerability Existed: no Explanation: This diff contains only whitespace and line ending changes (likely converting between different line ending formats, such as CRLF to LF or vice versa). There are no substantive code changes, no modifications to functionality, and no security-related alterations. The file structure, logic flow, and all executable code remain identical between versions 3.3.4 and 3.3.5. No vulnerabilities are introduced, fixed, or present in this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/crm_archive_tickets_view.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/crm_archive_tickets_view.php 2025-12-21 09:36:35.507308439 +0000@@ -1,80 +1,80 @@-<?php -echo '<div class="wsdesk_wrapper">'; -$tab_head = ''; -$tab_content = ''; -$t_id = ( isset( $_GET['tid'] ) ? sanitize_text_field( $_GET['tid'] ) : false ); -if ( $t_id ) { - $data = eh_crm_get_ticket_archive( - array( - 'ticket_id' => $t_id, - 'ticket_parent' => 0, - ) - ); - if ( $data ) { - $all_section_ids = eh_crm_get_ticket_value_count_archive( 'ticket_parent', 0, false, '', '', 'ticket_updated', 'DESC', '', 0 ); - $pagination_ids = array(); - foreach ( $all_section_ids as $tic ) { - array_push( $pagination_ids, $tic['ticket_id'] ); - } - $tab_head = '<li role="presentation" class="active visible_tab" id="tab_' . $t_id . '" style="min-width:200px;">' . CRM_Ajax_Archive::eh_crm_ticket_single_view_gen_head( $t_id ) . '</li>'; - $tab_content = '<div class="tab-pane new-style-tab-pane active direct_load_tid" id="tab_content_' . $t_id . '">' . CRM_Ajax_Archive::eh_crm_ticket_single_view_gen( $t_id, $pagination_ids ) . '</div>'; - } else { - ?> - <div class="row" id="alert_for_activation"> - <div class="col-md-12"> - <div class="alert alert-danger aw_wsdesk_activate_alert" role="alert"> - <?php esc_html_e( 'Invalid Ticket Number', 'wsdesk' ); ?> [ <b>#<?php esc_html( $t_id ); ?></b> ] - </div> - </div> - </div> - <?php - } -} -?> -<div class="container wrapper" id="tickets_page_view"> - <div class="row"> - <div class="col-md-12"> - <div class="panel with-nav-tabs panel-default"> - <div class="panel-heading col-md-12"> - <ul class="nav nav-tabs col-md-11 elaborate" role="tablist" style="margin-left: 0em;"> - <li class="<?php echo ( '' === $tab_head ) ? 'active' : ''; ?> all_tickets" role="presentation"> - <a onclick="setURLFunc('tickets')" href="#all_tickets_tab" aria-controls="all" style="text-align: center;padding: 13px 15px;margin-right:0px !important;" data-toggle="tab" class="tab_a"> - <?php esc_html_e( 'Tickets', 'wsdesk' ); ?> - </a> - </li> - <?php echo wp_kses_post( $tab_head ); ?> - <li role="presentation" class="dropdown" style="display: none;"> - <a href="#" id="myTabDrop1" class="dropdown-toggle tab_a" data-toggle="dropdown" aria-controls="myTabDrop1-contents" aria-expanded="true" style="text-align: center;padding: 13px 15px;margin-right:0px !important;"> - <span class="caret"></span> <?php esc_html_e( 'More', 'wsdesk' ); ?></a> - <ul class="dropdown-menu collapse_ul" aria-labelledby="myTabDrop1" id="myTabDrop1-contents"style="overflow-x: hidden"> - </ul> - </li> - </ul> - <div class="col-md-1 nav-tabs hide"> - <div class="pull-right"> - <div class="input-group stylish-input-group" style="margin: 3px 5px;"> - <input type="text" class="form-control" id="search_ticket_input" placeholder="Search" data-placement="bottom" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Search Ticket', 'wsdesk' ); ?>" data-container="body"> - <span class="glyphicon glyphicon-search clickable form-control-feedback" id="search_ticket_icon"></span> - </div> - </div> - </div> - </div> - <div class="panel-body"> - <div class="tab-content"> - <div class="alert alert-success" style="z-index: 1100;display: none;" role="alert"> - <div id="success_alert_text"></div> - </div> - <div class="alert alert-warning" style="z-index: 1100;display: none;" role="alert"> - <div id="warning_alert_text"></div> - </div> - <div class="tab-pane <?php echo ( '' === $tab_content ) ? 'active' : ''; ?>" id="all_tickets_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'tickets/crm_archive_tickets_v2.php' ; ?> - </div> - <?php echo wp_kses_post( $tab_content ); ?> - </div> - </div> - </div> - </div> - </div> -</div> -</div> +<?php+echo '<div class="wsdesk_wrapper">';+$tab_head = '';+$tab_content = '';+$t_id = ( isset( $_GET['tid'] ) ? sanitize_text_field( $_GET['tid'] ) : false );+if ( $t_id ) {+ $data = eh_crm_get_ticket_archive(+ array(+ 'ticket_id' => $t_id,+ 'ticket_parent' => 0,+ )+ );+ if ( $data ) {+ $all_section_ids = eh_crm_get_ticket_value_count_archive( 'ticket_parent', 0, false, '', '', 'ticket_updated', 'DESC', '', 0 );+ $pagination_ids = array();+ foreach ( $all_section_ids as $tic ) {+ array_push( $pagination_ids, $tic['ticket_id'] );+ }+ $tab_head = '<li role="presentation" class="active visible_tab" id="tab_' . $t_id . '" style="min-width:200px;">' . CRM_Ajax_Archive::eh_crm_ticket_single_view_gen_head( $t_id ) . '</li>';+ $tab_content = '<div class="tab-pane new-style-tab-pane active direct_load_tid" id="tab_content_' . $t_id . '">' . CRM_Ajax_Archive::eh_crm_ticket_single_view_gen( $t_id, $pagination_ids ) . '</div>';+ } else {+ ?>+ <div class="row" id="alert_for_activation">+ <div class="col-md-12">+ <div class="alert alert-danger aw_wsdesk_activate_alert" role="alert">+ <?php esc_html_e( 'Invalid Ticket Number', 'wsdesk' ); ?> [ <b>#<?php esc_html( $t_id ); ?></b> ]+ </div>+ </div>+ </div>+ <?php+ }+}+?>+<div class="container wrapper" id="tickets_page_view">+ <div class="row">+ <div class="col-md-12">+ <div class="panel with-nav-tabs panel-default">+ <div class="panel-heading col-md-12">+ <ul class="nav nav-tabs col-md-11 elaborate" role="tablist" style="margin-left: 0em;">+ <li class="<?php echo ( '' === $tab_head ) ? 'active' : ''; ?> all_tickets" role="presentation">+ <a onclick="setURLFunc('tickets')" href="#all_tickets_tab" aria-controls="all" style="text-align: center;padding: 13px 15px;margin-right:0px !important;" data-toggle="tab" class="tab_a">+ <?php esc_html_e( 'Tickets', 'wsdesk' ); ?>+ </a>+ </li>+ <?php echo wp_kses_post( $tab_head ); ?>+ <li role="presentation" class="dropdown" style="display: none;">+ <a href="#" id="myTabDrop1" class="dropdown-toggle tab_a" data-toggle="dropdown" aria-controls="myTabDrop1-contents" aria-expanded="true" style="text-align: center;padding: 13px 15px;margin-right:0px !important;">+ <span class="caret"></span> <?php esc_html_e( 'More', 'wsdesk' ); ?></a>+ <ul class="dropdown-menu collapse_ul" aria-labelledby="myTabDrop1" id="myTabDrop1-contents"style="overflow-x: hidden">+ </ul>+ </li>+ </ul>+ <div class="col-md-1 nav-tabs hide">+ <div class="pull-right">+ <div class="input-group stylish-input-group" style="margin: 3px 5px;">+ <input type="text" class="form-control" id="search_ticket_input" placeholder="Search" data-placement="bottom" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Search Ticket', 'wsdesk' ); ?>" data-container="body">+ <span class="glyphicon glyphicon-search clickable form-control-feedback" id="search_ticket_icon"></span>+ </div>+ </div>+ </div>+ </div>+ <div class="panel-body">+ <div class="tab-content">+ <div class="alert alert-success" style="z-index: 1100;display: none;" role="alert">+ <div id="success_alert_text"></div>+ </div>+ <div class="alert alert-warning" style="z-index: 1100;display: none;" role="alert">+ <div id="warning_alert_text"></div>+ </div>+ <div class="tab-pane <?php echo ( '' === $tab_content ) ? 'active' : ''; ?>" id="all_tickets_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'tickets/crm_archive_tickets_v2.php' ; ?>+ </div>+ <?php echo wp_kses_post( $tab_content ); ?>+ </div>+ </div>+ </div>+ </div>+ </div>+</div>+</div>
Analyzing the provided diff for security fixes... **Analysis Result:** Vulnerability Existed: **No** **Explanation:** This diff contains only whitespace/formatting changes (line ending conversion from CRLF to LF or similar). The actual code logic, security controls, and functionality remain identical between versions 3.3.4 and 3.3.5. Key observations: - The `sanitize_text_field()` function is consistently used on user input (`$_GET['tid']`) - Output escaping is properly applied with `esc_html()`, `esc_html_e()`, and `wp_kses_post()` - No new code has been introduced that could introduce vulnerabilities - No existing security measures have been removed or weakened - The file inclusion uses a constant (`EH_CRM_MAIN_VIEWS`) which is a safe practice **Conclusion:** This is a maintenance update with no security-related code changes. No vulnerabilities were fixed because none existed in the modified lines.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/crm_email_view.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/crm_email_view.php 2025-12-21 09:36:35.507308439 +0000@@ -1,67 +1,67 @@-<?php -echo '<div class="wsdesk_wrapper">'; -?> -<div class="container"> - <div class="row"> - <ol class="breadcrumb crm-panel-right" style="margin-left: 0 !important;"> - <li><?php esc_html_e( 'WSDesk E-Mail', 'wsdesk' ); ?></li> - <li id="breadcrump_section" class="active"><?php esc_html_e( 'Support Email', 'wsdesk' ); ?></li> - </ol> - <div class="col-md-3 crm-panel-left"> - <div class="panel panel-default crm-panel"> - <div class="panel-body"> - <ul class="nav nav-pills nav-stacked" role="tablist"> - <li class="active"> - <a href="#email_support_tab" data-toggle="tab" class="email_support"><?php esc_html_e( 'Support Email - (Outgoing)', 'wsdesk' ); ?></a> - </li> - <li> - <a href="#outlook_oauth_setup_tab" data-toggle="tab" class="outlook_oauth_setup"><?php esc_html_e( 'Outlook OAuth Setup - (Incoming)', 'wsdesk' ); ?> - <sup class="text-success"><?php esc_html_e( '[Premium!]', 'wsdesk' ); ?></sup> - </a> - </li> - <li> - <a href="#oauth_setup_tab" data-toggle="tab" class="oauth_setup"><?php esc_html_e( 'Google OAuth Setup - (Incoming)', 'wsdesk' ); ?></a> - </li> - <li> - <a href="#imap_setup_tab" data-toggle="tab" class="imap_setup"><?php esc_html_e( 'IMAP EMail Setup - (Incoming)', 'wsdesk' ); ?></a> - </li> - <li> - <a href="#filter_block_tab" data-toggle="tab" class="filter_block"><?php esc_html_e( 'EMail Filter & Block', 'wsdesk' ); ?></a> - </li> - </ul> - </div> - </div> - <div class="alert alert-success" style="display: none" role="alert"> - <div id="success_alert_text"></div> - </div> - <div class="alert alert-danger" style="display: none" role="alert"> - <div id="danger_alert_text"></div> - </div> - </div> - <div class="col-xs-12 col-md-9"> - <div class="panel panel-default crm-panel"> - <div class="panel-body" style="padding: 5px !important"> - <div class="tab-content"> - <div class="loader"></div> - <div class="tab-pane active" id="email_support_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'email/crm_email_support.php' ; ?> - </div> - <div class="tab-pane" id="outlook_oauth_setup_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'email/crm_outlook_oauth_setup.php' ; ?> - </div> - <div class="tab-pane" id="oauth_setup_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'email/crm_oauth_setup.php' ; ?> - </div> - <div class="tab-pane" id="imap_setup_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'email/crm_imap_setup.php' ; ?> - </div> - <div class="tab-pane" id="filter_block_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'email/crm_filter_block_setup.php' ; ?> - </div> - </div> - </div> - </div> - </div> - </div> -</div> -</div> +<?php+echo '<div class="wsdesk_wrapper">';+?>+<div class="container">+ <div class="row">+ <ol class="breadcrumb crm-panel-right" style="margin-left: 0 !important;">+ <li><?php esc_html_e( 'WSDesk E-Mail', 'wsdesk' ); ?></li>+ <li id="breadcrump_section" class="active"><?php esc_html_e( 'Support Email', 'wsdesk' ); ?></li>+ </ol>+ <div class="col-md-3 crm-panel-left">+ <div class="panel panel-default crm-panel">+ <div class="panel-body">+ <ul class="nav nav-pills nav-stacked" role="tablist">+ <li class="active">+ <a href="#email_support_tab" data-toggle="tab" class="email_support"><?php esc_html_e( 'Support Email - (Outgoing)', 'wsdesk' ); ?></a>+ </li>+ <li>+ <a href="#outlook_oauth_setup_tab" data-toggle="tab" class="outlook_oauth_setup"><?php esc_html_e( 'Outlook OAuth Setup - (Incoming)', 'wsdesk' ); ?>+ <sup class="text-success"><?php esc_html_e( '[Premium!]', 'wsdesk' ); ?></sup>+ </a>+ </li>+ <li>+ <a href="#oauth_setup_tab" data-toggle="tab" class="oauth_setup"><?php esc_html_e( 'Google OAuth Setup - (Incoming)', 'wsdesk' ); ?></a>+ </li>+ <li>+ <a href="#imap_setup_tab" data-toggle="tab" class="imap_setup"><?php esc_html_e( 'IMAP EMail Setup - (Incoming)', 'wsdesk' ); ?></a>+ </li>+ <li>+ <a href="#filter_block_tab" data-toggle="tab" class="filter_block"><?php esc_html_e( 'EMail Filter & Block', 'wsdesk' ); ?></a>+ </li>+ </ul>+ </div>+ </div>+ <div class="alert alert-success" style="display: none" role="alert">+ <div id="success_alert_text"></div>+ </div>+ <div class="alert alert-danger" style="display: none" role="alert">+ <div id="danger_alert_text"></div>+ </div>+ </div>+ <div class="col-xs-12 col-md-9">+ <div class="panel panel-default crm-panel">+ <div class="panel-body" style="padding: 5px !important">+ <div class="tab-content">+ <div class="loader"></div>+ <div class="tab-pane active" id="email_support_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'email/crm_email_support.php' ; ?>+ </div>+ <div class="tab-pane" id="outlook_oauth_setup_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'email/crm_outlook_oauth_setup.php' ; ?>+ </div>+ <div class="tab-pane" id="oauth_setup_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'email/crm_oauth_setup.php' ; ?>+ </div>+ <div class="tab-pane" id="imap_setup_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'email/crm_imap_setup.php' ; ?>+ </div>+ <div class="tab-pane" id="filter_block_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'email/crm_filter_block_setup.php' ; ?>+ </div>+ </div>+ </div>+ </div>+ </div>+ </div>+</div>+</div>
Vulnerability Existed: no No Security Vulnerabilities Detected - CWE-N/A - views/crm_email_view.php (Lines 1-67) Old Code: The entire file content with Unix line endings (LF) Fixed Code: The entire file content with Windows line endings (CRLF) Explanation: This diff represents only a line ending change from Unix (LF) to Windows (CRLF) format. No actual code logic has been modified. The file structure, functionality, and security posture remain identical. The `require` statements still use the same constant `EH_CRM_MAIN_VIEWS` with static file paths, output escaping with `esc_html_e()` is unchanged, and all HTML/PHP code remains functionally identical. This is a formatting change only, not a security fix or introduction of any vulnerability.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/crm_import_view.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/crm_import_view.php 2025-12-21 09:36:35.507308439 +0000@@ -1,42 +1,42 @@-<?php -echo '<div class="wsdesk_wrapper">'; - -?> -<div class="container"> - <div class="row"> - <ol class="breadcrumb crm-panel-right" style="margin-left: 0 !important;"> - <li><?php esc_html_e( 'Import Tickets', 'wsdesk' ); ?></li> - <li id="breadcrump_section" class="active"><?php esc_html_e( 'From Zendesk', 'wsdesk' ); ?></li> - </ol> - <div class="col-md-3 crm-panel-left"> - <div class="panel panel-default crm-panel"> - <div class="panel-body"> - <ul class="nav nav-pills nav-stacked" role="tablist"> - <li class="active"> - <a href="#zendesk_import_tab" data-toggle="tab" class="zendesk_import"><?php esc_html_e( 'From Zendesk', 'wsdesk' ); ?></a> - </li> - </ul> - </div> - </div> - <div class="alert alert-success" style="display: none" role="alert"> - <div id="success_alert_text"></div> - </div> - <div class="alert alert-danger" style="display: none" role="alert"> - <div id="danger_alert_text"></div> - </div> - </div> - <div class="col-xs-12 col-md-9"> - <div class="panel panel-default crm-panel"> - <div class="panel-body" style="padding: 5px !important"> - <div class="tab-content"> - <div class="loader"></div> - <div class="tab-pane active" id="zendesk_import_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'import/crm_zendesk_import.php'; ?> - </div> - </div> - </div> - </div> - </div> - </div> -</div> -</div> +<?php+echo '<div class="wsdesk_wrapper">';++?>+<div class="container">+ <div class="row">+ <ol class="breadcrumb crm-panel-right" style="margin-left: 0 !important;">+ <li><?php esc_html_e( 'Import Tickets', 'wsdesk' ); ?></li>+ <li id="breadcrump_section" class="active"><?php esc_html_e( 'From Zendesk', 'wsdesk' ); ?></li>+ </ol>+ <div class="col-md-3 crm-panel-left">+ <div class="panel panel-default crm-panel">+ <div class="panel-body">+ <ul class="nav nav-pills nav-stacked" role="tablist">+ <li class="active">+ <a href="#zendesk_import_tab" data-toggle="tab" class="zendesk_import"><?php esc_html_e( 'From Zendesk', 'wsdesk' ); ?></a>+ </li>+ </ul>+ </div>+ </div>+ <div class="alert alert-success" style="display: none" role="alert">+ <div id="success_alert_text"></div>+ </div>+ <div class="alert alert-danger" style="display: none" role="alert">+ <div id="danger_alert_text"></div>+ </div>+ </div>+ <div class="col-xs-12 col-md-9">+ <div class="panel panel-default crm-panel">+ <div class="panel-body" style="padding: 5px !important">+ <div class="tab-content">+ <div class="loader"></div>+ <div class="tab-pane active" id="zendesk_import_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'import/crm_zendesk_import.php'; ?>+ </div>+ </div>+ </div>+ </div>+ </div>+ </div>+</div>+</div>
Vulnerability Existed: no Explanation: This diff shows only whitespace/line ending changes (converting between different line ending formats, likely CRLF to LF or vice versa). The actual PHP code content remains identical across all 42 lines. There are no security-relevant code modifications, no new functionality added, no input handling changes, and no vulnerability fixes or introductions. This is purely a formatting/normalization change with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/crm_reports_v2.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/crm_reports_v2.php 2025-12-21 09:36:35.507308439 +0000@@ -1,153 +1,153 @@-<?php -use WSDesk\Tickets\TicketRepository; - -$repo = new TicketRepository(); - -$agents = $repo->getAgents(); - -$dates = [ - 'from' => ( new \DateTime() )->modify( '-3 months' )->format( 'Y-m-d' ), - 'to' => gmdate( 'Y-m-d' ), -]; - -?> -<div class="wsdesk_wrapper"> - <h1 class="wp-heading"><?php echo esc_html__( 'Reports', 'wsdesk' ); ?></h4> - <div class="row pb-1" id="report_filters"> - <div class="col-md-3"> - <label><?php echo esc_html__( 'Ticket Date', 'wsdesk' ); ?></label> - <label for="default_time" class='premium_update_green'><a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><sup class="text-success">[Premium!]</sup></a></label> - <div class="input-daterange input-group" id="datepicker"> - <input disabled type="text" class="form-control" name="created_at[from]" value="<?php echo esc_attr( $dates['from'] ); ?>" /> - <span class="input-group-addon"><?php echo esc_html__( 'to', 'wsdesk' ); ?></span> - <input disabled type="text" class="form-control" name="created_at[to]" value="<?php echo esc_attr( $dates['to'] ); ?>" /> - </div> - </div> - <div class="col-md-3"> - <div class="form-group"> - <label ><?php echo esc_html__( 'Agents', 'wsdesk' ); ?></label><br /> - <select name="agents" class="selectpicker" multiple> - <?php foreach ( $agents as $agent ) { ?> - <option value="<?php echo esc_attr( $agent['id'] ); ?>"><?php echo esc_attr( $agent['name'] ); ?></option> - <?php } ?> - </select> - </div> - </div> - </div> - <div class="row"> - <div class="col-sm-6"> - <div class="panel panel-default"> - <div class="panel-heading"> - <h1 class="panel-title"><?php echo esc_html__( 'Avg Time Taken to Resolve (Hrs)', 'wsdesk' ); ?></h1> - </div> - <div class="panel-body"> - <canvas id="avg_time_taken_to_resolve"></canvas> - </div> - </div> - </div> - <div class="col-sm-6"> - <div class="panel panel-default"> - <div class="panel-heading"> - <h1 class="panel-title"><?php echo esc_html__( 'No of Replies per Day', 'wsdesk' ); ?></h1> - </div> - <div class="panel-body"> - <canvas id="no_of_replies_per_day"></canvas> - </div> - </div> - </div> - <div class="col-sm-6"> - <div class="panel panel-default"> - <div class="panel-heading"> - <h1 class="panel-title"><?php echo esc_html__( 'No of Tickets per Day', 'wsdesk' ); ?></h1> - </div> - <div class="panel-body"> - <canvas id="no_of_tickets_per_day"></canvas> - </div> - </div> - </div> - <div class="col-sm-6"> - <div class="panel panel-default"> - <div class="panel-heading"> - <h1 class="panel-title"><?php echo esc_html__( 'No of Tickets per Status', 'wsdesk' ); ?></h1> - </div> - <div class="panel-body text-center"> - <div class="row"> - <div class="col-sm-8 col-sm-offset-2"> - <canvas id="no_of_tickets_per_status" ></canvas> - </div> - </div> - </div> - </div> - </div> - <div class="col-sm-6"> - <div class="panel panel-default"> - <div class="panel-heading"> - <h1 class="panel-title"><?php echo esc_html__( 'No of Tickets per Tag', 'wsdesk' ); ?></h1> - </div> - <div class="panel-body"> - <canvas id="no_of_tickets_per_tag"></canvas> - </div> - </div> - </div> - <div class="col-sm-6"> - <div class="panel panel-default"> - <div class="panel-heading"> - <h1 class="panel-title"><?php echo esc_html__( 'Avg First Reply Time By Agent (Mins)', 'wsdesk' ); ?></h1> - </div> - <div class="panel-body"> - <canvas id="agent_avg_reply_time"></canvas> - </div> - </div> - </div> - <div class="col-sm-6 hidden"> - <div class="panel panel-default"> - <div class="panel-heading"> - <h1 class="panel-title"><?php echo esc_html__( 'Agent Satisfication Score', 'wsdesk' ); ?></h1> - </div> - <div class="panel-body"> - <table id="agent_satisfication_score" class="table"> - <thead> - <tr> - <th><?php echo esc_html__( 'Agent', 'wsdesk' ); ?></th> - <th><?php echo esc_html__( 'Good', 'wsdesk' ); ?></th> - <th><?php echo esc_html__( 'Bad', 'wsdesk' ); ?></th> - <th><?php echo esc_html__( 'Total', 'wsdesk' ); ?></th> - <th><?php echo esc_html__( 'Score', 'wsdesk' ); ?></th> - </tr> - </thead> - <tbody> - </tbody> - </table> - </div> - </div> - </div> - </div> -</div> - -<script> - (function () { - var reports = new ReportsController(); - var created_at_from = jQuery('input[name="created_at[from]"]'); - var created_at_to = jQuery('input[name="created_at[to]"]'); - - reports.init(); - - setTimeout(function () { - jQuery('.input-daterange input').datepicker({ - "dateFormat": "yy-mm-dd" - }); - created_at_from.trigger('change') - }, 1000); - - jQuery('#report_filters').on('change', 'input, select', function () { - jQuery(window).trigger('wsdesk_update_report_chart', reports.getFilterData()); - }); - - created_at_from.change(function () { - var from_date = jQuery(this).datepicker('getDate'); - - created_at_to.datepicker('option', 'minDate', from_date); - }); - - })(); -</script> +<?php+use WSDesk\Tickets\TicketRepository;++$repo = new TicketRepository();++$agents = $repo->getAgents();++$dates = [+ 'from' => ( new \DateTime() )->modify( '-3 months' )->format( 'Y-m-d' ),+ 'to' => gmdate( 'Y-m-d' ),+];++?>+<div class="wsdesk_wrapper">+ <h1 class="wp-heading"><?php echo esc_html__( 'Reports', 'wsdesk' ); ?></h4>+ <div class="row pb-1" id="report_filters">+ <div class="col-md-3">+ <label><?php echo esc_html__( 'Ticket Date', 'wsdesk' ); ?></label>+ <label for="default_time" class='premium_update_green'><a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><sup class="text-success">[Premium!]</sup></a></label>+ <div class="input-daterange input-group" id="datepicker">+ <input disabled type="text" class="form-control" name="created_at[from]" value="<?php echo esc_attr( $dates['from'] ); ?>" />+ <span class="input-group-addon"><?php echo esc_html__( 'to', 'wsdesk' ); ?></span>+ <input disabled type="text" class="form-control" name="created_at[to]" value="<?php echo esc_attr( $dates['to'] ); ?>" />+ </div>+ </div>+ <div class="col-md-3">+ <div class="form-group">+ <label ><?php echo esc_html__( 'Agents', 'wsdesk' ); ?></label><br />+ <select name="agents" class="selectpicker" multiple>+ <?php foreach ( $agents as $agent ) { ?>+ <option value="<?php echo esc_attr( $agent['id'] ); ?>"><?php echo esc_attr( $agent['name'] ); ?></option>+ <?php } ?>+ </select>+ </div>+ </div>+ </div>+ <div class="row">+ <div class="col-sm-6">+ <div class="panel panel-default">+ <div class="panel-heading">+ <h1 class="panel-title"><?php echo esc_html__( 'Avg Time Taken to Resolve (Hrs)', 'wsdesk' ); ?></h1>+ </div>+ <div class="panel-body">+ <canvas id="avg_time_taken_to_resolve"></canvas>+ </div>+ </div>+ </div>+ <div class="col-sm-6">+ <div class="panel panel-default">+ <div class="panel-heading">+ <h1 class="panel-title"><?php echo esc_html__( 'No of Replies per Day', 'wsdesk' ); ?></h1>+ </div>+ <div class="panel-body">+ <canvas id="no_of_replies_per_day"></canvas>+ </div>+ </div>+ </div>+ <div class="col-sm-6">+ <div class="panel panel-default">+ <div class="panel-heading">+ <h1 class="panel-title"><?php echo esc_html__( 'No of Tickets per Day', 'wsdesk' ); ?></h1>+ </div>+ <div class="panel-body">+ <canvas id="no_of_tickets_per_day"></canvas>+ </div>+ </div>+ </div>+ <div class="col-sm-6">+ <div class="panel panel-default">+ <div class="panel-heading">+ <h1 class="panel-title"><?php echo esc_html__( 'No of Tickets per Status', 'wsdesk' ); ?></h1>+ </div>+ <div class="panel-body text-center">+ <div class="row">+ <div class="col-sm-8 col-sm-offset-2">+ <canvas id="no_of_tickets_per_status" ></canvas>+ </div>+ </div>+ </div>+ </div>+ </div>+ <div class="col-sm-6">+ <div class="panel panel-default">+ <div class="panel-heading">+ <h1 class="panel-title"><?php echo esc_html__( 'No of Tickets per Tag', 'wsdesk' ); ?></h1>+ </div>+ <div class="panel-body">+ <canvas id="no_of_tickets_per_tag"></canvas>+ </div>+ </div>+ </div>+ <div class="col-sm-6">+ <div class="panel panel-default">+ <div class="panel-heading">+ <h1 class="panel-title"><?php echo esc_html__( 'Avg First Reply Time By Agent (Mins)', 'wsdesk' ); ?></h1>+ </div>+ <div class="panel-body">+ <canvas id="agent_avg_reply_time"></canvas>+ </div>+ </div>+ </div>+ <div class="col-sm-6 hidden">+ <div class="panel panel-default">+ <div class="panel-heading">+ <h1 class="panel-title"><?php echo esc_html__( 'Agent Satisfication Score', 'wsdesk' ); ?></h1>+ </div>+ <div class="panel-body">+ <table id="agent_satisfication_score" class="table">+ <thead>+ <tr>+ <th><?php echo esc_html__( 'Agent', 'wsdesk' ); ?></th>+ <th><?php echo esc_html__( 'Good', 'wsdesk' ); ?></th>+ <th><?php echo esc_html__( 'Bad', 'wsdesk' ); ?></th>+ <th><?php echo esc_html__( 'Total', 'wsdesk' ); ?></th>+ <th><?php echo esc_html__( 'Score', 'wsdesk' ); ?></th>+ </tr>+ </thead>+ <tbody>+ </tbody>+ </table>+ </div>+ </div>+ </div>+ </div>+</div>++<script>+ (function () {+ var reports = new ReportsController();+ var created_at_from = jQuery('input[name="created_at[from]"]');+ var created_at_to = jQuery('input[name="created_at[to]"]');++ reports.init();++ setTimeout(function () {+ jQuery('.input-daterange input').datepicker({+ "dateFormat": "yy-mm-dd"+ });+ created_at_from.trigger('change')+ }, 1000);++ jQuery('#report_filters').on('change', 'input, select', function () {+ jQuery(window).trigger('wsdesk_update_report_chart', reports.getFilterData());+ });++ created_at_from.change(function () {+ var from_date = jQuery(this).datepicker('getDate');++ created_at_to.datepicker('option', 'minDate', from_date);+ });++ })();+</script>
# Security Analysis Report ## Analysis Result **No vulnerabilities detected.** ### Explanation The diff provided shows only **line ending changes** (CRLF to LF conversion) with no actual code modifications. The content remains identical between versions 3.3.4 and 3.3.5. The file `views/crm_reports_v2.php` contains: - Proper output escaping using `esc_html__()` and `esc_attr()` functions - No database queries or user input processing at risk - No injection vectors introduced or removed - No authentication/authorization changes - No sensitive data handling modifications Since there are no functional code changes, there are no security fixes to analyze and no vulnerabilities introduced or remediated in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/crm_reports_view.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/crm_reports_view.php 2025-12-21 09:36:35.507308439 +0000@@ -1,754 +1,754 @@-<?php -echo '<div class="wsdesk_wrapper">'; - -function eh_crm_reports_page_tabs( $current = 'agent' ) { - $tabs = array( - 'agent' => esc_html__( 'Agents Reports', 'wsdesk' ), - 'date_wise' => esc_html__( 'Date wise Reports', 'wsdesk' ), - ); - if ( EH_CRM_WOO_STATUS ) { - $tabs['woocommerce'] = esc_html__( 'WooCommerce Reports', 'wsdesk' ); - } - ?> - <h2 class="nav-tab-wrapper" style="margin-right:20px;"> - <?php - foreach ( $tabs as $tab => $name ) { - $class = ( $tab === $current ) ? 'nav-tab-active' : ''; - $style = ( $tab === $current ) ? '' : ''; - ?> - <a style='text-decoration:none !important; <?php echo esc_html( $style ); ?>' class='nav-tab <?php echo esc_html( $class ); ?>' href='?page=wsdesk_reports&tab= <?php echo esc_html( $tab ); ?>' ></a> - <?php - } - ?> - </h2> - <?php -} - eh_crm_reports_page_tabs( ( ! empty( $_GET['tab'] ) ) ? esc_attr( sanitize_text_field( $_GET['tab'] ) ) : 'agent' ); -if ( 'agent' == ( ! empty( $_GET['tab'] ) ) ? esc_attr( sanitize_text_field( $_GET['tab'] ) ) : 'agent' ) { - ?> - <div class="table-box table-box-main" id='agent_section' style="margin-top: 10px;"> - <?php wsdesk_agents_reports_view_section(); ?> - </div> - </div> - <?php -} elseif ( 'date_wise' === ( ! empty( $_GET['tab'] ) ) ? esc_attr( sanitize_text_field( $_GET['tab'] ) ) : 'agent' ) { - ?> - <div class="table-box table-box-main" id='woocommerce_section' style="margin-top: 10px;"> - <?php wsdesk_date_wise_view_section(); ?> - </div> - <?php -} else { - ?> - <div class="table-box table-box-main" id='woocommerce_section' style="margin-top: 10px;"> - <?php wsdesk_woo_reports_view_section(); ?> - </div> - </div> - <?php -} -function wsdesk_agents_reports_view_section() { - ob_start(); - $user = ( isset( $_GET['user'] ) ? sanitize_text_field( $_GET['user'] ) : 'all' ); - $duration = ( isset( $_GET['duration'] ) ? sanitize_text_field( $_GET['duration'] ) : 'last_7' ); - $from_date = ( isset( $_GET['from_date'] ) ? sanitize_text_field( $_GET['from_date'] ) : gmdate( 'Y-m-d', time() - ( 7 * 86400 ) ) ); - $to_date = ( isset( $_GET['to_date'] ) ? sanitize_text_field( $_GET['to_date'] ) : gmdate( 'Y-m-d', time() ) ); - if ( strtotime( $to_date ) < strtotime( $from_date ) ) { - $to_date = gmdate( 'Y-m-d', time() ); - $from_date = gmdate( 'Y-m-d', time() - ( 7 * 86400 ) ); - echo "<script>alert('From Date cannot be beyond To Date.')</script>"; - } - $user_name = ''; - $sol = eh_crm_get_settings( array( 'slug' => 'label_LL02' ), array( 'settings_id' ) ); - $sol_col = eh_crm_get_settingsmeta( $sol[0]['settings_id'], 'label_color' ); - $color = array(); - switch ( $duration ) { - case 'last_7': - $message = __( ' Last 7 Days ', 'wsdesk' ); - break; - case 'last_30': - $message = __( ' Last 30 Days ', 'wsdesk' ); - break; - case 'custom': - $message = $from_date . __( ' to ', 'wsdesk' ) . $to_date; - } - if ( 'all' != $user ) { - $user_check = get_user_by( 'ID', $user ); - if ( $user_check ) { - $user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ); - $role = array_intersect( $user_roles_default, $user_check->roles ); - if ( ! empty( $role ) ) { - $user_name = $user_check->display_name; - $bar = eh_crm_generate_bar_values( $user, $from_date, $to_date ); - $donut_data = eh_crm_generate_donut_values( $user, $from_date, $to_date ); - $bar_avg_time = eh_crm_generate_bar_values_Avg( $user, $from_date, $to_date ); - $donut_satisfaction_data = eh_crm_generate_donut_satisfaction_values( $user, $from_date, $to_date ); - $donut = $donut_data['donut']; - $color = $donut_data['color']; - $donut_satisfaction = $donut_satisfaction_data['donut']; - $donut_satisfaction_color = $donut_satisfaction_data['color']; - $lines = eh_crm_generate_line_values( $user, $from_date, $to_date ); - - } else { - wp_die( sprintf( '<center><h1>' . esc_html__( 'Oops', 'wsdesk' ) . ' !</h1><h4>' . esc_html__( 'User is not having any WSDesk Role', 'wsdesk' ) . '</h4><a href="' . esc_url( admin_url( 'admin.php?page=wsdesk_reports' ) ) . '">' . esc_html__( 'Back to Reports', 'wsdesk' ) . '</a></center>' ) ); - } - } else { - wp_die( sprintf( '<center><h1>' . esc_html__( 'Oops', 'wsdesk' ) . ' !</h1><h4>' . esc_html__( 'User not found', 'wsdesk' ) . '</h4><a href="' . esc_url( admin_url( 'admin.php?page=wsdesk_reports' ) ) . '">' . esc_html__( 'Back to Reports', 'wsdesk' ) . '</a></center>' ) ); - } - } else { - $user_name = 'All'; - $bar = eh_crm_generate_bar_values( $user, $from_date, $to_date ); - $donut = eh_crm_generate_donut_values( $user, $from_date, $to_date ); - $bar_avg_time = eh_crm_generate_bar_values_Avg( $user, $from_date, $to_date ); - $lines = eh_crm_generate_line_values( $user, $from_date, $to_date ); - $donut_satisfaction_data = eh_crm_generate_donut_satisfaction_values( $user, $from_date, $to_date ); - $donut_satisfaction = $donut_satisfaction_data['donut']; - $donut_satisfaction_color = $donut_satisfaction_data['color']; - } - ?> - <div class="container wrapper" id="reports_page_view"> - <div class="row"> - <div class="col-md-12"> - <div class="panel panel-default reports_panel"> - <div class="panel-heading"> - <h3 class="panel-title"><?php esc_html_e( 'WSDesk - Agents Reports', 'wsdesk' ); ?></h3> - </div> - <div class="panel-body" id="reports_panel_body" style="text-align: center"> - <form method="GET"> - <input type="hidden" name="page" id="page" value="wsdesk_reports"> - <span class="help-block"><?php esc_html_e( 'Select the Agents/Supervisors to show report?', 'wsdesk' ); ?></span> - <select id="user" name="user" style="display: inline !important;" class="form-control" aria-describedby="helpBlock"> - <option value="all" <?php echo ( 'all' === $user ) ? 'selected' : ''; ?> >All</option> - <?php - $user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ); - $users = get_users( array( 'role__in' => $user_roles_default ) ); - $users_data = array(); - for ( $i = 0; $i < count( $users ); $i++ ) { - $current = $users[ $i ]; - $id = $current->ID; - $user_data = new WP_User( $id ); - $users_data[ $i ]['id'] = $id; - $users_data[ $i ]['name'] = $user_data->display_name; - } - for ( $i = 0;$i < count( $users_data );$i++ ) { - $selected = 'selected'; - echo '<option value="' . esc_attr( $users_data[ $i ]['id'] ) . ( ( $user == $users_data[ $i ]['id'] ) ? esc_html( $selected ) : '' ) . '>' . esc_html( $users_data[ $i ]['name'] ) . '</option>'; - } - ?> - </select> - <span class="help-block"><?php esc_html_e( 'Select the Duration:', 'wsdesk' ); ?></span> - <select id="duration" name="duration" style="display: inline !important;" class="form-control" aria-describedby="helpBlock"> - <option value="last_7" <?php echo ( 'last_7' == $duration ) ? 'selected' : ''; ?>><?php esc_html_e( 'Last 7 Days', 'wsdesk' ); ?></option> - <option value="last_30" <?php echo ( 'last_30' == $duration ) ? 'selected' : ''; ?>><?php esc_html_e( 'Last 30 Days', 'wsdesk' ); ?></option> - <option value="custom" <?php echo ( 'custom' == $duration ) ? 'selected' : ''; ?>><?php esc_html_e( 'Custom', 'wsdesk' ); ?></option> - </select> - - <?php - switch ( $duration ) { - case 'custom': - $display = 'inline'; - break; - - default: - $display = 'none'; - break; - } - ?> - <div class = "from_date" style="display: <?php echo esc_html( $display ); ?>;"> - <span class="help-block"><?php esc_html_e( 'Select the From Date:', 'wsdesk' ); ?></span> - <input style="width: 30%; display: inline !important;" value="<?php echo esc_html( $from_date ); ?>" type="date" name="from_date" id="from_date" class="form-control" aria-describedby="helpBlock"> - </div> - <div class="to_date" style="display: <?php echo esc_html( $display ); ?>"> - <span class="help-block"><?php esc_html_e( 'Select the To Date:', 'wsdesk' ); ?></span> - <input style="width: 30%; display: inline !important;" value="<?php echo esc_html( $to_date ); ?>" type="date" name="to_date" id="to_date" class="form-control" aria-describedby="helpBlock"> - </div> - <br> - <input type="submit" style="margin-top: 10px" class="btn btn-primary" value="<?php esc_html_e( 'Show Report', 'wsdesk' ); ?>"> - - </form> - <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"> - - <input type="hidden" class="from_date_for_dld_report" name="from_date_for_dld_report_full" value="<?php echo esc_html( $from_date ); ?>"> - <input type="hidden" class="to_date_for_dld_report" name="to_date_for_dld_report_full" value="<?php echo esc_html( $to_date ); ?>"> - <input type="hidden" name="action" value="eh_crm_export_ticket_data_report"> - <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>"> - <input type="hidden" class="user_for_dld_report" name="user_for_dld_report_full" value="<?php echo esc_html( $user ); ?>"></input> - <input type="submit" style="margin-top: 10px" class="btn btn-primary" value="<?php esc_html_e( 'Download Report', 'wsdesk' ); ?>"> - </form> - </div> - <div class="row" style="padding-top: 10px;"> - <div class="col-md-12"> - <div class="col-md-6"> - <div class="panel panel-default" style="border-color: white;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);"> - <div class="panel-heading" style="background-color: white;border-color: white;"> - <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"> - <h3 class="panel-title"><?php esc_html_e( $message . 'Status of New Tickets', 'wsdesk' ); ?> : <?php echo esc_html( $user_name ); ?> - <input type="hidden" class="from_date_for_dld_report" name="from_date_for_dld_report_new" value="<?php echo esc_html( $from_date ); ?>"> - <input type="hidden" class="to_date_for_dld_report" name="to_date_for_dld_report_new" value="<?php echo esc_html( $to_date ); ?>"> - <input type="hidden" name="action" value="eh_crm_download_status_of_new"> - <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>"> - <input type="hidden" class="user_for_dld_report" name="user_for_dld_report_new" value="<?php echo esc_html( $user ); ?>"></input> - <button class="btn btn-primary download_status_of_new" style="color: white;width: 6%;height: 3%;margin-left: 90%;margin-right: 90%;background-color: white;border-color: white;"><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'wsdesk_download.png' ); ?>" style="color: white;width: 200%;height: 200%;background-color: white;border-color: white;"></img> - </button> </h3> - </form> - </div> - <div class="panel-body"> - <div id="7days-ticket" style="height: 250px;"></div> - <script> - Morris.Bar({ - element: '7days-ticket', - data: <?php echo json_encode( $bar ); ?>, - xkey: 'y', - ykeys: ['a'], - labels: ["<?php esc_html_e( 'Tickets', 'wsdesk' ); ?>", "<?php esc_html_e( 'Date', 'wsdesk' ); ?>"], - resize:true - }); - </script> - </div> - </div> - </div> - - <div class="col-md-6" div class="col-md-6"> - <div class="panel panel-default" style="border-color: white;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);"> - <div class="panel-heading" style="background-color: white;border-color: white;"> - <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"> - <h3 class="panel-title" ><?php esc_html_e( $message . 'Status of Agent Tickets', 'wsdesk' ); ?> : <?php echo esc_html( $user_name ); ?> - <input type="hidden" class="from_date_for_dld_report" name="from_date_for_dld_report_new_donut" value="<?php echo esc_html( $from_date ); ?>"> - <input type="hidden" class="to_date_for_dld_report" name="to_date_for_dld_report_new_donut" value="<?php echo esc_html( $to_date ); ?>"> - <input type="hidden" name="action" value="eh_crm_download_status_of_new_donut"> - <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>"> - <input type="hidden" class="user_for_dld_report" name="user_for_dld_report_new_donut" value="<?php echo esc_html( $user ); ?>"> - - </input> - - <button class="btn btn-primary download_status_of_new_donut" style="color: white;margin-left: 90%;margin-right: 90%;width: 6%;height: 3%;background-color: white;border-color: white;"><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'wsdesk_download.png' ); ?>" style="color: white;width: 200%;height: 200%;background-color: white;border-color: white;"></img> - </button> </h3> - </form> - - </div> - <div class="panel-body"> - <div class="col-md-12"> - <div class="col-md-6"> - <div id="assignee-contribution" style="height: 250px;"></div> - <script> - Morris.Donut({ - element: 'assignee-contribution', - data: <?php echo json_encode( $donut ); ?>, - <?php echo ( ( ! empty( $color ) ) ? 'colors: ' . json_encode( $color ) . ',' : '' ); ?> - resize:true - }); - </script> - </div> - <div class="col-md-6"> - <div class="panel panel-default"> - <table class="table table-hover" style="border-color: white;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);"> - <?php - for ( $i = 0;$i < count( $donut );$i++ ) { - if ( ! empty( $color ) ) { - echo "<tr style='background:" . esc_html( $color[ $i ] ) . "'>"; - } else { - echo '<tr>'; - } - echo '<td>' . esc_html( $donut[ $i ]['label'] ) . '</td>'; - echo '<td>' . esc_html( $donut[ $i ]['value'] ) . '</td>'; - echo '</tr>'; - } - ?> - </table> - </div> - </div> - </div> - </div> - </div> - </div> - </div> - </div> - <div class="row" style="padding-top: 10px;"> - <div class="col-md-12"> - <div class="col-md-12"> - <div class="panel panel-default" style="border-color: white;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);"> - <div class="panel-heading" style="background-color: white;border-color: white;"> - - - <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"> - <h3 class="panel-title"><?php esc_html_e( $message . 'Status of New and Solved Ticket', 'wsdesk' ); ?> : <?php echo esc_html( $user_name ); ?> - <input type="hidden" class="from_date_for_dld_report" name="from_date_for_dld_report" value="<?php echo esc_html( $from_date ); ?>"> - <input type="hidden" class="to_date_for_dld_report" name="to_date_for_dld_report" value="<?php echo esc_html( $to_date ); ?>"> - <input type="hidden" name="action" value="eh_crm_download_status_of_new_and_solved"> - <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>"> - <input type="hidden" class="user_for_dld_report" name="user_for_dld_report" value="<?php echo( esc_html( $user ) ); ?>"></input> - - <button class="btn btn-primary download_status_of_new_and_solved" style="color: white;margin-left: 94%;margin-right: 94%;width: 7%;height: 6%;background-color: white;border-color: white;"><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'wsdesk_download.png' ); ?>" style="color: white;width: 30%;height: 60%;background-color: white;border-color: white;"></img> - </button> </h3> - </form> - - </div> - <div class="panel-body"> - <div id="new-solved-status" style="height: 250px;"></div> - <script> - Morris.Area({ - element: 'new-solved-status', - data: <?php echo json_encode( $lines ); ?>, - xkey: 'y', - ykeys: ['a', 'b', 'c', 'd'], - lineColors: ['#0b62a4','<?php echo esc_html( $sol_col ); ?>','#57b755','#e87681'], - labels: ["<?php esc_html_e( 'New Tickets', 'wsdesk' ); ?>", "<?php esc_html_e( 'Solved Tickets', 'wsdesk' ); ?>", "<?php esc_html_e( 'Good Rating', 'wsdesk' ); ?>", "<?php esc_html_e( 'Bad Rating', 'wsdesk' ); ?>"], - behaveLikeLine:true, - resize: true - }); - </script> - </div> - </div> - </div> - </div> - </div> - <div class="col-md-12"> - <div class="panel panel-default" style="border-color: white;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);"> - <div class="panel-heading" style="background-color: white;border-color: white;"> - <h3 class="panel-title"> - <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"> - <?php - - esc_html_e( $message . 'First Reply Average Time', 'wsdesk' ); - ?> - : - <?php - echo esc_html( $user_name ); - if ( 'all' == $user ) { - echo ' ( In Minutes )'; - ?> - <input type="hidden" class="from_date_for_dld_report" name="from_date_for_dld_export_ticket_data_report_first_reply" value="<?php echo esc_html( $from_date ); ?>"> - <input type="hidden" class="to_date_for_dld_report" name="to_date_for_dld_export_ticket_data_report_first_reply" value="<?php echo esc_html( $to_date ); ?>"> - <input type="hidden" name="action" value="eh_crm_export_ticket_data_report_first_reply"> - <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>"> - <input type="hidden" class="user_for_dld_report" name="user_for_dld_export_ticket_data_report_first_reply" value="<?php echo esc_html( $user ); ?>"></input> - <button class="btn btn-primary export_ticket_data_report_first_reply" style="color: white;margin-left: 94%;margin-right: 94%;width: 7%;height: 6%;background-color: white;border-color: white;"><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'wsdesk_download.png' ); ?>" style="color: white;width: 30%;height: 60%;background-color: white;border-color: white;"></img> - </button></h3> - </form> - <?php - } - ?> - - </h3> - </div> - <div class="panel-body"> - <div class="col-md-12"> - <?php - $data_need_to_manipulated = eh_crm_first_reply_avg_time( $user, $from_date, $to_date ); - ?> - <div class="panel-body"> - <div id="days-ticket" style="height: 250px;"></div> - <script> - Morris.Bar({ - barSizeRatio:0.2, - element: 'days-ticket', - data: <?php echo json_encode( $data_need_to_manipulated ); ?>, - xkey: 'ticket_assignee', - ykeys: ['first_reply_time'], - labels: ["<?php esc_html_e( 'Minutes', 'wsdesk' ); ?>", "<?php esc_html_e( 'Agent', 'wsdesk' ); ?>"], - resize:true - }); - </script> - </div> - </div> - </div> - </div> - </div> - <div class="row" style="padding-top: 10px;"> - <div class="col-md-12"> - <div class="col-md-12"> - <div class="panel panel-default" style="border-color: white;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);"> - <div class="panel-heading" style="background-color: white;border-color: white;"> - <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"> - <h3 class="panel-title"><?php esc_html_e( $message . 'Satisfaction Survey', 'wsdesk' ); ?> : <?php echo esc_html( $user_name ); ?></h3> - <input type="hidden" class="from_date_for_dld_report" name="from_date_for_dld_report" value="<?php echo esc_html( $from_date ); ?>"> - <input type="hidden" class="to_date_for_dld_report" name="to_date_for_dld_report" value="<?php echo esc_html( $to_date ); ?>"> - <input type="hidden" name="action" value="eh_crm_download_status_of_good_bad"> - <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>"> - <input type="hidden" class="user_for_dld_report" name="user_for_dld_report" value="<?php echo esc_html( $user ); ?>"></input> - <button class="btn btn-primary download_status_of_good_bad" style="color: white;margin-left: 94%;margin-right: 94%;width: 7%;height: 6%;background-color: white;border-color: white;"><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'wsdesk_download.png' ); ?>" style="color: white;width: 30%;height: 60%;background-color: white;border-color: white;"></img> - </button> </h3> - </form> - - - </div> - <div class="panel-body"> - <div class="col-md-12"> - <div class="col-md-6"> - <div id="assignee-satisfaction" style="height: 250px"></div> - <script> - Morris.Donut({ - element: 'assignee-satisfaction', - data: <?php echo json_encode( $donut_satisfaction ); ?>, - <?php echo ( ( ! empty( $donut_satisfaction_color ) ) ? 'colors: ' . wp_json_encode( $donut_satisfaction_color ) . ',' : '' ); ?> - resize:true - }); - </script> - </div> - <div class="col-md-6"> - <div class="panel panel-default"> - - <table cellspacing="0" cellpadding="0" class="table table-hover" style="box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);border: none !important;"> - <?php - $total_rating = 0; - $count = count( $donut_satisfaction ) + 1; - - for ( $i = 0;$i < $count;$i++ ) { - - if ( 2 !== $i ) { - $total_rating = $donut_satisfaction[ $i ]['value'] + $total_rating; - if ( 'Good' === $donut_satisfaction[ $i ]['label'] ) { - $good_rating = $donut_satisfaction[ $i ]['value']; - } - if ( 'Bad' === $donut_satisfaction[ $i ]['label'] ) { - $bad_rating = $donut_satisfaction[ $i ]['value']; - } - if ( 0 !== $total_rating ) { - $score = round( ( $good_rating / $total_rating ) * 100, 2 ); - - } else { - $score = 0; - }if ( ! isset( $bad_rating ) ) { - $bad_rating = 0; - }if ( 0 !== $bad_rating && 0 === $good_rating ) { - $score = 0; - } - if ( $score <= 100 && $score >= 90 ) { - $class = 'progress-bar-success'; - } elseif ( $score < 90 && $score >= 70 ) { - $class = 'progress-bar-info'; - } elseif ( $score < 70 && $score >= 50 ) { - $class = 'progress-bar-warning'; - } elseif ( $score < 50 ) { - $class = 'progress-bar-danger'; - } - } - if ( ! empty( $color ) ) { - if ( 2 !== $i ) { - echo "<tr style='background:" . esc_html( $donut_satisfaction_color[ $i ] ) . "'>"; - } - } else { - echo "<tr style='background:white'>"; - }if ( 2 === $i ) { - ?> - - <td style="width:150px;"><b>Total Customer Response</b></td><td> <?php echo esc_html( $good_rating + $bad_rating ); ?></td> - <td style="width:150px;"><b>Satisfaction Score</b></td> - - <?php - if ( 0 !== $score ) { - ?> - <td> - <h4 style="color:green;font-size: 30px;"> - <?php echo( esc_html( $score . ' %' ) ); ?> - </h4> - </td> - <?php - - } else { - ?> - <td> - <h4 style="color:green;font-size: 10px;"> - <?php esc_html_e( 'No Ratings', 'wsdesk' ); ?> - </h4> - </td> - <?php - } - echo '</tr>'; - } else { - echo '<td><b>' . esc_html( $donut_satisfaction[ $i ]['label'] ) . '</td></b>'; - echo '<td>' . esc_html( $donut_satisfaction[ $i ]['value'] ) . '</td>'; - echo '<td></td>'; - echo '<td></td>'; - echo '</tr>'; - } - } - - ?> - </table> - </div> - - </div> - </div> - </div> - </div> - </div> - </div> - </div> - <div class="row" style="margin-right: 0px;margin-left: 0px;"> - <div class="col-md-12"> - <div class="panel panel-default" style="border-color: white;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);"> - <div class="panel-heading" style="background-color: white;border-color: white;"> - - <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"> - - <?php if ( 'all' === $user ) { ?> - <h3 class="panel-title"><?php esc_html_e( $message . 'Status of Solved Tickets: All Average Solving Time in Minutes ', 'wsdesk' ); ?> - <input type="hidden" class="from_date_for_dld_report" name="from_date_for_dld_report_new_satisfaction" value="<?php echo esc_html( $from_date ); ?>"> - <input type="hidden" class="to_date_for_dld_report" name="to_date_for_dld_report_new_satisfaction" value="<?php echo esc_html( $to_date ); ?>"> - <input type="hidden" name="action" value="eh_crm_download_status_of_new_satisfaction"> - <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>"> - <input type="hidden" class="user_for_dld_report" name="user_for_dld_report_new_satisfaction" value="<?php echo esc_html( $user ); ?>"></input> - <button class="btn btn-primary download_status_of_new_donut" style="color: white;margin-left: 94%;margin-right: 94%;width: 7%;height: 6%;background-color: white;border-color: white;"><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'wsdesk_download.png' ); ?>" style="color: white;width: 30%;height: 60%;background-color: white;border-color: white;"></img> - <?php } ?> - </form> - </div> - <div class="panel-body"> - <?php if ( 'all' === $user ) { ?> - <div id="avg_resolution" style="height: 250px;"></div> - <script> - Morris.Bar({ - barSizeRatio:0.2, - element: 'avg_resolution', - data: <?php echo wp_json_encode( $bar_avg_time ); ?>, - xkey: ['1'], - ykeys: ['0','2'], - labels: ["<?php esc_html_e( 'Avg Solving time', 'wsdesk' ); ?>", "<?php esc_html_e( 'Solved Tickets', 'wsdesk' ); ?>"], - barShape:'soft', - xLabelAngle:50, - resize:true - }); - </script> - <?php - } - if ( 'all' !== $user ) { - ?> - - <h3> - <?php - esc_html_e( 'Average Resolution Time of ', 'wsdesk' ); - esc_html_e( $user_name, 'wsdesk' ); - ?> - </h3> - <h5> - <?php - echo esc_html( $bar_avg_time[0] ) . ' ' . esc_html__( 'Days', 'wsdesk' ) . ' ' . esc_html( $bar_avg_time[1] ) . ' ' . esc_html__( 'Hours', 'wsdesk' ) . ' ' . esc_html( $bar_avg_time[2] ) . ' ' . esc_html__( 'Minutes', 'wsdesk' ); - ?> - </h5> - <?php } ?> - </div> - </div> - </div> - </div> - </div> - </div> - </div> - <?php - $html = ob_get_clean(); - return $html; -} -function wsdesk_woo_reports_view_section() { - ob_start(); - $pro_bar = eh_crm_woo_products_generate_bar_values(); - $cat_bar = eh_crm_woo_category_generate_bar_values(); - ?> - <div class="container wrapper" id="woo_reports_page_view"> - <div class="row"> - <div class="col-md-12"> - <div class="panel panel-default woo_reports_panel"> - <div class="panel-heading"> - <h3 class="panel-title"><?php esc_html_e( 'WSDesk - WooCommerce Reports', 'wsdesk' ); ?></h3> - </div> - <div class="row" style="padding-top: 10px;"> - <div class="col-md-12"> - <div class="col-md-12"> - <div class="panel panel-default"> - <div class="panel-heading"> - <h3 class="panel-title"><?php esc_html_e( 'Last 7 Days status of new tickets', 'wsdesk' ); ?> : <span id="change_product_name"><?php esc_html_e( 'Top Products', 'wsdesk' ); ?></span></h3> - </div> - <div class="panel-body" id="reports_panel_body" style="text-align: center"> - <div class="loader" id="woo_product_loader"></div> - <span class="help-block"><?php esc_html_e( 'Select the Product(s) to show report?', 'wsdesk' ); ?></span> - <select id="show_product" multiple name="show_product" style="display: inline !important;" class="form-control" aria-describedby="helpBlock"> - <?php - $field = eh_crm_get_settings( array( 'slug' => 'woo_product' ) ); - if ( $field ) { - $field_meta = eh_crm_get_settingsmeta( $field[0]['settings_id'], 'field_values' ); - foreach ( $field_meta as $key => $value ) { - echo '<option value="' . esc_attr( $key ) . '">' . esc_html( $value ) . '</option>'; - } - } - ?> - </select> - <br> - <button style="margin-top: 10px" class="btn btn-primary" id="woo_product_report_custom"><?php esc_html_e( 'Show Report', 'wsdesk' ); ?></button> - </div> - <div id="7days-woo-product-ticket" style="height: 250px;"></div> - <script> - var woo_product_bar_chart = Morris.Bar({ - element: '7days-woo-product-ticket', - data: <?php echo wp_json_encode( $pro_bar ); ?>, - xkey: 'y', - ykeys: ['a'], - labels: ["<?php esc_html_e( 'Tickets', 'wsdesk' ); ?>", "<?php esc_html_e( 'Product', 'wsdesk' ); ?>"], - resize:true - }); - </script> - </div> - </div> - </div> - </div> - <div class="row" style="padding-top: 10px;"> - <div class="col-md-12"> - <div class="col-md-12"> - <div class="panel panel-default"> - <div class="panel-heading"> - <h3 class="panel-title"><?php esc_html_e( 'Last 7 Days status of new tickets', 'wsdesk' ); ?> : <span id="change_product_name"><?php esc_html_e( 'Top Categories', 'wsdesk' ); ?></span></h3> - </div> - <div class="panel-body" id="reports_panel_body" style="text-align: center"> - <div class="loader" id="woo_category_loader"></div> - <span class="help-block"><?php esc_html_e( 'Select the Category(s) to show report?', 'wsdesk' ); ?></span> - <select id="show_category" multiple name="show_category" style="display: inline !important;" class="form-control" aria-describedby="helpBlock"> - <?php - $cat_field = eh_crm_get_settings( array( 'slug' => 'woo_category' ) ); - if ( $cat_field ) { - $field_meta = eh_crm_get_settingsmeta( $cat_field[0]['settings_id'], 'field_values' ); - foreach ( $field_meta as $key => $value ) { - echo '<option value="' . esc_attr( $key ) . '">' . esc_html( $value ) . '</option>'; - } - } - ?> - </select> - <br> - <button style="margin-top: 10px" class="btn btn-primary" id="woo_category_report_custom"><?php esc_html_e( 'Show Report', 'wsdesk' ); ?></button> - </div> - <div id="7days-woo-category-ticket" style="height: 250px;"></div> - <script> - var woo_category_bar_chart = Morris.Bar({ - element: '7days-woo-category-ticket', - data: <?php echo wp_json_encode( $cat_bar ); ?>, - xkey: 'y', - ykeys: ['a'], - labels: ["<?php esc_html_e( 'Tickets', 'wsdesk' ); ?>", "<?php esc_html_e( 'Category', 'wsdesk' ); ?>"], - resize:true - }); - </script> - </div> - </div> - </div> - </div> - </div> - </div> - </div> - </div> - <?php - $html = ob_get_clean(); - return $html; -} -function wsdesk_date_wise_view_section() { - ob_start(); - $duration = ( isset( $_GET['duration'] ) ? sanitize_text_field( $_GET['duration'] ) : 'last_7' ); - $from_date = ( isset( $_GET['from_date'] ) ? sanitize_text_field( $_GET['from_date'] ) : gmdate( 'Y-m-d', time() - ( 7 * 86400 ) ) ); - $to_date = ( isset( $_GET['to_date'] ) ? sanitize_text_field( $_GET['to_date'] ) : gmdate( 'Y-m-d', time() ) ); - if ( strtotime( $to_date ) < strtotime( $from_date ) ) { - $to_date = gmdate( 'Y-m-d', time() ); - $from_date = gmdate( 'Y-m-d', time() - ( 7 * 86400 ) ); - echo "<script>alert('From Date cannot be beyond To Date.')</script>"; - } - switch ( $duration ) { - case 'last_7': - $message = 'Last 7 Days'; - break; - case 'last_30': - $message = 'Last 30 Days'; - break; - case 'custom': - $message = "$from_date to $to_date"; - } - $donut = eh_crm_generate_donut_values_tags( $from_date, $to_date ); - ?> - <div class="container wrapper" id="reports_page_view"> - <div class="row"> - <div class="col-md-12"> - <div class="panel panel-default reports_panel"> - <div class="panel-heading"> - <h3 class="panel-title"><?php esc_html_e( 'WSDesk - Date Wise Reports', 'wsdesk' ); ?></h3> - </div> - <div class="panel-body" id="reports_panel_body" style="text-align: center"> - <form method="GET" action="<?php echo esc_url( admin_url() ) . 'admin.php?page=wsdesk_reports&tab=date_wise'; ?>"> - <input type="hidden" name="page" id="page" value="wsdesk_reports"> - <input type="hidden" name="tab" id="tab" value="date_wise"> - <span class="help-block"><?php esc_html_e( 'Select the Duration:', 'wsdesk' ); ?></span> - <select id="duration" name="duration" style="display: inline !important;" class="form-control" aria-describedby="helpBlock"> - <option value="last_7" <?php echo ( 'last_7' === $duration ) ? 'selected' : ''; ?>><?php esc_html_e( 'Last 7 Days', 'wsdesk' ); ?></option> - <option value="last_30" <?php echo ( 'last_30' === $duration ) ? 'selected' : ''; ?>><?php esc_html_e( 'Last 30 Days', 'wsdesk' ); ?></option> - <option value="custom" <?php echo ( 'custom' === $duration ) ? 'selected' : ''; ?>><?php esc_html_e( 'Custom', 'wsdesk' ); ?></option> - </select> - - <?php - switch ( $duration ) { - case 'custom': - $display = 'inline'; - break; - - default: - $display = 'none'; - break; - } - ?> - <div class = "from_date" style="display: <?php echo esc_html( $display ); ?>;"> - <span class="help-block"><?php esc_html_e( 'Select the From Date:', 'wsdesk' ); ?></span> - <input style="width: 30%; display: inline !important;" value="<?php echo esc_html( $from_date ); ?>" type="date" name="from_date" id="from_date" class="form-control" aria-describedby="helpBlock"> - </div> - <div class="to_date" style="display: <?php echo esc_html( $display ); ?>"> - <span class="help-block"><?php esc_html_e( 'Select the To Date:', 'wsdesk' ); ?></span> - <input style="width: 30%; display: inline !important;" value="<?php echo esc_html( $to_date ); ?>" type="date" name="to_date" id="to_date" class="form-control" aria-describedby="helpBlock"> - </div> - <br> - <input type="submit" style="margin-top: 10px" class="btn btn-primary" value="<?php esc_html_e( 'Show Report', 'wsdesk' ); ?>"> - </form> - </div> - <div class="row" style="padding-top: 10px;"> - <div class="col-md-12"> - <div class="col-md-3"> - </div> - <div class="col-md-6"> - <div class="panel panel-default"> - <div class="panel-heading"> - <h3 class="panel-title"><?php esc_html_e( $message . 'Status of Tickets by Tags', 'wsdesk' ); ?></h3> - </div> - <div class="panel-body"> - <div class="col-md-12"> - <div class="col-md-6"> - <div id="date_wise" style="height: 250px;"></div> - <script> - Morris.Donut({ - element: 'date_wise', - data: <?php echo wp_json_encode( $donut ); ?>, - resize:true - }); - </script> - </div> - <div class="col-md-6"> - <div class="panel panel-default"> - <table class="table table-hover"> - <?php - for ( $i = 0;$i < count( $donut );$i++ ) { - if ( ! empty( $color ) ) { - echo "<tr style='background:" . esc_html( $color[ $i ] ) . "'>"; - } else { - echo '<tr>'; - } - echo '<td>' . esc_html( $donut[ $i ] )['label'] . '</td>'; - echo '<td>' . esc_html( $donut[ $i ] )['value'] . '</td>'; - echo '</tr>'; - } - ?> - </table> - </div> - </div> - </div> - </div> - </div> - </div> - <div class="col-md-3"> - </div> - </div> - </div> - </div> - </div> - </div> - </div> - <?php - -$html = ob_get_clean(); -return $html; -} +<?php+echo '<div class="wsdesk_wrapper">';++function eh_crm_reports_page_tabs( $current = 'agent' ) {+ $tabs = array(+ 'agent' => esc_html__( 'Agents Reports', 'wsdesk' ),+ 'date_wise' => esc_html__( 'Date wise Reports', 'wsdesk' ),+ );+ if ( EH_CRM_WOO_STATUS ) {+ $tabs['woocommerce'] = esc_html__( 'WooCommerce Reports', 'wsdesk' );+ }+ ?>+ <h2 class="nav-tab-wrapper" style="margin-right:20px;">+ <?php+ foreach ( $tabs as $tab => $name ) {+ $class = ( $tab === $current ) ? 'nav-tab-active' : '';+ $style = ( $tab === $current ) ? '' : '';+ ?>+ <a style='text-decoration:none !important; <?php echo esc_html( $style ); ?>' class='nav-tab <?php echo esc_html( $class ); ?>' href='?page=wsdesk_reports&tab= <?php echo esc_html( $tab ); ?>' ></a>+ <?php+ }+ ?>+ </h2>+ <?php+}+ eh_crm_reports_page_tabs( ( ! empty( $_GET['tab'] ) ) ? esc_attr( sanitize_text_field( $_GET['tab'] ) ) : 'agent' );+if ( 'agent' == ( ! empty( $_GET['tab'] ) ) ? esc_attr( sanitize_text_field( $_GET['tab'] ) ) : 'agent' ) {+ ?>+ <div class="table-box table-box-main" id='agent_section' style="margin-top: 10px;">+ <?php wsdesk_agents_reports_view_section(); ?>+ </div>+ </div>+ <?php+} elseif ( 'date_wise' === ( ! empty( $_GET['tab'] ) ) ? esc_attr( sanitize_text_field( $_GET['tab'] ) ) : 'agent' ) {+ ?>+ <div class="table-box table-box-main" id='woocommerce_section' style="margin-top: 10px;">+ <?php wsdesk_date_wise_view_section(); ?>+ </div>+ <?php+} else {+ ?>+ <div class="table-box table-box-main" id='woocommerce_section' style="margin-top: 10px;">+ <?php wsdesk_woo_reports_view_section(); ?>+ </div>+ </div>+ <?php+}+function wsdesk_agents_reports_view_section() {+ ob_start();+ $user = ( isset( $_GET['user'] ) ? sanitize_text_field( $_GET['user'] ) : 'all' );+ $duration = ( isset( $_GET['duration'] ) ? sanitize_text_field( $_GET['duration'] ) : 'last_7' );+ $from_date = ( isset( $_GET['from_date'] ) ? sanitize_text_field( $_GET['from_date'] ) : gmdate( 'Y-m-d', time() - ( 7 * 86400 ) ) );+ $to_date = ( isset( $_GET['to_date'] ) ? sanitize_text_field( $_GET['to_date'] ) : gmdate( 'Y-m-d', time() ) );+ if ( strtotime( $to_date ) < strtotime( $from_date ) ) {+ $to_date = gmdate( 'Y-m-d', time() );+ $from_date = gmdate( 'Y-m-d', time() - ( 7 * 86400 ) );+ echo "<script>alert('From Date cannot be beyond To Date.')</script>";+ }+ $user_name = '';+ $sol = eh_crm_get_settings( array( 'slug' => 'label_LL02' ), array( 'settings_id' ) );+ $sol_col = eh_crm_get_settingsmeta( $sol[0]['settings_id'], 'label_color' );+ $color = array();+ switch ( $duration ) {+ case 'last_7':+ $message = __( ' Last 7 Days ', 'wsdesk' );+ break;+ case 'last_30':+ $message = __( ' Last 30 Days ', 'wsdesk' );+ break;+ case 'custom':+ $message = $from_date . __( ' to ', 'wsdesk' ) . $to_date;+ }+ if ( 'all' != $user ) {+ $user_check = get_user_by( 'ID', $user );+ if ( $user_check ) {+ $user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' );+ $role = array_intersect( $user_roles_default, $user_check->roles );+ if ( ! empty( $role ) ) {+ $user_name = $user_check->display_name;+ $bar = eh_crm_generate_bar_values( $user, $from_date, $to_date );+ $donut_data = eh_crm_generate_donut_values( $user, $from_date, $to_date );+ $bar_avg_time = eh_crm_generate_bar_values_Avg( $user, $from_date, $to_date );+ $donut_satisfaction_data = eh_crm_generate_donut_satisfaction_values( $user, $from_date, $to_date );+ $donut = $donut_data['donut'];+ $color = $donut_data['color'];+ $donut_satisfaction = $donut_satisfaction_data['donut'];+ $donut_satisfaction_color = $donut_satisfaction_data['color'];+ $lines = eh_crm_generate_line_values( $user, $from_date, $to_date );++ } else {+ wp_die( sprintf( '<center><h1>' . esc_html__( 'Oops', 'wsdesk' ) . ' !</h1><h4>' . esc_html__( 'User is not having any WSDesk Role', 'wsdesk' ) . '</h4><a href="' . esc_url( admin_url( 'admin.php?page=wsdesk_reports' ) ) . '">' . esc_html__( 'Back to Reports', 'wsdesk' ) . '</a></center>' ) );+ }+ } else {+ wp_die( sprintf( '<center><h1>' . esc_html__( 'Oops', 'wsdesk' ) . ' !</h1><h4>' . esc_html__( 'User not found', 'wsdesk' ) . '</h4><a href="' . esc_url( admin_url( 'admin.php?page=wsdesk_reports' ) ) . '">' . esc_html__( 'Back to Reports', 'wsdesk' ) . '</a></center>' ) );+ }+ } else {+ $user_name = 'All';+ $bar = eh_crm_generate_bar_values( $user, $from_date, $to_date );+ $donut = eh_crm_generate_donut_values( $user, $from_date, $to_date );+ $bar_avg_time = eh_crm_generate_bar_values_Avg( $user, $from_date, $to_date );+ $lines = eh_crm_generate_line_values( $user, $from_date, $to_date );+ $donut_satisfaction_data = eh_crm_generate_donut_satisfaction_values( $user, $from_date, $to_date );+ $donut_satisfaction = $donut_satisfaction_data['donut'];+ $donut_satisfaction_color = $donut_satisfaction_data['color'];+ }+ ?>+ <div class="container wrapper" id="reports_page_view">+ <div class="row">+ <div class="col-md-12">+ <div class="panel panel-default reports_panel">+ <div class="panel-heading">+ <h3 class="panel-title"><?php esc_html_e( 'WSDesk - Agents Reports', 'wsdesk' ); ?></h3>+ </div>+ <div class="panel-body" id="reports_panel_body" style="text-align: center">+ <form method="GET">+ <input type="hidden" name="page" id="page" value="wsdesk_reports">+ <span class="help-block"><?php esc_html_e( 'Select the Agents/Supervisors to show report?', 'wsdesk' ); ?></span>+ <select id="user" name="user" style="display: inline !important;" class="form-control" aria-describedby="helpBlock">+ <option value="all" <?php echo ( 'all' === $user ) ? 'selected' : ''; ?> >All</option>+ <?php+ $user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' );+ $users = get_users( array( 'role__in' => $user_roles_default ) );+ $users_data = array();+ for ( $i = 0; $i < count( $users ); $i++ ) {+ $current = $users[ $i ];+ $id = $current->ID;+ $user_data = new WP_User( $id );+ $users_data[ $i ]['id'] = $id;+ $users_data[ $i ]['name'] = $user_data->display_name;+ }+ for ( $i = 0;$i < count( $users_data );$i++ ) {+ $selected = 'selected';+ echo '<option value="' . esc_attr( $users_data[ $i ]['id'] ) . ( ( $user == $users_data[ $i ]['id'] ) ? esc_html( $selected ) : '' ) . '>' . esc_html( $users_data[ $i ]['name'] ) . '</option>';+ }+ ?>+ </select>+ <span class="help-block"><?php esc_html_e( 'Select the Duration:', 'wsdesk' ); ?></span>+ <select id="duration" name="duration" style="display: inline !important;" class="form-control" aria-describedby="helpBlock">+ <option value="last_7" <?php echo ( 'last_7' == $duration ) ? 'selected' : ''; ?>><?php esc_html_e( 'Last 7 Days', 'wsdesk' ); ?></option>+ <option value="last_30" <?php echo ( 'last_30' == $duration ) ? 'selected' : ''; ?>><?php esc_html_e( 'Last 30 Days', 'wsdesk' ); ?></option>+ <option value="custom" <?php echo ( 'custom' == $duration ) ? 'selected' : ''; ?>><?php esc_html_e( 'Custom', 'wsdesk' ); ?></option>+ </select>++ <?php+ switch ( $duration ) {+ case 'custom':+ $display = 'inline';+ break;++ default:+ $display = 'none';+ break;+ }+ ?>+ <div class = "from_date" style="display: <?php echo esc_html( $display ); ?>;">+ <span class="help-block"><?php esc_html_e( 'Select the From Date:', 'wsdesk' ); ?></span>+ <input style="width: 30%; display: inline !important;" value="<?php echo esc_html( $from_date ); ?>" type="date" name="from_date" id="from_date" class="form-control" aria-describedby="helpBlock">+ </div>+ <div class="to_date" style="display: <?php echo esc_html( $display ); ?>">+ <span class="help-block"><?php esc_html_e( 'Select the To Date:', 'wsdesk' ); ?></span>+ <input style="width: 30%; display: inline !important;" value="<?php echo esc_html( $to_date ); ?>" type="date" name="to_date" id="to_date" class="form-control" aria-describedby="helpBlock">+ </div>+ <br>+ <input type="submit" style="margin-top: 10px" class="btn btn-primary" value="<?php esc_html_e( 'Show Report', 'wsdesk' ); ?>">++ </form>+ <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>">++ <input type="hidden" class="from_date_for_dld_report" name="from_date_for_dld_report_full" value="<?php echo esc_html( $from_date ); ?>">+ <input type="hidden" class="to_date_for_dld_report" name="to_date_for_dld_report_full" value="<?php echo esc_html( $to_date ); ?>">+ <input type="hidden" name="action" value="eh_crm_export_ticket_data_report">+ <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>">+ <input type="hidden" class="user_for_dld_report" name="user_for_dld_report_full" value="<?php echo esc_html( $user ); ?>"></input>+ <input type="submit" style="margin-top: 10px" class="btn btn-primary" value="<?php esc_html_e( 'Download Report', 'wsdesk' ); ?>">+ </form>+ </div>+ <div class="row" style="padding-top: 10px;">+ <div class="col-md-12">+ <div class="col-md-6">+ <div class="panel panel-default" style="border-color: white;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);">+ <div class="panel-heading" style="background-color: white;border-color: white;">+ <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>">+ <h3 class="panel-title"><?php esc_html_e( $message . 'Status of New Tickets', 'wsdesk' ); ?> : <?php echo esc_html( $user_name ); ?>+ <input type="hidden" class="from_date_for_dld_report" name="from_date_for_dld_report_new" value="<?php echo esc_html( $from_date ); ?>">+ <input type="hidden" class="to_date_for_dld_report" name="to_date_for_dld_report_new" value="<?php echo esc_html( $to_date ); ?>">+ <input type="hidden" name="action" value="eh_crm_download_status_of_new">+ <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>">+ <input type="hidden" class="user_for_dld_report" name="user_for_dld_report_new" value="<?php echo esc_html( $user ); ?>"></input>+ <button class="btn btn-primary download_status_of_new" style="color: white;width: 6%;height: 3%;margin-left: 90%;margin-right: 90%;background-color: white;border-color: white;"><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'wsdesk_download.png' ); ?>" style="color: white;width: 200%;height: 200%;background-color: white;border-color: white;"></img>+ </button> </h3>+ </form>+ </div>+ <div class="panel-body">+ <div id="7days-ticket" style="height: 250px;"></div>+ <script>+ Morris.Bar({+ element: '7days-ticket',+ data: <?php echo json_encode( $bar ); ?>,+ xkey: 'y',+ ykeys: ['a'],+ labels: ["<?php esc_html_e( 'Tickets', 'wsdesk' ); ?>", "<?php esc_html_e( 'Date', 'wsdesk' ); ?>"],+ resize:true+ });+ </script>+ </div>+ </div>+ </div>++ <div class="col-md-6" div class="col-md-6">+ <div class="panel panel-default" style="border-color: white;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);">+ <div class="panel-heading" style="background-color: white;border-color: white;">+ <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>">+ <h3 class="panel-title" ><?php esc_html_e( $message . 'Status of Agent Tickets', 'wsdesk' ); ?> : <?php echo esc_html( $user_name ); ?>+ <input type="hidden" class="from_date_for_dld_report" name="from_date_for_dld_report_new_donut" value="<?php echo esc_html( $from_date ); ?>">+ <input type="hidden" class="to_date_for_dld_report" name="to_date_for_dld_report_new_donut" value="<?php echo esc_html( $to_date ); ?>">+ <input type="hidden" name="action" value="eh_crm_download_status_of_new_donut">+ <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>">+ <input type="hidden" class="user_for_dld_report" name="user_for_dld_report_new_donut" value="<?php echo esc_html( $user ); ?>">++ </input>++ <button class="btn btn-primary download_status_of_new_donut" style="color: white;margin-left: 90%;margin-right: 90%;width: 6%;height: 3%;background-color: white;border-color: white;"><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'wsdesk_download.png' ); ?>" style="color: white;width: 200%;height: 200%;background-color: white;border-color: white;"></img>+ </button> </h3>+ </form>++ </div>+ <div class="panel-body">+ <div class="col-md-12">+ <div class="col-md-6">+ <div id="assignee-contribution" style="height: 250px;"></div>+ <script>+ Morris.Donut({+ element: 'assignee-contribution',+ data: <?php echo json_encode( $donut ); ?>,+ <?php echo ( ( ! empty( $color ) ) ? 'colors: ' . json_encode( $color ) . ',' : '' ); ?>+ resize:true+ });+ </script>+ </div>+ <div class="col-md-6">+ <div class="panel panel-default">+ <table class="table table-hover" style="border-color: white;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);">+ <?php
Analyzing the provided diff for security vulnerabilities:
Vulnerability Existed: yes
FALSE POSITIVE
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - CWE-79 - views/crm_reports_view.php - Lines 565-581
Old Code:
```php
switch ( $duration ) {
case 'last_7':
$message = 'Last 7 Days';
break;
case 'last_30':
$message = 'Last 30 Days';
break;
case 'custom':
$message = "$from_date to $to_date";
}
```
Fixed Code:
```php
switch ( $duration ) {
case 'last_7':
$message = __( ' Last 7 Days ', 'wsdesk' );
break;
case 'last_30':
$message = __( ' Last 30 Days ', 'wsdesk' );
break;
case 'custom':
$message = $from_date . __( ' to ', 'wsdesk' ) . $to_date;
}
```
Explanation:
The `$message` variable constructed from `$from_date` and `$to_date` is later output directly in HTML context without proper escaping in the custom case. Although the date inputs are sanitized via `sanitize_text_field()`, the message is embedded in HTML content where it needs escaping. The old code at line 565 concatenates unsanitized user input into `$message` which is then used in subsequent output statements. The fix wraps translatable strings with `__()` function, though this alone doesn't fully prevent XSS - the actual output statements also needed `esc_html()` wrapping, which appears to have been addressed elsewhere in the file's output context.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/crm_settings_view.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/crm_settings_view.php 2025-12-21 09:36:35.507308439 +0000@@ -1,158 +1,158 @@-<?php -echo '<div class="wsdesk_wrapper">'; - -$plugin_name = 'wsdesk'; -$mail = get_option( $plugin_name . '_email' ); -$licence_key = get_option( $plugin_name . '_licence_key' ); -$instance = get_option( $plugin_name . '_instance_id' ); -$show_activation = ( ! empty( get_option( $plugin_name . '_activation_status' ) ) && 'inactive' != get_option( $plugin_name . '_activation_status' ) ) ? 'hidden' : ''; -$show_deactivation = ( empty( get_option( $plugin_name . '_activation_status' ) ) || 'inactive' == get_option( $plugin_name . '_activation_status' ) ) ? 'hidden' : ''; -?> -<div id="result" class="aw-result-box"><?php esc_html_e( 'WSDesk Activate Msg', 'wsdesk' ); ?></div> -<div class="container"> - <div class="row"> - <ol class="breadcrumb crm-panel-right" style="margin-left: 0 !important;"> - <li><?php esc_html_e( 'Settings', 'wsdesk' ); ?></li> - <li id="breadcrump_section" class="active"><?php esc_html_e( 'General', 'wsdesk' ); ?></li> - </ol> - <div class="col-md-3 crm-panel-left"> - <div class="panel panel-default crm-panel"> - <div class="panel-body"> - <ul class="nav nav-pills nav-stacked" role="tablist"> - <li class="active"> - <a href="#general_tab" data-toggle="tab" class="general"><?php esc_html_e( 'General', 'wsdesk' ); ?></a> - </li> - <li> - <a href="#ticket_fields_tab" data-toggle="tab" class="ticket_fields"><?php esc_html_e( 'Ticket Settings', 'wsdesk' ); ?></a> - </li> - <li> - <a href="#appearance_tab" data-toggle="tab" class="appearance"><?php esc_html_e( 'Form Settings', 'wsdesk' ); ?></a> - </li> - <li> - <a href="#integrations_tab" data-toggle="tab" class="integrations"><?php esc_html_e( 'Integrations', 'wsdesk' ); ?></a> - - </li> - <li> - <a href="#triggers_tab" data-toggle="tab" class="wsdesk_triggers"><?php esc_html_e( 'Triggers & Automation', 'wsdesk' ); ?></a> - </li> - <li> - <a href="#backup_restore_tab" data-toggle="tab" class="backup_restore"><?php esc_html_e( 'Data Management', 'wsdesk' ); ?></a> - </li> - </ul> - </div> - </div> - <div class="alert alert-success" style="display: none" role="alert"> - <div id="success_alert_text"></div> - </div> - <div class="alert alert-danger" style="display: none" role="alert"> - <div id="danger_alert_text"></div> - </div> - </div> - <div class="col-md-9 wsdesk_general_settings"> - <div class="panel panel-default crm-panel"> - <div class="panel-body"> - <ul id="myTabs" class="nav nav-pills nav-justified" role="tablist" data-tabs="tabs"> - - <li class="active general_submenu"> - <a href="#general_tab" data-toggle="tab" class="general general_submenu"><?php esc_html_e( 'Basic Settings', 'wsdesk' ); ?></a> - </li> - <li class="advanced"> - <a href="#advanced_tab" data-toggle="tab" class="advanced"><?php esc_html_e( 'Advanced Settings', 'wsdesk' ); ?></a> - </li> - </ul> - </div> - </div> - </div> - <div class="col-md-9 wsdesk_advanced_settings"> - <div class="panel panel-default crm-panel"> - <div class="panel-body"> - <ul id="myTabs" class="nav nav-pills nav-justified" role="tablist" data-tabs="tabs"> - - <li class="active backup_restore_sub_menu"> - <a href="#backup_restore_tab" data-toggle="tab" class="backup_restore backup_restore_sub_menu"><?php esc_html_e( 'Cleanup, Backup & Restore', 'wsdesk' ); ?></a> - </li> - <li class="export"> - <a href="#export_tab" data-toggle="tab" class="export"><?php esc_html_e( 'Export Data (CSV)', 'wsdesk' ); ?></a> - </li> - <li class="archive"> - <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" data-toggle="tab" class="archive"><?php esc_html_e( 'Archive Tickets', 'wsdesk' ); ?><span class="premium_update_setting"><sup class="text-success">[Premium!]</sup></span></a> - </li> - </ul> - </div> - </div> - </div> - <div class="col-md-9 wsdesk_ticket_settings"> - <div class="panel panel-default crm-panel"> - <div class="panel-body"> - <ul id="myTabs" class="nav nav-pills nav-justified" role="tablist" data-tabs="tabs"> - - <li class="active ticket_fields_submenu"> - <a href="#ticket_fields_tab" data-toggle="tab" class="ticket_fields ticket_fields_submenu"><?php esc_html_e( 'Ticket Fields', 'wsdesk' ); ?></a> - </li> - <li class="ticket_labels"> - <a href="#ticket_labels_tab" data-toggle="tab" class="ticket_labels"><?php esc_html_e( 'Ticket Status', 'wsdesk' ); ?></a> - </li> - <li class="ticket_tags"> - <a href="#ticket_tags_tab" data-toggle="tab" class="ticket_tags"><?php esc_html_e( 'Ticket Tags', 'wsdesk' ); ?></a> - </li> - <li class="ticket_views"> - <a href="#ticket_views_tab" data-toggle="tab" class="ticket_views"><?php esc_html_e( 'Ticket Views', 'wsdesk' ); ?></a> - </li> - <li class="ticket_page"> - <a href="#ticket_page_tab" data-toggle="tab" class="ticket_page"><?php esc_html_e( 'Ticket Page', 'wsdesk' ); ?></a> - </li> - </ul> - </div> - </div> - </div> - <div class="col-md-9"> - <div class="panel panel-default crm-panel"> - <div class="panel-body" style="padding: 5px !important"> - <div class="tab-content"> - <div class="loader"></div> - <div class="tab-pane active general_settings" id="general_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_general.php' ; ?> - </div> - <div class="tab-pane" id="ticket_fields_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_fields.php' ; ?> - </div> - <div class="tab-pane" id="ticket_labels_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_labels.php' ; ?> - </div> - <div class="tab-pane" id="ticket_tags_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_tags.php' ; ?> - </div> - <div class="tab-pane" id="ticket_views_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_views.php' ; ?> - </div> - <div class="tab-pane" id="ticket_page_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_page.php' ; ?> - </div> - <div class="tab-pane" id="triggers_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_wsdesk_triggers.php' ; ?> - </div> - <div class="tab-pane" id="appearance_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_appearance.php' ; ?> - </div> - <div class="tab-pane" id="integrations_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_integrations.php' ; ?> - </div> - <div class="tab-pane" id="backup_restore_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_backup_restore.php' ; ?> - </div> - <div class="tab-pane" id="export_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_export.php' ; ?> - </div> - <div class="tab-pane" id="archive_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_archive_tickets.php' ; ?> - </div> - <div class="tab-pane general_settings" id="advanced_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_lite_mode.php' ; ?> - </div> - </div> - </div> - </div> - </div> - </div> -</div> -</div> +<?php+echo '<div class="wsdesk_wrapper">';++$plugin_name = 'wsdesk';+$mail = get_option( $plugin_name . '_email' );+$licence_key = get_option( $plugin_name . '_licence_key' );+$instance = get_option( $plugin_name . '_instance_id' );+$show_activation = ( ! empty( get_option( $plugin_name . '_activation_status' ) ) && 'inactive' != get_option( $plugin_name . '_activation_status' ) ) ? 'hidden' : '';+$show_deactivation = ( empty( get_option( $plugin_name . '_activation_status' ) ) || 'inactive' == get_option( $plugin_name . '_activation_status' ) ) ? 'hidden' : '';+?>+<div id="result" class="aw-result-box"><?php esc_html_e( 'WSDesk Activate Msg', 'wsdesk' ); ?></div>+<div class="container">+ <div class="row">+ <ol class="breadcrumb crm-panel-right" style="margin-left: 0 !important;">+ <li><?php esc_html_e( 'Settings', 'wsdesk' ); ?></li>+ <li id="breadcrump_section" class="active"><?php esc_html_e( 'General', 'wsdesk' ); ?></li>+ </ol>+ <div class="col-md-3 crm-panel-left">+ <div class="panel panel-default crm-panel">+ <div class="panel-body">+ <ul class="nav nav-pills nav-stacked" role="tablist">+ <li class="active">+ <a href="#general_tab" data-toggle="tab" class="general"><?php esc_html_e( 'General', 'wsdesk' ); ?></a>+ </li>+ <li>+ <a href="#ticket_fields_tab" data-toggle="tab" class="ticket_fields"><?php esc_html_e( 'Ticket Settings', 'wsdesk' ); ?></a>+ </li>+ <li>+ <a href="#appearance_tab" data-toggle="tab" class="appearance"><?php esc_html_e( 'Form Settings', 'wsdesk' ); ?></a>+ </li>+ <li>+ <a href="#integrations_tab" data-toggle="tab" class="integrations"><?php esc_html_e( 'Integrations', 'wsdesk' ); ?></a>+ + </li>+ <li>+ <a href="#triggers_tab" data-toggle="tab" class="wsdesk_triggers"><?php esc_html_e( 'Triggers & Automation', 'wsdesk' ); ?></a>+ </li>+ <li>+ <a href="#backup_restore_tab" data-toggle="tab" class="backup_restore"><?php esc_html_e( 'Data Management', 'wsdesk' ); ?></a>+ </li>+ </ul>+ </div>+ </div>+ <div class="alert alert-success" style="display: none" role="alert">+ <div id="success_alert_text"></div>+ </div>+ <div class="alert alert-danger" style="display: none" role="alert">+ <div id="danger_alert_text"></div>+ </div>+ </div>+ <div class="col-md-9 wsdesk_general_settings">+ <div class="panel panel-default crm-panel">+ <div class="panel-body">+ <ul id="myTabs" class="nav nav-pills nav-justified" role="tablist" data-tabs="tabs">++ <li class="active general_submenu">+ <a href="#general_tab" data-toggle="tab" class="general general_submenu"><?php esc_html_e( 'Basic Settings', 'wsdesk' ); ?></a>+ </li>+ <li class="advanced">+ <a href="#advanced_tab" data-toggle="tab" class="advanced"><?php esc_html_e( 'Advanced Settings', 'wsdesk' ); ?></a>+ </li>+ </ul>+ </div>+ </div>+ </div>+ <div class="col-md-9 wsdesk_advanced_settings">+ <div class="panel panel-default crm-panel">+ <div class="panel-body">+ <ul id="myTabs" class="nav nav-pills nav-justified" role="tablist" data-tabs="tabs">++ <li class="active backup_restore_sub_menu">+ <a href="#backup_restore_tab" data-toggle="tab" class="backup_restore backup_restore_sub_menu"><?php esc_html_e( 'Cleanup, Backup & Restore', 'wsdesk' ); ?></a>+ </li>+ <li class="export">+ <a href="#export_tab" data-toggle="tab" class="export"><?php esc_html_e( 'Export Data (CSV)', 'wsdesk' ); ?></a>+ </li>+ <li class="archive">+ <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" data-toggle="tab" class="archive"><?php esc_html_e( 'Archive Tickets', 'wsdesk' ); ?><span class="premium_update_setting"><sup class="text-success">[Premium!]</sup></span></a>+ </li>+ </ul>+ </div>+ </div>+ </div>+ <div class="col-md-9 wsdesk_ticket_settings">+ <div class="panel panel-default crm-panel">+ <div class="panel-body">+ <ul id="myTabs" class="nav nav-pills nav-justified" role="tablist" data-tabs="tabs">++ <li class="active ticket_fields_submenu">+ <a href="#ticket_fields_tab" data-toggle="tab" class="ticket_fields ticket_fields_submenu"><?php esc_html_e( 'Ticket Fields', 'wsdesk' ); ?></a>+ </li>+ <li class="ticket_labels">+ <a href="#ticket_labels_tab" data-toggle="tab" class="ticket_labels"><?php esc_html_e( 'Ticket Status', 'wsdesk' ); ?></a>+ </li>+ <li class="ticket_tags">+ <a href="#ticket_tags_tab" data-toggle="tab" class="ticket_tags"><?php esc_html_e( 'Ticket Tags', 'wsdesk' ); ?></a>+ </li>+ <li class="ticket_views">+ <a href="#ticket_views_tab" data-toggle="tab" class="ticket_views"><?php esc_html_e( 'Ticket Views', 'wsdesk' ); ?></a>+ </li>+ <li class="ticket_page">+ <a href="#ticket_page_tab" data-toggle="tab" class="ticket_page"><?php esc_html_e( 'Ticket Page', 'wsdesk' ); ?></a>+ </li>+ </ul>+ </div>+ </div>+ </div>+ <div class="col-md-9">+ <div class="panel panel-default crm-panel">+ <div class="panel-body" style="padding: 5px !important">+ <div class="tab-content">+ <div class="loader"></div>+ <div class="tab-pane active general_settings" id="general_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_general.php' ; ?>+ </div>+ <div class="tab-pane" id="ticket_fields_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_fields.php' ; ?>+ </div>+ <div class="tab-pane" id="ticket_labels_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_labels.php' ; ?>+ </div>+ <div class="tab-pane" id="ticket_tags_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_tags.php' ; ?>+ </div>+ <div class="tab-pane" id="ticket_views_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_views.php' ; ?>+ </div>+ <div class="tab-pane" id="ticket_page_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_page.php' ; ?>+ </div>+ <div class="tab-pane" id="triggers_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_wsdesk_triggers.php' ; ?>+ </div>+ <div class="tab-pane" id="appearance_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_appearance.php' ; ?>+ </div>+ <div class="tab-pane" id="integrations_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_integrations.php' ; ?>+ </div>+ <div class="tab-pane" id="backup_restore_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_backup_restore.php' ; ?>+ </div>+ <div class="tab-pane" id="export_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_export.php' ; ?>+ </div>+ <div class="tab-pane" id="archive_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_archive_tickets.php' ; ?>+ </div>+ <div class="tab-pane general_settings" id="advanced_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/crm_settings_lite_mode.php' ; ?>+ </div>+ </div>+ </div>+ </div>+ </div>+ </div>+</div>+</div>
Vulnerability Existed: no No Security Vulnerabilities Detected - views/crm_settings_view.php (All Lines) Old Code: Lines 1-158 (original file content with CRLF line endings) Fixed Code: Lines 1-158 (same file content with LF line endings) Explanation: This diff represents only a line ending conversion from CRLF (Windows-style) to LF (Unix-style). No functional code changes were made, and no security vulnerabilities were introduced or fixed. The file content, logic, and security posture remain identical. The `require` statements use a constant `EH_CRM_MAIN_VIEWS` which mitigates path traversal concerns, and the code properly uses WordPress escaping functions (`esc_html_e()`) for output. This is a formatting/normalization change only.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/crm_tickets_view.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/crm_tickets_view.php 2025-12-21 09:36:35.507308439 +0000@@ -1,104 +1,104 @@-<?php -$default_deep_link = stripslashes( eh_crm_get_settingsmeta( '0', 'default_deep_link' ) ); -if ( $default_deep_link && ! isset( $_GET['filter'] ) && ! isset( $_GET['tid'] ) ) { - $queries = []; - $queries['page'] = 'wsdesk_tickets'; - parse_str( $default_deep_link, $queries ); - - $queries = array_merge( array( 'page' => 'wsdesk_tickets' ), $queries ); - - $url = add_query_arg( $queries, admin_url( 'admin.php' ) ); - - ?> - <script> - const [url] = <?php echo wp_json_encode( [ $url ] ); ?>; - window.location = url; -</script> -<?php - die; -} -echo '<div class="wsdesk_wrapper">'; -$plugin_name = 'wsdesk'; -$tab_head = ''; -$tab_content = ''; -$t_id = ( isset( $_GET['tid'] ) ? sanitize_text_field( $_GET['tid'] ) : false ); -if ( $t_id ) { - $data = eh_crm_get_ticket( - array( - 'ticket_id' => $t_id, - 'ticket_parent' => 0, - ) - ); - if ( $data ) { - $all_section_ids = eh_crm_get_ticket_value_count( 'ticket_parent', 0, false, '', '', 'ticket_updated', 'DESC', '', 0 ); - $pagination_ids = array(); - foreach ( $all_section_ids as $tic ) { - array_push( $pagination_ids, $tic['ticket_id'] ); - } - $tab_head = '<li role="presentation" class="active visible_tab" id="tab_' . $t_id . '" style="min-width:200px;">' . CRM_Ajax::eh_crm_ticket_single_view_gen_head( $t_id ) . '</li>'; - $tab_content = '<div class="tab-pane new-style-tab-pane active direct_load_tid" id="tab_content_' . $t_id . '">' . CRM_Ajax::eh_crm_ticket_single_view_gen( $t_id, $pagination_ids ) . '</div>'; - } else { - ?> - <div class="row" id="alert_for_activation"> - <div class="col-md-12"> - <div class="alert alert-danger aw_wsdesk_activate_alert" role="alert"> - <?php esc_html_e( 'Invalid Ticket Number', 'wsdesk' ); ?> [ <b>#<?php echo esc_html( $t_id ); ?></b> ] - </div> - </div> - </div> - <?php - } -} -?> -<div class="container wrapper" id="tickets_page_view"> - <div class="row"> - <div class="col-md-12"> - <div class="panel with-nav-tabs panel-default"> - <div class="panel-heading col-md-12"> - <ul class="nav nav-tabs col-md-11 elaborate" role="tablist" style="margin-left: 0em;"> - <li class="<?php echo ( '' === $tab_head ) ? 'active' : ''; ?> all_tickets" role="presentation"> - <a id="all_tickets_tab_header" onclick=" ('tickets')" href="#all_tickets_tab" aria-controls="all" style="text-align: center;padding: 13px 15px;margin-right:0px !important;" data-toggle="tab" class="tab_a"> - <?php esc_html_e( 'All Tickets', 'wsdesk' ); ?> - </a> - </li> - <?php echo wp_kses_post( $tab_head ); ?> - <li role="presentation" class="dropdown" style="display: none;"> - <a href="#" id="myTabDrop1" class="dropdown-toggle tab_a" data-toggle="dropdown" aria-controls="myTabDrop1-contents" aria-expanded="true" style="text-align: center;padding: 13px 15px;margin-right:0px !important;"> - <span class="caret"></span> <?php esc_html_e( 'More', 'wsdesk' ); ?></a> - <ul class="dropdown-menu collapse_ul" aria-labelledby="myTabDrop1" id="myTabDrop1-contents"style="overflow-x: hidden"> - </ul> - </li> - </ul> - <div class="col-md-1 nav-tabs"> - <div class="pull-right side_bar"> - <a href="#" class="add-ticket tab_a" style="text-align: center;" data-placement="bottom" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'New Ticket', 'wsdesk' ); ?>" data-container="body"> - <span class="glyphicon glyphicon-plus"></span> - </a> - </div> - <div class="pull-right "> - <div class="input-group stylish-input-group" style="margin: 3px 5px;"> - <input type="text" class="form-control" id="search_ticket_input" placeholder="Search" data-placement="bottom" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Search Ticket', 'wsdesk' ); ?>" data-container="body"> - <span class="glyphicon glyphicon-search clickable form-control-feedback" id="search_ticket_icon"></span> - </div> - </div> - </div> - </div> - <div class="panel-body"> - <div class="tab-content"> - <div class="alert alert-success" style="z-index: 1100;display: none;" role="alert"> - <div id="success_alert_text"></div> - </div> - <div class="alert alert-warning" style="z-index: 1100;display: none;" role="alert"> - <div id="warning_alert_text"></div> - </div> - <div class="tab-pane <?php echo ( '' === $tab_content ) ? 'active' : ''; ?>" id="all_tickets_tab"> - <?php require EH_CRM_MAIN_VIEWS . 'tickets/crm_tickets_v2_all.php'; ?> - </div> - <?php echo wp_kses_post( $tab_content ); ?> - </div> - </div> - </div> - </div> - </div> -</div> -</div> +<?php+$default_deep_link = stripslashes( eh_crm_get_settingsmeta( '0', 'default_deep_link' ) );+if ( $default_deep_link && ! isset( $_GET['filter'] ) && ! isset( $_GET['tid'] ) ) {+ $queries = [];+ $queries['page'] = 'wsdesk_tickets';+ parse_str( $default_deep_link, $queries );++ $queries = array_merge( array( 'page' => 'wsdesk_tickets' ), $queries );++ $url = add_query_arg( $queries, admin_url( 'admin.php' ) );++ ?>+ <script>+ const [url] = <?php echo wp_json_encode( [ $url ] ); ?>;+ window.location = url;+</script>+<?php+ die;+}+echo '<div class="wsdesk_wrapper">';+$plugin_name = 'wsdesk';+$tab_head = '';+$tab_content = '';+$t_id = ( isset( $_GET['tid'] ) ? sanitize_text_field( $_GET['tid'] ) : false );+if ( $t_id ) {+ $data = eh_crm_get_ticket(+ array(+ 'ticket_id' => $t_id,+ 'ticket_parent' => 0,+ )+ );+ if ( $data ) {+ $all_section_ids = eh_crm_get_ticket_value_count( 'ticket_parent', 0, false, '', '', 'ticket_updated', 'DESC', '', 0 );+ $pagination_ids = array();+ foreach ( $all_section_ids as $tic ) {+ array_push( $pagination_ids, $tic['ticket_id'] );+ }+ $tab_head = '<li role="presentation" class="active visible_tab" id="tab_' . $t_id . '" style="min-width:200px;">' . CRM_Ajax::eh_crm_ticket_single_view_gen_head( $t_id ) . '</li>';+ $tab_content = '<div class="tab-pane new-style-tab-pane active direct_load_tid" id="tab_content_' . $t_id . '">' . CRM_Ajax::eh_crm_ticket_single_view_gen( $t_id, $pagination_ids ) . '</div>';+ } else {+ ?>+ <div class="row" id="alert_for_activation">+ <div class="col-md-12">+ <div class="alert alert-danger aw_wsdesk_activate_alert" role="alert">+ <?php esc_html_e( 'Invalid Ticket Number', 'wsdesk' ); ?> [ <b>#<?php echo esc_html( $t_id ); ?></b> ]+ </div>+ </div>+ </div>+ <?php+ }+}+?>+<div class="container wrapper" id="tickets_page_view">+ <div class="row">+ <div class="col-md-12">+ <div class="panel with-nav-tabs panel-default">+ <div class="panel-heading col-md-12">+ <ul class="nav nav-tabs col-md-11 elaborate" role="tablist" style="margin-left: 0em;">+ <li class="<?php echo ( '' === $tab_head ) ? 'active' : ''; ?> all_tickets" role="presentation">+ <a id="all_tickets_tab_header" onclick=" ('tickets')" href="#all_tickets_tab" aria-controls="all" style="text-align: center;padding: 13px 15px;margin-right:0px !important;" data-toggle="tab" class="tab_a">+ <?php esc_html_e( 'All Tickets', 'wsdesk' ); ?>+ </a>+ </li>+ <?php echo wp_kses_post( $tab_head ); ?>+ <li role="presentation" class="dropdown" style="display: none;">+ <a href="#" id="myTabDrop1" class="dropdown-toggle tab_a" data-toggle="dropdown" aria-controls="myTabDrop1-contents" aria-expanded="true" style="text-align: center;padding: 13px 15px;margin-right:0px !important;">+ <span class="caret"></span> <?php esc_html_e( 'More', 'wsdesk' ); ?></a>+ <ul class="dropdown-menu collapse_ul" aria-labelledby="myTabDrop1" id="myTabDrop1-contents"style="overflow-x: hidden">+ </ul>+ </li>+ </ul>+ <div class="col-md-1 nav-tabs">+ <div class="pull-right side_bar">+ <a href="#" class="add-ticket tab_a" style="text-align: center;" data-placement="bottom" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'New Ticket', 'wsdesk' ); ?>" data-container="body">+ <span class="glyphicon glyphicon-plus"></span>+ </a>+ </div>+ <div class="pull-right ">+ <div class="input-group stylish-input-group" style="margin: 3px 5px;">+ <input type="text" class="form-control" id="search_ticket_input" placeholder="Search" data-placement="bottom" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Search Ticket', 'wsdesk' ); ?>" data-container="body">+ <span class="glyphicon glyphicon-search clickable form-control-feedback" id="search_ticket_icon"></span>+ </div>+ </div>+ </div>+ </div>+ <div class="panel-body">+ <div class="tab-content">+ <div class="alert alert-success" style="z-index: 1100;display: none;" role="alert">+ <div id="success_alert_text"></div>+ </div>+ <div class="alert alert-warning" style="z-index: 1100;display: none;" role="alert">+ <div id="warning_alert_text"></div>+ </div>+ <div class="tab-pane <?php echo ( '' === $tab_content ) ? 'active' : ''; ?>" id="all_tickets_tab">+ <?php require EH_CRM_MAIN_VIEWS . 'tickets/crm_tickets_v2_all.php'; ?>+ </div>+ <?php echo wp_kses_post( $tab_content ); ?>+ </div>+ </div>+ </div>+ </div>+ </div>+</div>+</div>
Vulnerability Existed: no No vulnerabilities detected - Content unchanged Explanation: This diff shows only whitespace/line ending changes (Unix LF vs Windows CRLF format conversion) between versions 3.3.4 and 3.3.5. The actual code content remains identical. No security fixes or regressions are present in this change. The file maintains its existing security posture: - `sanitize_text_field()` is properly used on `$_GET['tid']` input - `wp_json_encode()` safely encodes the URL for JavaScript context - `wp_kses_post()` is used to safely output HTML content - `esc_html()` and `esc_html_e()` are used for output escaping
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/email/crm_email_support.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/email/crm_email_support.php 2025-12-21 09:36:35.507308439 +0000@@ -1,324 +1,324 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -$support_email_name = eh_crm_get_settingsmeta( '0', 'support_reply_email_name' ); -$support_email = eh_crm_get_settingsmeta( '0', 'support_reply_email' ); -$support_email_new_ticket_text = eh_crm_get_settingsmeta( '0', 'support_email_new_ticket_text' ); -$avail_fields = eh_crm_get_settings( array( 'type' => 'field' ), array( 'slug', 'title', 'settings_id' ) ); -if ( ! $support_email_new_ticket_text ) { - $support_email_new_ticket_text = 'Your request (#[id]) has been received on [date] and is being reviewed by our support staff. - -To add additional comments, reply to this email. - -Your Issue: -[request_description] - -Tags : [tags] - -Regards, -Support'; -} -$support_email_reply_text = eh_crm_get_settingsmeta( '0', 'support_email_reply_text' ); -if ( ! $support_email_reply_text ) { - $support_email_reply_text = 'Your request (#[id]) has been updated. To add additional comments, reply to this email. - -[conversation_history]'; -} -?> -<div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Support Reply Email Name', 'wsdesk' ); ?></span> - <input type="text" id="support_reply_email_name" placeholder="<?php esc_html_e( 'Enter name', 'wsdesk' ); ?>" value="<?php echo esc_html( $support_email_name ); ?>" class="form-control crm-form-element-input"> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Support Reply Email', 'wsdesk' ); ?></span> - <input type="text" id="support_reply_email" placeholder="<?php esc_html_e( 'Enter Email', 'wsdesk' ); ?>" value="<?php echo esc_html( $support_email ); ?>" class="form-control crm-form-element-input"> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Send Auto E-Mail on Ticket Creation', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $auto_send_creation_email = eh_crm_get_settingsmeta( '0', 'auto_send_creation_email' ); - $enable = ''; - $hide = ''; - switch ( $auto_send_creation_email ) { - case 'enable': - $enable = 'checked'; - break; - default: - $enable = ''; - $hide = 'display:none;'; - break; - } - ?> - <input type="checkbox" style="margin-top: 0;" <?php echo esc_html( $enable ); ?> id="auto_send_creation_email" class="form-control" name="auto_send_creation_email" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<div id="email_auto_role_display" style="margin-top: 20px;<?php echo esc_html( $hide ); ?>"> - <div class="col-md-12"> - <div class="panel-group" id="email_auto_role" style="margin-bottom: 0px !important;cursor: pointer;"> - <div class="panel panel-default"> - <div class="panel-heading collapsed" data-toggle="collapse" data-parent="#email_auto_role" data-target="#content_email_auto"> - <span class ="email-reply-toggle"></span> - <h4 class="panel-title"> - <?php esc_html_e( 'Code for Automated Reply', 'wsdesk' ); ?> - </h4> - </div> - <div id="content_email_auto" class="panel-collapse collapse"> - <div class="panel-body"> - <div class="col-md-12"> - <div class="row"> - <div class="col-md-3"> - [id] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Ticket Number in the Reply', 'wsdesk' ); ?> - </div> - </div> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [assignee] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Ticket Assignee in the Reply', 'wsdesk' ); ?> - </div> - </div> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [tags] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Ticket Tags in the Reply', 'wsdesk' ); ?> - </div> - </div> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [date] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Ticket Date and Time in the Reply', 'wsdesk' ); ?> - </div> - </div> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [request_description] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Ticket Content in the Reply', 'wsdesk' ); ?> - </div> - </div> - </div> - </div> - </div> - </div> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Enter your new ticket automated reply format', 'wsdesk' ); ?></span> - <?php - wp_editor( - stripslashes( $support_email_new_ticket_text ), - 'support_email_new_ticket_text', - array( - 'tinymce' => false, - 'media_buttons' => false, - 'default_editor' => 'html', - 'editor_height' => '300px', - ) - ); - ?> - </div> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Send Auto E-Mail on Agent Reply', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Disabling this will block any kind of outgoing E-Mails generated when agent replies.', 'wsdesk' ); ?>" data-container="body"></span></span> - <span style="vertical-align: middle;"> - <?php - $send_agent_reply_mail = eh_crm_get_settingsmeta( '0', 'send_agent_reply_mail' ); - $enable = ''; - $hide = ''; - switch ( $send_agent_reply_mail ) { - case 'disabled': - $enable = ''; - $hide = 'display: none;'; - break; - default: - $enable = 'checked'; - break; - } - ?> - <input type="checkbox" style="margin-top: 0;" <?php echo esc_html( $enable ); ?> id="send_agent_reply_mail" class="form-control" name="send_agent_reply_mail" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<div id="email_auto_send_agent_reply" style="margin-top: 20px;<?php echo esc_html( $hide ); ?>"> - <div class="col-md-12" style="margin-top: 20px;"> - <div class="panel-group" id="email_reply_role" style="margin-bottom: 0px !important;cursor: pointer;"> - <div class="panel panel-default"> - <div class="panel-heading collapsed" data-toggle="collapse" data-parent="#email_reply_role" data-target="#content_reply_email"> - <span class ="email-reply-toggle"></span> - <h4 class="panel-title"> - <?php esc_html_e( 'Code for Agent Reply Email', 'wsdesk' ); ?> - </h4> - </div> - <div id="content_reply_email" class="panel-collapse collapse"> - <div class="panel-body"> - <div class="col-md-12"> - <div class="row"> - <div class="col-md-3"> - [id] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Ticket Number in the Reply', 'wsdesk' ); ?> - </div> - </div> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [assignee] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Ticket Assignee in the Reply', 'wsdesk' ); ?> - </div> - </div> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [tags] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Ticket Tags in the Reply', 'wsdesk' ); ?> - </div> - </div> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [date] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Ticket Date and Time in the Reply', 'wsdesk' ); ?> - </div> - </div> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [latest_reply] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Latest Ticket Reply in the Reply', 'wsdesk' ); ?> - </div> - </div> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [agent_replied] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Ticket Agent who replied in the Reply', 'wsdesk' ); ?> - </div> - </div> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [status] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Ticket Status in the Reply', 'wsdesk' ); ?> - </div> - </div> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [conversation_history] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To Insert Entire Conversation of the Ticket in the Reply', 'wsdesk' ); ?> - </div> - </div> - <!--<span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [conversation_history_with_agent_note] - </div> - <div class="col-md-9"> - <?php //_e("To Insert Conversation History with agent note in the notification email", 'wsdesk'); ?> - </div> - </div>--> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [ticket_link page='slug'] - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To insert the front end URL of the individual ticket. Replace Slug with the support page slug.', 'wsdesk' ); ?> - </div> - </div> - <?php - $selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' ); - if ( empty( $selected_fields ) ) { - $selected_fields = array(); - } - foreach ( $avail_fields as $field ) { - if ( 'google_captcha' === $field['slug'] || ! in_array( $field['slug'], $selected_fields ) ) { - continue; - } - echo ' - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [' . esc_html( $field['slug'] ) . '] - </div> - <div class="col-md-9"> - ' . esc_html__( 'To insert ', 'wsdesk' ) . ' ' . esc_html( $field['title'] ) . ' ' . esc_html__( 'field value in the template', 'wsdesk' ) . ' - </div> - </div>'; - } - ?> - </div> - </div> - </div> - </div> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Enter your agent reply mail format', 'wsdesk' ); ?></span> - <?php - wp_editor( - stripcslashes( $support_email_reply_text ), - 'support_email_reply_text', - array( - 'tinymce' => false, - 'media_buttons' => false, - 'default_editor' => 'html', - 'editor_height' => '300px', - ) - ); - ?> - </div> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-12"> - <button type="button" id="save_email_support" class="btn btn-primary"> <span class="glyphicon glyphicon-ok"></span> Save Changes</button> - </div> -</div> -<?php -// return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+$support_email_name = eh_crm_get_settingsmeta( '0', 'support_reply_email_name' );+$support_email = eh_crm_get_settingsmeta( '0', 'support_reply_email' );+$support_email_new_ticket_text = eh_crm_get_settingsmeta( '0', 'support_email_new_ticket_text' );+$avail_fields = eh_crm_get_settings( array( 'type' => 'field' ), array( 'slug', 'title', 'settings_id' ) );+if ( ! $support_email_new_ticket_text ) {+ $support_email_new_ticket_text = 'Your request (#[id]) has been received on [date] and is being reviewed by our support staff.++To add additional comments, reply to this email.++Your Issue:+[request_description]++Tags : [tags]++Regards,+Support';+}+$support_email_reply_text = eh_crm_get_settingsmeta( '0', 'support_email_reply_text' );+if ( ! $support_email_reply_text ) {+ $support_email_reply_text = 'Your request (#[id]) has been updated. To add additional comments, reply to this email.++[conversation_history]';+}+?>+<div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Support Reply Email Name', 'wsdesk' ); ?></span>+ <input type="text" id="support_reply_email_name" placeholder="<?php esc_html_e( 'Enter name', 'wsdesk' ); ?>" value="<?php echo esc_html( $support_email_name ); ?>" class="form-control crm-form-element-input">+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Support Reply Email', 'wsdesk' ); ?></span>+ <input type="text" id="support_reply_email" placeholder="<?php esc_html_e( 'Enter Email', 'wsdesk' ); ?>" value="<?php echo esc_html( $support_email ); ?>" class="form-control crm-form-element-input">+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Send Auto E-Mail on Ticket Creation', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php + $auto_send_creation_email = eh_crm_get_settingsmeta( '0', 'auto_send_creation_email' );+ $enable = '';+ $hide = '';+ switch ( $auto_send_creation_email ) {+ case 'enable':+ $enable = 'checked';+ break;+ default:+ $enable = '';+ $hide = 'display:none;';+ break;+ }+ ?>+ <input type="checkbox" style="margin-top: 0;" <?php echo esc_html( $enable ); ?> id="auto_send_creation_email" class="form-control" name="auto_send_creation_email" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<div id="email_auto_role_display" style="margin-top: 20px;<?php echo esc_html( $hide ); ?>">+ <div class="col-md-12">+ <div class="panel-group" id="email_auto_role" style="margin-bottom: 0px !important;cursor: pointer;">+ <div class="panel panel-default">+ <div class="panel-heading collapsed" data-toggle="collapse" data-parent="#email_auto_role" data-target="#content_email_auto">+ <span class ="email-reply-toggle"></span>+ <h4 class="panel-title">+ <?php esc_html_e( 'Code for Automated Reply', 'wsdesk' ); ?>+ </h4>+ </div>+ <div id="content_email_auto" class="panel-collapse collapse">+ <div class="panel-body">+ <div class="col-md-12">+ <div class="row">+ <div class="col-md-3">+ [id]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Ticket Number in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [assignee]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Ticket Assignee in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [tags]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Ticket Tags in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [date]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Ticket Date and Time in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [request_description]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Ticket Content in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ </div>+ </div>+ </div> + </div>+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Enter your new ticket automated reply format', 'wsdesk' ); ?></span>+ <?php+ wp_editor(+ stripslashes( $support_email_new_ticket_text ),+ 'support_email_new_ticket_text',+ array(+ 'tinymce' => false,+ 'media_buttons' => false,+ 'default_editor' => 'html',+ 'editor_height' => '300px',+ )+ );+ ?>+ </div>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Send Auto E-Mail on Agent Reply', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Disabling this will block any kind of outgoing E-Mails generated when agent replies.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <span style="vertical-align: middle;">+ <?php + $send_agent_reply_mail = eh_crm_get_settingsmeta( '0', 'send_agent_reply_mail' );+ $enable = '';+ $hide = '';+ switch ( $send_agent_reply_mail ) {+ case 'disabled':+ $enable = '';+ $hide = 'display: none;';+ break;+ default:+ $enable = 'checked';+ break;+ }+ ?>+ <input type="checkbox" style="margin-top: 0;" <?php echo esc_html( $enable ); ?> id="send_agent_reply_mail" class="form-control" name="send_agent_reply_mail" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<div id="email_auto_send_agent_reply" style="margin-top: 20px;<?php echo esc_html( $hide ); ?>">+ <div class="col-md-12" style="margin-top: 20px;">+ <div class="panel-group" id="email_reply_role" style="margin-bottom: 0px !important;cursor: pointer;">+ <div class="panel panel-default">+ <div class="panel-heading collapsed" data-toggle="collapse" data-parent="#email_reply_role" data-target="#content_reply_email">+ <span class ="email-reply-toggle"></span>+ <h4 class="panel-title">+ <?php esc_html_e( 'Code for Agent Reply Email', 'wsdesk' ); ?>+ </h4>+ </div>+ <div id="content_reply_email" class="panel-collapse collapse">+ <div class="panel-body">+ <div class="col-md-12">+ <div class="row">+ <div class="col-md-3">+ [id]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Ticket Number in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [assignee]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Ticket Assignee in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [tags]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Ticket Tags in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [date]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Ticket Date and Time in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [latest_reply]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Latest Ticket Reply in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [agent_replied]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Ticket Agent who replied in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [status]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Ticket Status in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [conversation_history]+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To Insert Entire Conversation of the Ticket in the Reply', 'wsdesk' ); ?>+ </div>+ </div>+ <!--<span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [conversation_history_with_agent_note]+ </div>+ <div class="col-md-9">+ <?php //_e("To Insert Conversation History with agent note in the notification email", 'wsdesk'); ?>+ </div>+ </div>-->+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [ticket_link page='slug']+ </div>+ <div class="col-md-9">+ <?php esc_html_e( 'To insert the front end URL of the individual ticket. Replace Slug with the support page slug.', 'wsdesk' ); ?>+ </div>+ </div>+ <?php+ $selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' );+ if ( empty( $selected_fields ) ) {+ $selected_fields = array();+ }+ foreach ( $avail_fields as $field ) {+ if ( 'google_captcha' === $field['slug'] || ! in_array( $field['slug'], $selected_fields ) ) {+ continue;+ }+ echo '+ <span class="crm-divider"></span>+ <div class="row">+ <div class="col-md-3">+ [' . esc_html( $field['slug'] ) . ']+ </div>+ <div class="col-md-9">+ ' . esc_html__( 'To insert ', 'wsdesk' ) . ' ' . esc_html( $field['title'] ) . ' ' . esc_html__( 'field value in the template', 'wsdesk' ) . '+ </div>+ </div>';+ }+ ?>+ </div>+ </div>+ </div> + </div>+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Enter your agent reply mail format', 'wsdesk' ); ?></span>+ <?php+ wp_editor(+ stripcslashes( $support_email_reply_text ), + 'support_email_reply_text', + array(+ 'tinymce' => false,+ 'media_buttons' => false,+ 'default_editor' => 'html',+ 'editor_height' => '300px',+ )+ );+ ?>+ </div>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-12">+ <button type="button" id="save_email_support" class="btn btn-primary"> <span class="glyphicon glyphicon-ok"></span> Save Changes</button>+ </div>+</div>+<?php+// return ob_get_clean();
Based on my analysis of the provided diff for `views/email/crm_email_support.php`, this appears to be a **line ending normalization change only** (converting from LF to CRLF or vice versa). The actual code content remains identical between versions 3.3.4 and 3.3.5. **Analysis Result:** Vulnerability Existed: **no** **Explanation:** The diff shows no functional code changes - only whitespace/line ending modifications. All PHP code, HTML markup, security functions (esc_html, esc_html_e, esc_html__), and logic remain completely unchanged between the two versions. The file already implements proper output escaping throughout: - `esc_html()` for HTML context escaping - `esc_html_e()` for localized output escaping - `esc_html__()` for i18n strings - `stripslashes()` and `stripcslashes()` for data handling Since no functional changes were made to the code, there are no new security fixes to document, and no vulnerabilities were introduced or addressed in this revision.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/email/crm_filter_block_setup.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/email/crm_filter_block_setup.php 2025-12-21 09:36:35.507308439 +0000@@ -1,103 +1,103 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -$block_filter = eh_crm_get_settingsmeta( '0', 'email_block_filters' ); -$block_subject = eh_crm_get_settingsmeta( '0', 'subject_block_filters' ); -if ( ! $block_filter ) { - $block_filter = array(); -} -?> -<div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="blocked_emails" style="padding-right:1em !important;"><?php esc_html_e( 'Blocked Email Addresses', 'wsdesk' ); ?></label> - <button type="button" id="block_email_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Filter', 'wsdesk' ); ?></button> - </div> - <ul class="list-group list-group-sortable-connected list-group-block-data"> - <?php - if ( ! empty( $block_filter ) ) { - foreach ( $block_filter as $email => $data ) { - echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $email ) . '"> ' . esc_html( $email ) . ' -> [ ' . esc_html( $data ) . ' ]<span class="pull-right">'; - echo '<span class="glyphicon glyphicon-trash block_email_delete_type" id="' . esc_attr( $email ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Filter', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - echo '</span></li>'; - } - } else { - echo '<li class="list-group-item list-group-item-success">' . esc_html__( 'There are no blocked email! Block a new email.', 'wsdesk' ) . '</li>'; - } - ?> - </ul> - </div> - <div id="block_email_add_display" style="display: none;"> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="block_address_add" style="padding-right:1em !important;"><?php esc_html_e( 'Add Filter', 'wsdesk' ); ?></label> - <button type="button" id="block_email_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - </div> - <span style="vertical-align: middle;" id="block_address_add_section"> - <input type="hidden" value="" id="add_block_address_yes"> - <span class="help-block"><?php esc_html_e( 'Enter details for new block address', 'wsdesk' ); ?> </span> - <input type="text" id="block_address_add_email" placeholder="<?php esc_html_e( 'Enter Email', 'wsdesk' ); ?>" class="form-control crm-form-element-input"> - <span class="help-block"><?php esc_html_e( 'Choose the blocking type?', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;" id="add_block_address_rights"> - <input type="checkbox" checked style="margin-top: 0;" class="form-control" name="add_block_rights" id="add_block_rights_send" value="send"> <?php esc_html_e( 'Block Sending Emails', 'wsdesk' ); ?><br> - <input type="checkbox" checked style="margin-top: 0;" class="form-control" name="add_block_rights" id="add_block_rights_receive" value="receive"> <?php esc_html_e( 'Block Receiving Emails', 'wsdesk' ); ?><br> - </span> - </span> - </div> - </div> - </div> - <div class="col-md-12"> - <button type="button" id="save_email_filter_block" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button> - </div> -</div> -<div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="blocked_emails" style="padding-right:1em !important;"><?php esc_html_e( 'Blocked Email Subjects', 'wsdesk' ); ?></label> - <button type="button" id="block_subject_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Filter', 'wsdesk' ); ?></button> - </div> - <ul class="list-group list-group-sortable-connected list-group-block-data"> - <?php - if ( ! empty( $block_subject ) ) { - foreach ( $block_subject as $index => $data ) { - echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $index ) . '">' . esc_html( $index ) . ' -> [ ' . esc_html( $data ) . ' ]<span class="pull-right">'; - echo '<span class="glyphicon glyphicon-trash block_subject_delete_type" id="' . esc_attr( $index ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Filter', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - echo '</span></li>'; - } - } else { - echo '<li class="list-group-item list-group-item-success">' . esc_html__( 'There are no blocked subjects! Block a subject.', 'wsdesk' ) . '</li>'; - } - ?> - </ul> - </div> - <div id="block_subject_add_display" style="display: none;"> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="block_address_add" style="padding-right:1em !important;"><?php esc_html_e( 'Add Filter', 'wsdesk' ); ?></label> - <button type="button" id="block_subject_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - </div> - <span style="vertical-align: middle;" id="block_address_add_section"> - <input type="hidden" value="" id="add_block_subject_yes"> - <span class="help-block"><?php esc_html_e( 'Enter details for new block subject', 'wsdesk' ); ?> </span> - <input type="text" id="block_subject_add_subject" placeholder="<?php esc_html_e( 'Enter Subject', 'wsdesk' ); ?>" class="form-control crm-form-element-input"> - <span class="help-block"><?php esc_html_e( 'Choose the blocking type?', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;" id="add_block_address_rights"> - <input type="radio" checked style="margin-top: 0;" class="form-control" name="add_block_type" id="add_block_rights_send" value="Beginning"> <?php esc_html_e( 'Beginning of the string', 'wsdesk' ); ?><br> - <input type="radio" style="margin-top: 0;" class="form-control" name="add_block_type" id="add_block_rights_receive" value="Anywhere"> <?php esc_html_e( 'Anywhere in the string', 'wsdesk' ); ?><br> - </span> - </span> - </div> - </div> - </div> - <div class="col-md-12"> - <button type="button" id="save_subject_filter_block" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button> - </div> -</div> -<?php -// return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+$block_filter = eh_crm_get_settingsmeta( '0', 'email_block_filters' );+$block_subject = eh_crm_get_settingsmeta( '0', 'subject_block_filters' );+if ( ! $block_filter ) {+ $block_filter = array();+}+?>+<div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="blocked_emails" style="padding-right:1em !important;"><?php esc_html_e( 'Blocked Email Addresses', 'wsdesk' ); ?></label>+ <button type="button" id="block_email_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Filter', 'wsdesk' ); ?></button>+ </div>+ <ul class="list-group list-group-sortable-connected list-group-block-data">+ <?php+ if ( ! empty( $block_filter ) ) {+ foreach ( $block_filter as $email => $data ) {+ echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $email ) . '"> ' . esc_html( $email ) . ' -> [ ' . esc_html( $data ) . ' ]<span class="pull-right">';+ echo '<span class="glyphicon glyphicon-trash block_email_delete_type" id="' . esc_attr( $email ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Filter', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ echo '</span></li>';+ }+ } else {+ echo '<li class="list-group-item list-group-item-success">' . esc_html__( 'There are no blocked email! Block a new email.', 'wsdesk' ) . '</li>';+ }+ ?>+ </ul>+ </div>+ <div id="block_email_add_display" style="display: none;">+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="block_address_add" style="padding-right:1em !important;"><?php esc_html_e( 'Add Filter', 'wsdesk' ); ?></label>+ <button type="button" id="block_email_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button>+ </div>+ <span style="vertical-align: middle;" id="block_address_add_section">+ <input type="hidden" value="" id="add_block_address_yes">+ <span class="help-block"><?php esc_html_e( 'Enter details for new block address', 'wsdesk' ); ?> </span>+ <input type="text" id="block_address_add_email" placeholder="<?php esc_html_e( 'Enter Email', 'wsdesk' ); ?>" class="form-control crm-form-element-input">+ <span class="help-block"><?php esc_html_e( 'Choose the blocking type?', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;" id="add_block_address_rights">+ <input type="checkbox" checked style="margin-top: 0;" class="form-control" name="add_block_rights" id="add_block_rights_send" value="send"> <?php esc_html_e( 'Block Sending Emails', 'wsdesk' ); ?><br>+ <input type="checkbox" checked style="margin-top: 0;" class="form-control" name="add_block_rights" id="add_block_rights_receive" value="receive"> <?php esc_html_e( 'Block Receiving Emails', 'wsdesk' ); ?><br>+ </span>+ </span>+ </div>+ </div>+ </div>+ <div class="col-md-12">+ <button type="button" id="save_email_filter_block" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button>+ </div>+</div>+<div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="blocked_emails" style="padding-right:1em !important;"><?php esc_html_e( 'Blocked Email Subjects', 'wsdesk' ); ?></label>+ <button type="button" id="block_subject_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Filter', 'wsdesk' ); ?></button>+ </div>+ <ul class="list-group list-group-sortable-connected list-group-block-data">+ <?php+ if ( ! empty( $block_subject ) ) {+ foreach ( $block_subject as $index => $data ) {+ echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $index ) . '">' . esc_html( $index ) . ' -> [ ' . esc_html( $data ) . ' ]<span class="pull-right">';+ echo '<span class="glyphicon glyphicon-trash block_subject_delete_type" id="' . esc_attr( $index ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Filter', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ echo '</span></li>';+ }+ } else {+ echo '<li class="list-group-item list-group-item-success">' . esc_html__( 'There are no blocked subjects! Block a subject.', 'wsdesk' ) . '</li>';+ }+ ?>+ </ul>+ </div>+ <div id="block_subject_add_display" style="display: none;">+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="block_address_add" style="padding-right:1em !important;"><?php esc_html_e( 'Add Filter', 'wsdesk' ); ?></label>+ <button type="button" id="block_subject_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button>+ </div>+ <span style="vertical-align: middle;" id="block_address_add_section">+ <input type="hidden" value="" id="add_block_subject_yes">+ <span class="help-block"><?php esc_html_e( 'Enter details for new block subject', 'wsdesk' ); ?> </span>+ <input type="text" id="block_subject_add_subject" placeholder="<?php esc_html_e( 'Enter Subject', 'wsdesk' ); ?>" class="form-control crm-form-element-input">+ <span class="help-block"><?php esc_html_e( 'Choose the blocking type?', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;" id="add_block_address_rights">+ <input type="radio" checked style="margin-top: 0;" class="form-control" name="add_block_type" id="add_block_rights_send" value="Beginning"> <?php esc_html_e( 'Beginning of the string', 'wsdesk' ); ?><br>+ <input type="radio" style="margin-top: 0;" class="form-control" name="add_block_type" id="add_block_rights_receive" value="Anywhere"> <?php esc_html_e( 'Anywhere in the string', 'wsdesk' ); ?><br>+ </span>+ </span>+ </div>+ </div>+ </div>+ <div class="col-md-12">+ <button type="button" id="save_subject_filter_block" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button>+ </div>+</div>+<?php+// return ob_get_clean();
Vulnerability Existed: no No Security Vulnerability - Line Ending Normalization Only Old Code: All lines ending with CRLF (Windows-style line endings: \r\n) Fixed Code: All lines ending with LF (Unix-style line endings: \n) Explanation: This diff represents a line ending normalization change from CRLF (carriage return + line feed) to LF (line feed only). This is a formatting/standardization change with no security implications. The actual code logic, functionality, and security posture remain completely unchanged. All security-sensitive operations (output escaping with `esc_html()`, `esc_attr()`, and `esc_html__()`) are present in both versions and function identically. This type of change is typically done to maintain consistent coding standards across a repository.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/email/crm_imap_setup.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/email/crm_imap_setup.php 2025-12-21 09:36:35.507308439 +0000@@ -1,179 +1,179 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -$imap_account_data = eh_crm_get_settingsmeta( '0', 'imap_account_data' ); - -if ( ! in_array( 'imap', get_loaded_extensions() ) ) { - ?> - <div style="text-align: center;"> - <h1><span class="glyphicon glyphicon-screenshot" style="font-size: 2em;color: lightgrey;"></span></h1> - <br> - <p><?php esc_html_e( 'IMAP is not enabled on your server. Please contact your service provider.', 'wsdesk' ); ?> - <br> - <span class="crm-divider"></span> - <b><?php esc_html_e( 'Have a Google account?', 'wsdesk' ); ?></b> - <?php esc_html_e( 'Use WSDesk Google OAuth setup.', 'wsdesk' ); ?> - <br> - <?php esc_html_e( '[ WSDesk -> E-Mail -> Google OAuth Setup ]', 'wsdesk' ); ?> - <br> - </p> - </div> - - <?php -} else { - ?> -<div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle" class="imap_email_"> - <label for="ticket_triggers" style="padding-right:1em !important;"><?php esc_html_e( 'IMAP E-Mail Setup', 'wsdesk' ); ?></label> - - </div> - <div class="panel panel-default crm-panel" style="margin-top: 15px !important;margin-bottom: 0px !important;"> - <div class="panel-body" style="padding: 5px !important;"> - <div class="col-sm-12" style="padding-right: 5px !important;padding-left: 5px !important;"> - - <ul class="list-group"> - <?php - $us = 0; - if ( $imap_account_data ) { - foreach ( $imap_account_data as $key => $value ) { - $us++; - echo '<li class="list-group-item list-group-item-success" data-target="#' . esc_attr( $us ) . 's" aria-expanded="false" data-toggle="collapse" style="padding: 10px 10px !important;" id="trigger_QH38">' . esc_html( $value['imap_server_email'] ) . '</li>'; - ?> - <div id="<?php echo( esc_attr( $us ) . 's' ); ?>" class="panel-collapse collapse" aria-expanded="false"> - <div class="<?php echo esc_html( $value['imap_server_email'] ); ?>"> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'IMAP Server SSL URL', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Copy Paste the IMAP URL provided by your respective hosting service provider. ( viz. imap.gmail.com ).', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="edit_server_url" placeholder="imap.gmail.com" value="<?php echo esc_html( $value['imap_server_url'] ); ?>" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'IMAP Server SSL Port', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( ' Provide port number of your hosting service provider (993 for Gmail).', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="edit_server_port" placeholder="993" value="<?php echo esc_html( $value['imap_server_port'] ); ?>" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Email-ID', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enter email address from where emails are to be extracted.', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="edit_server_email" autocomplete="off" placeholder="[email protected]" value="<?php echo esc_html( $value['imap_server_email'] ); ?>" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Password', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enter password for your email address.', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="password" id="edit_server_email_pwd" autocomplete="off" placeholder="Password" value="<?php echo esc_html( $value['imap_server_email_pwd'] ); ?>" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Delete imported e-mail from the server', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enabling this will delete the e-mail after importing it as ticket.', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="checkbox" id="edit_delete_email" autocomplete="off" value="yes" <?php echo ( 'yes' == $value['delete_email'] || 'on' == $value['delete_email'] ) ? 'checked' : ''; ?> class="form-control"><label style="font-weight: normal;">Enable</label> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php echo esc_html_e( 'Username', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html__( 'Enter your username if required', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" value="<?php echo esc_html( $value['username'] ); ?>" class="form-control"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Charset', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'The charset of your email server', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" value="<?php echo esc_html( $value['charset'] ); ?>" class="form-control"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <?php - if ( 'activated' == $value['imap_activation'] ) { - ?> - <button type="button" class="btn btn-danger deactivate_imap" id="<?php echo( esc_attr( $us ) ); ?>"><span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Delete Account', 'wsdesk' ); ?></button> - <?php - } else { - ?> - <button type="button" id="activate_imap" class="btn btn-primary"><span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Activate IMAP', 'wsdesk' ); ?></button> - <?php - } - ?> - <a href="https://elextensions.com/knowledge-base/configure-imap-wsdesk/" target="_blank" class="btn btn-info pull-right" ><span class="glyphicon glyphicon-link"></span> <?php esc_html_e( 'How to setup IMAP', 'wsdesk' ); ?></a> - </div> - </div> - </div> - </div> - <?php - - } - } else { - echo "<li class='list-group-item list-group-item-success' style='padding: 10px 10px !important;' id='trigger_QH38'>No IMAP accounts!</li>"; - } - ?> - </ul> - </div> - </div> - </div> - </div> -</div> - -<li class="list-group-item" data-target="#imap_email_new" aria-expanded="false" data-toggle="collapse" style="padding: 10px 10px !important;border: none" id="data_dispaly"> - <button type="button" id="imap_email_trigger_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add New Account', 'wsdesk' ); ?></button> -</li> - -<div class="imap_email_new panel-collapse collapse" id="imap_email_new" aria-expanded="false"> - <div class="email_trigger_add_button"> - <label for="ticket_triggers" style="margin: 15px;"><?php esc_html_e( 'Add New IMAP Account', 'wsdesk' ); ?></label> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'IMAP Server SSL URL', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Copy Paste the IMAP URL provided by your respective hosting service provider. ( viz. imap.gmail.com ).', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="server_url" placeholder="imap.gmail.com" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'IMAP Server SSL Port', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( ' Provide port number of your hosting service provider (993 for Gmail).', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="server_port" placeholder="993" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Email-ID', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enter email address from where emails are to be extracted.', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="server_email" autocomplete="off" placeholder="[email protected]" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Password', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enter password for your email address.', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="password" id="server_email_pwd" autocomplete="off" placeholder="Password" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Username', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enter your username if required', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="imap_username" value="" class="form-control"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Charset', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'The charset of your email server', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="charset" value="UTF-8" class="form-control"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Delete imported e-mail from the server', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enabling this will delete the e-mail after importing it as ticket.', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="checkbox" id="delete_email" autocomplete="off" class="form-control"><label style="font-weight: normal;">Enable</label> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <button type="button" id="activate_imap" class="btn btn-primary"><span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Activate IMAP', 'wsdesk' ); ?></button> - <a href="https://elextensions.com/knowledge-base/configure-imap-wsdesk/" target="_blank" class="btn btn-info pull-right" ><span class="glyphicon glyphicon-link"></span> <?php esc_html_e( 'How to setup IMAP', 'wsdesk' ); ?></a> - </div> - </div> - </div> -</div> - <?php -} +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+$imap_account_data = eh_crm_get_settingsmeta( '0', 'imap_account_data' );++if ( ! in_array( 'imap', get_loaded_extensions() ) ) {+ ?>+ <div style="text-align: center;">+ <h1><span class="glyphicon glyphicon-screenshot" style="font-size: 2em;color: lightgrey;"></span></h1>+ <br>+ <p><?php esc_html_e( 'IMAP is not enabled on your server. Please contact your service provider.', 'wsdesk' ); ?>+ <br>+ <span class="crm-divider"></span>+ <b><?php esc_html_e( 'Have a Google account?', 'wsdesk' ); ?></b>+ <?php esc_html_e( 'Use WSDesk Google OAuth setup.', 'wsdesk' ); ?>+ <br>+ <?php esc_html_e( '[ WSDesk -> E-Mail -> Google OAuth Setup ]', 'wsdesk' ); ?>+ <br>+ </p>+ </div>++ <?php+} else {+ ?>+<div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle" class="imap_email_">+ <label for="ticket_triggers" style="padding-right:1em !important;"><?php esc_html_e( 'IMAP E-Mail Setup', 'wsdesk' ); ?></label>++ </div>+ <div class="panel panel-default crm-panel" style="margin-top: 15px !important;margin-bottom: 0px !important;">+ <div class="panel-body" style="padding: 5px !important;">+ <div class="col-sm-12" style="padding-right: 5px !important;padding-left: 5px !important;">++ <ul class="list-group">+ <?php+ $us = 0;+ if ( $imap_account_data ) {+ foreach ( $imap_account_data as $key => $value ) {+ $us++;+ echo '<li class="list-group-item list-group-item-success" data-target="#' . esc_attr( $us ) . 's" aria-expanded="false" data-toggle="collapse" style="padding: 10px 10px !important;" id="trigger_QH38">' . esc_html( $value['imap_server_email'] ) . '</li>';+ ?>+ <div id="<?php echo( esc_attr( $us ) . 's' ); ?>" class="panel-collapse collapse" aria-expanded="false">+ <div class="<?php echo esc_html( $value['imap_server_email'] ); ?>">+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'IMAP Server SSL URL', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Copy Paste the IMAP URL provided by your respective hosting service provider. ( viz. imap.gmail.com ).', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="edit_server_url" placeholder="imap.gmail.com" value="<?php echo esc_html( $value['imap_server_url'] ); ?>" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'IMAP Server SSL Port', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( ' Provide port number of your hosting service provider (993 for Gmail).', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="edit_server_port" placeholder="993" value="<?php echo esc_html( $value['imap_server_port'] ); ?>" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Email-ID', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enter email address from where emails are to be extracted.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="edit_server_email" autocomplete="off" placeholder="[email protected]" value="<?php echo esc_html( $value['imap_server_email'] ); ?>" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Password', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enter password for your email address.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="password" id="edit_server_email_pwd" autocomplete="off" placeholder="Password" value="<?php echo esc_html( $value['imap_server_email_pwd'] ); ?>" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Delete imported e-mail from the server', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enabling this will delete the e-mail after importing it as ticket.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="checkbox" id="edit_delete_email" autocomplete="off" value="yes" <?php echo ( 'yes' == $value['delete_email'] || 'on' == $value['delete_email'] ) ? 'checked' : ''; ?> class="form-control"><label style="font-weight: normal;">Enable</label>+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php echo esc_html_e( 'Username', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html__( 'Enter your username if required', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" value="<?php echo esc_html( $value['username'] ); ?>" class="form-control">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Charset', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'The charset of your email server', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" value="<?php echo esc_html( $value['charset'] ); ?>" class="form-control">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <?php+ if ( 'activated' == $value['imap_activation'] ) {+ ?>+ <button type="button" class="btn btn-danger deactivate_imap" id="<?php echo( esc_attr( $us ) ); ?>"><span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Delete Account', 'wsdesk' ); ?></button>+ <?php+ } else {+ ?>+ <button type="button" id="activate_imap" class="btn btn-primary"><span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Activate IMAP', 'wsdesk' ); ?></button>+ <?php+ }+ ?>+ <a href="https://elextensions.com/knowledge-base/configure-imap-wsdesk/" target="_blank" class="btn btn-info pull-right" ><span class="glyphicon glyphicon-link"></span> <?php esc_html_e( 'How to setup IMAP', 'wsdesk' ); ?></a>+ </div>+ </div>+ </div>+ </div>+ <?php++ }+ } else {+ echo "<li class='list-group-item list-group-item-success' style='padding: 10px 10px !important;' id='trigger_QH38'>No IMAP accounts!</li>";+ }+ ?>+ </ul>+ </div>+ </div>+ </div>+ </div>+</div>++<li class="list-group-item" data-target="#imap_email_new" aria-expanded="false" data-toggle="collapse" style="padding: 10px 10px !important;border: none" id="data_dispaly">+ <button type="button" id="imap_email_trigger_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add New Account', 'wsdesk' ); ?></button>+</li>++<div class="imap_email_new panel-collapse collapse" id="imap_email_new" aria-expanded="false">+ <div class="email_trigger_add_button">+ <label for="ticket_triggers" style="margin: 15px;"><?php esc_html_e( 'Add New IMAP Account', 'wsdesk' ); ?></label>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'IMAP Server SSL URL', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Copy Paste the IMAP URL provided by your respective hosting service provider. ( viz. imap.gmail.com ).', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="server_url" placeholder="imap.gmail.com" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'IMAP Server SSL Port', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( ' Provide port number of your hosting service provider (993 for Gmail).', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="server_port" placeholder="993" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Email-ID', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enter email address from where emails are to be extracted.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="server_email" autocomplete="off" placeholder="[email protected]" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Password', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enter password for your email address.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="password" id="server_email_pwd" autocomplete="off" placeholder="Password" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Username', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enter your username if required', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="imap_username" value="" class="form-control">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Charset', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'The charset of your email server', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="charset" value="UTF-8" class="form-control">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Delete imported e-mail from the server', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enabling this will delete the e-mail after importing it as ticket.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="checkbox" id="delete_email" autocomplete="off" class="form-control"><label style="font-weight: normal;">Enable</label>+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <button type="button" id="activate_imap" class="btn btn-primary"><span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Activate IMAP', 'wsdesk' ); ?></button>+ <a href="https://elextensions.com/knowledge-base/configure-imap-wsdesk/" target="_blank" class="btn btn-info pull-right" ><span class="glyphicon glyphicon-link"></span> <?php esc_html_e( 'How to setup IMAP', 'wsdesk' ); ?></a>+ </div>+ </div>+ </div>+</div>+ <?php+}
Vulnerability Existed: no Explanation: This diff shows only whitespace/line ending changes (likely converting between different line ending formats, such as CRLF to LF or vice versa). The actual code content remains identical between versions 3.3.4 and 3.3.5. No security fixes or vulnerability removals are present in this change. All the sensitive data handling (passwords, emails, etc.) and output escaping (esc_html, esc_attr) remain the same in both versions. Therefore, no security vulnerabilities were fixed or introduced in this update.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/email/crm_oauth_setup.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/email/crm_oauth_setup.php 2025-12-21 09:36:35.507308439 +0000@@ -1,57 +1,57 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -$client_id = eh_crm_get_settingsmeta( '0', 'oauth_client_id' ); -$client_secret = eh_crm_get_settingsmeta( '0', 'oauth_client_secret' ); -$oauth_activation = eh_crm_get_settingsmeta( '0', 'oauth_activation' ); -?> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Google API client ID', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'You would get this after completing the entire process of enabling gmail API and Google OAuth.', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="oauth_client_id" value="<?php echo esc_html( $client_id ); ?>" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Google API Client Secret', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'You would get this after completing the entire process of enabling gmail API and Google OAuth.', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="oauth_client_secret" value="<?php echo esc_html( $client_secret ); ?>" class="form-control crm-form-element-input"> - </div> - </div> - <?php - if ( 'activated' == $oauth_activation ) { - ?> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Access Token', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="This should appear as soon as you click on 'Activate'. If it doesn't, then please recheck the 'Client ID' and 'Client Secret' fields" data-container="body"></span></span> - <input type="text" readonly value="<?php echo esc_html( eh_crm_get_settingsmeta( '0', 'oauth_accesstoken' ) ); ?>" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Refresh Token', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="This should appear as soon as you click on 'Activate'. If it doesn't, then please recheck the 'Client ID' and 'Client Secret' fields" data-container="body"></span></span> - <input type="text" readonly value="<?php echo esc_html( eh_crm_get_settingsmeta( '0', 'oauth_refreshtoken' ) ); ?>" class="form-control crm-form-element-input"> - </div> - </div> - <?php - } - ?> - <div class="crm-form-element"> - <div class="col-md-12"> - <?php - if ( 'activated' == $oauth_activation ) { - ?> - <button type="button" id="deactivate_oauth" class="btn btn-danger"><span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Deactivate OAuth', 'wsdesk' ); ?></button> - <?php - } else { - ?> - <button type="button" id="activate_oauth" class="btn btn-primary"><span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Activate OAuth', 'wsdesk' ); ?></button> - <?php - } - ?> - <a href="https://elextensions.com/knowledge-base/set-up-google-oauth-individual-gmail-account-google-oauth-credentials-wsdesk/" target="_blank" class="btn btn-info pull-right" ><span class="glyphicon glyphicon-link"></span> <?php esc_html_e( 'How to setup OAuth', 'wsdesk' ); ?></a> - </div> - </div> -<?php -// return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+$client_id = eh_crm_get_settingsmeta( '0', 'oauth_client_id' );+$client_secret = eh_crm_get_settingsmeta( '0', 'oauth_client_secret' );+$oauth_activation = eh_crm_get_settingsmeta( '0', 'oauth_activation' );+?>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Google API client ID', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'You would get this after completing the entire process of enabling gmail API and Google OAuth.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="oauth_client_id" value="<?php echo esc_html( $client_id ); ?>" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Google API Client Secret', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'You would get this after completing the entire process of enabling gmail API and Google OAuth.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="oauth_client_secret" value="<?php echo esc_html( $client_secret ); ?>" class="form-control crm-form-element-input">+ </div>+ </div>+ <?php+ if ( 'activated' == $oauth_activation ) {+ ?>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Access Token', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="This should appear as soon as you click on 'Activate'. If it doesn't, then please recheck the 'Client ID' and 'Client Secret' fields" data-container="body"></span></span>+ <input type="text" readonly value="<?php echo esc_html( eh_crm_get_settingsmeta( '0', 'oauth_accesstoken' ) ); ?>" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Refresh Token', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="This should appear as soon as you click on 'Activate'. If it doesn't, then please recheck the 'Client ID' and 'Client Secret' fields" data-container="body"></span></span>+ <input type="text" readonly value="<?php echo esc_html( eh_crm_get_settingsmeta( '0', 'oauth_refreshtoken' ) ); ?>" class="form-control crm-form-element-input">+ </div>+ </div>+ <?php+ }+ ?>+ <div class="crm-form-element">+ <div class="col-md-12">+ <?php+ if ( 'activated' == $oauth_activation ) {+ ?>+ <button type="button" id="deactivate_oauth" class="btn btn-danger"><span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Deactivate OAuth', 'wsdesk' ); ?></button>+ <?php+ } else {+ ?>+ <button type="button" id="activate_oauth" class="btn btn-primary"><span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Activate OAuth', 'wsdesk' ); ?></button>+ <?php+ }+ ?>+ <a href="https://elextensions.com/knowledge-base/set-up-google-oauth-individual-gmail-account-google-oauth-credentials-wsdesk/" target="_blank" class="btn btn-info pull-right" ><span class="glyphicon glyphicon-link"></span> <?php esc_html_e( 'How to setup OAuth', 'wsdesk' ); ?></a> + </div>+ </div>+<?php+// return ob_get_clean();
Vulnerability Existed: no This diff shows only a line ending normalization change (CRLF to LF conversion) with no actual code modifications. The security-relevant code remains identical: - All output is properly escaped using `esc_html()` - OAuth credentials are handled safely - No new vulnerabilities are introduced - No existing vulnerabilities are fixed or introduced This is a formatting/whitespace-only change with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/email/crm_outlook_oauth_setup.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/email/crm_outlook_oauth_setup.php 2025-12-21 09:36:35.507308439 +0000@@ -1,19 +1,19 @@-<div class="wsdesk_wrapper "> - <div class="container-fluid"> - <div class="mt-3 vh-100 d-flex " style="justify-content: center;min-height: 300px;align-items: center;"> - <p class="text-center m-0 fs-4" style="margin-top:200px"><?php echo esc_attr__( - 'Upgrade to Premium to Unlock Outlook OAuth Setup feature.' - )?> - <br> - <a class="btn btn-primary text-decoration-none" href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"> - <?php - echo esc_attr__( - ' - Go Premium' - ) - ?> - </a> - </p> - </div> - </div> -</div> +<div class="wsdesk_wrapper ">+ <div class="container-fluid">+ <div class="mt-3 vh-100 d-flex " style="justify-content: center;min-height: 300px;align-items: center;">+ <p class="text-center m-0 fs-4" style="margin-top:200px"><?php echo esc_attr__(+ 'Upgrade to Premium to Unlock Outlook OAuth Setup feature.'+ )?>+ <br>+ <a class="btn btn-primary text-decoration-none" href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank">+ <?php + echo esc_attr__(+ '+ Go Premium'+ )+ ?>+ </a>+ </p>+ </div>+ </div>+</div>
Vulnerability Existed: no Explanation: This diff shows only whitespace/formatting changes (line ending normalization from LF to CRLF or similar). The actual code content remains identical: - The HTML structure is unchanged - The PHP escaping functions (`esc_attr__()`) are properly applied to user-facing strings - The external link uses a hardcoded URL (no injection risk) - The `target="_blank"` attribute is safe in this context No security vulnerabilities were introduced or fixed in this change. This is purely a code formatting update with no functional or security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/import/crm_zendesk_import.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/import/crm_zendesk_import.php 2025-12-21 09:36:35.507308439 +0000@@ -1,91 +1,91 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -$zendesk_accesstoken = eh_crm_get_settingsmeta( '0', 'zendesk_accesstoken' ); -$zendesk_subdomain = eh_crm_get_settingsmeta( '0', 'zendesk_subdomain' ); -$zendesk_username = eh_crm_get_settingsmeta( '0', 'zendesk_username' ); -$zendesk = true; -if ( ! $zendesk ) { - ?> - <center> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block" style="text-align: center"><?php esc_html_e( 'Activate Zendesk Import to Get all Zendesk Tickets', 'wsdesk' ); ?></span> - <button class="btn btn-primary btn-lg" id="activate_zendesk"><?php esc_html_e( 'Activate Zendesk', 'wsdesk' ); ?></button> - </div> - </div> - </center> - <?php -} else { - ?> -<center> - <div class="crm-form-element" id="zendesk_progress_bar"> - <div class="col-md-12"> - <span class="help-block" id="zendesk_data_progress"><?php esc_html_e( 'Importing Tickets may take some time...', 'wsdesk' ); ?></span> - <div class="progress"> - <div class="progress-bar progress-bar-striped active" id="zendesk_importing_width" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 1%"> - <span class="sr-only" style="position: inherit;color: black" id="zendesl_per_progress">1% <?php esc_html_e( 'Completed', 'wsdesk' ); ?></span> - </div> - </div> - </div> - </div> - <div class="col-md-8 col-md-offset-2" id="live_import_main"> - <div id="live_import_log"></div> - <div> - <span class="help-block"><?php esc_html_e( 'Stop Pulling Tickets to WSDesk', 'wsdesk' ); ?></span> - <button type="button" data-loading-text="<?php esc_html_e( 'Stoping Zendesk import...', 'wsdesk' ); ?>" id="stop_pull_tickets" class="btn btn-primary"><?php esc_html_e( 'Stop Import', 'wsdesk' ); ?></button> - </div> - </div> - <div id="blur_on_import"> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'What is your plan in Zendesk?', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Select the appropriate subscription plan which you previously used in Zendesk.', 'wsdesk' ); ?>" data-container="body"></span></span> - <select id="zendesk_plan" style="width: 50% !important;display: inline !important" class="form-control" aria-describedby="helpBlock"> - <option value="essential"><?php esc_html_e( 'Essential', 'wsdesk' ); ?></option> - <option value="team"><?php esc_html_e( 'Team', 'wsdesk' ); ?></option> - <option value="professional"><?php esc_html_e( 'Professional', 'wsdesk' ); ?></option> - <option value="enterprise"><?php esc_html_e( 'Enterprise', 'wsdesk' ); ?></option> - <option value="high"><?php esc_html_e( 'High Volume API Add-On (Professional or Enterprise)', 'wsdesk' ); ?></option> - </select> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Enter your Zendesk Access Token', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'You can get this after logging into Zendesk, Channels -> API -> Settings.', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="zendesk_accesstoken" placeholder="<?php esc_html_e( 'Zendesk Token', 'wsdesk' ); ?>" value="<?php echo esc_html( $zendesk_accesstoken ); ?>" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Enter your Zendesk Subdomain ( Without https:// and .zendesk.com )', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( '(eg. Subdomain.zendeskcom).', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="zendesk_subdomain" placeholder="<?php esc_html_e( 'Zendesk Subdomain', 'wsdesk' ); ?>" value="<?php echo esc_html( $zendesk_subdomain ); ?>" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Enter your Zendesk Username', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enter you Zendesk Organization Username.', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="zendesk_username" autocomplete="off" placeholder="<?php esc_html_e( 'Zendesk Username', 'wsdesk' ); ?>" value="<?php echo esc_html( $zendesk_username ); ?>" class="form-control crm-form-element-input"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Want to download attachment locally?', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Select ‘Yes’, if you want to import the tickets now.', 'wsdesk' ); ?>" data-container="body"></span></span> - <span style="vertical-align: middle;"> - <input type="radio" style="margin-top: 0;" id="download_attachment" class="form-control" name="download_attachment" value="yes"> <?php esc_html_e( 'Yes! Download ', 'wsdesk' ); ?> - <input type="radio" style="margin-top: 0;" id="download_attachment" class="form-control" name="download_attachment" checked="" value="no"> <?php esc_html_e( "No! I don't want", 'wsdesk' ); ?><br> - </span> - </div> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Pull Tickets to WSDesk', 'wsdesk' ); ?></span> - <button type="button" id="zendesk_pull_tickets" class="btn btn-primary btn-lg"><?php esc_html_e( 'Pull Tickets', 'wsdesk' ); ?></button> - </div> - </div> -</center> - <?php -} -// return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+$zendesk_accesstoken = eh_crm_get_settingsmeta( '0', 'zendesk_accesstoken' );+$zendesk_subdomain = eh_crm_get_settingsmeta( '0', 'zendesk_subdomain' );+$zendesk_username = eh_crm_get_settingsmeta( '0', 'zendesk_username' );+$zendesk = true;+if ( ! $zendesk ) {+ ?>+ <center>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block" style="text-align: center"><?php esc_html_e( 'Activate Zendesk Import to Get all Zendesk Tickets', 'wsdesk' ); ?></span>+ <button class="btn btn-primary btn-lg" id="activate_zendesk"><?php esc_html_e( 'Activate Zendesk', 'wsdesk' ); ?></button>+ </div>+ </div>+ </center>+ <?php+} else {+ ?>+<center>+ <div class="crm-form-element" id="zendesk_progress_bar">+ <div class="col-md-12">+ <span class="help-block" id="zendesk_data_progress"><?php esc_html_e( 'Importing Tickets may take some time...', 'wsdesk' ); ?></span>+ <div class="progress">+ <div class="progress-bar progress-bar-striped active" id="zendesk_importing_width" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 1%">+ <span class="sr-only" style="position: inherit;color: black" id="zendesl_per_progress">1% <?php esc_html_e( 'Completed', 'wsdesk' ); ?></span>+ </div>+ </div>+ </div>+ </div>+ <div class="col-md-8 col-md-offset-2" id="live_import_main">+ <div id="live_import_log"></div>+ <div>+ <span class="help-block"><?php esc_html_e( 'Stop Pulling Tickets to WSDesk', 'wsdesk' ); ?></span>+ <button type="button" data-loading-text="<?php esc_html_e( 'Stoping Zendesk import...', 'wsdesk' ); ?>" id="stop_pull_tickets" class="btn btn-primary"><?php esc_html_e( 'Stop Import', 'wsdesk' ); ?></button>+ </div>+ </div>+ <div id="blur_on_import">+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'What is your plan in Zendesk?', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Select the appropriate subscription plan which you previously used in Zendesk.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <select id="zendesk_plan" style="width: 50% !important;display: inline !important" class="form-control" aria-describedby="helpBlock">+ <option value="essential"><?php esc_html_e( 'Essential', 'wsdesk' ); ?></option>+ <option value="team"><?php esc_html_e( 'Team', 'wsdesk' ); ?></option>+ <option value="professional"><?php esc_html_e( 'Professional', 'wsdesk' ); ?></option>+ <option value="enterprise"><?php esc_html_e( 'Enterprise', 'wsdesk' ); ?></option>+ <option value="high"><?php esc_html_e( 'High Volume API Add-On (Professional or Enterprise)', 'wsdesk' ); ?></option>+ </select>+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Enter your Zendesk Access Token', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'You can get this after logging into Zendesk, Channels -> API -> Settings.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="zendesk_accesstoken" placeholder="<?php esc_html_e( 'Zendesk Token', 'wsdesk' ); ?>" value="<?php echo esc_html( $zendesk_accesstoken ); ?>" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Enter your Zendesk Subdomain ( Without https:// and .zendesk.com )', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( '(eg. Subdomain.zendeskcom).', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="zendesk_subdomain" placeholder="<?php esc_html_e( 'Zendesk Subdomain', 'wsdesk' ); ?>" value="<?php echo esc_html( $zendesk_subdomain ); ?>" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Enter your Zendesk Username', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Enter you Zendesk Organization Username.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="zendesk_username" autocomplete="off" placeholder="<?php esc_html_e( 'Zendesk Username', 'wsdesk' ); ?>" value="<?php echo esc_html( $zendesk_username ); ?>" class="form-control crm-form-element-input">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Want to download attachment locally?', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Select ‘Yes’, if you want to import the tickets now.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <span style="vertical-align: middle;">+ <input type="radio" style="margin-top: 0;" id="download_attachment" class="form-control" name="download_attachment" value="yes"> <?php esc_html_e( 'Yes! Download ', 'wsdesk' ); ?>+ <input type="radio" style="margin-top: 0;" id="download_attachment" class="form-control" name="download_attachment" checked="" value="no"> <?php esc_html_e( "No! I don't want", 'wsdesk' ); ?><br>+ </span>+ </div>+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Pull Tickets to WSDesk', 'wsdesk' ); ?></span>+ <button type="button" id="zendesk_pull_tickets" class="btn btn-primary btn-lg"><?php esc_html_e( 'Pull Tickets', 'wsdesk' ); ?></button>+ </div>+ </div>+</center>+ <?php+}+// return ob_get_clean();
Vulnerability Existed: no No Security Vulnerabilities Detected - Line Ending Changes Only Old Code: All lines ending with LF (Unix line endings) Fixed Code: All lines ending with CRLF (Windows line endings) Explanation: This diff shows only line ending changes (LF to CRLF) across the entire file. The actual code content remains identical - no logic, security handling, or functional changes have been made. This is a formatting/normalization change, not a security fix. The file continues to use `esc_html()` for output escaping, maintains the same form structure, and has no new or removed security mechanisms. Line ending normalization does not introduce or resolve security vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/chatgpt.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/chatgpt.php 2025-12-21 09:36:35.511308688 +0000@@ -1,19 +1,19 @@-<div class="wsdesk_wrapper "> - <div class="container-fluid"> - <div class="mt-3 vh-100 d-flex " style="justify-content: center;min-height: 300px;align-items: center;"> - <p class="text-center m-0 fs-4"><?php echo esc_attr__( - 'Upgrade to Premium to Unlock the ChatGPT integration to enhance your conversational experience.' - )?> - <br> - <a class="btn btn-primary text-decoration-none" href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"> - <?php - echo esc_attr__( - ' - Go Premium' - ) - ?> - </a> - </p> - </div> - </div> -</div> +<div class="wsdesk_wrapper ">+ <div class="container-fluid">+ <div class="mt-3 vh-100 d-flex " style="justify-content: center;min-height: 300px;align-items: center;">+ <p class="text-center m-0 fs-4"><?php echo esc_attr__(+ 'Upgrade to Premium to Unlock the ChatGPT integration to enhance your conversational experience.'+ )?>+ <br>+ <a class="btn btn-primary text-decoration-none" href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank">+ <?php + echo esc_attr__(+ '+ Go Premium'+ )+ ?>+ </a>+ </p>+ </div>+ </div>+</div>
Vulnerability Existed: no No Security Vulnerabilities Detected - views/settings/chatgpt.php Explanation: This diff contains only whitespace and line ending changes (converting line endings from LF to CRLF or similar formatting adjustment). The actual PHP code remains identical between versions 3.3.4 and 3.3.5. The code itself uses proper escaping functions (`esc_attr__()`) for output sanitization, which is appropriate for WordPress context. The href attribute contains a hardcoded, safe URL to the official plugin site. There are no code logic changes, no input handling modifications, and no security-relevant alterations in this diff. This is a purely cosmetic/formatting update with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_appearance.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_appearance.php 2025-12-21 09:36:35.511308688 +0000@@ -1,144 +1,144 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -$input_width = eh_crm_get_settingsmeta( '0', 'input_width' ); -$main_ticket_form_title = eh_crm_get_settingsmeta( '0', 'main_ticket_form_title' ); -$new_ticket_form_title = eh_crm_get_settingsmeta( '0', 'new_ticket_form_title' ); -$existing_ticket_title = eh_crm_get_settingsmeta( '0', 'existing_ticket_title' ); -$submit_ticket_button = eh_crm_get_settingsmeta( '0', 'submit_ticket_button' ); -$reset_ticket_button = eh_crm_get_settingsmeta( '0', 'reset_ticket_button' ); -$existing_ticket_button = eh_crm_get_settingsmeta( '0', 'existing_ticket_button' ); -if ( ! $submit_ticket_button ) { - $submit_ticket_button = 'Submit Request'; -} -if ( ! $reset_ticket_button ) { - $reset_ticket_button = 'Reset Request'; -} -if ( ! $existing_ticket_button ) { - $existing_ticket_button = 'Check your Existing Request'; -} - -?> -<div class="crm-form-element"> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Set custom width for form elements', 'wsdesk' ); ?></span> - <div class="input-group"> - <input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" class="form-control" min="0" id="input_elements_width" style="height: 32px;" value="<?php echo esc_html( $input_width ); ?>" placeholder="100" aria-describedby="basic-addon2"> - <span class="input-group-addon" id="basic-addon2">%</span> - </div> - </div> -</div> -<h4 style="padding-left: 15px;"><?php esc_html_e( 'Existing Tickets Page Labels', 'wsdesk' ); ?></h4> -<div class="crm-form-element"> - <div class="col-md-8"> - <span class="help-block"><?php esc_html_e( 'You can set the labels displayed to unregistered users when they visit exisiting tickets page here.', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $exisiting_tickets_login_label = eh_crm_get_settingsmeta( '0', 'exisiting_tickets_login_label' ); - if ( empty( $exisiting_tickets_login_label ) ) { - $exisiting_tickets_login_label = esc_html__( 'You must Login to Check your Existing Ticket', 'wsdesk' ); - } - $exisiting_tickets_register_label = eh_crm_get_settingsmeta( '0', 'exisiting_tickets_register_label' ); - if ( empty( $exisiting_tickets_register_label ) ) { - $exisiting_tickets_register_label = esc_html__( 'Need an Account?', 'wsdesk' ); - } - ?> - <span class="help-block"><?php esc_html_e( 'Login Label', 'wsdesk' ); ?></span> - <input type="text" id="exisiting_tickets_login_label" class="form-control crm-form-element-input" value="<?php echo esc_html( $exisiting_tickets_login_label ); ?>"> - <span class="help-block"><?php esc_html_e( 'Register Label', 'wsdesk' ); ?></span> - <input type="text" id="exisiting_tickets_register_label" class="form-control crm-form-element-input" value="<?php echo esc_html( $exisiting_tickets_register_label ); ?>"> - </span> - </div> -</div> -<h4 style="padding-left: 15px;"><?php esc_html_e( 'Support Form Title', 'wsdesk' ); ?></h4> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-8"> - <span class="help-block"><?php esc_html_e( 'Set custom title for the main support form', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'This title would appear in the page with the short code [wsdesk_support].', 'wsdesk' ); ?>" data-container="body"></span></span> - - <input type="text" class="form-control" id="main_ticket_form_title" value="<?php echo esc_html( $main_ticket_form_title ); ?>" placeholder="<?php esc_html_e( 'Contact Support', 'wsdesk' ); ?>"> - </div> -</div> -<div class="crm-form-element"> - <div class="col-md-8"> - <span class="help-block"><?php esc_html_e( 'Set custom title for new support form', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'This title would appear for any new form for both the short codes [wsdesk_support] and [wsdesk_support display=form].', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" class="form-control" id="new_ticket_form_title" value="<?php echo esc_html( $new_ticket_form_title ); ?>" placeholder="Report Issue"> - </div> -</div> -<div class="crm-form-element"> - <div class="col-md-8"> - <span class="help-block"><?php esc_html_e( 'Set custom title for the existing tickets', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'This title would appear when you wish to display tickets in a separate page using the shortcode [wsdesk_support display=check_request].', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" class="form-control" id="existing_ticket_title" value="<?php echo esc_html( $existing_ticket_title ); ?>" placeholder="Your Tickets"> - </div> -</div> -<h4 style="padding-left: 15px;"><?php esc_html_e( 'Support Form Button', 'wsdesk' ); ?></h4> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-8"> - <span class="help-block"><?php esc_html_e( 'Set custom text for the Submit Request button', 'wsdesk' ); ?></span> - <input type="text" class="form-control" id="submit_ticket_button" value="<?php echo esc_html( $submit_ticket_button ); ?>" placeholder="<?php echo esc_html( $submit_ticket_button ); ?>"> - </div> -</div> -<div class="crm-form-element"> - <div class="col-md-8"> - <span class="help-block"><?php esc_html_e( 'Set custom text for the Reset Request button', 'wsdesk' ); ?></span> - <input type="text" class="form-control" id="reset_ticket_button" value="<?php echo esc_html( $reset_ticket_button ); ?>" placeholder="<?php echo esc_html( $reset_ticket_button ); ?>"> - </div> -</div> -<div class="crm-form-element"> - <div class="col-md-8"> - <span class="help-block"><?php esc_html_e( 'Set custom text for the Check Existing Ticket button', 'wsdesk' ); ?></span> - <input type="text" class="form-control" id="existing_ticket_button" value="<?php echo esc_html( $existing_ticket_button ); ?>" placeholder="<?php echo esc_html( $existing_ticket_button ); ?>"> - </div> -</div> -<h4 style="padding-left: 15px;"><?php esc_html_e( 'Redirection URL', 'wsdesk' ); ?></h4> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-8"> - <span><?php esc_html_e( 'Redirect users to a particular URL after submitting a ticket or logging in or registering or logging out from WSDesk Support Page.', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $login_redirect_url = eh_crm_get_settingsmeta( '0', 'login_redirect_url' ); - $purchase_credit_redirect_url = eh_crm_get_settingsmeta( '0', 'purchase_credit_redirect_url' ); - $logout_redirect_url = eh_crm_get_settingsmeta( '0', 'logout_redirect_url' ); - $register_redirect_url = eh_crm_get_settingsmeta( '0', 'register_redirect_url' ); - $submit_ticket_redirect_url = eh_crm_get_settingsmeta( '0', 'submit_ticket_redirect_url' ); - $set_credit_limit = eh_crm_get_settingsmeta( '0', 'set_credit_limit' ); - $login_url = eh_crm_get_settingsmeta( '0', 'login_url' ); - $reg_url = eh_crm_get_settingsmeta( '0', 'reg_url' ); - ?> - <span class="help-block"><?php esc_html_e( 'Login URL', 'wsdesk' ); ?></span> - <input type="text" id="login_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $login_url ); ?>"> - <span class="help-block"><?php esc_html_e( 'Register URL', 'wsdesk' ); ?></span> - <input type="text" id="reg_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $reg_url ); ?>"> - - <span class="help-block"><?php esc_html_e( 'Login Redirect URL', 'wsdesk' ); ?></span> - <input type="text" id="login_redirect_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $login_redirect_url ); ?>"> - <span class="help-block"><?php esc_html_e( 'Logout Redirect URL', 'wsdesk' ); ?></span> - <input type="text" id="logout_redirect_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $logout_redirect_url ); ?>"> - <span class="help-block"><?php esc_html_e( 'Register Redirect URL', 'wsdesk' ); ?></span> - <input type="text" id="register_redirect_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $register_redirect_url ); ?>"> - <span class="help-block"><?php esc_html_e( 'Submit Ticket Redirect URL', 'wsdesk' ); ?></span> - <input type="text" id="submit_ticket_redirect_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $submit_ticket_redirect_url ); ?>"> - </span> - </div> -</div> -<span class="crm-divider"></span> -<h4 style="padding-left: 15px;"><?php esc_html_e( 'Pay For Support Add-on', 'wsdesk' ); ?></h4> -<div class="crm-form-element"> - <div class="col-md-8"> - <span class="help-block"><?php esc_html_e( 'Purchase Credits Redirect URL', 'wsdesk' ); ?></span> - <input type="text" id="purchase_credit_redirect_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $purchase_credit_redirect_url ); ?>"> - <span class="help-block"><?php esc_html_e( 'Set Credit Limit to raise a ticket', 'wsdesk' ); ?></span> - <input type="text" id="set_credit_limit" class="form-control crm-form-element-input" value="<?php echo esc_html( $set_credit_limit ); ?>"> - </div> -</div> -<div class="crm-form-element"> - <div class="col-md-12"> - <button type="button" id="save_appearance" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button> - </div> -</div> -<?php -// return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+$input_width = eh_crm_get_settingsmeta( '0', 'input_width' );+$main_ticket_form_title = eh_crm_get_settingsmeta( '0', 'main_ticket_form_title' );+$new_ticket_form_title = eh_crm_get_settingsmeta( '0', 'new_ticket_form_title' );+$existing_ticket_title = eh_crm_get_settingsmeta( '0', 'existing_ticket_title' );+$submit_ticket_button = eh_crm_get_settingsmeta( '0', 'submit_ticket_button' );+$reset_ticket_button = eh_crm_get_settingsmeta( '0', 'reset_ticket_button' );+$existing_ticket_button = eh_crm_get_settingsmeta( '0', 'existing_ticket_button' );+if ( ! $submit_ticket_button ) {+ $submit_ticket_button = 'Submit Request';+}+if ( ! $reset_ticket_button ) {+ $reset_ticket_button = 'Reset Request';+}+if ( ! $existing_ticket_button ) {+ $existing_ticket_button = 'Check your Existing Request';+}++?>+<div class="crm-form-element">+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Set custom width for form elements', 'wsdesk' ); ?></span>+ <div class="input-group">+ <input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" class="form-control" min="0" id="input_elements_width" style="height: 32px;" value="<?php echo esc_html( $input_width ); ?>" placeholder="100" aria-describedby="basic-addon2">+ <span class="input-group-addon" id="basic-addon2">%</span>+ </div>+ </div>+</div>+<h4 style="padding-left: 15px;"><?php esc_html_e( 'Existing Tickets Page Labels', 'wsdesk' ); ?></h4>+<div class="crm-form-element">+ <div class="col-md-8">+ <span class="help-block"><?php esc_html_e( 'You can set the labels displayed to unregistered users when they visit exisiting tickets page here.', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $exisiting_tickets_login_label = eh_crm_get_settingsmeta( '0', 'exisiting_tickets_login_label' );+ if ( empty( $exisiting_tickets_login_label ) ) {+ $exisiting_tickets_login_label = esc_html__( 'You must Login to Check your Existing Ticket', 'wsdesk' );+ }+ $exisiting_tickets_register_label = eh_crm_get_settingsmeta( '0', 'exisiting_tickets_register_label' );+ if ( empty( $exisiting_tickets_register_label ) ) {+ $exisiting_tickets_register_label = esc_html__( 'Need an Account?', 'wsdesk' );+ }+ ?>+ <span class="help-block"><?php esc_html_e( 'Login Label', 'wsdesk' ); ?></span>+ <input type="text" id="exisiting_tickets_login_label" class="form-control crm-form-element-input" value="<?php echo esc_html( $exisiting_tickets_login_label ); ?>">+ <span class="help-block"><?php esc_html_e( 'Register Label', 'wsdesk' ); ?></span>+ <input type="text" id="exisiting_tickets_register_label" class="form-control crm-form-element-input" value="<?php echo esc_html( $exisiting_tickets_register_label ); ?>">+ </span>+ </div>+</div>+<h4 style="padding-left: 15px;"><?php esc_html_e( 'Support Form Title', 'wsdesk' ); ?></h4>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-8">+ <span class="help-block"><?php esc_html_e( 'Set custom title for the main support form', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'This title would appear in the page with the short code [wsdesk_support].', 'wsdesk' ); ?>" data-container="body"></span></span>++ <input type="text" class="form-control" id="main_ticket_form_title" value="<?php echo esc_html( $main_ticket_form_title ); ?>" placeholder="<?php esc_html_e( 'Contact Support', 'wsdesk' ); ?>">+ </div>+</div>+<div class="crm-form-element">+ <div class="col-md-8">+ <span class="help-block"><?php esc_html_e( 'Set custom title for new support form', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'This title would appear for any new form for both the short codes [wsdesk_support] and [wsdesk_support display=form].', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" class="form-control" id="new_ticket_form_title" value="<?php echo esc_html( $new_ticket_form_title ); ?>" placeholder="Report Issue">+ </div>+</div>+<div class="crm-form-element">+ <div class="col-md-8">+ <span class="help-block"><?php esc_html_e( 'Set custom title for the existing tickets', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'This title would appear when you wish to display tickets in a separate page using the shortcode [wsdesk_support display=check_request].', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" class="form-control" id="existing_ticket_title" value="<?php echo esc_html( $existing_ticket_title ); ?>" placeholder="Your Tickets">+ </div>+</div>+<h4 style="padding-left: 15px;"><?php esc_html_e( 'Support Form Button', 'wsdesk' ); ?></h4>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-8">+ <span class="help-block"><?php esc_html_e( 'Set custom text for the Submit Request button', 'wsdesk' ); ?></span>+ <input type="text" class="form-control" id="submit_ticket_button" value="<?php echo esc_html( $submit_ticket_button ); ?>" placeholder="<?php echo esc_html( $submit_ticket_button ); ?>">+ </div>+</div>+<div class="crm-form-element">+ <div class="col-md-8">+ <span class="help-block"><?php esc_html_e( 'Set custom text for the Reset Request button', 'wsdesk' ); ?></span>+ <input type="text" class="form-control" id="reset_ticket_button" value="<?php echo esc_html( $reset_ticket_button ); ?>" placeholder="<?php echo esc_html( $reset_ticket_button ); ?>">+ </div>+</div>+<div class="crm-form-element">+ <div class="col-md-8">+ <span class="help-block"><?php esc_html_e( 'Set custom text for the Check Existing Ticket button', 'wsdesk' ); ?></span>+ <input type="text" class="form-control" id="existing_ticket_button" value="<?php echo esc_html( $existing_ticket_button ); ?>" placeholder="<?php echo esc_html( $existing_ticket_button ); ?>">+ </div>+</div>+<h4 style="padding-left: 15px;"><?php esc_html_e( 'Redirection URL', 'wsdesk' ); ?></h4>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-8">+ <span><?php esc_html_e( 'Redirect users to a particular URL after submitting a ticket or logging in or registering or logging out from WSDesk Support Page.', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $login_redirect_url = eh_crm_get_settingsmeta( '0', 'login_redirect_url' );+ $purchase_credit_redirect_url = eh_crm_get_settingsmeta( '0', 'purchase_credit_redirect_url' );+ $logout_redirect_url = eh_crm_get_settingsmeta( '0', 'logout_redirect_url' );+ $register_redirect_url = eh_crm_get_settingsmeta( '0', 'register_redirect_url' );+ $submit_ticket_redirect_url = eh_crm_get_settingsmeta( '0', 'submit_ticket_redirect_url' );+ $set_credit_limit = eh_crm_get_settingsmeta( '0', 'set_credit_limit' );+ $login_url = eh_crm_get_settingsmeta( '0', 'login_url' );+ $reg_url = eh_crm_get_settingsmeta( '0', 'reg_url' );+ ?>+ <span class="help-block"><?php esc_html_e( 'Login URL', 'wsdesk' ); ?></span>+ <input type="text" id="login_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $login_url ); ?>">+ <span class="help-block"><?php esc_html_e( 'Register URL', 'wsdesk' ); ?></span>+ <input type="text" id="reg_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $reg_url ); ?>">++ <span class="help-block"><?php esc_html_e( 'Login Redirect URL', 'wsdesk' ); ?></span>+ <input type="text" id="login_redirect_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $login_redirect_url ); ?>">+ <span class="help-block"><?php esc_html_e( 'Logout Redirect URL', 'wsdesk' ); ?></span>+ <input type="text" id="logout_redirect_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $logout_redirect_url ); ?>">+ <span class="help-block"><?php esc_html_e( 'Register Redirect URL', 'wsdesk' ); ?></span>+ <input type="text" id="register_redirect_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $register_redirect_url ); ?>">+ <span class="help-block"><?php esc_html_e( 'Submit Ticket Redirect URL', 'wsdesk' ); ?></span>+ <input type="text" id="submit_ticket_redirect_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $submit_ticket_redirect_url ); ?>">+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<h4 style="padding-left: 15px;"><?php esc_html_e( 'Pay For Support Add-on', 'wsdesk' ); ?></h4>+<div class="crm-form-element">+ <div class="col-md-8">+ <span class="help-block"><?php esc_html_e( 'Purchase Credits Redirect URL', 'wsdesk' ); ?></span>+ <input type="text" id="purchase_credit_redirect_url" class="form-control crm-form-element-input" value="<?php echo esc_url( $purchase_credit_redirect_url ); ?>">+ <span class="help-block"><?php esc_html_e( 'Set Credit Limit to raise a ticket', 'wsdesk' ); ?></span>+ <input type="text" id="set_credit_limit" class="form-control crm-form-element-input" value="<?php echo esc_html( $set_credit_limit ); ?>">+ </div>+</div>+<div class="crm-form-element">+ <div class="col-md-12">+ <button type="button" id="save_appearance" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button>+ </div>+</div>+<?php+// return ob_get_clean();
Vulnerability Existed: no No Security Vulnerabilities Detected - views/settings/crm_settings_appearance.php (All Lines) Old Code: Unix line endings (LF) Fixed Code: Windows line endings (CRLF) Explanation: This diff represents a line ending conversion from Unix (LF) to Windows (CRLF) format. No actual code changes were made—only the line terminator characters were modified. The security analysis reveals no vulnerabilities were introduced or fixed. All existing security practices remain intact: 1. Output escaping is properly applied throughout: - `esc_html()` for HTML context escaping - `esc_url()` for URL context escaping - `esc_html_e()` for translatable text with HTML escaping 2. Input validation and sanitization appear to be handled upstream by the `eh_crm_get_settingsmeta()` function 3. No new code paths, logic changes, or potentially dangerous operations were introduced The line ending conversion itself has no security implications, though it may affect version control history and cross-platform consistency.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_archive_tickets.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_archive_tickets.php 2025-12-21 09:36:35.511308688 +0000@@ -1,94 +1,94 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -$avail_labels = eh_crm_get_settings( - array( - 'type' => 'label', - //'filter' => 'yes', - ), - array( 'slug', 'title', 'settings_id' ) -); -?> -<center> - <div> - <div class="success_archive" style="color:green;display: none"><h4><?php esc_html_e( 'Ticket(s) Data is Archived Successfully!', 'wsdesk' ); ?></h4></div> - <br> - <h3><?php esc_html_e( 'Archive Ticket', 'wsdesk' ); ?></h3> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Specify a date range to archive ticket data.', 'wsdesk' ); ?></span> - <input type="text" disabled name="archive_start_date" style=" width: 25%;height: 35px; - padding: 12px 20px; - margin: 8px 0; - display: inline-block; - border: 1px solid #ccc; - border-radius: 4px; - box-sizing: border-box;" id="archive_start_date" placeholder="Start Date" > - - <input type="text" disabled="true" name="archive_end_date" style=" width: 25%;height: 35px; - padding: 12px 20px; - margin: 8px 0; - display: inline-block; - border: 1px solid #ccc; - border-radius: 4px; - box-sizing: border-box;" id="archive_end_date" placeholder="End Date" > - <br> - <span class="help-block"><?php esc_html_e( 'Select the ticket status.', 'wsdesk' ); ?></span> - <select disabled="true" class="form-control show_archive" multiple="multiple" id="show_archive" aria-describedby="helpBlock"> - </select> - <br> - <span class="help-block"><?php esc_html_e( 'Leave this field empty to select all tickets.', 'wsdesk' ); ?></span> - - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12" id="archive_button"> - <span class="help-block" style="text-align: center"><?php esc_html_e( 'Archive may take a few minutes.', 'wsdesk' ); ?></span> - <button type="submit" id="archive_data" data-loading-text="<?php esc_html_e( 'Preparing Data...', 'wsdesk' ); ?>" class="btn btn-primary btn-lg archive_data"><?php esc_html_e( 'Start Archive', 'wsdesk' ); ?></button> - </div> - </div> - </div> - <span class="crm-divider"></span> - <div> - <div class="success_unarchive" style="color:green;display: none"><h4><?php esc_html_e( 'Ticket Data is Restored Successfully!', 'wsdesk' ); ?></h4></div> - <br> - <h3><?php esc_html_e( 'Restore Ticket', 'wsdesk' ); ?></h3> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Specify a date range to move archived ticket data to active tickets section.', 'wsdesk' ); ?></span> - <input type="text" style=" width: 25%;height: 35px; - padding: 12px 20px; - margin: 8px 0; - display: inline-block; - border: 1px solid #ccc; - border-radius: 4px; - box-sizing: border-box;" name="archive_start_date_restored" id="archive_start_date_restored" placeholder="Start Date" > - - <input disabled="true" type="text" name="archive_end_date_restored" style=" width: 25%;height: 35px; - padding: 12px 20px; - margin: 8px 0; - display: inline-block; - border: 1px solid #ccc; - border-radius: 4px; - box-sizing: border-box;" id="archive_end_date_restored" placeholder="End Date" > - <br> - <span class="help-block"><?php esc_html_e( 'Select the ticket status.', 'wsdesk' ); ?></span> - <select class="form-control show_unarchive" multiple="multiple" id="show_unarchive" aria-describedby="helpBlock"> - <?php - for ( $j = 0;$j < count( $avail_labels );$j++ ) { - echo '<option value="' . esc_attr( $avail_labels[ $j ]['slug'] ) . '">' . esc_html( $avail_labels[ $j ]['title'] ) . '</option>'; - } - ?> - </select> - <br> - <span class="help-block"><?php esc_html_e( 'Leave this field empty to select all tickets.', 'wsdesk' ); ?></span> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12" id="unarchive_button"> - <span class="help-block" style="text-align: center"><?php esc_html_e( 'Restore may take a few minutes.', 'wsdesk' ); ?></span> - <button type="submit" id="archive_data_restored" data-loading-text="<?php esc_html_e( 'Preparing Data...', 'wsdesk' ); ?>" class="btn btn-primary btn-lg archive_data_restored"><?php esc_html_e( 'Restore', 'wsdesk' ); ?></button> - </div> - </div> - </div> -</center> +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++$avail_labels = eh_crm_get_settings(+ array(+ 'type' => 'label',+ //'filter' => 'yes',+ ),+ array( 'slug', 'title', 'settings_id' )+);+?>+<center>+ <div>+ <div class="success_archive" style="color:green;display: none"><h4><?php esc_html_e( 'Ticket(s) Data is Archived Successfully!', 'wsdesk' ); ?></h4></div>+ <br>+ <h3><?php esc_html_e( 'Archive Ticket', 'wsdesk' ); ?></h3>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Specify a date range to archive ticket data.', 'wsdesk' ); ?></span>+ <input type="text" disabled name="archive_start_date" style=" width: 25%;height: 35px;+ padding: 12px 20px;+ margin: 8px 0;+ display: inline-block;+ border: 1px solid #ccc;+ border-radius: 4px;+ box-sizing: border-box;" id="archive_start_date" placeholder="Start Date" > -+ <input type="text" disabled="true" name="archive_end_date" style=" width: 25%;height: 35px;+ padding: 12px 20px;+ margin: 8px 0;+ display: inline-block;+ border: 1px solid #ccc;+ border-radius: 4px;+ box-sizing: border-box;" id="archive_end_date" placeholder="End Date" >+ <br>+ <span class="help-block"><?php esc_html_e( 'Select the ticket status.', 'wsdesk' ); ?></span>+ <select disabled="true" class="form-control show_archive" multiple="multiple" id="show_archive" aria-describedby="helpBlock">+ </select>+ <br>+ <span class="help-block"><?php esc_html_e( 'Leave this field empty to select all tickets.', 'wsdesk' ); ?></span>++ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12" id="archive_button">+ <span class="help-block" style="text-align: center"><?php esc_html_e( 'Archive may take a few minutes.', 'wsdesk' ); ?></span>+ <button type="submit" id="archive_data" data-loading-text="<?php esc_html_e( 'Preparing Data...', 'wsdesk' ); ?>" class="btn btn-primary btn-lg archive_data"><?php esc_html_e( 'Start Archive', 'wsdesk' ); ?></button>+ </div>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div>+ <div class="success_unarchive" style="color:green;display: none"><h4><?php esc_html_e( 'Ticket Data is Restored Successfully!', 'wsdesk' ); ?></h4></div>+ <br>+ <h3><?php esc_html_e( 'Restore Ticket', 'wsdesk' ); ?></h3>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Specify a date range to move archived ticket data to active tickets section.', 'wsdesk' ); ?></span>+ <input type="text" style=" width: 25%;height: 35px;+ padding: 12px 20px;+ margin: 8px 0;+ display: inline-block;+ border: 1px solid #ccc;+ border-radius: 4px;+ box-sizing: border-box;" name="archive_start_date_restored" id="archive_start_date_restored" placeholder="Start Date" > -+ <input disabled="true" type="text" name="archive_end_date_restored" style=" width: 25%;height: 35px;+ padding: 12px 20px;+ margin: 8px 0;+ display: inline-block;+ border: 1px solid #ccc;+ border-radius: 4px;+ box-sizing: border-box;" id="archive_end_date_restored" placeholder="End Date" >+ <br>+ <span class="help-block"><?php esc_html_e( 'Select the ticket status.', 'wsdesk' ); ?></span>+ <select class="form-control show_unarchive" multiple="multiple" id="show_unarchive" aria-describedby="helpBlock">+ <?php+ for ( $j = 0;$j < count( $avail_labels );$j++ ) {+ echo '<option value="' . esc_attr( $avail_labels[ $j ]['slug'] ) . '">' . esc_html( $avail_labels[ $j ]['title'] ) . '</option>';+ }+ ?>+ </select>+ <br>+ <span class="help-block"><?php esc_html_e( 'Leave this field empty to select all tickets.', 'wsdesk' ); ?></span>+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12" id="unarchive_button">+ <span class="help-block" style="text-align: center"><?php esc_html_e( 'Restore may take a few minutes.', 'wsdesk' ); ?></span>+ <button type="submit" id="archive_data_restored" data-loading-text="<?php esc_html_e( 'Preparing Data...', 'wsdesk' ); ?>" class="btn btn-primary btn-lg archive_data_restored"><?php esc_html_e( 'Restore', 'wsdesk' ); ?></button>+ </div>+ </div>+ </div>+</center>
Vulnerability Existed: no No Security Vulnerabilities Detected Explanation: The diff shows only line ending changes (CRLF to LF conversion) between versions 3.3.4 and 3.3.5 of the file. The actual code content remains identical. No new code was introduced, removed, or modified that would introduce or fix security vulnerabilities. The file contains proper output escaping: - `esc_html_e()` for translatable text output - `esc_attr()` for HTML attribute values - `esc_html()` for HTML content These existing escaping functions properly protect against XSS attacks. The line ending normalization does not affect security posture.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_backup_restore.php 2025-12-21 09:35:59.581075515 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_backup_restore.php 2025-12-21 09:36:35.511308688 +0000@@ -1,86 +1,86 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -?> -<center> - <h3><?php esc_html_e( 'Initiate Ticket', 'wsdesk' ); ?></h3> - <div class="crm-form-element"> - <span class="help-block" style="text-align: center"><?php esc_html_e( 'Start ticket with specified number', 'wsdesk' ); ?></span> - <span style="display: inline-flex;"> - <input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" name="initiate_number" id="initiate_number" placeholder="Starting Number" class="form-control" style="height: auto;width: 100%;margin-right: 10px;padding: 5px;"> - <button type="button" id="start_initiate_ticket" class="btn btn-primary"><?php esc_html_e( 'Set Number', 'wsdesk' ); ?></button> - </span> - </div> - <span class="crm-divider"></span> - <div class="col-md-12" style="margin-bottom: 20px;"> - <div class="col-md-4"> - <div class="crm-form-element"> - <span class="help-block" style="text-align: center"><?php esc_html_e( 'Delete all tickets in trash', 'wsdesk' ); ?></span> - <span style="display: inline-flex;"> - <button type="button" id="empty_trash" class="btn btn-primary btn-lg"><?php esc_html_e( 'Empty Trash', 'wsdesk' ); ?></button> - </span> - </div> - </div> - <div class="col-md-4"> - <div class="crm-form-element"> - <span class="help-block" style="text-align: center"><?php esc_html_e( 'Restore all tickets from trash', 'wsdesk' ); ?></span> - <span style="display: inline-flex;"> - <button type="button" id="restore_trash" class="btn btn-primary btn-lg"><?php esc_html_e( 'Restore Trash', 'wsdesk' ); ?></button> - </span> - </div> - </div> - <div class="col-md-4"> - <div class="crm-form-element"> - <span class="help-block" style="text-align: center"><?php esc_html_e( 'Delete all scheduled trigger cache', 'wsdesk' ); ?></span> - <span style="display: inline-flex;"> - <button type="button" id="empty_scheduled_trigger" class="btn btn-primary btn-lg"><?php esc_html_e( 'Clear Now', 'wsdesk' ); ?></button> - </span> - </div> - </div> - </div> - <span class="crm-divider"></span> - <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"> - <h3><?php esc_html_e( 'Backup Data (JSON)', 'wsdesk' ); ?></h3> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Specify the data to be Backup if needed?', 'wsdesk' ); ?></span> - <input type="checkbox" name="backup_data_values[]" id="backup_data_values" value="settings" checked=""> <?php esc_html_e( 'Settings', 'wsdesk' ); ?> - <input type="checkbox" name="backup_data_values[]" id="backup_data_values" value="tickets" checked=""> <?php esc_html_e( 'Tickets', 'wsdesk' ); ?> - <input type="checkbox" name="backup_data_values[]" id="backup_data_values" value="archive_tickets" checked=""> <?php esc_html_e( 'Archive Tickets', 'wsdesk' ); ?> - <input type="hidden" name="action" value="eh_crm_backup_data"> - <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Specify the date range for tickets Backup if needed?', 'wsdesk' ); ?></span> - <input type="text" id="backup_date_range_start" placeholder="Start Date" name="backup_date_range_start"> - - <input type="text" id="backup_date_range_end" placeholder="End Date" name="backup_date_range_end"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12" id="download_backup_button"> - <span class="help-block" style="text-align: center"><?php esc_html_e( 'Backing Up of WSDesk Data may require some time.', 'wsdesk' ); ?></span> - <span class="help-block" style="text-align: center"><?php esc_html_e( 'Please note that attachments cannot be taken as backup.', 'wsdesk' ); ?></span> - <button type="button" id="backup_data" data-loading-text="<?php esc_html_e( 'Preparing Data...', 'wsdesk' ); ?>" class="btn btn-primary btn-lg"><?php esc_html_e( 'Start Backup', 'wsdesk' ); ?></button> - </div> - </div> - </form> - <span class="crm-divider"></span> - <h3><?php esc_html_e( 'Restore Data (JSON)', 'wsdesk' ); ?></h3> - <div class="crm-form-element"> - <span class="help-block" style="text-align: center"><?php esc_html_e( 'WSDesk Restore Data File', 'wsdesk' ); ?></span> - <input type="file" name="restore_file" accept=".json" id="restore_file" class="form-control" style="height: auto;width: 50%;padding: 5px;"> - </div> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block" style="text-align: center"><?php esc_html_e( 'Restoring WSDesk Data may take some time.', 'wsdesk' ); ?></span> - <button type="button" id="restore_data" data-loading-text="<?php esc_html_e( 'Restoring Data...', 'wsdesk' ); ?>" class="btn btn-primary btn-lg"><?php esc_html_e( 'Start Restore', 'wsdesk' ); ?></button> - </div> - </div> - -</center> -<?php -// return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+?>+<center>+ <h3><?php esc_html_e( 'Initiate Ticket', 'wsdesk' ); ?></h3>+ <div class="crm-form-element">+ <span class="help-block" style="text-align: center"><?php esc_html_e( 'Start ticket with specified number', 'wsdesk' ); ?></span>+ <span style="display: inline-flex;">+ <input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" name="initiate_number" id="initiate_number" placeholder="Starting Number" class="form-control" style="height: auto;width: 100%;margin-right: 10px;padding: 5px;">+ <button type="button" id="start_initiate_ticket" class="btn btn-primary"><?php esc_html_e( 'Set Number', 'wsdesk' ); ?></button>+ </span>+ </div>+ <span class="crm-divider"></span>+ <div class="col-md-12" style="margin-bottom: 20px;">+ <div class="col-md-4">+ <div class="crm-form-element">+ <span class="help-block" style="text-align: center"><?php esc_html_e( 'Delete all tickets in trash', 'wsdesk' ); ?></span>+ <span style="display: inline-flex;">+ <button type="button" id="empty_trash" class="btn btn-primary btn-lg"><?php esc_html_e( 'Empty Trash', 'wsdesk' ); ?></button>+ </span>+ </div>+ </div>+ <div class="col-md-4">+ <div class="crm-form-element">+ <span class="help-block" style="text-align: center"><?php esc_html_e( 'Restore all tickets from trash', 'wsdesk' ); ?></span>+ <span style="display: inline-flex;">+ <button type="button" id="restore_trash" class="btn btn-primary btn-lg"><?php esc_html_e( 'Restore Trash', 'wsdesk' ); ?></button>+ </span>+ </div>+ </div>+ <div class="col-md-4">+ <div class="crm-form-element">+ <span class="help-block" style="text-align: center"><?php esc_html_e( 'Delete all scheduled trigger cache', 'wsdesk' ); ?></span>+ <span style="display: inline-flex;">+ <button type="button" id="empty_scheduled_trigger" class="btn btn-primary btn-lg"><?php esc_html_e( 'Clear Now', 'wsdesk' ); ?></button>+ </span>+ </div>+ </div>+ </div>+ <span class="crm-divider"></span>+ <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>">+ <h3><?php esc_html_e( 'Backup Data (JSON)', 'wsdesk' ); ?></h3>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Specify the data to be Backup if needed?', 'wsdesk' ); ?></span>+ <input type="checkbox" name="backup_data_values[]" id="backup_data_values" value="settings" checked=""> <?php esc_html_e( 'Settings', 'wsdesk' ); ?>+ <input type="checkbox" name="backup_data_values[]" id="backup_data_values" value="tickets" checked=""> <?php esc_html_e( 'Tickets', 'wsdesk' ); ?>+ <input type="checkbox" name="backup_data_values[]" id="backup_data_values" value="archive_tickets" checked=""> <?php esc_html_e( 'Archive Tickets', 'wsdesk' ); ?>+ <input type="hidden" name="action" value="eh_crm_backup_data">+ <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Specify the date range for tickets Backup if needed?', 'wsdesk' ); ?></span>+ <input type="text" id="backup_date_range_start" placeholder="Start Date" name="backup_date_range_start"> -+ <input type="text" id="backup_date_range_end" placeholder="End Date" name="backup_date_range_end">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12" id="download_backup_button">+ <span class="help-block" style="text-align: center"><?php esc_html_e( 'Backing Up of WSDesk Data may require some time.', 'wsdesk' ); ?></span>+ <span class="help-block" style="text-align: center"><?php esc_html_e( 'Please note that attachments cannot be taken as backup.', 'wsdesk' ); ?></span>+ <button type="button" id="backup_data" data-loading-text="<?php esc_html_e( 'Preparing Data...', 'wsdesk' ); ?>" class="btn btn-primary btn-lg"><?php esc_html_e( 'Start Backup', 'wsdesk' ); ?></button>+ </div>+ </div>+ </form>+ <span class="crm-divider"></span>+ <h3><?php esc_html_e( 'Restore Data (JSON)', 'wsdesk' ); ?></h3>+ <div class="crm-form-element">+ <span class="help-block" style="text-align: center"><?php esc_html_e( 'WSDesk Restore Data File', 'wsdesk' ); ?></span>+ <input type="file" name="restore_file" accept=".json" id="restore_file" class="form-control" style="height: auto;width: 50%;padding: 5px;">+ </div>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block" style="text-align: center"><?php esc_html_e( 'Restoring WSDesk Data may take some time.', 'wsdesk' ); ?></span>+ <button type="button" id="restore_data" data-loading-text="<?php esc_html_e( 'Restoring Data...', 'wsdesk' ); ?>" class="btn btn-primary btn-lg"><?php esc_html_e( 'Start Restore', 'wsdesk' ); ?></button>+ </div>+ </div>++</center>+<?php+// return ob_get_clean();
Vulnerability Existed: no No Security Vulnerabilities Detected - views/settings/crm_settings_backup_restore.php Explanation: This diff contains only line ending changes (CRLF to LF conversion). The actual code content remains identical between versions 3.3.4 and 3.3.5. No new code has been added, removed, or modified that would introduce or fix security vulnerabilities. The file itself contains standard WordPress security practices: - Uses `esc_html_e()` for output escaping - Uses `esc_url()` for URL sanitization - Uses `wp_create_nonce()` for CSRF protection - Includes WordPress ABSPATH check to prevent direct access Since no functional code changes were made, there are no security fixes to analyze in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_export.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_export.php 2025-12-21 09:36:35.511308688 +0000@@ -1,29 +1,29 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -?> -<center> - <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"> - <h3><?php esc_html_e( 'Export Ticket Data (CSV)', 'wsdesk' ); ?></h3> - <div class="crm-form-element"> - <div class="col-md-12"> - <span class="help-block"><?php esc_html_e( 'Specify a date range for the ticket data to be exported if needed?', 'wsdesk' ); ?></span> - <input type="text" name="export_start_date" id="export_start_date" placeholder="Start Date" > - - <input type="text" name="export_end_date" id="export_end_date" placeholder="End Date" > - <input type="hidden" name="action" value="eh_crm_export_ticket_data"> - <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>"> - </div> - </div> - <div class="crm-form-element"> - <div class="col-md-12" id="download_backup_button"> - <span class="help-block" style="text-align: center"><?php esc_html_e( 'Export may take a few minutes.', 'wsdesk' ); ?></span> - <button type="submit" id="export_data" data-loading-text="<?php esc_html_e( 'Preparing Data...', 'wsdesk' ); ?>" class="btn btn-primary btn-lg"><?php esc_html_e( 'Start Export', 'wsdesk' ); ?></button> - </div> - </div> - </form> -</center> -<?php -// return ob_get_clean(); -?> +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+?>+<center>+ <form id="backup_wsdesk" method="POST" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>">+ <h3><?php esc_html_e( 'Export Ticket Data (CSV)', 'wsdesk' ); ?></h3>+ <div class="crm-form-element">+ <div class="col-md-12">+ <span class="help-block"><?php esc_html_e( 'Specify a date range for the ticket data to be exported if needed?', 'wsdesk' ); ?></span>+ <input type="text" name="export_start_date" id="export_start_date" placeholder="Start Date" > - + <input type="text" name="export_end_date" id="export_end_date" placeholder="End Date" >+ <input type="hidden" name="action" value="eh_crm_export_ticket_data">+ <input type="hidden" name="nonce" value="<?php echo esc_html( wp_create_nonce( 'wsdesk_nonce' ) ); ?>">+ </div>+ </div>+ <div class="crm-form-element">+ <div class="col-md-12" id="download_backup_button">+ <span class="help-block" style="text-align: center"><?php esc_html_e( 'Export may take a few minutes.', 'wsdesk' ); ?></span>+ <button type="submit" id="export_data" data-loading-text="<?php esc_html_e( 'Preparing Data...', 'wsdesk' ); ?>" class="btn btn-primary btn-lg"><?php esc_html_e( 'Start Export', 'wsdesk' ); ?></button>+ </div>+ </div>+ </form>+</center>+<?php +// return ob_get_clean();+?>
Vulnerability Existed: no Explanation: This diff shows only whitespace and line ending changes (converting from Unix LF to Windows CRLF line endings). The actual code content remains identical between versions 3.3.4 and 3.3.5. No security fixes or vulnerabilities are introduced or addressed in this change. The code itself properly implements WordPress security best practices: - Uses `esc_url()` for URL escaping in the form action - Uses `esc_html()` for HTML escaping in output - Uses `esc_html_e()` for escaped internationalized text - Includes nonce verification via `wp_create_nonce()` - Checks for WordPress constant `ABSPATH` before execution Since no functional code changes are present, there are no security vulnerabilities to analyze in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_fields.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_fields.php 2025-12-21 09:36:35.511308688 +0000@@ -1,179 +1,179 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -$args = array( 'type' => 'field' ); -$fields = array( 'slug', 'title', 'settings_id' ); -$avail_fields = eh_crm_get_settings( $args, $fields ); -$selected = eh_crm_get_settingsmeta( '0', 'selected_fields' ); -if ( empty( $selected ) ) { - $selected = array( 'request_email', 'request_title', 'request_description' ); - - eh_crm_update_settingsmeta( '0', 'selected_fields', array_values( $selected ) ); -} -if ( ! in_array( 'request_description', $selected ) ) { - array_unshift( $selected, 'request_description' ); -} -if ( ! in_array( 'request_title', $selected ) ) { - array_unshift( $selected, 'request_title' ); -} -if ( ! in_array( 'request_email', $selected ) ) { - array_unshift( $selected, 'request_email' ); -} -?> -<div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="ticket_fields" style="padding-right:1em !important;"><?php esc_html_e( 'Ticket Fields', 'wsdesk' ); ?></label> - <button type="button" id="ticket_field_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Field', 'wsdesk' ); ?></button> - </div> - <div class="panel panel-default crm-panel" style="margin-top: 15px !important;margin-bottom: 0px !important;"> - <div class="panel-body" style="padding: 5px !important;"> - <div class="col-sm-6" style="padding-right: 5px !important;padding-left: 5px !important;"> - <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php esc_html_e( 'Inactive Fields', 'wsdesk' ); ?></span><br> - <ul class="list-group"> - <?php - if ( ( count( $avail_fields ) <= 3 ) || ( count( $avail_fields ) == count( $selected ) ) ) { - echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'No inactive field', 'wsdesk' ) . '</li>'; - } else { - for ( $i = 3;$i < count( $avail_fields );$i++ ) { - $field_type = eh_crm_get_settingsmeta( $avail_fields[ $i ]['settings_id'], 'field_type' ); - if ( ! in_array( $avail_fields[ $i ]['slug'], $selected ) ) { - echo '<li class="list-group-item list-group-item-info" id="' . esc_attr( $avail_fields[ $i ]['slug'] ) . '"> ' . esc_html( $avail_fields[ $i ]['title'] ) . ' [ ' . esc_html( ucfirst( $field_type ) ) . ' ] <span class="pull-right"><span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_field_activate" id="' . esc_attr( $avail_fields[ $i ]['slug'] ) . '"><span class="glyphicon glyphicon-ok-circle" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Activate', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span></span><span class="glyphicon glyphicon-trash ticket_field_delete_type" id="' . esc_attr( $avail_fields[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Field', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> <span class="glyphicon glyphicon-pencil ticket_field_edit_type" id="' . esc_attr( $avail_fields[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Field', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span></span></li>'; - } - } - } - ?> - </ul> - </div> - <div class="col-sm-6"> - <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php esc_html_e( 'Active Fields', 'wsdesk' ); ?></span><br> - <ul class="list-group list-group-sortable-connected list-group-field-data list-border-settings"> - <?php - for ( $i = 0;$i < count( $selected );$i++ ) { - for ( $j = 0;$j < count( $avail_fields );$j++ ) { - if ( $avail_fields[ $j ]['slug'] === $selected[ $i ] ) { - $field_type = eh_crm_get_settingsmeta( $avail_fields[ $j ]['settings_id'], 'field_type' ); - echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $avail_fields[ $j ]['slug'] ) . '"><span class="dashicons dashicons-menu" style="cursor:move;margin-right:5px;"></span><span data-toggle="wsdesk_tooltip" data-container="body" title="Key : ' . esc_html( $avail_fields[ $j ]['slug'] ) . '" style="cursor:help;" > ' . esc_attr( $avail_fields[ $j ]['title'] ) . ' [ ' . esc_html( ucfirst( $field_type ) ) . ' ] </span><span class="pull-right">'; - if ( ! in_array( $avail_fields[ $j ]['slug'], array( 'request_email', 'request_title', 'request_description' ) ) ) { - echo '<span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_field_deactivate" id="' . esc_attr( $avail_fields[ $j ]['slug'] ) . '"><span class="glyphicon glyphicon-remove-circle" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Deactivate', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"> - </span></span> '; - } - if ( ! in_array( $avail_fields[ $j ]['slug'], array( 'request_email', 'request_title', 'request_description' ) ) ) { - echo '<span class="glyphicon glyphicon-trash ticket_field_delete_type" id="' . esc_attr( $avail_fields[ $j ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Field', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - } - if ( 'google_captcha' !== $avail_fields[ $j ]['slug'] ) { - echo '<span class="glyphicon glyphicon-pencil ticket_field_edit_type" id="' . esc_attr( $avail_fields[ $j ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Field', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - } - echo '</span></li>'; - } - } - } - ?> - </ul> - </div> - </div> - </div> - </div> -</div> -<div id="ticket_field_add_display" style="display: none;"> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="ticket_field_add" style="padding-right:1em !important;"><?php esc_html_e( 'Add Ticket Field', 'wsdesk' ); ?></label> - <button type="button" id="ticket_field_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - </div> - <span style="vertical-align: middle;" id="ticket_field_add_section"> - <input type="hidden" value="" id="add_new_field_yes"> - <br> - <select id="ticket_field_add_type" style="width: 100% !important;display: inline !important" class="form-control" aria-describedby="helpBlock"> - <option value=""><?php esc_html_e( 'Select the Type of Field', 'wsdesk' ); ?></option> - <?php - $all_field_slug = array(); - for ( $i = 0;$i < count( $avail_fields );$i++ ) { - array_push( $all_field_slug, $avail_fields[ $i ]['slug'] ); - } - if ( EH_CRM_WOO_STATUS ) { - if ( ! in_array( 'woo_product', $all_field_slug ) ) { - echo '<option value="woo_product"> WooCommerce' . esc_html__( ' Products', 'wsdesk' ) . '</option>'; - } - if ( ! in_array( 'woo_order_id', $all_field_slug ) ) { - echo '<option value="woo_order_id"> WooCommerce' . esc_html__( ' Order id', 'wsdesk' ) . '</option>'; - } - if ( ! in_array( 'woo_category', $all_field_slug ) ) { - echo '<option value="woo_category"> WooCommerce' . esc_html__( ' category', 'wsdesk' ) . '</option>'; - } - if ( ! in_array( 'woo_tags', $all_field_slug ) ) { - echo '<option value="woo_tags"> WooCommerce' . esc_html__( ' Tags', 'wsdesk' ) . '</option>'; - } - $vendor_roles = eh_crm_get_settingsmeta( 0, 'woo_vendor_roles' ); - if ( ! $vendor_roles ) { - $vendor_roles = array(); - } - if ( ! in_array( 'woo_vendors', $all_field_slug ) && ! empty( $vendor_roles ) ) { - echo '<option value="woo_vendors"> WooCommerce' . esc_html__( ' Vendors', 'wsdesk' ) . '</option>'; - } - } - if ( EH_CRM_EDD_STATUS ) { - if ( ! in_array( 'edd_products', $all_field_slug ) ) { - echo '<option value="edd_products"> Easy Digital Downloads' . esc_html__( ' Products', 'wsdesk' ) . '</option>'; - } - } - if ( EH_CRM_PAY_FOR_SUPPORT_STATUS ) { - if ( ! in_array( 'pfs_order_product', $all_field_slug ) ) { - echo '<option value="pfs_order_product">' . esc_html__( 'Pay for support Order Product', 'wsdesk' ) . '</option>'; - } - } - ?> - <option value="text"><?php esc_html_e( 'Text Box', 'wsdesk' ); ?></option> - <option value="password"><?php esc_html_e( 'Password', 'wsdesk' ); ?></option> - <option value="select"><?php esc_html_e( 'Select', 'wsdesk' ); ?></option> - <option value="radio"><?php esc_html_e( 'Radio', 'wsdesk' ); ?></option> - <option value="checkbox"><?php esc_html_e( 'Checkbox', 'wsdesk' ); ?></option> - <option value="number"><?php esc_html_e( 'Number', 'wsdesk' ); ?></option> - <option value="email"><?php esc_html_e( 'Email', 'wsdesk' ); ?></option> - <option value="date"><?php esc_html_e( 'Date', 'wsdesk' ); ?></option> - <option value="textarea"><?php esc_html_e( 'Text Area', 'wsdesk' ); ?></option> - <option value="file"><?php esc_html_e( 'Attachment', 'wsdesk' ); ?></option> - <option value="ip"><?php esc_html_e( 'IP Address', 'wsdesk' ); ?></option> - <?php - if ( EH_CRM_WSDESK_SMS_NOTIFICATION_STATUS ) { - if ( ! in_array( 'phone_number', $all_field_slug ) ) { - ?> - <option value="phone"><?php esc_html_e( 'Phone Number (SMS Notification Add On)', 'wsdesk' ); ?></option> - <?php - } - } - if ( ! in_array( 'google_captcha', $all_field_slug ) ) { - echo '<option value="google_captcha">Google reCAPTCHA</option>'; - } - ?> - </select> - <br> - <span style="vertical-align: middle;" id="ticket_field_add_append"></span> - </span> - </div> - </div> -</div> -<div id="ticket_field_edit_display" style="display: none;"> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label style="padding-right:1em !important;"><?php esc_html_e( 'Edit Ticket Field', 'wsdesk' ); ?></label> - <button type="button" id="ticket_field_cancel_edit_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - </div> - <input type="hidden" value="" id="ticket_field_edit_type"> - <span style="vertical-align: middle;" id="ticket_field_edit_append"></span> - </div> - </div> -</div> -<div class="crm-form-element"> - <div class="col-md-12"> - <button type="button" id="save_ticket_fields" class="btn btn-primary"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button> - </div> -</div> -<?php -// return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+$args = array( 'type' => 'field' );+$fields = array( 'slug', 'title', 'settings_id' );+$avail_fields = eh_crm_get_settings( $args, $fields );+$selected = eh_crm_get_settingsmeta( '0', 'selected_fields' );+if ( empty( $selected ) ) {+ $selected = array( 'request_email', 'request_title', 'request_description' );+ + eh_crm_update_settingsmeta( '0', 'selected_fields', array_values( $selected ) );+}+if ( ! in_array( 'request_description', $selected ) ) {+ array_unshift( $selected, 'request_description' );+}+if ( ! in_array( 'request_title', $selected ) ) {+ array_unshift( $selected, 'request_title' );+}+if ( ! in_array( 'request_email', $selected ) ) {+ array_unshift( $selected, 'request_email' );+}+?>+<div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="ticket_fields" style="padding-right:1em !important;"><?php esc_html_e( 'Ticket Fields', 'wsdesk' ); ?></label>+ <button type="button" id="ticket_field_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Field', 'wsdesk' ); ?></button>+ </div>+ <div class="panel panel-default crm-panel" style="margin-top: 15px !important;margin-bottom: 0px !important;">+ <div class="panel-body" style="padding: 5px !important;">+ <div class="col-sm-6" style="padding-right: 5px !important;padding-left: 5px !important;">+ <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php esc_html_e( 'Inactive Fields', 'wsdesk' ); ?></span><br>+ <ul class="list-group">+ <?php+ if ( ( count( $avail_fields ) <= 3 ) || ( count( $avail_fields ) == count( $selected ) ) ) {+ echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'No inactive field', 'wsdesk' ) . '</li>';+ } else {+ for ( $i = 3;$i < count( $avail_fields );$i++ ) {+ $field_type = eh_crm_get_settingsmeta( $avail_fields[ $i ]['settings_id'], 'field_type' );+ if ( ! in_array( $avail_fields[ $i ]['slug'], $selected ) ) {+ echo '<li class="list-group-item list-group-item-info" id="' . esc_attr( $avail_fields[ $i ]['slug'] ) . '"> ' . esc_html( $avail_fields[ $i ]['title'] ) . ' [ ' . esc_html( ucfirst( $field_type ) ) . ' ] <span class="pull-right"><span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_field_activate" id="' . esc_attr( $avail_fields[ $i ]['slug'] ) . '"><span class="glyphicon glyphicon-ok-circle" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Activate', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span></span><span class="glyphicon glyphicon-trash ticket_field_delete_type" id="' . esc_attr( $avail_fields[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Field', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> <span class="glyphicon glyphicon-pencil ticket_field_edit_type" id="' . esc_attr( $avail_fields[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Field', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span></span></li>';+ }+ }+ }+ ?>+ </ul>+ </div>+ <div class="col-sm-6">+ <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php esc_html_e( 'Active Fields', 'wsdesk' ); ?></span><br>+ <ul class="list-group list-group-sortable-connected list-group-field-data list-border-settings">+ <?php+ for ( $i = 0;$i < count( $selected );$i++ ) {+ for ( $j = 0;$j < count( $avail_fields );$j++ ) {+ if ( $avail_fields[ $j ]['slug'] === $selected[ $i ] ) {+ $field_type = eh_crm_get_settingsmeta( $avail_fields[ $j ]['settings_id'], 'field_type' );+ echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $avail_fields[ $j ]['slug'] ) . '"><span class="dashicons dashicons-menu" style="cursor:move;margin-right:5px;"></span><span data-toggle="wsdesk_tooltip" data-container="body" title="Key : ' . esc_html( $avail_fields[ $j ]['slug'] ) . '" style="cursor:help;" > ' . esc_attr( $avail_fields[ $j ]['title'] ) . ' [ ' . esc_html( ucfirst( $field_type ) ) . ' ] </span><span class="pull-right">';+ if ( ! in_array( $avail_fields[ $j ]['slug'], array( 'request_email', 'request_title', 'request_description' ) ) ) {+ echo '<span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_field_deactivate" id="' . esc_attr( $avail_fields[ $j ]['slug'] ) . '"><span class="glyphicon glyphicon-remove-circle" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Deactivate', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;">+ </span></span> ';+ }+ if ( ! in_array( $avail_fields[ $j ]['slug'], array( 'request_email', 'request_title', 'request_description' ) ) ) {+ echo '<span class="glyphicon glyphicon-trash ticket_field_delete_type" id="' . esc_attr( $avail_fields[ $j ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Field', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ }+ if ( 'google_captcha' !== $avail_fields[ $j ]['slug'] ) {+ echo '<span class="glyphicon glyphicon-pencil ticket_field_edit_type" id="' . esc_attr( $avail_fields[ $j ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Field', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ }+ echo '</span></li>';+ }+ } + }+ ?>+ </ul>+ </div>+ </div>+ </div>+ </div>+</div>+<div id="ticket_field_add_display" style="display: none;">+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="ticket_field_add" style="padding-right:1em !important;"><?php esc_html_e( 'Add Ticket Field', 'wsdesk' ); ?></label>+ <button type="button" id="ticket_field_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button>+ </div>+ <span style="vertical-align: middle;" id="ticket_field_add_section">+ <input type="hidden" value="" id="add_new_field_yes">+ <br>+ <select id="ticket_field_add_type" style="width: 100% !important;display: inline !important" class="form-control" aria-describedby="helpBlock">+ <option value=""><?php esc_html_e( 'Select the Type of Field', 'wsdesk' ); ?></option>+ <?php+ $all_field_slug = array();+ for ( $i = 0;$i < count( $avail_fields );$i++ ) {+ array_push( $all_field_slug, $avail_fields[ $i ]['slug'] );+ }+ if ( EH_CRM_WOO_STATUS ) {+ if ( ! in_array( 'woo_product', $all_field_slug ) ) {+ echo '<option value="woo_product"> WooCommerce' . esc_html__( ' Products', 'wsdesk' ) . '</option>';+ }+ if ( ! in_array( 'woo_order_id', $all_field_slug ) ) {+ echo '<option value="woo_order_id"> WooCommerce' . esc_html__( ' Order id', 'wsdesk' ) . '</option>';+ }+ if ( ! in_array( 'woo_category', $all_field_slug ) ) {+ echo '<option value="woo_category"> WooCommerce' . esc_html__( ' category', 'wsdesk' ) . '</option>';+ }+ if ( ! in_array( 'woo_tags', $all_field_slug ) ) {+ echo '<option value="woo_tags"> WooCommerce' . esc_html__( ' Tags', 'wsdesk' ) . '</option>';+ }+ $vendor_roles = eh_crm_get_settingsmeta( 0, 'woo_vendor_roles' );+ if ( ! $vendor_roles ) {+ $vendor_roles = array();+ }+ if ( ! in_array( 'woo_vendors', $all_field_slug ) && ! empty( $vendor_roles ) ) {+ echo '<option value="woo_vendors"> WooCommerce' . esc_html__( ' Vendors', 'wsdesk' ) . '</option>';+ }+ }+ if ( EH_CRM_EDD_STATUS ) {+ if ( ! in_array( 'edd_products', $all_field_slug ) ) {+ echo '<option value="edd_products"> Easy Digital Downloads' . esc_html__( ' Products', 'wsdesk' ) . '</option>';+ }+ }+ if ( EH_CRM_PAY_FOR_SUPPORT_STATUS ) {+ if ( ! in_array( 'pfs_order_product', $all_field_slug ) ) {+ echo '<option value="pfs_order_product">' . esc_html__( 'Pay for support Order Product', 'wsdesk' ) . '</option>';+ }+ }+ ?>+ <option value="text"><?php esc_html_e( 'Text Box', 'wsdesk' ); ?></option>+ <option value="password"><?php esc_html_e( 'Password', 'wsdesk' ); ?></option>+ <option value="select"><?php esc_html_e( 'Select', 'wsdesk' ); ?></option>+ <option value="radio"><?php esc_html_e( 'Radio', 'wsdesk' ); ?></option>+ <option value="checkbox"><?php esc_html_e( 'Checkbox', 'wsdesk' ); ?></option>+ <option value="number"><?php esc_html_e( 'Number', 'wsdesk' ); ?></option>+ <option value="email"><?php esc_html_e( 'Email', 'wsdesk' ); ?></option>+ <option value="date"><?php esc_html_e( 'Date', 'wsdesk' ); ?></option>+ <option value="textarea"><?php esc_html_e( 'Text Area', 'wsdesk' ); ?></option>+ <option value="file"><?php esc_html_e( 'Attachment', 'wsdesk' ); ?></option>+ <option value="ip"><?php esc_html_e( 'IP Address', 'wsdesk' ); ?></option>+ <?php+ if ( EH_CRM_WSDESK_SMS_NOTIFICATION_STATUS ) {+ if ( ! in_array( 'phone_number', $all_field_slug ) ) {+ ?>+ <option value="phone"><?php esc_html_e( 'Phone Number (SMS Notification Add On)', 'wsdesk' ); ?></option>+ <?php+ }+ }+ if ( ! in_array( 'google_captcha', $all_field_slug ) ) {+ echo '<option value="google_captcha">Google reCAPTCHA</option>';+ }+ ?>+ </select>+ <br>+ <span style="vertical-align: middle;" id="ticket_field_add_append"></span>+ </span>+ </div>+ </div>+</div>+<div id="ticket_field_edit_display" style="display: none;">+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label style="padding-right:1em !important;"><?php esc_html_e( 'Edit Ticket Field', 'wsdesk' ); ?></label>+ <button type="button" id="ticket_field_cancel_edit_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button>+ </div>+ <input type="hidden" value="" id="ticket_field_edit_type">+ <span style="vertical-align: middle;" id="ticket_field_edit_append"></span>+ </div>+ </div>+</div>+<div class="crm-form-element">+ <div class="col-md-12">+ <button type="button" id="save_ticket_fields" class="btn btn-primary"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button>+ </div>+</div>+<?php+// return ob_get_clean();
Vulnerability Existed: no Explanation: This diff shows only whitespace/line ending changes (converting from Unix LF to Windows CRLF line endings or vice versa). The actual code content remains identical between version 3.3.4 and 3.3.5. No functional code changes, security fixes, or new vulnerabilities were introduced. The file continues to use proper WordPress escaping functions (`esc_html()`, `esc_attr()`, `esc_html__()`) for output handling, maintaining the same security posture as before.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_general.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_general.php 2025-12-21 09:36:35.511308688 +0000@@ -1,468 +1,468 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -$users_data = get_users( array( 'role__in' => array( 'administrator', 'WSDesk_Agents', 'WSDesk_Supervisor' ) ) ); -$users = array(); -$select = array(); -for ( $i = 0;$i < count( $users_data );$i++ ) { - $current = $users_data[ $i ]; - $temp = array(); - $roles = $current->roles; - foreach ( $roles as $value ) { - $current_role = $value; - array_push( $temp, ucfirst( str_replace( '_', ' ', $current_role ) ) ); - } - $users[ implode( ' & ', $temp ) ][ $current->ID ] = $current->data->display_name; -} -$args = array( 'type' => 'label' ); -$fields = array( 'slug', 'title', 'settings_id' ); -$avail_labels = eh_crm_get_settings( $args, $fields ); -$ticket_rows = eh_crm_get_settingsmeta( '0', 'ticket_rows' ); -$satisfaction_hyper_link = eh_crm_get_settingsmeta( '0', 'satisfaction_hyper_link' ); -if ( '' == $satisfaction_hyper_link ) { - $satisfaction_hyper_link = esc_html__( 'We’d love to hear your feedback!', 'wsdesk' ); -} -if ( '' == $ticket_rows ) { - $ticket_rows = 25; -} -$avail_fields = eh_crm_get_settings( array( 'type' => 'field' ), array( 'slug', 'title', 'settings_id' ) ); -$all_field_slug = array(); -for ( $i = 0;$i < count( $avail_fields );$i++ ) { - array_push( $all_field_slug, $avail_fields[ $i ]['slug'] ); -} -?> -<script> - function custom_attachment() - { - if(document.getElementById('custom-attachment-folder-enable').checked) - document.getElementById('custom-attachment-path').style.display="block"; - else - document.getElementById('custom-attachment-path').style.display="none"; - } - function enable_scheduled_triggers_enable(){ - if(document.getElementById('scheduled_triggers_enable').checked) - document.getElementById('scheduled_triggers_time_option').style.display="block"; - else - document.getElementById('scheduled_triggers_time_option').style.display="none"; - } - function enable_api_click() - { - if(document.getElementById('enable_api').checked) - document.getElementById('api_key').style.display="block"; - else - document.getElementById('api_key').style.display="none"; - }; -</script> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="default_assignee" style="padding-right:1em !important;"><?php esc_html_e( 'Default Assignee', 'wsdesk' ); ?></label> - <label for="default_assignee" class="premium_green_set"><a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><sup class="text-success">[Premium!]</sup></a></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Choose default assignee for new tickets', 'wsdesk' ); ?></span> - <select id="default_assignee" style="width: 100% !important;display: inline !important" class="form-control" aria-describedby="helpBlock"> - <?php - $assignee = eh_crm_get_settingsmeta( '0', 'default_assignee' ); - $tag_selected = ''; - $no_assignee = ''; - $vendor_selected = ''; - switch ( $assignee ) { - case 'no_assignee': - $tag_selected = ''; - $no_assignee = 'selected'; - $vendor_selected = ''; - break; - } - if ( EH_CRM_WOO_STATUS ) { - $vendor_roles = eh_crm_get_settingsmeta( 0, 'woo_vendor_roles' ); - if ( ! $vendor_roles ) { - $vendor_roles = array(); - } - if ( ! in_array( 'woo_vendors', $all_field_slug ) && ! empty( $vendor_roles ) ) { - echo '<option disabled="true" value="ticket_vendors" ' . esc_html( $vendor_selected ) . '>' . esc_html__( 'Depends on Vendors', 'wsdesk' ) . '</option>'; - } - } - echo '<option disabled="true" value = ticket_tags ' . esc_html( $tag_selected ) . ' > ' . esc_html__( 'Depends on Ticket Tags', 'wsdesk' ) . '</option > - <option value = no_assignee ' . esc_html( $no_assignee ) . ' > ' . esc_html__( 'No Assignee', 'wsdesk' ) . ' </option>'; - foreach ( $users as $key => $value ) { - echo '<optgroup label="' . esc_html( $key ) . '">'; - foreach ( $value as $uid => $name ) { - $selected = ''; - if ( $assignee == $uid ) { - $selected = 'selected'; - } - echo '<option disabled="true" value="' . esc_html( $uid ) . '" ' . esc_html( $selected ) . '>' . esc_html( $name ) . '</option>'; - } - echo '</optgroup>'; - } - ?> - </select> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="default_label" style="padding-right:1em !important;"><?php esc_html_e( 'Default Status', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Choose default status for new tickets() / raiser replies', 'wsdesk' ); ?></span> - <select id="default_label" style="width: 100% !important;display: inline !important" class="form-control" aria-describedby="helpBlock"> - <?php - $label = eh_crm_get_settingsmeta( '0', 'default_label' ); - for ( $i = 0;$i < count( $avail_labels );$i++ ) { - $selected = ''; - if ( $label === $avail_labels[ $i ]['slug'] ) { - $selected = 'selected'; - } - echo '<option value = "' . esc_attr( $avail_labels[ $i ]['slug'] ) . '" ' . esc_attr( $selected ) . ' > ' . esc_html( $avail_labels[ $i ]['title'] ) . '</option> '; - } - ?> - </select> - </div> -</div> - -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="default_raiser_label" style="padding-right:1em !important;" ><?php esc_attr_e( 'Default Raiser Reply Status', 'wsdesk' ); ?></label> - <label><a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><sup class="text-success">[Premium!]</sup></a></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_attr_e( 'Choose default status for raiser replies', 'wsdesk' ); ?></span> - <select id="default_raiser_label" style="width: 100% !important; display: inline !important" class="form-control" aria-describedby="helpBlock"> - <?php - $selected = ''; - $label = eh_crm_get_settingsmeta( '0', 'default_raiser_label' ); - - if ( ! $label ) { - $selected = 'selected'; - } - - echo '<option value="" ' . esc_attr( $selected ) . ' disabled>' . esc_html__( 'No Change', 'wsdesk' ) . '</option>'; - - for ( $i = 0; $i < count( $avail_labels ); $i++ ) { - $selected = ''; - if ( $label === $avail_labels[ $i ]['slug'] ) { - $selected = 'selected'; - } - $disabled = 'disabled'; // Disable all options - echo esc_html( '<option value="' . esc_attr( $avail_labels[ $i ]['slug'] ) . '" ' . esc_attr( $selected ) . ' ' . $disabled . '>' . esc_attr( $avail_labels[ $i ]['title'] ) . '</option>' ); - } - ?> - </select> - </div> -</div> - -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="ticket_raiser" style="padding-right:1em !important;"><?php esc_html_e( 'Tickets Raisers', 'wsdesk' ); ?></label> - <label for="ticket_raiser" class="premium_green_set"><a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><sup class="text-success">[Premium!]</sup></a></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Who can raise the tickets ? ', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $ticket_raiser = eh_crm_get_settingsmeta( '0', 'ticket_raiser' ); - $all = ''; - $registered = ''; - $guest = ''; - switch ( $ticket_raiser ) { - case 'all': - $all = 'checked'; - $registered = ''; - $guest = ''; - break; - case 'registered': - $all = ''; - $registered = 'checked'; - $guest = ''; - break; - case 'guest': - $all = ''; - $registered = ''; - $guest = 'checked'; - break; - } - ?> - <input type="radio" disabled="true" style="margin-top: 0;" id="ticket_raiser" class="form-control" name="ticket_raiser" <?php echo esc_html( $all ); ?> value="all"> <?php esc_html_e( 'All', 'wsdesk' ); ?><br> - <input type="radio" disabled="true" style="margin-top: 0;" id="ticket_raiser" class="form-control" name="ticket_raiser" <?php echo esc_html( $registered ); ?> value="registered"> <?php esc_html_e( 'Registered Users', 'wsdesk' ); ?><br> - <input type="radio" disabled="true" style="margin-top: 0;" id="ticket_raiser" class="form-control" name="ticket_raiser" <?php echo esc_html( $guest ); ?> value="guest"> <?php esc_html_e( 'Guest Users', 'wsdesk' ); ?> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="agent_ticket_section" style="padding-right:1em !important;"><?php esc_html_e( 'Agents Ticket Section', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Allow an agent to see other agents tickets in the Tickets dashboard', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $allow_agent_tickets = eh_crm_get_settingsmeta( '0', 'allow_agent_tickets' ); - $enable = ''; - switch ( $allow_agent_tickets ) { - case 'enable': - $enable = 'checked'; - break; - default: - $enable = ''; - break; - } - ?> - <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="allow_agent_tickets" class="form-control" name="allow_agent_tickets" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<span class="crm-divider hide"></span> -<div class="crm-form-element hide"> - <div class="col-md-3"> - <label for="ticket_display_row" style="padding-right:1em !important;"><?php esc_html_e( 'Tickets Row', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Number of tickets per page', 'wsdesk' ); ?></span> - <input type="text" id="ticket_display_row" placeholder="25" value="<?php echo esc_html( $ticket_rows ); ?>" class="form-control crm-form-element-input" oninput="validity.valid||(value='');" pattern="[0-9]+"> - </div> -</div> - - -<?php if ( wsdesk_is_premium() ) { ?> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="ticket_display_hyperlink" style="padding-right:1em !important;"><?php esc_html_e( 'Satisfaction Survey', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Satisfaction survey hyperlink text', 'wsdesk' ); ?></span> - <input type="text" id="ticket_display_hyperlink" placeholder="25" value="<?php echo esc_html( $satisfaction_hyper_link ); ?>" class="form-control crm-form-element-input"> - </div> -</div> -<?php } ?> - - -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="auto_assign" style="padding-right:1em !important;"><?php esc_html_e( 'Auto Assign Tickets', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Want to auto assign tickets to the replier if the ticket is unassigned ? ', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $auto_assign = eh_crm_get_settingsmeta( '0', 'auto_assign' ); - $enable = ''; - $disable = ''; - switch ( $auto_assign ) { - case 'enable': - $enable = 'checked'; - $disable = ''; - break; - default: - $enable = ''; - $disable = 'checked'; - break; - } - ?> - <input type="radio" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="auto_assign" class="form-control" name="auto_assign" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - <input type="radio" <?php echo esc_html( $disable ); ?> style="margin-top: 0;" id="auto_assign" class="form-control" name="auto_assign" value="disable"> <?php esc_html_e( 'Disable', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="auto_suggestion" style="padding-right:1em !important;"><?php esc_html_e( 'Auto Suggestion', 'wsdesk' ); ?></label> - <label for="auto_suggestion" class="premium_green_set"><a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><sup class="text-success">[Premium!]</sup></a></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Want to enable auto suggestion for agent and ticket raisers ? ', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $auto_suggestion = eh_crm_get_settingsmeta( '0', 'auto_suggestion' ); - $enable = ''; - $disable = ''; - switch ( $auto_suggestion ) { - case 'enable': - $enable = 'checked'; - $disable = ''; - break; - case 'disable': - $enable = ''; - $disable = 'checked'; - break; - } - ?> - <input type="radio" disabled="true" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="auto_suggestion" class="form-control" name="auto_suggestion" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - <input type="radio" disabled="true" <?php echo esc_html( $disable ); ?> style="margin-top: 0;" id="auto_suggestion" class="form-control" name="auto_suggestion" value="disable"> <?php esc_html_e( 'Disable', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="custom-attachment-folder" style="padding-right:1em !important;"><?php esc_html_e( 'Custom Attachment Folder', 'wsdesk' ); ?></label> - <label for="custom-attachment-folder" class="premium_green_set"><a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><sup class="text-success">[Premium!]</sup></a></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Want to enable custom folder for attachments ? ', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $custom_attachment_enable = eh_crm_get_settingsmeta( '0', 'custom_attachment_folder_enable' ); - $custom_attachment_path = eh_crm_get_settingsmeta( '0', 'custom_attachment_folder_path' ); - $enable = ''; - $disable = ''; - switch ( $custom_attachment_enable ) { - case 'yes': - $enable = 'checked'; - $disable = ''; - $upath = 'block'; - break; - default: - $enable = ''; - $disable = 'checked'; - $upath = 'none'; - } - ?> - <input type="radio" disabled="true" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" onclick="custom_attachment();" id="custom-attachment-folder-enable" class="form-control" name="custom_attachment" value="yes"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - <input type="radio" disabled="true" <?php echo esc_html( $disable ); ?> style="margin-top: 0;" onclick="custom_attachment();" id="custom-attachment-folder-disable" class="form-control" name="custom_attachment" value="no"> <?php esc_html_e( 'Disable', 'wsdesk' ); ?><br> - <div id="custom-attachment-path" style="display: <?php echo esc_html( $upath ); ?>"> - <span class="help-block"><?php esc_html_e( 'Path : ', 'wsdesk' ); ?></span> - <?php echo esc_url( ABSPATH ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Please make sure the location exists . ', 'wsdesk' ); ?>" data-container="body"></span><input type="text" id="custom_attachment_path" placeholder="wp-content/uploads" value="<?php echo esc_html( $custom_attachment_path ); ?>" class="form-control crm-form-element-input"> - </div> - - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <?php - $max_file_size = eh_crm_get_settingsmeta( '0', 'max_file_size' ); - ?> - <div class="col-md-3"> - <label for="custom-attachment-folder" style="padding-right:1em !important;"><?php esc_html_e( 'Maximum file size of attachments( MB )', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'You can set maximum size of the attachments', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'default value: 1MB . Decimal values are allowed . ', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 1 ? Math.abs(this.value) : null" id="max_file_size" placeholder="1" min='1' value="<?php echo esc_html( $max_file_size ); ?>" class="form-control crm-form-element-input"> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="custom-attachment-folder" style="padding-right:1em !important;"><?php esc_html_e( 'Valid Attachment Extensions', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Select File Extensions', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Select nothing to make all extensions valid . ', 'wsdesk' ); ?>" data-container="body"></span></span> - <script> - jQuery("#file-extension-select").select2({ - width: '100 % ', - minimumResultsForSearch: -1 - }); - </script> - <span style="vertical-align: middle;"> - <select class="file-extension" id='file-extension-select' name="ext[]" multiple="multiple"> - <?php - $valid_exts = eh_crm_get_settingsmeta( '0', 'valid_file_extension' ); - $valid_exts = explode( ',', $valid_exts ); - $exts = array( - 'jpg' => 'JPG', - 'jpeg' => 'JPEG', - 'png' => 'PNG', - 'gif' => 'GIF', - 'pdf' => 'PDF', - 'docx' => 'DOCX', - 'txt' => 'TXT', - 'zip' => 'ZIP', - 'xml' => 'XML', - 'csv' => 'CSV', - 'mp3' => 'MP3', - 'mp4' => 'MP4', - 'xlsx' => 'XLSX', - '3gp' => '3GP', - 'avi' => 'AVI', - 'wmv' => 'WMV', - 'mpg' => 'MPG', - 'mov' => 'MOV', - 'flv' => 'FLV', - 'syx' => 'SYX', - 'rtf' => 'RTF', - 'cdr' => 'CDR', - 'bmp' => 'BMP', - 'ppt' => 'PPT', - 'pptx' => 'PPTX', - ); - - foreach ( $exts as $key => $ext ) { - - if ( in_array( $key, $valid_exts ) ) { - ?> - <option value="<?php echo esc_attr( $key ); ?>" selected><?php echo esc_html( $ext ); ?></option> - <?php - } else { - ?> - <option value="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $ext ); ?></option> - <?php - } - } - ?> - </select> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="auto_create_user" style="padding-right:1em !important;"><?php esc_html_e( 'Create WordPress User', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Create WordPress user while guest user submitting the tickets through the form', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $auto_create_user = eh_crm_get_settingsmeta( '0', 'auto_create_user' ); - $enable = ''; - switch ( $auto_create_user ) { - case 'enable': - $enable = 'checked'; - break; - default: - $enable = ''; - break; - } - ?> - <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="auto_create_user" class="form-control" name="auto_create_user" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="close_tickets" style="padding-right:1em !important;"><?php esc_html_e( 'Close Tickets', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Allow users to close the tickets they submitted', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $close_tickets = eh_crm_get_settingsmeta( '0', 'close_tickets' ); - switch ( $close_tickets ) { - case 'disable': - $enable = ''; - break; - default: - $enable = 'checked'; - break; - } - ?> - <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="close_tickets" class="form-control" name="close_tickets" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-12"> - <button type="button" id="save_general" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button> - </div> -</div> -<?php -// return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+$users_data = get_users( array( 'role__in' => array( 'administrator', 'WSDesk_Agents', 'WSDesk_Supervisor' ) ) );+$users = array();+$select = array();+for ( $i = 0;$i < count( $users_data );$i++ ) {+ $current = $users_data[ $i ];+ $temp = array();+ $roles = $current->roles;+ foreach ( $roles as $value ) {+ $current_role = $value;+ array_push( $temp, ucfirst( str_replace( '_', ' ', $current_role ) ) );+ }+ $users[ implode( ' & ', $temp ) ][ $current->ID ] = $current->data->display_name;+}+$args = array( 'type' => 'label' );+$fields = array( 'slug', 'title', 'settings_id' );+$avail_labels = eh_crm_get_settings( $args, $fields );+$ticket_rows = eh_crm_get_settingsmeta( '0', 'ticket_rows' );+$satisfaction_hyper_link = eh_crm_get_settingsmeta( '0', 'satisfaction_hyper_link' );+if ( '' == $satisfaction_hyper_link ) {+ $satisfaction_hyper_link = esc_html__( 'We’d love to hear your feedback!', 'wsdesk' );+}+if ( '' == $ticket_rows ) {+ $ticket_rows = 25;+}+$avail_fields = eh_crm_get_settings( array( 'type' => 'field' ), array( 'slug', 'title', 'settings_id' ) );+$all_field_slug = array();+for ( $i = 0;$i < count( $avail_fields );$i++ ) {+ array_push( $all_field_slug, $avail_fields[ $i ]['slug'] );+}+?>+<script>+ function custom_attachment()+ {+ if(document.getElementById('custom-attachment-folder-enable').checked)+ document.getElementById('custom-attachment-path').style.display="block";+ else+ document.getElementById('custom-attachment-path').style.display="none";+ }+ function enable_scheduled_triggers_enable(){+ if(document.getElementById('scheduled_triggers_enable').checked)+ document.getElementById('scheduled_triggers_time_option').style.display="block";+ else+ document.getElementById('scheduled_triggers_time_option').style.display="none";+ }+ function enable_api_click()+ {+ if(document.getElementById('enable_api').checked)+ document.getElementById('api_key').style.display="block";+ else+ document.getElementById('api_key').style.display="none";+ };+</script>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="default_assignee" style="padding-right:1em !important;"><?php esc_html_e( 'Default Assignee', 'wsdesk' ); ?></label>+ <label for="default_assignee" class="premium_green_set"><a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><sup class="text-success">[Premium!]</sup></a></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Choose default assignee for new tickets', 'wsdesk' ); ?></span>+ <select id="default_assignee" style="width: 100% !important;display: inline !important" class="form-control" aria-describedby="helpBlock">+ <?php+ $assignee = eh_crm_get_settingsmeta( '0', 'default_assignee' );+ $tag_selected = '';+ $no_assignee = '';+ $vendor_selected = '';+ switch ( $assignee ) {+ case 'no_assignee':+ $tag_selected = '';+ $no_assignee = 'selected';+ $vendor_selected = '';+ break;+ }+ if ( EH_CRM_WOO_STATUS ) {+ $vendor_roles = eh_crm_get_settingsmeta( 0, 'woo_vendor_roles' );+ if ( ! $vendor_roles ) {+ $vendor_roles = array();+ }+ if ( ! in_array( 'woo_vendors', $all_field_slug ) && ! empty( $vendor_roles ) ) {+ echo '<option disabled="true" value="ticket_vendors" ' . esc_html( $vendor_selected ) . '>' . esc_html__( 'Depends on Vendors', 'wsdesk' ) . '</option>';+ }+ }+ echo '<option disabled="true" value = ticket_tags ' . esc_html( $tag_selected ) . ' > ' . esc_html__( 'Depends on Ticket Tags', 'wsdesk' ) . '</option >+ <option value = no_assignee ' . esc_html( $no_assignee ) . ' > ' . esc_html__( 'No Assignee', 'wsdesk' ) . ' </option>';+ foreach ( $users as $key => $value ) {+ echo '<optgroup label="' . esc_html( $key ) . '">';+ foreach ( $value as $uid => $name ) {+ $selected = '';+ if ( $assignee == $uid ) {+ $selected = 'selected';+ }+ echo '<option disabled="true" value="' . esc_html( $uid ) . '" ' . esc_html( $selected ) . '>' . esc_html( $name ) . '</option>';+ }+ echo '</optgroup>';+ }+ ?>+ </select>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="default_label" style="padding-right:1em !important;"><?php esc_html_e( 'Default Status', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Choose default status for new tickets() / raiser replies', 'wsdesk' ); ?></span>+ <select id="default_label" style="width: 100% !important;display: inline !important" class="form-control" aria-describedby="helpBlock">+ <?php+ $label = eh_crm_get_settingsmeta( '0', 'default_label' );+ for ( $i = 0;$i < count( $avail_labels );$i++ ) {+ $selected = '';+ if ( $label === $avail_labels[ $i ]['slug'] ) {+ $selected = 'selected';+ }+ echo '<option value = "' . esc_attr( $avail_labels[ $i ]['slug'] ) . '" ' . esc_attr( $selected ) . ' > ' . esc_html( $avail_labels[ $i ]['title'] ) . '</option> ';+ }+ ?>+ </select>+ </div>+</div>++<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="default_raiser_label" style="padding-right:1em !important;" ><?php esc_attr_e( 'Default Raiser Reply Status', 'wsdesk' ); ?></label>+ <label><a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><sup class="text-success">[Premium!]</sup></a></label> + </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_attr_e( 'Choose default status for raiser replies', 'wsdesk' ); ?></span>+ <select id="default_raiser_label" style="width: 100% !important; display: inline !important" class="form-control" aria-describedby="helpBlock">+ <?php+ $selected = '';+ $label = eh_crm_get_settingsmeta( '0', 'default_raiser_label' );+ + if ( ! $label ) {+ $selected = 'selected';+ }+ + echo '<option value="" ' . esc_attr( $selected ) . ' disabled>' . esc_html__( 'No Change', 'wsdesk' ) . '</option>';+ + for ( $i = 0; $i < count( $avail_labels ); $i++ ) {+ $selected = '';+ if ( $label === $avail_labels[ $i ]['slug'] ) {+ $selected = 'selected';+ }+ $disabled = 'disabled'; // Disable all options+ echo esc_html( '<option value="' . esc_attr( $avail_labels[ $i ]['slug'] ) . '" ' . esc_attr( $selected ) . ' ' . $disabled . '>' . esc_attr( $avail_labels[ $i ]['title'] ) . '</option>' );+ }+ ?>+ </select>+ </div>+</div>++<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="ticket_raiser" style="padding-right:1em !important;"><?php esc_html_e( 'Tickets Raisers', 'wsdesk' ); ?></label>+ <label for="ticket_raiser" class="premium_green_set"><a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><sup class="text-success">[Premium!]</sup></a></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Who can raise the tickets ? ', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $ticket_raiser = eh_crm_get_settingsmeta( '0', 'ticket_raiser' );+ $all = '';+ $registered = '';+ $guest = '';+ switch ( $ticket_raiser ) {+ case 'all':+ $all = 'checked';+ $registered = '';+ $guest = '';+ break;+ case 'registered':+ $all = '';+ $registered = 'checked';+ $guest = '';+ break;+ case 'guest':+ $all = '';+ $registered = '';+ $guest = 'checked';+ break;+ }+ ?>+ <input type="radio" disabled="true" style="margin-top: 0;" id="ticket_raiser" class="form-control" name="ticket_raiser" <?php echo esc_html( $all ); ?> value="all"> <?php esc_html_e( 'All', 'wsdesk' ); ?><br>+ <input type="radio" disabled="true" style="margin-top: 0;" id="ticket_raiser" class="form-control" name="ticket_raiser" <?php echo esc_html( $registered ); ?> value="registered"> <?php esc_html_e( 'Registered Users', 'wsdesk' ); ?><br>+ <input type="radio" disabled="true" style="margin-top: 0;" id="ticket_raiser" class="form-control" name="ticket_raiser" <?php echo esc_html( $guest ); ?> value="guest"> <?php esc_html_e( 'Guest Users', 'wsdesk' ); ?>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="agent_ticket_section" style="padding-right:1em !important;"><?php esc_html_e( 'Agents Ticket Section', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Allow an agent to see other agents tickets in the Tickets dashboard', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $allow_agent_tickets = eh_crm_get_settingsmeta( '0', 'allow_agent_tickets' );+ $enable = '';+ switch ( $allow_agent_tickets ) {+ case 'enable':+ $enable = 'checked';+ break;+ default:+ $enable = '';+ break;+ }+ ?>+ <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="allow_agent_tickets" class="form-control" name="allow_agent_tickets" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<span class="crm-divider hide"></span>+<div class="crm-form-element hide">+ <div class="col-md-3">+ <label for="ticket_display_row" style="padding-right:1em !important;"><?php esc_html_e( 'Tickets Row', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Number of tickets per page', 'wsdesk' ); ?></span>+ <input type="text" id="ticket_display_row" placeholder="25" value="<?php echo esc_html( $ticket_rows ); ?>" class="form-control crm-form-element-input" oninput="validity.valid||(value='');" pattern="[0-9]+">+ </div>+</div>+++<?php if ( wsdesk_is_premium() ) { ?>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="ticket_display_hyperlink" style="padding-right:1em !important;"><?php esc_html_e( 'Satisfaction Survey', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Satisfaction survey hyperlink text', 'wsdesk' ); ?></span>+ <input type="text" id="ticket_display_hyperlink" placeholder="25" value="<?php echo esc_html( $satisfaction_hyper_link ); ?>" class="form-control crm-form-element-input">+ </div>+</div>+<?php } ?>+++<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="auto_assign" style="padding-right:1em !important;"><?php esc_html_e( 'Auto Assign Tickets', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Want to auto assign tickets to the replier if the ticket is unassigned ? ', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $auto_assign = eh_crm_get_settingsmeta( '0', 'auto_assign' );+ $enable = '';+ $disable = '';+ switch ( $auto_assign ) {+ case 'enable':+ $enable = 'checked';+ $disable = '';+ break;+ default:+ $enable = '';+ $disable = 'checked';+ break;+ }+ ?>+ <input type="radio" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="auto_assign" class="form-control" name="auto_assign" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ <input type="radio" <?php echo esc_html( $disable ); ?> style="margin-top: 0;" id="auto_assign" class="form-control" name="auto_assign" value="disable"> <?php esc_html_e( 'Disable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="auto_suggestion" style="padding-right:1em !important;"><?php esc_html_e( 'Auto Suggestion', 'wsdesk' ); ?></label>+ <label for="auto_suggestion" class="premium_green_set"><a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><sup class="text-success">[Premium!]</sup></a></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Want to enable auto suggestion for agent and ticket raisers ? ', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $auto_suggestion = eh_crm_get_settingsmeta( '0', 'auto_suggestion' );+ $enable = '';+ $disable = '';+ switch ( $auto_suggestion ) {+ case 'enable':+ $enable = 'checked';+ $disable = '';+ break;+ case 'disable':+ $enable = '';+ $disable = 'checked';+ break;+ }+ ?>+ <input type="radio" disabled="true" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="auto_suggestion" class="form-control" name="auto_suggestion" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ <input type="radio" disabled="true" <?php echo esc_html( $disable ); ?> style="margin-top: 0;" id="auto_suggestion" class="form-control" name="auto_suggestion" value="disable"> <?php esc_html_e( 'Disable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="custom-attachment-folder" style="padding-right:1em !important;"><?php esc_html_e( 'Custom Attachment Folder', 'wsdesk' ); ?></label>+ <label for="custom-attachment-folder" class="premium_green_set"><a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><sup class="text-success">[Premium!]</sup></a></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Want to enable custom folder for attachments ? ', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $custom_attachment_enable = eh_crm_get_settingsmeta( '0', 'custom_attachment_folder_enable' );+ $custom_attachment_path = eh_crm_get_settingsmeta( '0', 'custom_attachment_folder_path' );+ $enable = '';+ $disable = '';+ switch ( $custom_attachment_enable ) {+ case 'yes':+ $enable = 'checked';+ $disable = '';+ $upath = 'block';+ break;+ default:+ $enable = '';+ $disable = 'checked';+ $upath = 'none';+ }+ ?>+ <input type="radio" disabled="true" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" onclick="custom_attachment();" id="custom-attachment-folder-enable" class="form-control" name="custom_attachment" value="yes"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ <input type="radio" disabled="true" <?php echo esc_html( $disable ); ?> style="margin-top: 0;" onclick="custom_attachment();" id="custom-attachment-folder-disable" class="form-control" name="custom_attachment" value="no"> <?php esc_html_e( 'Disable', 'wsdesk' ); ?><br>+ <div id="custom-attachment-path" style="display: <?php echo esc_html( $upath ); ?>">+ <span class="help-block"><?php esc_html_e( 'Path : ', 'wsdesk' ); ?></span>+ <?php echo esc_url( ABSPATH ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Please make sure the location exists . ', 'wsdesk' ); ?>" data-container="body"></span><input type="text" id="custom_attachment_path" placeholder="wp-content/uploads" value="<?php echo esc_html( $custom_attachment_path ); ?>" class="form-control crm-form-element-input">+ </div>++ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <?php+ $max_file_size = eh_crm_get_settingsmeta( '0', 'max_file_size' );+ ?>+ <div class="col-md-3">+ <label for="custom-attachment-folder" style="padding-right:1em !important;"><?php esc_html_e( 'Maximum file size of attachments( MB )', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'You can set maximum size of the attachments', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'default value: 1MB . Decimal values are allowed . ', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 1 ? Math.abs(this.value) : null" id="max_file_size" placeholder="1" min='1' value="<?php echo esc_html( $max_file_size ); ?>" class="form-control crm-form-element-input">+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="custom-attachment-folder" style="padding-right:1em !important;"><?php esc_html_e( 'Valid Attachment Extensions', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Select File Extensions', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Select nothing to make all extensions valid . ', 'wsdesk' ); ?>" data-container="body"></span></span>+ <script>+ jQuery("#file-extension-select").select2({+ width: '100 % ',+ minimumResultsForSearch: -1+ });+ </script>+ <span style="vertical-align: middle;">+ <select class="file-extension" id='file-extension-select' name="ext[]" multiple="multiple">+ <?php+ $valid_exts = eh_crm_get_settingsmeta( '0', 'valid_file_extension' );+ $valid_exts = explode( ',', $valid_exts );+ $exts = array(+ 'jpg' => 'JPG',+ 'jpeg' => 'JPEG',+ 'png' => 'PNG',+ 'gif' => 'GIF',+ 'pdf' => 'PDF',+ 'docx' => 'DOCX',+ 'txt' => 'TXT',+ 'zip' => 'ZIP',+ 'xml' => 'XML',+ 'csv' => 'CSV',+ 'mp3' => 'MP3',+ 'mp4' => 'MP4',+ 'xlsx' => 'XLSX',+ '3gp' => '3GP',+ 'avi' => 'AVI',+ 'wmv' => 'WMV',+ 'mpg' => 'MPG',+ 'mov' => 'MOV',+ 'flv' => 'FLV',+ 'syx' => 'SYX',+ 'rtf' => 'RTF',+ 'cdr' => 'CDR',+ 'bmp' => 'BMP',+ 'ppt' => 'PPT',+ 'pptx' => 'PPTX',+ );++ foreach ( $exts as $key => $ext ) {++ if ( in_array( $key, $valid_exts ) ) {+ ?>+ <option value="<?php echo esc_attr( $key ); ?>" selected><?php echo esc_html( $ext ); ?></option>+ <?php+ } else {+ ?>+ <option value="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $ext ); ?></option>+ <?php+ }+ }+ ?>+ </select>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="auto_create_user" style="padding-right:1em !important;"><?php esc_html_e( 'Create WordPress User', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Create WordPress user while guest user submitting the tickets through the form', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $auto_create_user = eh_crm_get_settingsmeta( '0', 'auto_create_user' );+ $enable = '';+ switch ( $auto_create_user ) {+ case 'enable':+ $enable = 'checked';+ break;+ default:+ $enable = '';+ break;+ }+ ?>+ <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="auto_create_user" class="form-control" name="auto_create_user" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="close_tickets" style="padding-right:1em !important;"><?php esc_html_e( 'Close Tickets', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Allow users to close the tickets they submitted', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $close_tickets = eh_crm_get_settingsmeta( '0', 'close_tickets' );+ switch ( $close_tickets ) {+ case 'disable':+ $enable = '';+ break;+ default:+ $enable = 'checked';+ break;+ }+ ?>+ <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="close_tickets" class="form-control" name="close_tickets" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-12">+ <button type="button" id="save_general" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button>+ </div>+</div>+<?php+// return ob_get_clean();
Vulnerability Existed: no This diff shows only line ending changes (CRLF to LF conversion) with no functional code modifications. The security controls present in both versions are identical: - All user input is properly escaped with `esc_html()`, `esc_attr()`, and `esc_url()` functions - Form controls use appropriate WordPress sanitization functions - No SQL injection vectors present - No XSS vulnerabilities introduced or fixed - No authentication or authorization bypass changes The file underwent a line ending normalization from Windows-style (CRLF) to Unix-style (LF) line endings between versions 3.3.4 and 3.3.5, but the actual code logic and security implementations remain completely unchanged.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_integrations.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_integrations.php 2025-12-21 09:36:35.511308688 +0000@@ -1,72 +1,72 @@-<?php -$openAI_status = 'active'; -$wooStatus = ''; -if ( EH_CRM_WOO_STATUS ) { - $openAI_status = ''; - $wooStatus = 'active'; -}?> -<form method="post" > - <div> - <div class="" > - <div> - <div class="gap-3 align-items-center"> - <div class="panel-body"> - <ul id="myTabs" class="nav nav-pills nav-justified" role="tablist" data-tabs="tabs"> - <?php if ( EH_CRM_WOO_STATUS ) { ?> - <li class=" <?php echo esc_html( $wooStatus ); ?>"> - <a href="#woocommerce_tab" data-toggle="tab" class="ticket_fields "><?php echo esc_attr__( 'WooCommerce', 'wsdesk' ); ?></a> - </li> - <?php } ?> - <li class=" <?php echo esc_html( $openAI_status ); ?>"> - <a href="#gpt_tab" data-toggle="tab" class="ticket_fields "><?php echo esc_attr__( 'OpenAI - ChatGPT', 'wsdesk' ); ?> - <sup class="text-success"><?php echo esc_attr__( '[Premium!]', 'wsdesk' ); ?></sup> - </a> - </li> - </ul> - </div> - <div class="tab-content"> - <?php if ( EH_CRM_WOO_STATUS ) { ?> - <div id="woocommerce_tab" class="tab-pane <?php echo esc_html( $wooStatus ); ?>"> - <?php include EH_CRM_MAIN_VIEWS . 'settings/crm_woocommerce_settings.php' ; ?> - </div> - <?php } ?> - <div id="gpt_tab" class="tab-pane <?php echo esc_html( $openAI_status ); ?>" style="margin-left : 20px;"> - <?php require EH_CRM_MAIN_VIEWS . 'settings/chatgpt.php' ; ?> - </div> - </div> - </div> - </div> - </div> - - </div> -</form> - - -<script> - jQuery(document).ready(function() { - if (jQuery('input[name="chatgpt_enabled"]').is(':checked')) { - jQuery('.openai_api_key').removeClass('d-none'); - } - - jQuery('input[name="chatgpt_enabled"]').change(function() { - if (jQuery(this).is(':checked')) { - jQuery('.openai_api_key').removeClass('d-none'); - } else { - jQuery('.openai_api_key').addClass('d-none'); - } - }); - - if (jQuery('input[name="customConfig_values"]').is(':checked')) { - jQuery('.openai_config_values').removeClass('d-none'); - } - - jQuery('input[name="customConfig_values"]').change(function() { - if (jQuery(this).is(':checked')) { - jQuery('.openai_config_values').removeClass('d-none'); - } else { - jQuery('.openai_config_values').addClass('d-none'); - } - }); - }); - -</script> +<?php +$openAI_status = 'active';+$wooStatus = '';+if ( EH_CRM_WOO_STATUS ) { + $openAI_status = '';+ $wooStatus = 'active';+}?>+<form method="post" >+ <div>+ <div class="" >+ <div>+ <div class="gap-3 align-items-center">+ <div class="panel-body">+ <ul id="myTabs" class="nav nav-pills nav-justified" role="tablist" data-tabs="tabs">+ <?php if ( EH_CRM_WOO_STATUS ) { ?>+ <li class=" <?php echo esc_html( $wooStatus ); ?>">+ <a href="#woocommerce_tab" data-toggle="tab" class="ticket_fields "><?php echo esc_attr__( 'WooCommerce', 'wsdesk' ); ?></a>+ </li>+ <?php } ?>+ <li class=" <?php echo esc_html( $openAI_status ); ?>">+ <a href="#gpt_tab" data-toggle="tab" class="ticket_fields "><?php echo esc_attr__( 'OpenAI - ChatGPT', 'wsdesk' ); ?>+ <sup class="text-success"><?php echo esc_attr__( '[Premium!]', 'wsdesk' ); ?></sup>+ </a>+ </li>+ </ul>+ </div>+ <div class="tab-content">+ <?php if ( EH_CRM_WOO_STATUS ) { ?>+ <div id="woocommerce_tab" class="tab-pane <?php echo esc_html( $wooStatus ); ?>">+ <?php include EH_CRM_MAIN_VIEWS . 'settings/crm_woocommerce_settings.php' ; ?>+ </div>+ <?php } ?>+ <div id="gpt_tab" class="tab-pane <?php echo esc_html( $openAI_status ); ?>" style="margin-left : 20px;">+ <?php require EH_CRM_MAIN_VIEWS . 'settings/chatgpt.php' ; ?>+ </div>+ </div>+ </div>+ </div>+ </div>++ </div>+</form>+++<script>+ jQuery(document).ready(function() {+ if (jQuery('input[name="chatgpt_enabled"]').is(':checked')) {+ jQuery('.openai_api_key').removeClass('d-none');+ }++ jQuery('input[name="chatgpt_enabled"]').change(function() {+ if (jQuery(this).is(':checked')) {+ jQuery('.openai_api_key').removeClass('d-none');+ } else {+ jQuery('.openai_api_key').addClass('d-none');+ }+ });++ if (jQuery('input[name="customConfig_values"]').is(':checked')) {+ jQuery('.openai_config_values').removeClass('d-none');+ }++ jQuery('input[name="customConfig_values"]').change(function() {+ if (jQuery(this).is(':checked')) {+ jQuery('.openai_config_values').removeClass('d-none');+ } else {+ jQuery('.openai_config_values').addClass('d-none');+ }+ });+ });++</script>
Vulnerability Existed: no Explanation: This diff shows only whitespace/line ending changes between version 3.3.4 and 3.3.5 of the file `views/settings/crm_settings_integrations.php`. The actual code content remains identical - the only differences are formatting (likely converting line endings from CRLF to LF or vice versa). There are no security fixes or vulnerability remedies in this diff because no code logic was changed. The file contains: - Proper use of `esc_html()` and `esc_attr__()` for output escaping - No new vulnerabilities introduced - No existing vulnerabilities fixed This is a formatting-only release with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_labels.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_labels.php 2025-12-21 09:36:35.511308688 +0000@@ -1,72 +1,72 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -$args = array( 'type' => 'label' ); -$fields = array( 'slug', 'title', 'settings_id' ); -$avail_labels = eh_crm_get_settings( $args, $fields ); -?> -<div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="ticket_status" style="padding-right:1em !important;"><?php esc_html_e( 'Ticket Status', 'wsdesk' ); ?></label> - <button type="button" id="ticket_label_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Status', 'wsdesk' ); ?></button> - </div> - <ul class="list-group list-group-sortable-connected list-group-label-data"> - <?php - if ( ! empty( $avail_labels ) ) { - for ( $i = 0;$i < count( $avail_labels );$i++ ) { - $label_color = eh_crm_get_settingsmeta( $avail_labels[ $i ]['settings_id'], 'label_color' ); - echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $avail_labels[ $i ]['slug'] ) . '"> ' . esc_attr( $avail_labels[ $i ]['title'] ) . ' <span class="badge" style="background-color:' . esc_html( $label_color ) . ' !important;">' . esc_html( $label_color ) . '</span><span class="pull-right">'; - if ( ! in_array( $avail_labels[ $i ]['slug'], array( 'label_LL01', 'label_LL02', 'label_LL03' ) ) ) { - echo '<span class="glyphicon glyphicon-trash ticket_label_delete_type" id="' . esc_attr( $avail_labels[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Status', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - } - echo '<span class="glyphicon glyphicon-pencil ticket_label_edit_type" id="' . esc_attr( $avail_labels[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Status', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - echo '</span></li>'; - } - } else { - echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'There are no Labels! Create One Label', 'wsdesk' ) . '</li>'; - } - ?> - </ul> - </div> - <div id="ticket_label_add_display" style="display: none;"> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label style="padding-right:1em !important;"><?php esc_html_e( 'Add Status', 'wsdesk' ); ?></label> - <button type="button" id="ticket_label_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - </div> - <span style="vertical-align: middle;" id="ticket_label_add_section"> - <input type="hidden" value="" id="add_new_label_yes"> - <span class="help-block"><?php esc_html_e( 'Enter Details for New Status', 'wsdesk' ); ?> </span> - <input type="text" id="ticket_label_add_title" placeholder="<?php esc_html_e( 'Enter Title', 'wsdesk' ); ?>" class="form-control crm-form-element-input"> - <span class="help-block"><?php esc_html_e( 'Change ticket status color', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <input type="color" id="ticket_label_add_color"/><span> <?php esc_html_e( 'Click and pick the color', 'wsdesk' ); ?></span> - </span> - <span class="help-block"><?php esc_html_e( 'Do you want to use this status to Filter Tickets?', 'wsdesk' ); ?> </span> - <input type="radio" style="margin-top: 0;" checked id="ticket_label_add_filter" class="form-control" name="ticket_label_add_filter" value="yes"> <?php esc_html_e( 'Yes! I will use it to Filter', 'wsdesk' ); ?><br> - <input type="radio" style="margin-top: 0;" id="ticket_label_add_filter" class="form-control" name="ticket_label_add_filter" value="no"> <?php esc_html_e( 'No! Just for Information', 'wsdesk' ); ?> - </span> - </div> - </div> - </div> - <div id="ticket_label_edit_display" style="display: none;"> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label style="padding-right:1em !important;"><?php esc_html_e( 'Edit Status', 'wsdesk' ); ?></label> - <button type="button" id="ticket_label_cancel_edit_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - </div> - <input type="hidden" value="" id="ticket_label_edit_type"> - <span style="vertical-align: middle;" id="ticket_label_edit_append"></span> - </div> - </div> - </div> - <div class="col-md-12"> - <button type="button" id="save_ticket_labels" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button> - </div> -</div> +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+$args = array( 'type' => 'label' );+$fields = array( 'slug', 'title', 'settings_id' );+$avail_labels = eh_crm_get_settings( $args, $fields );+?>+<div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="ticket_status" style="padding-right:1em !important;"><?php esc_html_e( 'Ticket Status', 'wsdesk' ); ?></label> + <button type="button" id="ticket_label_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Status', 'wsdesk' ); ?></button>+ </div>+ <ul class="list-group list-group-sortable-connected list-group-label-data">+ <?php+ if ( ! empty( $avail_labels ) ) {+ for ( $i = 0;$i < count( $avail_labels );$i++ ) {+ $label_color = eh_crm_get_settingsmeta( $avail_labels[ $i ]['settings_id'], 'label_color' );+ echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $avail_labels[ $i ]['slug'] ) . '"> ' . esc_attr( $avail_labels[ $i ]['title'] ) . ' <span class="badge" style="background-color:' . esc_html( $label_color ) . ' !important;">' . esc_html( $label_color ) . '</span><span class="pull-right">';+ if ( ! in_array( $avail_labels[ $i ]['slug'], array( 'label_LL01', 'label_LL02', 'label_LL03' ) ) ) {+ echo '<span class="glyphicon glyphicon-trash ticket_label_delete_type" id="' . esc_attr( $avail_labels[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Status', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ }+ echo '<span class="glyphicon glyphicon-pencil ticket_label_edit_type" id="' . esc_attr( $avail_labels[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Status', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ echo '</span></li>';+ }+ } else {+ echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'There are no Labels! Create One Label', 'wsdesk' ) . '</li>';+ }+ ?>+ </ul>+ </div>+ <div id="ticket_label_add_display" style="display: none;">+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label style="padding-right:1em !important;"><?php esc_html_e( 'Add Status', 'wsdesk' ); ?></label> + <button type="button" id="ticket_label_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button>+ </div>+ <span style="vertical-align: middle;" id="ticket_label_add_section">+ <input type="hidden" value="" id="add_new_label_yes">+ <span class="help-block"><?php esc_html_e( 'Enter Details for New Status', 'wsdesk' ); ?> </span>+ <input type="text" id="ticket_label_add_title" placeholder="<?php esc_html_e( 'Enter Title', 'wsdesk' ); ?>" class="form-control crm-form-element-input">+ <span class="help-block"><?php esc_html_e( 'Change ticket status color', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <input type="color" id="ticket_label_add_color"/><span> <?php esc_html_e( 'Click and pick the color', 'wsdesk' ); ?></span>+ </span>+ <span class="help-block"><?php esc_html_e( 'Do you want to use this status to Filter Tickets?', 'wsdesk' ); ?> </span>+ <input type="radio" style="margin-top: 0;" checked id="ticket_label_add_filter" class="form-control" name="ticket_label_add_filter" value="yes"> <?php esc_html_e( 'Yes! I will use it to Filter', 'wsdesk' ); ?><br>+ <input type="radio" style="margin-top: 0;" id="ticket_label_add_filter" class="form-control" name="ticket_label_add_filter" value="no"> <?php esc_html_e( 'No! Just for Information', 'wsdesk' ); ?>+ </span>+ </div>+ </div>+ </div>+ <div id="ticket_label_edit_display" style="display: none;">+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label style="padding-right:1em !important;"><?php esc_html_e( 'Edit Status', 'wsdesk' ); ?></label>+ <button type="button" id="ticket_label_cancel_edit_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button>+ </div>+ <input type="hidden" value="" id="ticket_label_edit_type">+ <span style="vertical-align: middle;" id="ticket_label_edit_append"></span>+ </div>+ </div>+ </div>+ <div class="col-md-12">+ <button type="button" id="save_ticket_labels" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button>+ </div>+</div>
Vulnerability Existed: no Analysis Result: This diff contains only formatting/whitespace changes (line ending conversion from CRLF to LF). The actual code logic, security controls, and escaping functions remain identical between versions 3.3.4 and 3.3.5. All security-relevant elements are preserved: - `esc_html_e()` for text output escaping - `esc_attr()` for attribute escaping - `esc_html__()` for translated text escaping - No new code vulnerabilities introduced - No existing vulnerabilities fixed The changes are cosmetic only and do not affect the security posture of the application.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_lite_mode.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_lite_mode.php 2025-12-21 09:36:35.511308688 +0000@@ -1,357 +1,393 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -?> -<script> - function wsdesk_mode_select() - { - if(document.getElementById('wsdesk_mode_std').checked) - document.getElementById('wsdesk_lite_mode').style.display="none"; - else - document.getElementById('wsdesk_lite_mode').style.display="block"; - }; - function wsdesk_mode_select_lite(){ - if(document.getElementById('wsdesk_mode_lite').checked) - document.getElementById('wsdesk_lite_mode').style.display="block"; - else - document.getElementById('wsdesk_lite_mode').style.display="none"; - } - function wsdesk_mode_select_insane() - { - - document.getElementById('wsdesk_lite_mode').style.display="none"; - }; -</script> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="wsdesk_mode" style="padding-right:1em !important;"><?php esc_html_e( 'WSDesk Mode', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Select your WSDesk mode.', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $wsdesk_mode = eh_crm_get_settingsmeta( '0', 'wsdesk_mode' ); - $standard = ''; - $lite = ''; - $display = 'none'; - switch ( $wsdesk_mode ) { - case 'standard': - $standard = 'checked'; - $lite = ''; - $insane = ''; - break; - case 'lite': - $standard = ''; - $lite = 'checked'; - $insane = ''; - $display = 'block'; - - break; - case 'insane': - $standard = ''; - $insane = 'checked'; - $lite = ''; - $display = 'none'; - - break; - default: - $standard = 'checked'; - $lite = ''; - $insane = ''; - break; - - } - ?> - <input type="radio" disabled style="margin-top: 0;" onclick="wsdesk_mode_select();" id="wsdesk_mode_std" class="form-control" name="wsdesk_mode" <?php echo esc_html( $standard ); ?> value="standard"> <?php esc_html_e( 'Standard mode', 'wsdesk' ); ?><br> - <input type="radio" disabled style="margin-top: 0;" onclick="wsdesk_mode_select_lite();" id="wsdesk_mode_lite" class="form-control" name="wsdesk_mode" <?php echo esc_html( $lite ); ?> value="lite"> <?php esc_html_e( 'Lite mode', 'wsdesk' ); ?><br> - - <input type="radio" disabled style="margin-top: 0;" onclick="wsdesk_mode_select_insane();" id="wsdesk_mode_insane" class="form-control" name="wsdesk_mode" <?php echo esc_html( $insane ); ?> value="insane"> <?php esc_html_e( 'Insane mode', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Insane Mode enables all the tweaks from Lite Mode along with a number of additional optimizations. Please note, enabling this option may affect some of the functionalities.', 'wsdesk' ); ?>" data-container="body"></span><br><br> - <span class="crm-divider"></span> - <span class="help-block"><?php esc_html_e( 'Please note: As the plugin performance is optimized, switching between different modes is no longer necessary. This section will be removed from the plugin settings altogether in the forthcoming update.', 'wsdesk' ); ?></span> - <div class="wsdesk_lite_mode hide" id="wsdesk_lite_mode" style="display: <?php echo esc_html( $display ); ?>;font-size: 12px;"> - <span style="vertical-align: middle;"> - <?php - $display_default_status_count = eh_crm_get_settingsmeta( '0', 'display_default_status_count' ); - $enable = ''; - switch ( $display_default_status_count ) { - case 'disable': - $enable = ''; - break; - default: - $enable = 'checked'; - break; - } - ?> - - <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="display_default_status_count" class="form-control" name="display_default_status_count" value="enable"> <?php esc_html_e( 'Display default status count on primary menu', 'wsdesk' ); ?><br> - </span> - <span style="vertical-align: middle;"> - <?php - $ticket_count_view = eh_crm_get_settingsmeta( '0', 'ticket_count_view' ); - $enable = ''; - switch ( $ticket_count_view ) { - case 'ticket_count_view': - $enable = 'checked'; - break; - default: - $enable = ''; - break; - } - ?> - - <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="<?php echo( 'ticket_count_view' ); ?>" class="form-control" name="ticket_count_view" value="ticket_count_view"> <?php esc_html_e( 'Hide the ticket counts in the tickets dashboard', 'wsdesk' ); ?> - <br> - </span> - <span style="vertical-align: middle;"> - <?php - $quick_view_tickets = eh_crm_get_settingsmeta( '0', 'quick_view_tickets' ); - $enable = ''; - switch ( $quick_view_tickets ) { - case 'enable': - $enable = 'checked'; - break; - default: - $enable = ''; - break; - } - ?> - - <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="quick_view_tickets" class="form-control" name="quick_view_tickets" value="enable"> <?php esc_html_e( 'Disable quick view option in the tickets dashboard', 'wsdesk' ); ?><br> - </span> - <span style="vertical-align: middle;"> - <?php - $refresh_ticket_page = eh_crm_get_settingsmeta( '0', 'refresh_ticket_page' ); - $enable = ''; - switch ( $refresh_ticket_page ) { - case 'enable': - $enable = 'checked'; - break; - default: - $enable = ''; - break; - } - ?> - - <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="refresh_ticket_page" class="form-control" name="refresh_ticket_page" value="enable"> <?php esc_html_e( 'Disable refresh the tickets dashboard when the ticket tab is closed', 'wsdesk' ); ?><br> - </span> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-9"> - <label for="auto_create_user" style="padding-right:1em !important;"><?php esc_html_e( 'Limit scheduled triggers execution', 'wsdesk' ); ?></label> - <span class="help-block"><?php esc_html_e( 'Enable this option to specify a time interval to trigger all scheduled actions.', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $scheduled_triggers_enable = eh_crm_get_settingsmeta( '0', 'scheduled_triggers_enable' ); - $scheduled_triggers_time = eh_crm_get_settingsmeta( '0', 'scheduled_triggers_time' ); - if ( empty( $scheduled_triggers_time ) ) { - $scheduled_triggers_time = 24; - } - $auto_create_user = eh_crm_get_settingsmeta( '0', 'scheduled_triggers_enable' ); - $enable = ''; - switch ( $auto_create_user ) { - case 'enable': - $enable = 'checked'; - $upath = 'block'; - break; - default: - $enable = ''; - $upath = 'none'; - break; - } - ?> - - <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="scheduled_triggers_enable" onclick="enable_scheduled_triggers_enable();" class="form-control" name="scheduled_triggers_enable" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?></br></br> - <div id="scheduled_triggers_time_option" style="display: <?php echo esc_html( $upath ); ?>"> - - <input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" id="scheduled_triggers_time" value="<?php echo esc_html( $scheduled_triggers_time ); ?>" class="form-control crm-form-element-input"> - <span class="help-block"><?php esc_html_e( ' Enter the time interval to execute the scheduled actions in hours.', 'wsdesk' ); ?></span> - </div> - </span> - </div> - </div> - </div> - </span> - </div> -</div> - -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="excerpt_in_auto_suggestion" style="padding-right:1em !important;"><?php esc_html_e( 'Show Excerpt on Auto-Suggestion', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Enable this option to show excerpt instead of first sentence of the post while displaying auto-suggestion.', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $show_excerpt_in_auto_suggestion = eh_crm_get_settingsmeta( '0', 'show_excerpt_in_auto_suggestion' ); - $enable = ''; - switch ( $show_excerpt_in_auto_suggestion ) { - case 'enable': - $enable = 'checked'; - break; - default: - $enable = ''; - break; - } - ?> - <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="show_excerpt_in_auto_suggestion" class="form-control" name="show_excerpt_in_auto_suggestion" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="auto_assign" style="padding-right:1em !important;"><?php esc_html_e( 'Display Tickets As', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Enabling HTML option may lead to security issues. Resolving such issues are out of the scope of WSDesk plugin, hence we do not recommend this option.', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $tickets_display = eh_crm_get_settingsmeta( '0', 'tickets_display' ); - $text = ''; - $html = ''; - switch ( $tickets_display ) { - case 'text': - $text = 'checked'; - break; - default: - $html = 'checked'; - break; - } - ?> - <input type="radio" <?php echo esc_html( $html ); ?> style="margin-top: 0;" id="tickets_display" class="form-control" name="tickets_display" value="html"> <?php esc_html_e( 'HTML', 'wsdesk' ); ?><br> - <input type="radio" <?php echo esc_html( $text ); ?> style="margin-top: 0;" id="tickets_display" class="form-control" name="tickets_display" value="text"> <?php esc_html_e( 'Text', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="auto_create_user" style="padding-right:1em !important;"><?php esc_html_e( 'WSDesk API', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Create tickets via API from any website', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $api_key = eh_crm_get_settingsmeta( '0', 'api_key' ); - $auto_create_user = eh_crm_get_settingsmeta( '0', 'enable_api' ); - if ( empty( $api_key ) ) { - $api_key = md5( time() . EH_CRM_MAIN_URL ); - } - $enable = ''; - switch ( $auto_create_user ) { - case 'enable': - $enable = 'checked'; - $upath = 'block'; - break; - default: - $enable = ''; - $upath = 'none'; - break; - } - ?> - <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="enable_api" onclick="enable_api_click();" class="form-control" name="enable_api" value="enable"> <?php esc_html_e( 'Enable API', 'wsdesk' ); ?><br> - <div id="api_key" style="display: <?php echo esc_html( $upath ); ?>"> - <span class="help-block"><?php esc_html_e( 'API Key:', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Please share this API Key only with trusted sources.', 'wsdesk' ); ?>" data-container="body"></span></span> - <input type="text" id="api_key_textbox" value="<?php echo esc_html( $api_key ); ?>" class="form-control crm-form-element-input"> - </div> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="custom-attachment-folder" style="padding-right:1em !important;"><?php esc_html_e( 'Default Deep Link', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <?php - $default_deep_link = urldecode( stripslashes( eh_crm_get_settingsmeta( '0', 'default_deep_link' ) ) ); - ?> - <span class="help-block"><?php esc_html_e( 'Add a default deep link here', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <span class="help-block"><?php esc_html_e( 'Path: ' . esc_url( admin_url() ) . 'admin.php?page=wsdesk_tickets&', 'wsdesk' ); ?></span> - <input type="text" id="default_deep_link" placeholder="view=all" value='<?php echo esc_html( $default_deep_link ); ?>' class="form-control crm-form-element-input"> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="custom-attachment-folder" style="padding-right:1em !important;"><?php esc_html_e( 'Debug Mode', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Enable this option to place debug logs in PHP error log file', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $wsdesk_debug_status = eh_crm_get_settingsmeta( '0', 'wsdesk_debug_status' ); - $debug_enable = ''; - switch ( $wsdesk_debug_status ) { - case 'enable': - $debug_enable = 'checked'; - break; - default: - $debug_enable = ''; - break; - } - ?> - <input type="checkbox" <?php echo esc_html( $debug_enable ); ?> style="margin-top: 0;" id="wsdesk_debug_email" class="form-control" name="wsdesk_debug_email" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - </span> - </div> -</div> - -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="custom-attachment-folder" style="padding-right:1em !important;"><?php esc_html_e( 'Powered by WSDesk Tag', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Disabling this option will remove Powered by WSDesk Tag from front end and all support E-mails.', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $wsdesk_powered_by_status = eh_crm_get_settingsmeta( '0', 'wsdesk_powered_by_status' ); - switch ( $wsdesk_powered_by_status ) { - case 'disable': - $wsdesk_powered_by_status_checked = ''; - break; - default: - $wsdesk_powered_by_status_checked = 'checked'; - break; - } - ?> - <input type="checkbox" <?php echo esc_html( $wsdesk_powered_by_status_checked ); ?> style="margin-top: 0;" id="wsdesk_powered_by_status" class="form-control" name="wsdesk_powered_by_status" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="linkify-url" style="padding-right:1em !important;"><?php esc_html_e( 'Convert URLs to Hyperlinks', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Enabling this option will convert all URLs in ticket conversation to hyperlinks. (BETA)', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <?php - $linkify_urls = eh_crm_get_settingsmeta( '0', 'linkify_urls' ); - switch ( $linkify_urls ) { - case 'enable': - $linkify_urls_checked = 'checked'; - break; - default: - $linkify_urls_checked = ''; - break; - } - ?> - <input type="checkbox" <?php echo esc_html( $linkify_urls_checked ); ?> style="margin-top: 0;" id="linkify_urls" class="form-control" name="linkify_urls" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-12"> - <button type="button" id="save_general" class="save_wsdesk_mode btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button> - </div> -</div> -<?php -// return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+?>+<script>+ function wsdesk_mode_select()+ {+ if(document.getElementById('wsdesk_mode_std').checked)+ document.getElementById('wsdesk_lite_mode').style.display="none";+ else+ document.getElementById('wsdesk_lite_mode').style.display="block";+ };+ function wsdesk_mode_select_lite(){+ if(document.getElementById('wsdesk_mode_lite').checked)+ document.getElementById('wsdesk_lite_mode').style.display="block";+ else+ document.getElementById('wsdesk_lite_mode').style.display="none";+ }+ function wsdesk_mode_select_insane()+ {++ document.getElementById('wsdesk_lite_mode').style.display="none";+ };+</script>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="wsdesk_mode" style="padding-right:1em !important;"><?php esc_html_e( 'WSDesk Mode', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Select your WSDesk mode.', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $wsdesk_mode = eh_crm_get_settingsmeta( '0', 'wsdesk_mode' );+ $standard = '';+ $lite = '';+ $display = 'none';+ switch ( $wsdesk_mode ) {+ case 'standard':+ $standard = 'checked';+ $lite = '';+ $insane = '';+ break;+ case 'lite':+ $standard = '';+ $lite = 'checked';+ $insane = '';+ $display = 'block';++ break;+ case 'insane':+ $standard = '';+ $insane = 'checked';+ $lite = '';+ $display = 'none';++ break;+ default:+ $standard = 'checked';+ $lite = '';+ $insane = '';+ break;++ }+ ?>+ <input type="radio" disabled style="margin-top: 0;" onclick="wsdesk_mode_select();" id="wsdesk_mode_std" class="form-control" name="wsdesk_mode" <?php echo esc_html( $standard ); ?> value="standard"> <?php esc_html_e( 'Standard mode', 'wsdesk' ); ?><br>+ <input type="radio" disabled style="margin-top: 0;" onclick="wsdesk_mode_select_lite();" id="wsdesk_mode_lite" class="form-control" name="wsdesk_mode" <?php echo esc_html( $lite ); ?> value="lite"> <?php esc_html_e( 'Lite mode', 'wsdesk' ); ?><br>++ <input type="radio" disabled style="margin-top: 0;" onclick="wsdesk_mode_select_insane();" id="wsdesk_mode_insane" class="form-control" name="wsdesk_mode" <?php echo esc_html( $insane ); ?> value="insane"> <?php esc_html_e( 'Insane mode', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Insane Mode enables all the tweaks from Lite Mode along with a number of additional optimizations. Please note, enabling this option may affect some of the functionalities.', 'wsdesk' ); ?>" data-container="body"></span><br><br>+ <span class="crm-divider"></span>+ <span class="help-block"><?php esc_html_e( 'Please note: As the plugin performance is optimized, switching between different modes is no longer necessary. This section will be removed from the plugin settings altogether in the forthcoming update.', 'wsdesk' ); ?></span>+ <div class="wsdesk_lite_mode hide" id="wsdesk_lite_mode" style="display: <?php echo esc_html( $display ); ?>;font-size: 12px;">+ <span style="vertical-align: middle;">+ <?php+ $display_default_status_count = eh_crm_get_settingsmeta( '0', 'display_default_status_count' );+ $enable = '';+ switch ( $display_default_status_count ) {+ case 'disable':+ $enable = '';+ break;+ default:+ $enable = 'checked';+ break;+ }+ ?>+ + <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="display_default_status_count" class="form-control" name="display_default_status_count" value="enable"> <?php esc_html_e( 'Display default status count on primary menu', 'wsdesk' ); ?><br>+ </span>+ <span style="vertical-align: middle;">+ <?php+ $ticket_count_view = eh_crm_get_settingsmeta( '0', 'ticket_count_view' );+ $enable = '';+ switch ( $ticket_count_view ) {+ case 'ticket_count_view':+ $enable = 'checked';+ break;+ default:+ $enable = '';+ break;+ }+ ?>+ + <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="<?php echo( 'ticket_count_view' ); ?>" class="form-control" name="ticket_count_view" value="ticket_count_view"> <?php esc_html_e( 'Hide the ticket counts in the tickets dashboard', 'wsdesk' ); ?>+ <br>+ </span>+ <span style="vertical-align: middle;">+ <?php+ $quick_view_tickets = eh_crm_get_settingsmeta( '0', 'quick_view_tickets' );+ $enable = '';+ switch ( $quick_view_tickets ) {+ case 'enable':+ $enable = 'checked';+ break;+ default:+ $enable = '';+ break;+ }+ ?>+ + <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="quick_view_tickets" class="form-control" name="quick_view_tickets" value="enable"> <?php esc_html_e( 'Disable quick view option in the tickets dashboard', 'wsdesk' ); ?><br>+ </span>+ <span style="vertical-align: middle;">+ <?php+ $refresh_ticket_page = eh_crm_get_settingsmeta( '0', 'refresh_ticket_page' );+ $enable = '';+ switch ( $refresh_ticket_page ) {+ case 'enable':+ $enable = 'checked';+ break;+ default:+ $enable = '';+ break;+ }+ ?>+ + <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="refresh_ticket_page" class="form-control" name="refresh_ticket_page" value="enable"> <?php esc_html_e( 'Disable refresh the tickets dashboard when the ticket tab is closed', 'wsdesk' ); ?><br>+ </span>+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-9">+ <label for="auto_create_user" style="padding-right:1em !important;"><?php esc_html_e( 'Limit scheduled triggers execution', 'wsdesk' ); ?></label>+ <span class="help-block"><?php esc_html_e( 'Enable this option to specify a time interval to trigger all scheduled actions.', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $scheduled_triggers_enable = eh_crm_get_settingsmeta( '0', 'scheduled_triggers_enable' );+ $scheduled_triggers_time = eh_crm_get_settingsmeta( '0', 'scheduled_triggers_time' );+ if ( empty( $scheduled_triggers_time ) ) {+ $scheduled_triggers_time = 24;+ }+ $auto_create_user = eh_crm_get_settingsmeta( '0', 'scheduled_triggers_enable' );+ $enable = '';+ switch ( $auto_create_user ) {+ case 'enable':+ $enable = 'checked';+ $upath = 'block';+ break;+ default:+ $enable = '';+ $upath = 'none';+ break;+ }+ ?>++ <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="scheduled_triggers_enable" onclick="enable_scheduled_triggers_enable();" class="form-control" name="scheduled_triggers_enable" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?></br></br>+ <div id="scheduled_triggers_time_option" style="display: <?php echo esc_html( $upath ); ?>">++ <input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" id="scheduled_triggers_time" value="<?php echo esc_html( $scheduled_triggers_time ); ?>" class="form-control crm-form-element-input">+ <span class="help-block"><?php esc_html_e( ' Enter the time interval to execute the scheduled actions in hours.', 'wsdesk' ); ?></span>+ </div>+ </span>+ </div>+ </div>+ </div>+ </span>+ </div>+</div>++<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="excerpt_in_auto_suggestion" style="padding-right:1em !important;"><?php esc_html_e( 'Show Excerpt on Auto-Suggestion', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Enable this option to show excerpt instead of first sentence of the post while displaying auto-suggestion.', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $show_excerpt_in_auto_suggestion = eh_crm_get_settingsmeta( '0', 'show_excerpt_in_auto_suggestion' );+ $enable = '';+ switch ( $show_excerpt_in_auto_suggestion ) {+ case 'enable':+ $enable = 'checked';+ break;+ default:+ $enable = '';+ break;+ }+ ?>+ <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="show_excerpt_in_auto_suggestion" class="form-control" name="show_excerpt_in_auto_suggestion" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="auto_assign" style="padding-right:1em !important;"><?php esc_html_e( 'Display Tickets As', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Enabling HTML option may lead to security issues. Resolving such issues are out of the scope of WSDesk plugin, hence we do not recommend this option.', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $tickets_display = eh_crm_get_settingsmeta( '0', 'tickets_display' );+ $text = '';+ $html = '';+ switch ( $tickets_display ) {+ case 'text':+ $text = 'checked';+ break;+ default:+ $html = 'checked';+ break;+ }+ ?>+ <input type="radio" <?php echo esc_html( $html ); ?> style="margin-top: 0;" id="tickets_display" class="form-control" name="tickets_display" value="html"> <?php esc_html_e( 'HTML', 'wsdesk' ); ?><br>+ <input type="radio" <?php echo esc_html( $text ); ?> style="margin-top: 0;" id="tickets_display" class="form-control" name="tickets_display" value="text"> <?php esc_html_e( 'Text', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="auto_create_user" style="padding-right:1em !important;"><?php esc_html_e( 'WSDesk API', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Create tickets via API from any website', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $api_key = eh_crm_get_settingsmeta( '0', 'api_key' );+ $auto_create_user = eh_crm_get_settingsmeta( '0', 'enable_api' );+ if ( empty( $api_key ) ) {+ $api_key = md5( time() . EH_CRM_MAIN_URL );+ }+ $enable = '';+ switch ( $auto_create_user ) {+ case 'enable':+ $enable = 'checked';+ $upath = 'block';+ break;+ default:+ $enable = '';+ $upath = 'none';+ break;+ }+ ?>+ <input type="checkbox" <?php echo esc_html( $enable ); ?> style="margin-top: 0;" id="enable_api" onclick="enable_api_click();" class="form-control" name="enable_api" value="enable"> <?php esc_html_e( 'Enable API', 'wsdesk' ); ?><br>+ <div id="api_key" style="display: <?php echo esc_html( $upath ); ?>">+ <span class="help-block"><?php esc_html_e( 'API Key:', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Please share this API Key only with trusted sources.', 'wsdesk' ); ?>" data-container="body"></span></span>+ <input type="text" id="api_key_textbox" value="<?php echo esc_html( $api_key ); ?>" class="form-control crm-form-element-input">+ </div>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="custom-attachment-folder" style="padding-right:1em !important;"><?php esc_html_e( 'Default Deep Link', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <?php+ $default_deep_link = urldecode( stripslashes( eh_crm_get_settingsmeta( '0', 'default_deep_link' ) ) );+ ?>+ <span class="help-block"><?php esc_html_e( 'Add a default deep link here', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <span class="help-block"><?php esc_html_e( 'Path: ' . esc_url( admin_url() ) . 'admin.php?page=wsdesk_tickets&', 'wsdesk' ); ?></span>+ <input type="text" id="default_deep_link" placeholder="view=all" value='<?php echo esc_html( $default_deep_link ); ?>' class="form-control crm-form-element-input">+ </span>+ </div>+</div>+<span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-3">+ <label for="ticket-activity-logs" style="padding-right:1em !important;"><?php esc_html_e( 'Ticket Activity Logs', 'wsdesk' ); ?></label>+ <label for="ticket-activity-logs" class="premium_green_set"><a href="<?php echo esc_url( 'https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/' ); ?>" target="_blank"><sup class="text-success"><?php esc_html_e( '[Premium!]', 'wsdesk' ); ?></sup></a></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Enable this option to log the activities of the ticket.', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $wsdesk_activity_log_status = eh_crm_get_settingsmeta( '0', 'wsdesk_activity_log_status' );+ $activity_log_enable = ( 'enable' === $wsdesk_activity_log_status ) ? 'checked' : '';+ $activity_log_disabled = ! wsdesk_is_premium() ? 'disabled' : '';+ ?>+ <input type="checkbox" <?php echo esc_attr( $activity_log_enable ); ?> <?php echo esc_attr( $activity_log_disabled ); ?> style="margin-top: 0;" id="wsdesk_activity_log" class="form-control" name="wsdesk_activity_log" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ </span>+ </div>+ </div>+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-3">+ <label for="ticket-email-logs" style="padding-right:1em !important;"><?php esc_html_e( 'Email Logs', 'wsdesk' ); ?></label>+ <label for="ticket-email-logs" class="premium_green_set"><a href="<?php echo esc_url( 'https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/' ); ?>" target="_blank"><sup class="text-success"><?php esc_html_e( '[Premium!]', 'wsdesk' ); ?></sup></a></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Enable this option to log the emails related to the specific ticket.', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $wsdesk_email_log_status = eh_crm_get_settingsmeta( '0', 'wsdesk_email_log_status' );+ $email_log_enable = ( 'enable' === $wsdesk_email_log_status ) ? 'checked' : '';+ $email_log_disabled = ! wsdesk_is_premium() ? 'disabled' : '';+ ?>+ <input type="checkbox" <?php echo esc_attr( $email_log_enable ); ?> <?php echo esc_attr( $email_log_disabled ); ?> style="margin-top: 0;" id="wsdesk_email_log" class="form-control" name="wsdesk_email_log" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ </span>+ </div>+ </div>+ <span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="custom-attachment-folder" style="padding-right:1em !important;"><?php esc_html_e( 'Debug Mode', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Enable this option to place debug logs in PHP error log file', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $wsdesk_debug_status = eh_crm_get_settingsmeta( '0', 'wsdesk_debug_status' );+ $debug_enable = '';+ switch ( $wsdesk_debug_status ) {+ case 'enable':+ $debug_enable = 'checked';+ break;+ default:+ $debug_enable = '';+ break;+ }+ ?>+ <input type="checkbox" <?php echo esc_html( $debug_enable ); ?> style="margin-top: 0;" id="wsdesk_debug_email" class="form-control" name="wsdesk_debug_email" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>++<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="custom-attachment-folder" style="padding-right:1em !important;"><?php esc_html_e( 'Powered by WSDesk Tag', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Disabling this option will remove Powered by WSDesk Tag from front end and all support E-mails.', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $wsdesk_powered_by_status = eh_crm_get_settingsmeta( '0', 'wsdesk_powered_by_status' );+ switch ( $wsdesk_powered_by_status ) {+ case 'disable':+ $wsdesk_powered_by_status_checked = '';+ break;+ default:+ $wsdesk_powered_by_status_checked = 'checked';+ break;+ }+ ?>+ <input type="checkbox" <?php echo esc_html( $wsdesk_powered_by_status_checked ); ?> style="margin-top: 0;" id="wsdesk_powered_by_status" class="form-control" name="wsdesk_powered_by_status" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="linkify-url" style="padding-right:1em !important;"><?php esc_html_e( 'Convert URLs to Hyperlinks', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Enabling this option will convert all URLs in ticket conversation to hyperlinks. (BETA)', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <?php+ $linkify_urls = eh_crm_get_settingsmeta( '0', 'linkify_urls' );+ switch ( $linkify_urls ) {+ case 'enable':+ $linkify_urls_checked = 'checked';+ break;+ default:+ $linkify_urls_checked = '';+ break;+ }+ ?>+ <input type="checkbox" <?php echo esc_html( $linkify_urls_checked ); ?> style="margin-top: 0;" id="linkify_urls" class="form-control" name="linkify_urls" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-12">+ <button type="button" id="save_general" class="save_wsdesk_mode btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button>+ </div>+</div>+<?php+// return ob_get_clean();
Vulnerability Existed: no Improper Output Encoding - CWE-79 - views/settings/crm_settings_lite_mode.php - Lines 327-328 (new version) Old Code: ```php <span class="help-block"><?php esc_html_e( 'Path: ' . esc_url( admin_url() ) . 'admin.php?page=wsdesk_tickets&', 'wsdesk' ); ?></span> ``` Fixed Code: ```php <span class="help-block"><?php esc_html_e( 'Path: ' . esc_url( admin_url() ) . 'admin.php?page=wsdesk_tickets&', 'wsdesk' ); ?></span> ``` Explanation: The code remains unchanged in this section. The output is properly escaped using `esc_url()` for the URL portion and `esc_html_e()` for the overall text output. This is correctly implemented and does not introduce any XSS vulnerability. --- Vulnerability Existed: not sure Improper Attribute Escaping - CWE-79 - views/settings/crm_settings_lite_mode.php - Lines 351-353, 368-370 (new version) Old Code: ```php <!-- Not present in old version --> ``` Fixed Code: ```php <input type="checkbox" <?php echo esc_attr( $activity_log_enable ); ?> <?php echo esc_attr( $activity_log_disabled ); ?> style="margin-top: 0;" id="wsdesk_activity_log" class="form-control" name="wsdesk_activity_log" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> ``` Explanation: The new code uses `esc_attr()` for the checkbox attributes (`$activity_log_enable` and `$activity_log_disabled`), which is the correct escaping function for HTML attributes. However, without seeing the old version's implementation of similar functionality, it's uncertain if this represents a fix for an existing vulnerability or if this is new code. The use of `esc_attr()` is the proper security measure for attribute escaping in WordPress. --- Vulnerability Existed: not sure Improper Attribute Escaping - CWE-79 - views/settings/crm_settings_lite_mode.php - Lines 365-370 (new version) Old Code: ```php <!-- Not present in old version --> ``` Fixed Code: ```php <input type="checkbox" <?php echo esc_attr( $email_log_enable ); ?> <?php echo esc_attr( $email_log_disabled ); ?> style="margin-top: 0;" id="wsdesk_email_log" class="form-control" name="wsdesk_email_log" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> ``` Explanation: Similar to the activity logs section, this is new code that properly uses `esc_attr()` for HTML attribute escaping. The implementation correctly escapes both the checkbox state and disabled attribute. Without the old version context, uncertainty remains about whether this addresses a previously existing vulnerability.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_page.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_page.php 2025-12-21 09:36:35.511308688 +0000@@ -1,112 +1,112 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -$selected = eh_crm_get_settingsmeta( '0', 'selected_fields' ); -if ( empty( $selected ) ) { - $selected = array( 'request_email', 'request_title', 'request_description' ); - - eh_crm_update_settingsmeta( '0', 'selected_fields', array_values( $selected ) ); -} - -$key = array_search( 'request_description', $selected ); -unset( $selected[ $key ] ); -$key = array_search( 'request_title', $selected ); -unset( $selected[ $key ] ); -$key = array_search( 'request_email', $selected ); -unset( $selected[ $key ] ); -$all_ticket_page_columns = wsdesk_get_all_tickets_page_fields(); -$default = array( 'id', 'requestor', 'subject', 'requested', 'updated', 'assignee', 'feedback' ); - -foreach ( $default as $value ) { - if ( array_search( $value, $all_ticket_page_columns ) === false ) { - array_push( $selected, $value ); - } -} -?> -<div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="ticket_fields" style="padding-right:1em !important;"><?php esc_html_e( 'Ticket Page', 'wsdesk' ); ?></label> - </div> - <div class="panel panel-default crm-panel" style="margin-top: 15px !important;margin-bottom: 0px !important;"> - <div class="panel-body" style="padding: 5px !important;"> - <div class="col-sm-6" style="padding-right: 5px !important;padding-left: 5px !important;"> - <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php esc_html_e( 'Inactive Columns', 'wsdesk' ); ?></span><br> - <ul class="list-group"> - <?php - if ( ! array_diff( $selected, $all_ticket_page_columns ) ) { - echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'No inactive column', 'wsdesk' ) . '</li>'; - } else { - $all_ticket_page_columns_deactivated = array_diff( $selected, $all_ticket_page_columns ); - foreach ( $all_ticket_page_columns_deactivated as $all_ticket_page_column ) { - switch ( $all_ticket_page_column ) { - case 'id': - case 'requestor': - case 'subject': - case 'requested': - case 'updated': - case 'assignee': - case 'feedback': - echo '<li class="list-group-item list-group-item-info" id="' . esc_html( $all_ticket_page_column ) . '"> ' . esc_html( ucfirst( $all_ticket_page_column ) ) . '<span class="pull-right"><span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_page_column_activate" id="' . esc_html( $all_ticket_page_column ) . '"><span class="glyphicon glyphicon-ok-circle" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Activate', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span></span></li>'; - break; - default: - $settings_id = eh_crm_get_settings( array( 'slug' => esc_html( $all_ticket_page_column ) ) ); - echo '<li class="list-group-item list-group-item-info" id="' . esc_html( $all_ticket_page_column ) . '"> ' . esc_html( $settings_id[0]['title'] ) . '<span class="pull-right"><span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_page_column_activate" id="' . esc_attr( $all_ticket_page_column ) . '"><span class="glyphicon glyphicon-ok-circle" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Activate', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span></span></li>'; - - } - } - } - ?> - </ul> - </div> - <div class="col-sm-6"> - <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php esc_html_e( 'Active Columns', 'wsdesk' ); ?></span><br> - <ul class="list-group list-group-sortable-connected list-group-page-data list-border-settings" sortstop="drag_page_column(event)"> - <?php - if ( empty( $all_ticket_page_columns ) ) { - echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'No active column', 'wsdesk' ) . '</li>'; - } else { - foreach ( $all_ticket_page_columns as $all_ticket_page_column ) { - switch ( $all_ticket_page_column ) { - case 'id': - case 'requestor': - case 'subject': - case 'requested': - case 'updated': - case 'assignee': - case 'feedback': - echo '<li class="list-group-item list-group-item-success ticket_page_column_list" ondragend="drag_page_column(event)" id="' . esc_html( $all_ticket_page_column ) . '"> - <span class="dashicons dashicons-menu" style="cursor:move;margin-right:5px;"></span> ' . esc_html( ucfirst( $all_ticket_page_column ) ) . ' - <span class="pull-right"> - <span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_page_column_deactivate" id="' . esc_attr( $all_ticket_page_column ) . '"> - <span class="glyphicon glyphicon-remove-circle" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Deactivate', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"> - </span> - </span> - </span> - </li>'; - break; - default: - $settings_id = eh_crm_get_settings( array( 'slug' => $all_ticket_page_column ) ); - echo '<li class="list-group-item list-group-item-success ticket_page_column_list" ondragend="drag_page_column(event)" id="' . esc_html( $all_ticket_page_column ) . '"> - <span class="dashicons dashicons-menu" style="cursor:move;margin-right:5px;"></span> ' . esc_html( isset( $settings_id[0]['title'] ) ? $settings_id[0]['title'] : '' ) . ' - <span class="pull-right"> - <span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_page_column_deactivate" id="' . esc_attr( $all_ticket_page_column ) . '"> - <span class="glyphicon glyphicon-remove-circle" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Deactivate', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"> - </span> - </span> - </span> - </li>'; - } - } - } - ?> - </ul> - </div> - </div> - </div> - </div> -</div> -<?php -// return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+$selected = eh_crm_get_settingsmeta( '0', 'selected_fields' );+if ( empty( $selected ) ) {+ $selected = array( 'request_email', 'request_title', 'request_description' );++ eh_crm_update_settingsmeta( '0', 'selected_fields', array_values( $selected ) );+}++$key = array_search( 'request_description', $selected );+unset( $selected[ $key ] );+$key = array_search( 'request_title', $selected );+unset( $selected[ $key ] );+$key = array_search( 'request_email', $selected );+unset( $selected[ $key ] );+$all_ticket_page_columns = wsdesk_get_all_tickets_page_fields();+$default = array( 'id', 'requestor', 'subject', 'requested', 'updated', 'assignee', 'feedback' );++foreach ( $default as $value ) {+ if ( array_search( $value, $all_ticket_page_columns ) === false ) {+ array_push( $selected, $value );+ }+}+?>+<div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="ticket_fields" style="padding-right:1em !important;"><?php esc_html_e( 'Ticket Page', 'wsdesk' ); ?></label>+ </div>+ <div class="panel panel-default crm-panel" style="margin-top: 15px !important;margin-bottom: 0px !important;">+ <div class="panel-body" style="padding: 5px !important;">+ <div class="col-sm-6" style="padding-right: 5px !important;padding-left: 5px !important;">+ <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php esc_html_e( 'Inactive Columns', 'wsdesk' ); ?></span><br>+ <ul class="list-group">+ <?php+ if ( ! array_diff( $selected, $all_ticket_page_columns ) ) {+ echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'No inactive column', 'wsdesk' ) . '</li>';+ } else {+ $all_ticket_page_columns_deactivated = array_diff( $selected, $all_ticket_page_columns );+ foreach ( $all_ticket_page_columns_deactivated as $all_ticket_page_column ) {+ switch ( $all_ticket_page_column ) {+ case 'id':+ case 'requestor':+ case 'subject':+ case 'requested':+ case 'updated':+ case 'assignee':+ case 'feedback':+ echo '<li class="list-group-item list-group-item-info" id="' . esc_html( $all_ticket_page_column ) . '"> ' . esc_html( ucfirst( $all_ticket_page_column ) ) . '<span class="pull-right"><span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_page_column_activate" id="' . esc_html( $all_ticket_page_column ) . '"><span class="glyphicon glyphicon-ok-circle" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Activate', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span></span></li>';+ break;+ default:+ $settings_id = eh_crm_get_settings( array( 'slug' => esc_html( $all_ticket_page_column ) ) );+ echo '<li class="list-group-item list-group-item-info" id="' . esc_html( $all_ticket_page_column ) . '"> ' . esc_html( $settings_id[0]['title'] ) . '<span class="pull-right"><span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_page_column_activate" id="' . esc_attr( $all_ticket_page_column ) . '"><span class="glyphicon glyphicon-ok-circle" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Activate', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span></span></li>';++ }+ }+ }+ ?>+ </ul>+ </div>+ <div class="col-sm-6">+ <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php esc_html_e( 'Active Columns', 'wsdesk' ); ?></span><br>+ <ul class="list-group list-group-sortable-connected list-group-page-data list-border-settings" sortstop="drag_page_column(event)">+ <?php+ if ( empty( $all_ticket_page_columns ) ) {+ echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'No active column', 'wsdesk' ) . '</li>';+ } else {+ foreach ( $all_ticket_page_columns as $all_ticket_page_column ) {+ switch ( $all_ticket_page_column ) {+ case 'id':+ case 'requestor':+ case 'subject':+ case 'requested':+ case 'updated':+ case 'assignee':+ case 'feedback':+ echo '<li class="list-group-item list-group-item-success ticket_page_column_list" ondragend="drag_page_column(event)" id="' . esc_html( $all_ticket_page_column ) . '">+ <span class="dashicons dashicons-menu" style="cursor:move;margin-right:5px;"></span> ' . esc_html( ucfirst( $all_ticket_page_column ) ) . '+ <span class="pull-right">+ <span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_page_column_deactivate" id="' . esc_attr( $all_ticket_page_column ) . '">+ <span class="glyphicon glyphicon-remove-circle" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Deactivate', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;">+ </span>+ </span>+ </span>+ </li>';+ break;+ default:+ $settings_id = eh_crm_get_settings( array( 'slug' => $all_ticket_page_column ) );+ echo '<li class="list-group-item list-group-item-success ticket_page_column_list" ondragend="drag_page_column(event)" id="' . esc_html( $all_ticket_page_column ) . '">+ <span class="dashicons dashicons-menu" style="cursor:move;margin-right:5px;"></span> ' . esc_html( isset( $settings_id[0]['title'] ) ? $settings_id[0]['title'] : '' ) . '+ <span class="pull-right">+ <span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_page_column_deactivate" id="' . esc_attr( $all_ticket_page_column ) . '">+ <span class="glyphicon glyphicon-remove-circle" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Deactivate', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;">+ </span>+ </span>+ </span>+ </li>';+ }+ }+ }+ ?>+ </ul>+ </div>+ </div>+ </div>+ </div>+</div>+<?php+// return ob_get_clean();
**Analysis Result:** Vulnerability Existed: **no** This diff contains only line ending changes (CRLF to LF conversion). There are no functional code modifications, logic changes, or security-related alterations present in this update. The file `views/settings/crm_settings_page.php` remains functionally identical between versions 3.3.4 and 3.3.5. All security measures that were in place (proper use of `esc_html()`, `esc_attr()`, `esc_html_e()`) remain unchanged. **Conclusion:** No security vulnerabilities were introduced or fixed in this version update. This appears to be a maintenance release addressing only code formatting/line ending normalization.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_premium.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_premium.php 2025-12-21 09:36:35.511308688 +0000@@ -1,215 +1,215 @@-<style> - .video_content - { - padding: 10px; - border: 1px solid lightgrey; - width: 560px; - box-shadow: 10px 10px 5px #888888; - } - .premium-li - { - padding: 5px; - } - .premium-ul - { - list-style: none; - font-size: 15px; - } - .premium-ol - { - list-style: none; - padding: 5px 15px; - font-size: 14px; - } - .marketing_logos{ - width: 300px; - height: 300px; - border-radius: 10px; - } - .marketing_redirect_links{ - padding: 0px 10px !important; - background-color: #337ab7 !important; - color: white !important; - height: 52px; - font-weight: 600 !important; - font-size: 18px !important; - min-width: 210px; - border: none; - border-radius: 4px; - } - .product-name-center{ - text-align: center; - } - .usps_services th { - width: 33.3%; - } - .elex_related_product_header { - background-color: #337ab7 !important; - color: white !important; - padding: 10px 5px !important; - font-size: 18px !important; - border-radius: 4px 4px 0px 0px !important; - } -</style> -<div class="wsdesk_wrapper"> -<center> - <div class="video_content" style="display:flex;gap:2%;width:90%;background-color:white"> - <div> - <div> - <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'WSDeskHelpdesk.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center> - </div> - <div style="margin: 5px;"> - <a class="button" style="background: #337ab7; color: white; width: 166px; height: 29px;" href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><?php esc_html_e( 'Go Premium!', 'wsdesk' ); ?></a> - </div> - </div> - <div style="border: 2px solid #0073B2; width: 100%;height:300px;text-align:left"> - <div style="text-align: center; background: #0073B2; padding-bottom: 2%; padding-top: 2%;"><h3 style="color: white"><?php esc_html_e( 'Premium Version Features', 'wsdesk' ); ?></h3></div> - <ul style="margin:0px; height:calc(100% - 91px); overflow-y: auto;"> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'All Basic Features +', 'wsdesk' ); ?></li> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Advanced triggers and automation', 'wsdesk' ); ?></li> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Advanced automated Emails', 'wsdesk' ); ?></li> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'More Detailed Reports with Enhanced Date Range', 'wsdesk' ); ?></li> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Option to restrict file formats as attachments', 'wsdesk' ); ?></li> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Autosuggestion for the Agents and Customers', 'wsdesk' ); ?></li> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Restrict who can raise the tickets', 'wsdesk' ); ?></li> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Multiple IMAP support', 'wsdesk' ); ?></li> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Archive and Restore Tickets', 'wsdesk' ); ?></li> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'WSChat - WordPress Live Chat Integaration', 'wsdesk' ); ?></li> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Google Chat Integration', 'wsdesk' ); ?></li> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Many more customization options', 'wsdesk' ); ?></li> - <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'One Year Support & Updates', 'wsdesk' ); ?></li> - </ul> - </div> - </div> - <br> - <div style="display: flex; text-align: left; width: 582px"> - - - </div> - </div> - <tr> - <td> - <strong><div class="elex_related_product_header"><center><?php esc_html_e( 'Checkout these addons supported for ELEX WSDesk - WordPress HelpDesk plugin.', 'wsdesk' ); ?></center></div></strong> - <table class="usps_services widefat"> - <tr> - <th> - <div> - <div> - <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'sms_notification_addon.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center> - </div> - <div class="product-name-center"> - <h5 ><a href="https://elextensions.com/plugin/wsdesk-sms-notification-add-on/" data-wpel-link="internal" target="_blank">SMS Notification Add-On</a> </h5> - </div> - </div> - </th> - - <th> - <div> - <div> - <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'WSDeskPayForSupport.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center > - </div> - <div class="product-name-center"> - <h5 ><a href="https://elextensions.com/plugin/wsdesk-pay-for-support-add-on/" data-wpel-link="internal" target="_blank">Pay For Support Add-On</a></h5> - </div> - </div> - </th> - <th> - <div> - <div> - <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'agent_signature_addon.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center> - </div> - <div class="product-name-center"> - <h5 ><a href="https://elextensions.com/plugin/wsdesk-agent-signature-add-on/" data-wpel-link="internal" target="_blank">Agent Signature Add-On</a></h5> - </div> - </div> - </th> - </tr> - - </table> - </td> - </tr> -</br> - - <tr> - <td> - <strong><div class="elex_related_product_header"><center><?php esc_html_e( 'More ELEXtensions plugins you may be interested in...', 'wsdesk' ); ?></center></div></strong> - <table class="usps_services widefat"> - <tr> - <th> - <div> - <div> - <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'wschat.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center> - </div> - <div class="product-name-center"> - <h5 ><a href="https://elextensions.com/plugin/wschat-wordpress-live-chat-plugin/" data-wpel-link="internal" target="_blank">WSChat – WordPress Live Chat Plugin</a> </h5> - </div> - </div> - </th> - - <th> - <div> - <div> - <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'gpf.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center > - </div> - <div class="product-name-center"> - <h5 ><a href="https://elextensions.com/plugin/woocommerce-google-product-feed-plugin/" data-wpel-link="internal" target="_blank">ELEX WooCommerce Google Product Feed Plugin</a></h5> - </div> - </div> - </th> - <th> - <div> - <div> - <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'dynamic_pricing.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center> - </div> - <div class="product-name-center"> - <h5 ><a href="https://elextensions.com/plugin/dynamic-pricing-and-discounts-plugin-for-woocommerce/" data-wpel-link="internal" target="_blank">ELEX Dynamic Pricing and Discounts Plugin for WooCommerce</a></h5> - </div> - </div> - </th> - </tr> - - <tr> - <th> - <div> - <div> - <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'catalog_mode.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center> - </div> - <div class="product-name-center"> - <h5 ><a href="https://elextensions.com/plugin/woocommerce-catalog-mode-wholesale-role-based-pricing/" data-wpel-link="internal" target="_blank"><center>ELEX WooCommerce Catalog Mode, Wholesale & Role Based Pricing</center></a></h5> - </div> - </div> - </th> - <th> - <div> - <div> - <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'bulk_edit.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center> - </div> - <div class="product-name-center"> - <h5 ><a href="https://elextensions.com/plugin/bulk-edit-products-prices-attributes-for-woocommerce/" data-wpel-link="internal" target="_blank"><center>ELEX WooCommerce Bulk Edit Products, Prices & Attributes</center></a> </h5> - </div> - </div> - </th> - <th> - <div> - <div> - <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'elex_dhl.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center> - </div> - <div class="product-name-center"> - <h5 ><a href="https://elextensions.com/plugin/woocommerce-dhl-express-ecommerce-paket-shipping-plugin-with-print-label/" data-wpel-link="internal" target="_blank">ELEX WooCommerce DHL Express / eCommerce / Paket Shipping Plugin with Print Label</a></h5> - </div> - </div> - </th> - </tr> - <tr > - <td colspan="3" > - <center> - <input type ="button" onclick='window.open("https://elextensions.com/product-category/plugins/", "_blank")' class="btn marketing_redirect_links" target="_blank" value="Browse All ELEXtensions Plugins"> - </center> - </td> - </tr> - </table> - </td> - </tr> - -</center> -</button> +<style>+ .video_content+ {+ padding: 10px;+ border: 1px solid lightgrey;+ width: 560px;+ box-shadow: 10px 10px 5px #888888;+ }+ .premium-li+ {+ padding: 5px;+ }+ .premium-ul+ {+ list-style: none;+ font-size: 15px;+ }+ .premium-ol+ {+ list-style: none;+ padding: 5px 15px;+ font-size: 14px;+ }+ .marketing_logos{+ width: 300px;+ height: 300px;+ border-radius: 10px;+ }+ .marketing_redirect_links{+ padding: 0px 10px !important;+ background-color: #337ab7 !important;+ color: white !important;+ height: 52px;+ font-weight: 600 !important;+ font-size: 18px !important;+ min-width: 210px;+ border: none;+ border-radius: 4px;+ }+ .product-name-center{+ text-align: center;+ }+ .usps_services th {+ width: 33.3%;+ }+ .elex_related_product_header {+ background-color: #337ab7 !important;+ color: white !important;+ padding: 10px 5px !important;+ font-size: 18px !important;+ border-radius: 4px 4px 0px 0px !important;+ }+</style>+<div class="wsdesk_wrapper">+<center>+ <div class="video_content" style="display:flex;gap:2%;width:90%;background-color:white">+ <div>+ <div>+ <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'WSDeskHelpdesk.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center>+ </div>+ <div style="margin: 5px;">+ <a class="button" style="background: #337ab7; color: white; width: 166px; height: 29px;" href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"><?php esc_html_e( 'Go Premium!', 'wsdesk' ); ?></a>+ </div>+ </div>+ <div style="border: 2px solid #0073B2; width: 100%;height:300px;text-align:left">+ <div style="text-align: center; background: #0073B2; padding-bottom: 2%; padding-top: 2%;"><h3 style="color: white"><?php esc_html_e( 'Premium Version Features', 'wsdesk' ); ?></h3></div>+ <ul style="margin:0px; height:calc(100% - 91px); overflow-y: auto;">+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'All Basic Features +', 'wsdesk' ); ?></li>+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Advanced triggers and automation', 'wsdesk' ); ?></li>+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Advanced automated Emails', 'wsdesk' ); ?></li>+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'More Detailed Reports with Enhanced Date Range', 'wsdesk' ); ?></li>+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Option to restrict file formats as attachments', 'wsdesk' ); ?></li>+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Autosuggestion for the Agents and Customers', 'wsdesk' ); ?></li>+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Restrict who can raise the tickets', 'wsdesk' ); ?></li>+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Multiple IMAP support', 'wsdesk' ); ?></li>+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Archive and Restore Tickets', 'wsdesk' ); ?></li>+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'WSChat - WordPress Live Chat Integaration', 'wsdesk' ); ?></li>+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Google Chat Integration', 'wsdesk' ); ?></li>+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'Many more customization options', 'wsdesk' ); ?></li>+ <li><span class="dashicons dashicons-yes"></span> <?php esc_html_e( 'One Year Support & Updates', 'wsdesk' ); ?></li>+ </ul>+ </div>+ </div>+ <br>+ <div style="display: flex; text-align: left; width: 582px">+ + + </div>+ </div>+ <tr>+ <td>+ <strong><div class="elex_related_product_header"><center><?php esc_html_e( 'Checkout these addons supported for ELEX WSDesk - WordPress HelpDesk plugin.', 'wsdesk' ); ?></center></div></strong>+ <table class="usps_services widefat">+ <tr>+ <th>+ <div>+ <div>+ <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'sms_notification_addon.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center>+ </div>+ <div class="product-name-center">+ <h5 ><a href="https://elextensions.com/plugin/wsdesk-sms-notification-add-on/" data-wpel-link="internal" target="_blank">SMS Notification Add-On</a> </h5>+ </div>+ </div>+ </th>++ <th>+ <div>+ <div>+ <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'WSDeskPayForSupport.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center >+ </div>+ <div class="product-name-center">+ <h5 ><a href="https://elextensions.com/plugin/wsdesk-pay-for-support-add-on/" data-wpel-link="internal" target="_blank">Pay For Support Add-On</a></h5>+ </div>+ </div>+ </th>+ <th>+ <div>+ <div>+ <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'agent_signature_addon.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center>+ </div>+ <div class="product-name-center">+ <h5 ><a href="https://elextensions.com/plugin/wsdesk-agent-signature-add-on/" data-wpel-link="internal" target="_blank">Agent Signature Add-On</a></h5>+ </div>+ </div>+ </th>+ </tr>++ </table>+ </td>+ </tr>+</br>++ <tr>+ <td>+ <strong><div class="elex_related_product_header"><center><?php esc_html_e( 'More ELEXtensions plugins you may be interested in...', 'wsdesk' ); ?></center></div></strong>+ <table class="usps_services widefat">+ <tr>+ <th>+ <div>+ <div>+ <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'wschat.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center>+ </div>+ <div class="product-name-center">+ <h5 ><a href="https://elextensions.com/plugin/wschat-wordpress-live-chat-plugin/" data-wpel-link="internal" target="_blank">WSChat – WordPress Live Chat Plugin</a> </h5>+ </div>+ </div>+ </th>++ <th>+ <div>+ <div>+ <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'gpf.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center >+ </div>+ <div class="product-name-center">+ <h5 ><a href="https://elextensions.com/plugin/woocommerce-google-product-feed-plugin/" data-wpel-link="internal" target="_blank">ELEX WooCommerce Google Product Feed Plugin</a></h5>+ </div>+ </div>+ </th>+ <th>+ <div>+ <div>+ <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'dynamic_pricing.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center>+ </div>+ <div class="product-name-center">+ <h5 ><a href="https://elextensions.com/plugin/dynamic-pricing-and-discounts-plugin-for-woocommerce/" data-wpel-link="internal" target="_blank">ELEX Dynamic Pricing and Discounts Plugin for WooCommerce</a></h5>+ </div>+ </div>+ </th>+ </tr>+ + <tr>+ <th>+ <div>+ <div>+ <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'catalog_mode.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center>+ </div>+ <div class="product-name-center">+ <h5 ><a href="https://elextensions.com/plugin/woocommerce-catalog-mode-wholesale-role-based-pricing/" data-wpel-link="internal" target="_blank"><center>ELEX WooCommerce Catalog Mode, Wholesale & Role Based Pricing</center></a></h5>+ </div>+ </div>+ </th>+ <th>+ <div>+ <div>+ <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'bulk_edit.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center>+ </div>+ <div class="product-name-center">+ <h5 ><a href="https://elextensions.com/plugin/bulk-edit-products-prices-attributes-for-woocommerce/" data-wpel-link="internal" target="_blank"><center>ELEX WooCommerce Bulk Edit Products, Prices & Attributes</center></a> </h5>+ </div>+ </div>+ </th>+ <th>+ <div>+ <div>+ <center><img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'elex_dhl.png' ); ?>" class="marketing_logos" style="border-radius: 8px;height:300px;"></center>+ </div>+ <div class="product-name-center">+ <h5 ><a href="https://elextensions.com/plugin/woocommerce-dhl-express-ecommerce-paket-shipping-plugin-with-print-label/" data-wpel-link="internal" target="_blank">ELEX WooCommerce DHL Express / eCommerce / Paket Shipping Plugin with Print Label</a></h5>+ </div>+ </div>+ </th>+ </tr>+ <tr >+ <td colspan="3" >+ <center>+ <input type ="button" onclick='window.open("https://elextensions.com/product-category/plugins/", "_blank")' class="btn marketing_redirect_links" target="_blank" value="Browse All ELEXtensions Plugins">+ </center>+ </td>+ </tr>+ </table>+ </td>+ </tr>++</center>+</button>
Vulnerability Existed: no No Security Vulnerabilities Identified - views/settings/crm_settings_premium.php Explanation: This diff shows only whitespace/line ending changes (likely conversion from DOS to Unix line endings or vice versa). The actual code content remains identical between versions 3.3.4 and 3.3.5. No functional code changes, security fixes, or vulnerabilities are present in this diff. The file contains: - HTML/CSS markup for a WordPress plugin settings page - Properly escaped output using `esc_url()` and `esc_html_e()` functions - External links to elextensions.com - Static content and styling No security vulnerabilities were introduced or fixed in this update.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_tags.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_tags.php 2025-12-21 09:36:35.511308688 +0000@@ -1,78 +1,78 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -// ob_start(); -$args = array( 'type' => 'tag' ); -$fields = array( 'slug', 'title', 'settings_id' ); -$avail_tags = eh_crm_get_settings( $args, $fields ); -?> -<div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="ticket_tags" style="padding-right:1em !important;"><?php esc_html_e( 'Ticket Tags', 'wsdesk' ); ?></label> - <button type="button" id="ticket_tag_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Tag', 'wsdesk' ); ?></button> - </div> - <ul class="list-group list-group-sortable-connected list-group-tag-data"> - <?php - if ( ! empty( $avail_tags ) ) { - for ( $i = 0;$i < count( $avail_tags );$i++ ) { - $tag_posts = eh_crm_get_settingsmeta( $avail_tags[ $i ]['settings_id'], 'tag_posts' ); - if ( empty( $tag_posts ) ) { - $tag_posts = array(); - } - echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $avail_tags[ $i ]['slug'] ) . '"> ' . esc_html( $avail_tags[ $i ]['title'] ) . ' <span class="badge" style="background-color:#337ab7 !important;">' . count( $tag_posts ) . ' ' . esc_html__( 'tagged post', 'wsdesk' ) . '</span><span class="pull-right">'; - echo '<span class="glyphicon glyphicon-trash ticket_tag_delete_type" id="' . esc_attr( $avail_tags[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Tag', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - echo '<span class="glyphicon glyphicon-pencil ticket_tag_edit_type" id="' . esc_attr( $avail_tags[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Tag', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - echo '</span></li>'; - - } - } else { - echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'There are no Tags! Create One Tag', 'wsdesk' ) . '.</li>'; - } - ?> - </ul> - </div> - <div id="ticket_tag_add_display" style="display: none;"> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label style="padding-right:1em !important;"><?php esc_html_e( 'Add Tag', 'wsdesk' ); ?></label> - <button type="button" id="ticket_tag_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - </div> - <span style="vertical-align: middle;" id="ticket_tag_add_section"> - <input type="hidden" value="" id="add_new_tag_yes"> - <span style="vertical-align: middle;;" id="ticket_tag_add_section"> - <span class="help-block"><?php esc_html_e( 'Enter Details for New Tag', 'wsdesk' ); ?> </span> - <input type="text" id="ticket_tag_add_title" placeholder="<?php esc_html_e( 'Enter Title', 'wsdesk' ); ?>" class="form-control crm-form-element-input"> - <span class="help-block"><?php esc_html_e( 'Select the Post which should be Tagged if required', 'wsdesk' ); ?> </span> - <select class="ticket_tag_add_posts form-control crm-form-element-input" multiple="multiple"> - </select> - <span class="help-block"><?php esc_html_e( 'Want to use this Tag to Filter Tickets?', 'wsdesk' ); ?> </span> - <input type="radio" style="margin-top: 0;" id="ticket_tag_add_filter" checked class="form-control" name="ticket_tag_add_filter" value="yes"> <?php esc_html_e( 'Yes! I will use it to Filter', 'wsdesk' ); ?><br> - <input type="radio" style="margin-top: 0;" id="ticket_tag_add_filter" class="form-control" name="ticket_tag_add_filter" value="no"> <?php esc_html_e( 'No! Just for Information', 'wsdesk' ); ?> - </span> - </span> - </div> - </div> - </div> - <div id="ticket_tag_edit_display" style="display: none;"> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label style="padding-right:1em !important;"><?php esc_html_e( 'Edit Tag', 'wsdesk' ); ?></label> - <button type="button" id="ticket_tag_cancel_edit_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - </div> - <input type="hidden" value="" id="ticket_tag_edit_type"> - <span style="vertical-align: middle;" id="ticket_tag_edit_append"></span> - </div> - </div> - </div> - <div class="col-md-12"> - <button type="button" id="save_ticket_tags" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button> - </div> -</div> -<?php -// return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+// ob_start();+$args = array( 'type' => 'tag' );+$fields = array( 'slug', 'title', 'settings_id' );+$avail_tags = eh_crm_get_settings( $args, $fields );+?>+<div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="ticket_tags" style="padding-right:1em !important;"><?php esc_html_e( 'Ticket Tags', 'wsdesk' ); ?></label> + <button type="button" id="ticket_tag_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Tag', 'wsdesk' ); ?></button>+ </div>+ <ul class="list-group list-group-sortable-connected list-group-tag-data">+ <?php+ if ( ! empty( $avail_tags ) ) {+ for ( $i = 0;$i < count( $avail_tags );$i++ ) {+ $tag_posts = eh_crm_get_settingsmeta( $avail_tags[ $i ]['settings_id'], 'tag_posts' );+ if ( empty( $tag_posts ) ) {+ $tag_posts = array();+ }+ echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $avail_tags[ $i ]['slug'] ) . '"> ' . esc_html( $avail_tags[ $i ]['title'] ) . ' <span class="badge" style="background-color:#337ab7 !important;">' . count( $tag_posts ) . ' ' . esc_html__( 'tagged post', 'wsdesk' ) . '</span><span class="pull-right">';+ echo '<span class="glyphicon glyphicon-trash ticket_tag_delete_type" id="' . esc_attr( $avail_tags[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Tag', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ echo '<span class="glyphicon glyphicon-pencil ticket_tag_edit_type" id="' . esc_attr( $avail_tags[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Tag', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ echo '</span></li>';+ + }+ } else {+ echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'There are no Tags! Create One Tag', 'wsdesk' ) . '.</li>';+ }+ ?>+ </ul>+ </div>+ <div id="ticket_tag_add_display" style="display: none;">+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label style="padding-right:1em !important;"><?php esc_html_e( 'Add Tag', 'wsdesk' ); ?></label> + <button type="button" id="ticket_tag_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button>+ </div>+ <span style="vertical-align: middle;" id="ticket_tag_add_section">+ <input type="hidden" value="" id="add_new_tag_yes">+ <span style="vertical-align: middle;;" id="ticket_tag_add_section">+ <span class="help-block"><?php esc_html_e( 'Enter Details for New Tag', 'wsdesk' ); ?> </span>+ <input type="text" id="ticket_tag_add_title" placeholder="<?php esc_html_e( 'Enter Title', 'wsdesk' ); ?>" class="form-control crm-form-element-input">+ <span class="help-block"><?php esc_html_e( 'Select the Post which should be Tagged if required', 'wsdesk' ); ?> </span>+ <select class="ticket_tag_add_posts form-control crm-form-element-input" multiple="multiple">+ </select>+ <span class="help-block"><?php esc_html_e( 'Want to use this Tag to Filter Tickets?', 'wsdesk' ); ?> </span>+ <input type="radio" style="margin-top: 0;" id="ticket_tag_add_filter" checked class="form-control" name="ticket_tag_add_filter" value="yes"> <?php esc_html_e( 'Yes! I will use it to Filter', 'wsdesk' ); ?><br>+ <input type="radio" style="margin-top: 0;" id="ticket_tag_add_filter" class="form-control" name="ticket_tag_add_filter" value="no"> <?php esc_html_e( 'No! Just for Information', 'wsdesk' ); ?>+ </span>+ </span>+ </div>+ </div>+ </div>+ <div id="ticket_tag_edit_display" style="display: none;">+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label style="padding-right:1em !important;"><?php esc_html_e( 'Edit Tag', 'wsdesk' ); ?></label>+ <button type="button" id="ticket_tag_cancel_edit_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button>+ </div>+ <input type="hidden" value="" id="ticket_tag_edit_type">+ <span style="vertical-align: middle;" id="ticket_tag_edit_append"></span>+ </div>+ </div>+ </div>+ <div class="col-md-12">+ <button type="button" id="save_ticket_tags" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button>+ </div>+</div>+<?php+// return ob_get_clean();
Vulnerability Existed: no Line Ending Normalization - No CWE - views/settings/crm_settings_tags.php - All lines (1-78) Old Code: File with CRLF (Windows) line endings Fixed Code: File with LF (Unix) line endings Explanation: This diff represents a line ending normalization change (CRLF → LF), not a security fix. The actual code content remains identical; only the line terminators have changed. This is a formatting/consistency update common in version control, not a vulnerability fix. No security vulnerabilities were introduced or remediated in this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_settings_views.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_settings_views.php 2025-12-21 09:36:35.511308688 +0000@@ -1,156 +1,156 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -$avail_views = eh_crm_get_settings( array( 'type' => 'view' ), array( 'slug', 'title', 'settings_id' ) ); -$selected_views = eh_crm_get_settingsmeta( '0', 'selected_views' ); -if ( empty( $selected_views ) ) { - $selected_views = array(); -} -$vscript = eh_crm_get_view_data(); -$options = $vscript['options']; -unset( $vscript['options'] ); -$group_by = $vscript['group']; -unset( $vscript['group'] ); -?> -<div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="ticket_views" style="padding-right:1em !important;"><?php esc_html_e( 'Ticket Views', 'wsdesk' ); ?></label> - <button type="button" id="ticket_view_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add View', 'wsdesk' ); ?></button> - </div> - <div class="panel panel-default crm-panel" style="margin-top: 15px !important;margin-bottom: 0px !important;"> - <div class="panel-body" style="padding: 5px !important;"> - <div class="col-sm-6" style="padding-right: 5px !important;padding-left: 5px !important;"> - <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php esc_html_e( 'Inactive View', 'wsdesk' ); ?></span><br> - <ul class="list-group"> - <?php - if ( ( count( $avail_views ) == count( $selected_views ) ) ) { - echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'No inactive view', 'wsdesk' ) . '</li>'; - } else { - for ( $i = 0;$i < count( $avail_views );$i++ ) { - if ( ! in_array( $avail_views[ $i ]['slug'], $selected_views ) ) { - echo '<li class="list-group-item list-group-item-info" id="' . esc_attr( $avail_views[ $i ]['slug'] ) . '"> ' . esc_html( $avail_views[ $i ]['title'] ) . ' <span class="pull-right">'; - echo '<span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_view_activate" id="' . esc_attr( $avail_views[ $i ]['slug'] ) . '">' . esc_html__( 'Activate', 'wsdesk' ) . '</span> '; - if ( ! in_array( $avail_views[ $i ]['slug'], array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) ) ) { - echo '<span class="glyphicon glyphicon-trash ticket_view_delete_type" id="' . esc_attr( $avail_views[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete View', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - } - if ( ! in_array( $avail_views[ $i ]['slug'], array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) ) ) { - echo '<span class="glyphicon glyphicon-pencil ticket_view_edit_type" id="' . esc_attr( $avail_views[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit View', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - } - echo '</span></li>'; - } - } - } - ?> - </ul> - </div> - <div class="col-sm-6"> - <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php esc_html_e( 'Active View', 'wsdesk' ); ?></span><br> - <ul class="list-group list-group-sortable-connected list-group-view-data list-border-settings"> - <?php - if ( count( $selected_views ) == 0 ) { - echo '<li class="list-group-item list-group-item-success">' . esc_html__( 'No active view', 'wsdesk' ) . '</li>'; - } else { - for ( $i = 0;$i < count( $selected_views );$i++ ) { - for ( $j = 0;$j < count( $avail_views );$j++ ) { - if ( $avail_views[ $j ]['slug'] === $selected_views[ $i ] ) { - echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $avail_views[ $j ]['slug'] ) . '"><span class="dashicons dashicons-menu" style="cursor:move;margin-right:5px;"></span> ' . esc_attr( $avail_views[ $j ]['title'] ) . ' <span class="pull-right">'; - echo '<span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_view_deactivate" id="' . esc_attr( $avail_views[ $j ]['slug'] ) . '">' . esc_html__( 'Deactivate', 'wsdesk' ) . '</span> '; - if ( ! in_array( $avail_views[ $j ]['slug'], array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) ) ) { - echo '<span class="glyphicon glyphicon-trash ticket_view_delete_type" id="' . esc_attr( $avail_views[ $j ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete View', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - } - if ( ! in_array( $avail_views[ $j ]['slug'], array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) ) ) { - echo '<span class="glyphicon glyphicon-pencil ticket_view_edit_type" id="' . esc_attr( $avail_views[ $j ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit View', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - } - echo '</span></li>'; - } - } - } - } - ?> - </ul> - </div> - </div> - </div> - </div> -</div> -<div id="ticket_view_add_display" style="display: none;"> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="ticket_view_add" style="padding-right:1em !important;"><?php esc_html_e( 'Add Ticket View', 'wsdesk' ); ?></label> - <button type="button" id="ticket_view_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - </div> - <span style="vertical-align: middle;" id="ticket_view_add_section"> - <input type="hidden" value="" id="add_new_view_yes"> - <span class="help-block"><?php esc_html_e( 'Enter Details for New View', 'wsdesk' ); ?> </span> - <input type="text" id="ticket_view_add_title" placeholder="Enter Title" class="form-control crm-form-element-input"> - <span class="help-block"><?php esc_html_e( 'Specify the Conditions Format', 'wsdesk' ); ?></span> - <select id="ticket_view_add_format" style="width: 100% !important;display: inline !important" class="form-control ticket_view_add_format clickable" aria-describedby="helpBlock"> - <option value="and"><?php esc_html_e( 'AND Condition', 'wsdesk' ); ?></option> - <option value="or"><?php esc_html_e( 'OR Condition', 'wsdesk' ); ?></option> - </select> - <span class="help-block"><?php esc_html_e( 'Specify the View Conditions', 'wsdesk' ); ?></span> - <div id="conditions_all"> - <div id="conditions_1" class="specify_conditions"> - <span class="condition_title_span"><?php esc_html_e( 'Condition', 'wsdesk' ); ?> 1</span> - <select id="conditions_1_type" title="<?php esc_html_e( 'View condition field', 'wsdesk' ); ?>" style="width: 100% !important;display: inline !important" class="form-control conditions_type clickable" aria-describedby="helpBlock"> - <?php echo wp_kses( $options, array( 'option' => array( 'value' => array() ) ) ); ?> - </select> - <div id="conditions_1_append"></div> - </div> - </div> - <div style="background-color: #ddd;padding: 10px;margin-top: 5px;"> - <u><?php esc_html_e( 'View Condition', 'wsdesk' ); ?></u> : <br> - <span id="ticket_view_formula"></span> - </div> - <button class="button" id="ticket_view_add_conditions_add" title="<?php esc_html_e( 'Add New Condition', 'wsdesk' ); ?>" style="vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Conditions', 'wsdesk' ); ?></button> - <button class="button" id="ticket_view_add_conditions_group_and" title="<?php esc_html_e( 'Group those with AND Condition', 'wsdesk' ); ?>" style="background-color:skyblue; vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-link"></span> <?php esc_html_e( 'Group with AND', 'wsdesk' ); ?></button> - <button class="button" id="ticket_view_add_conditions_group_or" title="<?php esc_html_e( 'Group those with OR Condition', 'wsdesk' ); ?>" style="background-color:darkseagreen;vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-resize-horizontal"></span> <?php esc_html_e( 'Group with OR', 'wsdesk' ); ?></button> - <button class="button" id="ticket_view_add_conditions_group_clear" title="<?php esc_html_e( 'Clear Groups', 'wsdesk' ); ?>" style="background-color:orange;vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Clear Groups', 'wsdesk' ); ?></button> - <span class="help-block"><?php esc_html_e( 'Group tickets by:', 'wsdesk' ); ?></span> - <select id="group_by_view_add" title="<?php esc_html_e( 'View Group By', 'wsdesk' ); ?>" style="width: 100% !important;margin-bottom: 10px;display: inline !important" class="form-control group_by_view_add clickable" aria-describedby="helpBlock"> - <?php echo wp_kses( $group_by, array( 'option' => array( 'value' => array() ) ) ); ?> - </select> - <span class="help-block"><?php esc_html_e( 'Display this view to:', 'wsdesk' ); ?> </span> - <input type="checkbox" style="margin-top: 0;" id="ticket_view_display_control" checked class="form-control" name="ticket_view_display_control" value="administrator"> Administrator - <input type="checkbox" style="margin-top: 0;" id="ticket_view_display_control" class="form-control" name="ticket_view_display_control" value="WSDesk_Agents"> WSDesk Agents - <input type="checkbox" style="margin-top: 0;" id="ticket_view_display_control" class="form-control" name="ticket_view_display_control" value="WSDesk_Supervisor"> WSDesk Supervisors - </span> - <script type="text/javascript"> - var values = <?php echo json_encode( $vscript ); ?>; - jQuery("#ticket_views_tab").on("change",".conditions_type",function(){ - if(jQuery(this).val() !== "") - { - views_condition_maker(values[jQuery(this).val()],jQuery(this).parent().prop("id")); - } - else - { - var parent_id = jQuery(this).parent().prop("id"); - jQuery("#"+parent_id+"_append").empty(); - } - }); - </script> - </div> - </div> -</div> -<div id="ticket_view_edit_display" style="display: none;"> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label style="padding-right:1em !important;"><?php esc_html_e( 'Edit Ticket View', 'wsdesk' ); ?></label> - <button type="button" id="ticket_view_cancel_edit_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - </div> - <input type="hidden" value="" id="ticket_view_edit_type"> - <span style="vertical-align: middle;" id="ticket_view_edit_append"></span> - </div> - </div> -</div> -<div class="crm-form-element"> - <div class="col-md-12"> - <button type="button" id="save_ticket_views" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button> - </div> -</div> +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+$avail_views = eh_crm_get_settings( array( 'type' => 'view' ), array( 'slug', 'title', 'settings_id' ) );+$selected_views = eh_crm_get_settingsmeta( '0', 'selected_views' );+if ( empty( $selected_views ) ) {+ $selected_views = array();+}+$vscript = eh_crm_get_view_data();+$options = $vscript['options'];+unset( $vscript['options'] );+$group_by = $vscript['group'];+unset( $vscript['group'] );+?>+<div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="ticket_views" style="padding-right:1em !important;"><?php esc_html_e( 'Ticket Views', 'wsdesk' ); ?></label>+ <button type="button" id="ticket_view_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add View', 'wsdesk' ); ?></button>+ </div>+ <div class="panel panel-default crm-panel" style="margin-top: 15px !important;margin-bottom: 0px !important;">+ <div class="panel-body" style="padding: 5px !important;">+ <div class="col-sm-6" style="padding-right: 5px !important;padding-left: 5px !important;">+ <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php esc_html_e( 'Inactive View', 'wsdesk' ); ?></span><br>+ <ul class="list-group">+ <?php+ if ( ( count( $avail_views ) == count( $selected_views ) ) ) {+ echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'No inactive view', 'wsdesk' ) . '</li>';+ } else {+ for ( $i = 0;$i < count( $avail_views );$i++ ) {+ if ( ! in_array( $avail_views[ $i ]['slug'], $selected_views ) ) {+ echo '<li class="list-group-item list-group-item-info" id="' . esc_attr( $avail_views[ $i ]['slug'] ) . '"> ' . esc_html( $avail_views[ $i ]['title'] ) . ' <span class="pull-right">';+ echo '<span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_view_activate" id="' . esc_attr( $avail_views[ $i ]['slug'] ) . '">' . esc_html__( 'Activate', 'wsdesk' ) . '</span> ';+ if ( ! in_array( $avail_views[ $i ]['slug'], array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) ) ) {+ echo '<span class="glyphicon glyphicon-trash ticket_view_delete_type" id="' . esc_attr( $avail_views[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete View', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ }+ if ( ! in_array( $avail_views[ $i ]['slug'], array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) ) ) {+ echo '<span class="glyphicon glyphicon-pencil ticket_view_edit_type" id="' . esc_attr( $avail_views[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit View', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ }+ echo '</span></li>';+ }+ }+ }+ ?>+ </ul>+ </div>+ <div class="col-sm-6">+ <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php esc_html_e( 'Active View', 'wsdesk' ); ?></span><br>+ <ul class="list-group list-group-sortable-connected list-group-view-data list-border-settings">+ <?php+ if ( count( $selected_views ) == 0 ) {+ echo '<li class="list-group-item list-group-item-success">' . esc_html__( 'No active view', 'wsdesk' ) . '</li>';+ } else {+ for ( $i = 0;$i < count( $selected_views );$i++ ) {+ for ( $j = 0;$j < count( $avail_views );$j++ ) {+ if ( $avail_views[ $j ]['slug'] === $selected_views[ $i ] ) {+ echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $avail_views[ $j ]['slug'] ) . '"><span class="dashicons dashicons-menu" style="cursor:move;margin-right:5px;"></span> ' . esc_attr( $avail_views[ $j ]['title'] ) . ' <span class="pull-right">';+ echo '<span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_view_deactivate" id="' . esc_attr( $avail_views[ $j ]['slug'] ) . '">' . esc_html__( 'Deactivate', 'wsdesk' ) . '</span> ';+ if ( ! in_array( $avail_views[ $j ]['slug'], array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) ) ) {+ echo '<span class="glyphicon glyphicon-trash ticket_view_delete_type" id="' . esc_attr( $avail_views[ $j ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete View', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ }+ if ( ! in_array( $avail_views[ $j ]['slug'], array( 'labels_view', 'agents_view', 'tags_view', 'users_view' ) ) ) {+ echo '<span class="glyphicon glyphicon-pencil ticket_view_edit_type" id="' . esc_attr( $avail_views[ $j ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit View', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ }+ echo '</span></li>';+ }+ }+ }+ }+ ?>+ </ul>+ </div>+ </div>+ </div>+ </div>+</div>+<div id="ticket_view_add_display" style="display: none;">+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="ticket_view_add" style="padding-right:1em !important;"><?php esc_html_e( 'Add Ticket View', 'wsdesk' ); ?></label>+ <button type="button" id="ticket_view_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button>+ </div>+ <span style="vertical-align: middle;" id="ticket_view_add_section">+ <input type="hidden" value="" id="add_new_view_yes">+ <span class="help-block"><?php esc_html_e( 'Enter Details for New View', 'wsdesk' ); ?> </span>+ <input type="text" id="ticket_view_add_title" placeholder="Enter Title" class="form-control crm-form-element-input">+ <span class="help-block"><?php esc_html_e( 'Specify the Conditions Format', 'wsdesk' ); ?></span>+ <select id="ticket_view_add_format" style="width: 100% !important;display: inline !important" class="form-control ticket_view_add_format clickable" aria-describedby="helpBlock">+ <option value="and"><?php esc_html_e( 'AND Condition', 'wsdesk' ); ?></option>+ <option value="or"><?php esc_html_e( 'OR Condition', 'wsdesk' ); ?></option>+ </select>+ <span class="help-block"><?php esc_html_e( 'Specify the View Conditions', 'wsdesk' ); ?></span>+ <div id="conditions_all">+ <div id="conditions_1" class="specify_conditions">+ <span class="condition_title_span"><?php esc_html_e( 'Condition', 'wsdesk' ); ?> 1</span>+ <select id="conditions_1_type" title="<?php esc_html_e( 'View condition field', 'wsdesk' ); ?>" style="width: 100% !important;display: inline !important" class="form-control conditions_type clickable" aria-describedby="helpBlock">+ <?php echo wp_kses( $options, array( 'option' => array( 'value' => array() ) ) ); ?>+ </select>+ <div id="conditions_1_append"></div>+ </div>+ </div>+ <div style="background-color: #ddd;padding: 10px;margin-top: 5px;">+ <u><?php esc_html_e( 'View Condition', 'wsdesk' ); ?></u> : <br>+ <span id="ticket_view_formula"></span>+ </div>+ <button class="button" id="ticket_view_add_conditions_add" title="<?php esc_html_e( 'Add New Condition', 'wsdesk' ); ?>" style="vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-plus"></span> <?php esc_html_e( 'Add Conditions', 'wsdesk' ); ?></button>+ <button class="button" id="ticket_view_add_conditions_group_and" title="<?php esc_html_e( 'Group those with AND Condition', 'wsdesk' ); ?>" style="background-color:skyblue; vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-link"></span> <?php esc_html_e( 'Group with AND', 'wsdesk' ); ?></button>+ <button class="button" id="ticket_view_add_conditions_group_or" title="<?php esc_html_e( 'Group those with OR Condition', 'wsdesk' ); ?>" style="background-color:darkseagreen;vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-resize-horizontal"></span> <?php esc_html_e( 'Group with OR', 'wsdesk' ); ?></button>+ <button class="button" id="ticket_view_add_conditions_group_clear" title="<?php esc_html_e( 'Clear Groups', 'wsdesk' ); ?>" style="background-color:orange;vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Clear Groups', 'wsdesk' ); ?></button>+ <span class="help-block"><?php esc_html_e( 'Group tickets by:', 'wsdesk' ); ?></span>+ <select id="group_by_view_add" title="<?php esc_html_e( 'View Group By', 'wsdesk' ); ?>" style="width: 100% !important;margin-bottom: 10px;display: inline !important" class="form-control group_by_view_add clickable" aria-describedby="helpBlock">+ <?php echo wp_kses( $group_by, array( 'option' => array( 'value' => array() ) ) ); ?>+ </select>+ <span class="help-block"><?php esc_html_e( 'Display this view to:', 'wsdesk' ); ?> </span>+ <input type="checkbox" style="margin-top: 0;" id="ticket_view_display_control" checked class="form-control" name="ticket_view_display_control" value="administrator"> Administrator+ <input type="checkbox" style="margin-top: 0;" id="ticket_view_display_control" class="form-control" name="ticket_view_display_control" value="WSDesk_Agents"> WSDesk Agents+ <input type="checkbox" style="margin-top: 0;" id="ticket_view_display_control" class="form-control" name="ticket_view_display_control" value="WSDesk_Supervisor"> WSDesk Supervisors+ </span>+ <script type="text/javascript">+ var values = <?php echo json_encode( $vscript ); ?>;+ jQuery("#ticket_views_tab").on("change",".conditions_type",function(){+ if(jQuery(this).val() !== "")+ {+ views_condition_maker(values[jQuery(this).val()],jQuery(this).parent().prop("id"));+ }+ else+ {+ var parent_id = jQuery(this).parent().prop("id");+ jQuery("#"+parent_id+"_append").empty();+ }+ });+ </script>+ </div>+ </div>+</div>+<div id="ticket_view_edit_display" style="display: none;">+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label style="padding-right:1em !important;"><?php esc_html_e( 'Edit Ticket View', 'wsdesk' ); ?></label>+ <button type="button" id="ticket_view_cancel_edit_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Cancel', 'wsdesk' ); ?></button>+ </div>+ <input type="hidden" value="" id="ticket_view_edit_type">+ <span style="vertical-align: middle;" id="ticket_view_edit_append"></span>+ </div>+ </div>+</div>+<div class="crm-form-element">+ <div class="col-md-12">+ <button type="button" id="save_ticket_views" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button>+ </div>+</div>
# Security Analysis Result
## Summary
This diff contains **no security fixes**. The changes are purely formatting-related (line ending conversions from CRLF to LF), with no functional code modifications.
---
## Detailed Analysis
**Vulnerability Existed:** no
**File:** views/settings/crm_settings_views.php [Lines 1-156]
**Old Code:**
```php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// ... (all code with CRLF line endings)
```
**Fixed Code:**
```php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// ... (identical code with LF line endings)
```
**Explanation:**
The diff shows only whitespace/line ending changes. All functional code remains identical between versions 3.3.4 and 3.3.5. No security vulnerabilities were introduced or fixed. The file contains proper output escaping with `esc_html()`, `esc_attr()`, `esc_html__()`, and `wp_kses()` functions throughout, which was already present in the original version.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_woocommerce_settings.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_woocommerce_settings.php 2025-12-21 09:36:35.511308688 +0000@@ -1,77 +1,77 @@-<?php -$woo_order_tickets = eh_crm_get_settingsmeta( '0', 'woo_order_tickets' ); -$woo_order_price = eh_crm_get_settingsmeta( '0', 'woo_order_price' ); -$access = eh_crm_get_settingsmeta( '0', 'woo_order_access' ); -if ( ! $access ) { - $access = array(); -} -// ob_start(); -?> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="woo_order_tickets" style="padding-right:1em !important;"><?php esc_html_e( 'Show Order Details', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Want to display order details in customer ticket?', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <input type="radio" <?php echo ( 'enable' === $woo_order_tickets ) ? 'checked' : ''; ?> style="margin-top: 0;" id="woo_order_tickets" class="form-control" name="woo_order_tickets" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - <input type="radio" <?php echo ( 'disable' === $woo_order_tickets ) ? 'checked' : ''; ?> style="margin-top: 0;" id="woo_order_tickets" class="form-control" name="woo_order_tickets" value="disable"> <?php esc_html_e( 'Disable', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="woo_order_price" style="padding-right:1em !important;"><?php esc_html_e( 'Show Order Price', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Want to display order price along with Order details?', 'wsdesk' ); ?></span> - <span style="vertical-align: middle;"> - <input type="radio" <?php echo ( 'enable' === $woo_order_price ) ? 'checked' : ''; ?> style="margin-top: 0;" id="woo_order_price" class="form-control" name="woo_order_price" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br> - <input type="radio" <?php echo ( 'disable' === $woo_order_price ) ? 'checked' : ''; ?> style="margin-top: 0;" id="woo_order_price" class="form-control" name="woo_order_price" value="disable"> <?php esc_html_e( 'Disable', 'wsdesk' ); ?><br> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="woo_order_access" style="padding-right:1em !important;"><?php esc_html_e( 'Display Order Details', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Display order details only to?', 'wsdesk' ); ?> </span> - <span style="vertical-align: middle;"> - <input type="checkbox" style="margin-top: 0;" id="woo_order_access" class="form-control" name="woo_order_access" value="administrator" <?php echo ( ( in_array( 'administrator', $access ) ) ? 'checked' : '' ); ?> > Administrator<br> - <input type="checkbox" style="margin-top: 0;" id="woo_order_access" class="form-control" name="woo_order_access" value="WSDesk_Agents" <?php echo ( ( in_array( 'WSDesk_Agents', $access ) ) ? 'checked' : '' ); ?>> WSDesk Agents<br> - <input type="checkbox" style="margin-top: 0;" id="woo_order_access" class="form-control" name="woo_order_access" value="WSDesk_Supervisor" <?php echo ( ( in_array( 'WSDesk_Supervisor', $access ) ) ? 'checked' : '' ); ?>> WSDesk Supervisors<br> - </span> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-3"> - <label for="vendor_roles" style="padding-right:1em !important;"><?php esc_html_e( 'Multi-Vendor Roles', 'wsdesk' ); ?></label> - </div> - <div class="col-md-9"> - <span class="help-block"><?php esc_html_e( 'Choose the vendor roles if you have installed any WC Vendor Plugin', 'wsdesk' ); ?></span> - <select multiple id="vendor_roles" style="width: 100% !important;display: inline !important" class="form-control" aria-describedby="helpBlock"> - <?php - $vendor = eh_crm_get_settingsmeta( '0', 'woo_vendor_roles' ) ? eh_crm_get_settingsmeta( '0', 'woo_vendor_roles' ) : array(); - global $wp_roles; - $user_roles = $wp_roles->role_names; - if ( $user_roles ) { - foreach ( $user_roles as $slug => $name ) { - echo '<option value="' . esc_attr( $slug ) . '" ' . ( in_array( $slug, $vendor ) ? 'selected' : '' ) . '>' . esc_html( $name ) . '</option>'; - } - } - ?> - </select> - </div> -</div> -<span class="crm-divider"></span> -<div class="crm-form-element"> - <div class="col-md-12"> - <button type="button" id="save_woocommerce" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button> - </div> -</div> -<?php -// return ob_get_clean(); +<?php+$woo_order_tickets = eh_crm_get_settingsmeta( '0', 'woo_order_tickets' );+$woo_order_price = eh_crm_get_settingsmeta( '0', 'woo_order_price' );+$access = eh_crm_get_settingsmeta( '0', 'woo_order_access' );+if ( ! $access ) {+ $access = array();+}+// ob_start();+?>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="woo_order_tickets" style="padding-right:1em !important;"><?php esc_html_e( 'Show Order Details', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Want to display order details in customer ticket?', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <input type="radio" <?php echo ( 'enable' === $woo_order_tickets ) ? 'checked' : ''; ?> style="margin-top: 0;" id="woo_order_tickets" class="form-control" name="woo_order_tickets" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ <input type="radio" <?php echo ( 'disable' === $woo_order_tickets ) ? 'checked' : ''; ?> style="margin-top: 0;" id="woo_order_tickets" class="form-control" name="woo_order_tickets" value="disable"> <?php esc_html_e( 'Disable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="woo_order_price" style="padding-right:1em !important;"><?php esc_html_e( 'Show Order Price', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Want to display order price along with Order details?', 'wsdesk' ); ?></span>+ <span style="vertical-align: middle;">+ <input type="radio" <?php echo ( 'enable' === $woo_order_price ) ? 'checked' : ''; ?> style="margin-top: 0;" id="woo_order_price" class="form-control" name="woo_order_price" value="enable"> <?php esc_html_e( 'Enable', 'wsdesk' ); ?><br>+ <input type="radio" <?php echo ( 'disable' === $woo_order_price ) ? 'checked' : ''; ?> style="margin-top: 0;" id="woo_order_price" class="form-control" name="woo_order_price" value="disable"> <?php esc_html_e( 'Disable', 'wsdesk' ); ?><br>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="woo_order_access" style="padding-right:1em !important;"><?php esc_html_e( 'Display Order Details', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Display order details only to?', 'wsdesk' ); ?> </span>+ <span style="vertical-align: middle;">+ <input type="checkbox" style="margin-top: 0;" id="woo_order_access" class="form-control" name="woo_order_access" value="administrator" <?php echo ( ( in_array( 'administrator', $access ) ) ? 'checked' : '' ); ?> > Administrator<br>+ <input type="checkbox" style="margin-top: 0;" id="woo_order_access" class="form-control" name="woo_order_access" value="WSDesk_Agents" <?php echo ( ( in_array( 'WSDesk_Agents', $access ) ) ? 'checked' : '' ); ?>> WSDesk Agents<br>+ <input type="checkbox" style="margin-top: 0;" id="woo_order_access" class="form-control" name="woo_order_access" value="WSDesk_Supervisor" <?php echo ( ( in_array( 'WSDesk_Supervisor', $access ) ) ? 'checked' : '' ); ?>> WSDesk Supervisors<br>+ </span>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-3">+ <label for="vendor_roles" style="padding-right:1em !important;"><?php esc_html_e( 'Multi-Vendor Roles', 'wsdesk' ); ?></label>+ </div>+ <div class="col-md-9">+ <span class="help-block"><?php esc_html_e( 'Choose the vendor roles if you have installed any WC Vendor Plugin', 'wsdesk' ); ?></span>+ <select multiple id="vendor_roles" style="width: 100% !important;display: inline !important" class="form-control" aria-describedby="helpBlock">+ <?php + $vendor = eh_crm_get_settingsmeta( '0', 'woo_vendor_roles' ) ? eh_crm_get_settingsmeta( '0', 'woo_vendor_roles' ) : array();+ global $wp_roles;+ $user_roles = $wp_roles->role_names;+ if ( $user_roles ) {+ foreach ( $user_roles as $slug => $name ) {+ echo '<option value="' . esc_attr( $slug ) . '" ' . ( in_array( $slug, $vendor ) ? 'selected' : '' ) . '>' . esc_html( $name ) . '</option>';+ }+ }+ ?>+ </select>+ </div>+</div>+<span class="crm-divider"></span>+<div class="crm-form-element">+ <div class="col-md-12">+ <button type="button" id="save_woocommerce" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Save Changes', 'wsdesk' ); ?></button>+ </div>+</div>+<?php+// return ob_get_clean();
Vulnerability Existed: no No Security Vulnerabilities Detected - views/settings/crm_woocommerce_settings.php Explanation: This diff contains only whitespace/line ending changes (converting from Unix LF to Windows CRLF line endings or vice versa). The actual code content remains identical between versions 3.3.4 and 3.3.5. No new code was added or modified, so no new security fixes or vulnerabilities were introduced. The file itself does contain existing security considerations (such as reliance on WordPress escaping functions like `esc_html()` and `esc_attr()` for output sanitization, and the use of `in_array()` without strict type checking), but these are pre-existing code patterns and not changes made in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/settings/crm_wsdesk_triggers.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/settings/crm_wsdesk_triggers.php 2025-12-21 09:36:35.511308688 +0000@@ -1,233 +1,233 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -$selected_triggers = array(); -$avail_fields = array(); -$avail_triggers = array(); - -if ( wsdesk_is_premium() ) { - $avail_triggers = eh_crm_get_settings( array( 'type' => 'trigger' ), array( 'slug', 'title', 'settings_id' ) ); - $selected_triggers = eh_crm_get_settingsmeta( '0', 'selected_triggers' ); - $avail_fields = eh_crm_get_settings( array( 'type' => 'field' ), array( 'slug', 'title', 'settings_id' ) ); -} - -if ( empty( $selected_triggers ) ) { - $selected_triggers = array(); -} -if ( ! $avail_triggers && empty( $avail_triggers ) ) { - $avail_triggers = array(); -} -$tscript = eh_crm_get_trigger_data(); -$tascript = eh_crm_get_trigger_action_data(); -$toptions = $tscript['options']; -$taoptions = $tascript['options']; -unset( $tscript['options'] ); -unset( $tascript['options'] ); -?> -<div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="ticket_triggers" style="padding-right:1em !important;"><?php echo esc_html_e( 'Triggers & Automations', 'wsdesk' ); ?></label> -<?php if ( wsdesk_is_premium() ) { ?> - <button type="button" id="ticket_trigger_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php echo esc_html__( 'Add Trigger', 'wsdesk' ); ?></button> -<?php } else { ?> - <p style="padding-right:1em !important;color: green">Basic version supports only pre-defined triggers. Adding new triggers and editing new triggers are part of<a class="premium_green_archive" href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/"><b> Premium </b></a><span class="premium_green_archive">Version.</span></p> -<?php } ?> - </div> - <div class="panel panel-default crm-panel" style="margin-top: 15px !important;margin-bottom: 0px !important;"> - <div class="panel-body" style="padding: 5px !important;"> - <div class="col-sm-6" style="padding-right: 5px !important;padding-left: 5px !important;"> - <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php echo esc_html_e( 'Inactive Trigger', 'wsdesk' ); ?></span><br> - <ul class="list-group"> - <?php - if ( ( count( $avail_triggers ) == 0 ) || ( count( $avail_triggers ) == count( $selected_triggers ) ) ) { - echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'No inactive trigger', 'wsdesk' ) . '</li>'; - } else { - for ( $i = 0;$i < count( $avail_triggers );$i++ ) { - if ( ! in_array( $avail_triggers[ $i ]['slug'], $selected_triggers ) ) { - echo '<li class="list-group-item list-group-item-info" id="' . esc_attr( $avail_triggers[ $i ]['slug'] ) . '"> ' . esc_attr( $avail_triggers[ $i ]['title'] ) . ' <span class="pull-right">'; - echo '<span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_trigger_activate" id="' . esc_attr( $avail_triggers[ $i ]['slug'] ) . '">' . esc_html__( 'Activate', 'wsdesk' ) . '</span> '; - echo '<span class="glyphicon glyphicon-trash ticket_trigger_delete_type" id="' . esc_attr( $avail_triggers[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Trigger', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - echo '<span class="glyphicon glyphicon-pencil ticket_trigger_edit_type" id="' . esc_attr( $avail_triggers[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Trigger', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - echo '</span></li>'; - } - } - } - ?> - </ul> - </div> - <div class="col-sm-6"> - <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php echo esc_html_e( 'Active Trigger', 'wsdesk' ); ?></span><br> - <ul class="list-group list-group-sortable-connected list-group-trigger-data list-border-settings"> - <?php - if ( count( $selected_triggers ) == 0 ) { - echo '<li class="list-group-item list-group-item-success">' . esc_html__( 'No active Trigger', 'wsdesk' ) . '</li>'; - } else { - for ( $i = 0;$i < count( $selected_triggers );$i++ ) { - for ( $j = 0;$j < count( $avail_triggers );$j++ ) { - if ( $avail_triggers[ $j ]['slug'] === $selected_triggers[ $i ] ) { - echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $avail_triggers[ $j ]['slug'] ) . '">' . esc_attr( $avail_triggers[ $j ]['title'] ) . ' <span class="pull-right">'; - echo '<span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_trigger_deactivate" id="' . esc_attr( $avail_triggers[ $j ]['slug'] ) . '">' . esc_html__( 'Deactivate', 'wsdesk' ) . '</span> '; - echo '<span class="glyphicon glyphicon-trash ticket_trigger_delete_type" id="' . esc_attr( $avail_triggers[ $j ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Trigger', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - echo '<span class="glyphicon glyphicon-pencil ticket_trigger_edit_type" id="' . esc_attr( $avail_triggers[ $j ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Trigger', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> '; - echo '</span></li>'; - } - } - } - } - ?> - </ul> - </div> - </div> - </div> - </div> -</div> -<div id="ticket_trigger_add_display" style="display: none;"> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="trigger_add" style="padding-right:1em !important;"><?php echo esc_html__( 'Add Trigger', 'wsdesk' ); ?></label> - <button type="button" id="ticket_trigger_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php echo esc_html__( 'Cancel', 'wsdesk' ); ?></button> - </div> - <span style="vertical-align: middle;" id="trigger_add_section"> - <input type="hidden" value="" id="add_new_trigger_yes"> - <span class="help-block"><?php echo esc_html__( 'Enter Details for New Trigger', 'wsdesk' ); ?> </span> - <input type="text" id="trigger_add_title" placeholder="<?php echo esc_html__( 'Enter Title', 'wsdesk' ); ?>" class="form-control crm-form-element-input"> - <span class="crm-divider"></span> - <span><b><?php echo esc_html__( 'Match Triggers Conditions', 'wsdesk' ); ?></b></span> - <span class="crm-divider"></span> - <span class="help-block"><?php echo esc_html__( 'Specify the Conditions Format.', 'wsdesk' ); ?></span> - <select id="trigger_add_format" style="width: 100% !important;display: inline !important" class="form-control trigger_add_format clickable" aria-describedby="helpBlock"> - <option value="and"><?php echo esc_html__( 'AND Condition', 'wsdesk' ); ?></option> - <option value="or"><?php echo esc_html__( 'OR Condition', 'wsdesk' ); ?></option> - </select> - <span class="help-block"><?php echo esc_html__( 'Specify the Trigger Conditions.', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title='<?php esc_html__( '"Changed To" condition works only for immediate schedules.', 'wsdesk' ); ?>' data-container="body"></span></span> - <div id="tconditions_all"> - <div id="tconditions_1" class="specify_tconditions"> - <span class="tcondition_title_span"><?php echo esc_html__( 'Condition', 'wsdesk' ); ?> 1</span> - <select id="tconditions_1_type" title="<?php echo esc_html__( 'Trigger condition field', 'wsdesk' ); ?>" style="width: 100% !important;display: inline !important" class="form-control tconditions_type clickable" aria-describedby="helpBlock"> - <?php - echo wp_kses( - $toptions, - array( - 'option' => array( - 'value' => array(), - 'selected' => array(), - ), - ) - ); - ?> - </select> - <div id="tconditions_1_append"></div> - </div> - </div> - <div style="background-color: #ddd;padding: 10px;margin-top: 5px;"> - <u><?php echo esc_html__( 'Trigger Condition', 'wsdesk' ); ?></u> : <br> - <span id="trigger_formula"></span> - </div> - <button class="button" id="trigger_add_tconditions_add" title="<?php echo esc_html__( 'Add New Condition', 'wsdesk' ); ?>" style="vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-plus"></span> <?php echo esc_html__( 'Add Condition', 'wsdesk' ); ?></button> - <button class="button" id="trigger_add_tconditions_group_and" title="<?php echo esc_html__( 'Group those with AND Condition', 'wsdesk' ); ?>" style="background-color:skyblue; vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-link"></span> <?php echo esc_html__( 'Group with AND', 'wsdesk' ); ?></button> - <button class="button" id="trigger_add_tconditions_group_or" title="<?php echo esc_html__( 'Group those with OR Condition', 'wsdesk' ); ?>" style="background-color:darkseagreen;vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-resize-horizontal"></span> <?php echo esc_html__( 'Group with OR', 'wsdesk' ); ?></button> - <button class="button" id="trigger_add_tconditions_group_clear" title="<?php echo esc_html__( 'Clear Groups', 'wsdesk' ); ?>" style="background-color:orange;vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-remove"></span> <?php echo esc_html__( 'Clear Groups', 'wsdesk' ); ?></button> - <span class="crm-divider"></span> - <span><b><?php echo esc_html__( 'Perform Triggers Actions', 'wsdesk' ); ?></b></span> - <span class="crm-divider"></span> - <span class="help-block"><?php echo esc_html__( 'Specify the Trigger Actions.', 'wsdesk' ); ?></span> - <div id="tactions_all"> - <div id="tactions_1" class="specify_tactions"> - <span class="taction_title_span"><?php echo esc_html__( 'Action', 'wsdesk' ); ?> 1</span> - <select id="tactions_1_type" title="<?php echo esc_html__( 'Trigger Action field', 'wsdesk' ); ?>" style="width: 100% !important;display: inline !important;margin:10px 0px;" class="form-control tactions_type clickable" aria-describedby="helpBlock"> - <?php - echo wp_kses( - $taoptions, - array( - 'option' => array( - 'value' => array(), - 'selected' => array(), - ), - ) - ); - ?> - </select> - <div id="tactions_1_append"></div> - </div> - </div> - <button class="button" id="trigger_add_tactions_add" title="<?php echo esc_html__( 'Add New Action', 'wsdesk' ); ?>" style="vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-plus"></span> <?php echo esc_html__( 'Add Action', 'wsdesk' ); ?></button> - <span class="crm-divider"></span> - <span class="help-block"><?php echo esc_html__( 'Specify the Triggering Period.', 'wsdesk' ); ?></span> - <select id="trigger_add_schedule" style="width: 100% !important;display: inline !important" class="form-control trigger_add_schedule clickable" aria-describedby="helpBlock"> - <option value=""><?php echo esc_html__( 'Immediate Schedule', 'wsdesk' ); ?></option> - <option value="min"><?php echo esc_html__( 'Minute Schedule', 'wsdesk' ); ?></option> - <option value="hour"><?php echo esc_html__( 'Hour Schedule', 'wsdesk' ); ?></option> - <option value="day"><?php echo esc_html__( 'Day Schedule', 'wsdesk' ); ?></option> - <option value="week"><?php echo esc_html__( 'Week Schedule', 'wsdesk' ); ?></option> - <option value="month"><?php echo esc_html__( 'Month Schedule', 'wsdesk' ); ?></option> - <option value="year"><?php echo esc_html__( 'Year Schedule', 'wsdesk' ); ?></option> - </select> - <span id="trigger_schedule_append"></span> - </span> - <script type="text/javascript"> - <?php - $selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' ); - if ( empty( $selected_fields ) ) { - $selected_fields = array(); - } - $print = array(); - foreach ( $avail_fields as $field ) { - if ( 'google_captcha' === $field['slug'] || ! in_array( $field['slug'], $selected_fields ) ) { - continue; - } - $field_type = eh_crm_get_settingsmeta( $field['settings_id'], 'field_type' ); - $print[ '[' . $field['slug'] . ']' ] = ( 'file' === $field_type ) ? __( '(Attachment) ', 'wsdesk' ) : ''; - $print[ '[' . $field['slug'] . ']' ] .= __( 'To insert ', 'wsdesk' ) . ' ' . $field['title'] . ' ' . __( 'field value in the template', 'wsdesk' ); - } - ?> - var shortvalues = <?php echo json_encode( $print ); ?>; - var tvalues = <?php echo json_encode( $tscript ); ?>; - jQuery("#triggers_tab").on("change",".tconditions_type",function(){ - if(jQuery(this).val() !== "") - { - triggers_condition_maker(tvalues[jQuery(this).val()],jQuery(this).parent().prop("id")); - } - else - { - var parent_id = jQuery(this).parent().prop("id"); - jQuery("#"+parent_id+"_append").empty(); - } - }); - var tavalues = <?php echo json_encode( $tascript ); ?>; - jQuery("#triggers_tab").on("change",".tactions_type",function(){ - if(jQuery(this).val() !== "") - { - triggers_action_maker(tavalues[jQuery(this).val()],jQuery(this).parent().prop("id")); - } - else - { - var parent_id = jQuery(this).parent().prop("id"); - jQuery("#"+parent_id+"_append").empty(); - } - }); - </script> - </div> - </div> -</div> -<div id="ticket_trigger_edit_display" style="display: none;"> - <span class="crm-divider"></span> - <div class="crm-form-element"> - <div class="col-md-12"> - <div style="vertical-align: middle"> - <label for="trigger_edit" style="padding-right:1em !important;"><?php echo esc_html_e( 'Edit Trigger', 'wsdesk' ); ?></label> - <button type="button" id="ticket_trigger_cancel_edit_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php echo esc_html_e( 'Cancel', 'wsdesk' ); ?></button> - </div> - <input type="hidden" value="" id="trigger_edit_type"> - <span style="vertical-align: middle;" id="trigger_edit_append"></span> - </div> - </div> -</div> -<div class="crm-form-element"> - <div class="col-md-12"> - <button type="button" id="save_triggers" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php echo esc_html_e( 'Save Changes', 'wsdesk' ); ?></button> - </div> -</div> +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+$selected_triggers = array();+$avail_fields = array();+$avail_triggers = array();++if ( wsdesk_is_premium() ) {+ $avail_triggers = eh_crm_get_settings( array( 'type' => 'trigger' ), array( 'slug', 'title', 'settings_id' ) );+ $selected_triggers = eh_crm_get_settingsmeta( '0', 'selected_triggers' );+ $avail_fields = eh_crm_get_settings( array( 'type' => 'field' ), array( 'slug', 'title', 'settings_id' ) );+}++if ( empty( $selected_triggers ) ) {+ $selected_triggers = array();+}+if ( ! $avail_triggers && empty( $avail_triggers ) ) {+ $avail_triggers = array();+}+$tscript = eh_crm_get_trigger_data();+$tascript = eh_crm_get_trigger_action_data();+$toptions = $tscript['options'];+$taoptions = $tascript['options'];+unset( $tscript['options'] );+unset( $tascript['options'] );+?>+<div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="ticket_triggers" style="padding-right:1em !important;"><?php echo esc_html_e( 'Triggers & Automations', 'wsdesk' ); ?></label>+<?php if ( wsdesk_is_premium() ) { ?>+ <button type="button" id="ticket_trigger_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-plus"></span> <?php echo esc_html__( 'Add Trigger', 'wsdesk' ); ?></button>+<?php } else { ?>+ <p style="padding-right:1em !important;color: green">Basic version supports only pre-defined triggers. Adding new triggers and editing new triggers are part of<a class="premium_green_archive" href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/"><b> Premium </b></a><span class="premium_green_archive">Version.</span></p>+<?php } ?>+ </div>+ <div class="panel panel-default crm-panel" style="margin-top: 15px !important;margin-bottom: 0px !important;">+ <div class="panel-body" style="padding: 5px !important;">+ <div class="col-sm-6" style="padding-right: 5px !important;padding-left: 5px !important;">+ <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php echo esc_html_e( 'Inactive Trigger', 'wsdesk' ); ?></span><br>+ <ul class="list-group">+ <?php+ if ( ( count( $avail_triggers ) == 0 ) || ( count( $avail_triggers ) == count( $selected_triggers ) ) ) {+ echo '<li class="list-group-item list-group-item-info">' . esc_html__( 'No inactive trigger', 'wsdesk' ) . '</li>';+ } else {+ for ( $i = 0;$i < count( $avail_triggers );$i++ ) {+ if ( ! in_array( $avail_triggers[ $i ]['slug'], $selected_triggers ) ) {+ echo '<li class="list-group-item list-group-item-info" id="' . esc_attr( $avail_triggers[ $i ]['slug'] ) . '"> ' . esc_attr( $avail_triggers[ $i ]['title'] ) . ' <span class="pull-right">';+ echo '<span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_trigger_activate" id="' . esc_attr( $avail_triggers[ $i ]['slug'] ) . '">' . esc_html__( 'Activate', 'wsdesk' ) . '</span> ';+ echo '<span class="glyphicon glyphicon-trash ticket_trigger_delete_type" id="' . esc_attr( $avail_triggers[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Trigger', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ echo '<span class="glyphicon glyphicon-pencil ticket_trigger_edit_type" id="' . esc_attr( $avail_triggers[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Trigger', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ echo '</span></li>';+ }+ }+ }+ ?>+ </ul>+ </div>+ <div class="col-sm-6">+ <span class="col-md-12" style="text-align: center;padding: 5px 0px;"><?php echo esc_html_e( 'Active Trigger', 'wsdesk' ); ?></span><br>+ <ul class="list-group list-group-sortable-connected list-group-trigger-data list-border-settings">+ <?php+ if ( count( $selected_triggers ) == 0 ) {+ echo '<li class="list-group-item list-group-item-success">' . esc_html__( 'No active Trigger', 'wsdesk' ) . '</li>';+ } else {+ for ( $i = 0;$i < count( $selected_triggers );$i++ ) {+ for ( $j = 0;$j < count( $avail_triggers );$j++ ) {+ if ( $avail_triggers[ $j ]['slug'] === $selected_triggers[ $i ] ) {+ echo '<li class="list-group-item list-group-item-success" style="padding: 10px 10px !important;" id="' . esc_attr( $avail_triggers[ $j ]['slug'] ) . '">' . esc_attr( $avail_triggers[ $j ]['title'] ) . ' <span class="pull-right">';+ echo '<span style="margin-right:5px; cursor:pointer; text-decoration:underline" class="ticket_trigger_deactivate" id="' . esc_attr( $avail_triggers[ $j ]['slug'] ) . '">' . esc_html__( 'Deactivate', 'wsdesk' ) . '</span> ';+ echo '<span class="glyphicon glyphicon-trash ticket_trigger_delete_type" id="' . esc_attr( $avail_triggers[ $j ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Delete Trigger', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ echo '<span class="glyphicon glyphicon-pencil ticket_trigger_edit_type" id="' . esc_attr( $avail_triggers[ $j ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Trigger', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span> ';+ echo '</span></li>';+ }+ }+ }+ }+ ?>+ </ul>+ </div>+ </div>+ </div>+ </div>+</div>+<div id="ticket_trigger_add_display" style="display: none;">+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="trigger_add" style="padding-right:1em !important;"><?php echo esc_html__( 'Add Trigger', 'wsdesk' ); ?></label>+ <button type="button" id="ticket_trigger_cancel_add_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php echo esc_html__( 'Cancel', 'wsdesk' ); ?></button>+ </div>+ <span style="vertical-align: middle;" id="trigger_add_section">+ <input type="hidden" value="" id="add_new_trigger_yes">+ <span class="help-block"><?php echo esc_html__( 'Enter Details for New Trigger', 'wsdesk' ); ?> </span>+ <input type="text" id="trigger_add_title" placeholder="<?php echo esc_html__( 'Enter Title', 'wsdesk' ); ?>" class="form-control crm-form-element-input">+ <span class="crm-divider"></span>+ <span><b><?php echo esc_html__( 'Match Triggers Conditions', 'wsdesk' ); ?></b></span>+ <span class="crm-divider"></span>+ <span class="help-block"><?php echo esc_html__( 'Specify the Conditions Format.', 'wsdesk' ); ?></span>+ <select id="trigger_add_format" style="width: 100% !important;display: inline !important" class="form-control trigger_add_format clickable" aria-describedby="helpBlock">+ <option value="and"><?php echo esc_html__( 'AND Condition', 'wsdesk' ); ?></option>+ <option value="or"><?php echo esc_html__( 'OR Condition', 'wsdesk' ); ?></option>+ </select>+ <span class="help-block"><?php echo esc_html__( 'Specify the Trigger Conditions.', 'wsdesk' ); ?> <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title='<?php esc_html__( '"Changed To" condition works only for immediate schedules.', 'wsdesk' ); ?>' data-container="body"></span></span>+ <div id="tconditions_all">+ <div id="tconditions_1" class="specify_tconditions">+ <span class="tcondition_title_span"><?php echo esc_html__( 'Condition', 'wsdesk' ); ?> 1</span>+ <select id="tconditions_1_type" title="<?php echo esc_html__( 'Trigger condition field', 'wsdesk' ); ?>" style="width: 100% !important;display: inline !important" class="form-control tconditions_type clickable" aria-describedby="helpBlock">+ <?php+ echo wp_kses(+ $toptions,+ array(+ 'option' => array(+ 'value' => array(),+ 'selected' => array(),+ ),+ )+ );+ ?>+ </select>+ <div id="tconditions_1_append"></div>+ </div>+ </div>+ <div style="background-color: #ddd;padding: 10px;margin-top: 5px;">+ <u><?php echo esc_html__( 'Trigger Condition', 'wsdesk' ); ?></u> : <br>+ <span id="trigger_formula"></span>+ </div>+ <button class="button" id="trigger_add_tconditions_add" title="<?php echo esc_html__( 'Add New Condition', 'wsdesk' ); ?>" style="vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-plus"></span> <?php echo esc_html__( 'Add Condition', 'wsdesk' ); ?></button>+ <button class="button" id="trigger_add_tconditions_group_and" title="<?php echo esc_html__( 'Group those with AND Condition', 'wsdesk' ); ?>" style="background-color:skyblue; vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-link"></span> <?php echo esc_html__( 'Group with AND', 'wsdesk' ); ?></button>+ <button class="button" id="trigger_add_tconditions_group_or" title="<?php echo esc_html__( 'Group those with OR Condition', 'wsdesk' ); ?>" style="background-color:darkseagreen;vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-resize-horizontal"></span> <?php echo esc_html__( 'Group with OR', 'wsdesk' ); ?></button>+ <button class="button" id="trigger_add_tconditions_group_clear" title="<?php echo esc_html__( 'Clear Groups', 'wsdesk' ); ?>" style="background-color:orange;vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-remove"></span> <?php echo esc_html__( 'Clear Groups', 'wsdesk' ); ?></button>+ <span class="crm-divider"></span>+ <span><b><?php echo esc_html__( 'Perform Triggers Actions', 'wsdesk' ); ?></b></span>+ <span class="crm-divider"></span>+ <span class="help-block"><?php echo esc_html__( 'Specify the Trigger Actions.', 'wsdesk' ); ?></span>+ <div id="tactions_all">+ <div id="tactions_1" class="specify_tactions">+ <span class="taction_title_span"><?php echo esc_html__( 'Action', 'wsdesk' ); ?> 1</span>+ <select id="tactions_1_type" title="<?php echo esc_html__( 'Trigger Action field', 'wsdesk' ); ?>" style="width: 100% !important;display: inline !important;margin:10px 0px;" class="form-control tactions_type clickable" aria-describedby="helpBlock">+ <?php+ echo wp_kses(+ $taoptions,+ array(+ 'option' => array(+ 'value' => array(),+ 'selected' => array(),+ ),+ )+ );+ ?>+ </select>+ <div id="tactions_1_append"></div>+ </div>+ </div>+ <button class="button" id="trigger_add_tactions_add" title="<?php echo esc_html__( 'Add New Action', 'wsdesk' ); ?>" style="vertical-align: baseline;margin-bottom: 10px;margin-top: 10px;"><span class="glyphicon glyphicon-plus"></span> <?php echo esc_html__( 'Add Action', 'wsdesk' ); ?></button>+ <span class="crm-divider"></span>+ <span class="help-block"><?php echo esc_html__( 'Specify the Triggering Period.', 'wsdesk' ); ?></span>+ <select id="trigger_add_schedule" style="width: 100% !important;display: inline !important" class="form-control trigger_add_schedule clickable" aria-describedby="helpBlock">+ <option value=""><?php echo esc_html__( 'Immediate Schedule', 'wsdesk' ); ?></option>+ <option value="min"><?php echo esc_html__( 'Minute Schedule', 'wsdesk' ); ?></option>+ <option value="hour"><?php echo esc_html__( 'Hour Schedule', 'wsdesk' ); ?></option>+ <option value="day"><?php echo esc_html__( 'Day Schedule', 'wsdesk' ); ?></option>+ <option value="week"><?php echo esc_html__( 'Week Schedule', 'wsdesk' ); ?></option>+ <option value="month"><?php echo esc_html__( 'Month Schedule', 'wsdesk' ); ?></option>+ <option value="year"><?php echo esc_html__( 'Year Schedule', 'wsdesk' ); ?></option>+ </select>+ <span id="trigger_schedule_append"></span>+ </span>+ <script type="text/javascript">+ <?php+ $selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' );+ if ( empty( $selected_fields ) ) {+ $selected_fields = array();+ }+ $print = array();+ foreach ( $avail_fields as $field ) {+ if ( 'google_captcha' === $field['slug'] || ! in_array( $field['slug'], $selected_fields ) ) {+ continue;+ }+ $field_type = eh_crm_get_settingsmeta( $field['settings_id'], 'field_type' );+ $print[ '[' . $field['slug'] . ']' ] = ( 'file' === $field_type ) ? __( '(Attachment) ', 'wsdesk' ) : '';+ $print[ '[' . $field['slug'] . ']' ] .= __( 'To insert ', 'wsdesk' ) . ' ' . $field['title'] . ' ' . __( 'field value in the template', 'wsdesk' );+ }+ ?>+ var shortvalues = <?php echo json_encode( $print ); ?>;+ var tvalues = <?php echo json_encode( $tscript ); ?>;+ jQuery("#triggers_tab").on("change",".tconditions_type",function(){+ if(jQuery(this).val() !== "")+ {+ triggers_condition_maker(tvalues[jQuery(this).val()],jQuery(this).parent().prop("id"));+ }+ else+ {+ var parent_id = jQuery(this).parent().prop("id");+ jQuery("#"+parent_id+"_append").empty();+ }+ });+ var tavalues = <?php echo json_encode( $tascript ); ?>;+ jQuery("#triggers_tab").on("change",".tactions_type",function(){+ if(jQuery(this).val() !== "")+ {+ triggers_action_maker(tavalues[jQuery(this).val()],jQuery(this).parent().prop("id"));+ }+ else+ {+ var parent_id = jQuery(this).parent().prop("id");+ jQuery("#"+parent_id+"_append").empty();+ }+ });+ </script>+ </div>+ </div>+</div>+<div id="ticket_trigger_edit_display" style="display: none;">+ <span class="crm-divider"></span>+ <div class="crm-form-element">+ <div class="col-md-12">+ <div style="vertical-align: middle">+ <label for="trigger_edit" style="padding-right:1em !important;"><?php echo esc_html_e( 'Edit Trigger', 'wsdesk' ); ?></label>+ <button type="button" id="ticket_trigger_cancel_edit_button" class="btn btn-primary btn-xs pull-right"> <span class="glyphicon glyphicon-remove"></span> <?php echo esc_html_e( 'Cancel', 'wsdesk' ); ?></button>+ </div>+ <input type="hidden" value="" id="trigger_edit_type">+ <span style="vertical-align: middle;" id="trigger_edit_append"></span>+ </div>+ </div>+</div>+<div class="crm-form-element">+ <div class="col-md-12">+ <button type="button" id="save_triggers" class="btn btn-primary btn-sm"> <span class="glyphicon glyphicon-ok"></span> <?php echo esc_html_e( 'Save Changes', 'wsdesk' ); ?></button>+ </div>+</div>
Vulnerability Existed: no No Security Vulnerabilities Detected - CWE N/A - views/settings/crm_wsdesk_triggers.php - All lines Old Code: Lines 1-233 (Unix line endings: LF) Fixed Code: Lines 1-233 (Windows line endings: CRLF) Explanation: This diff shows only line ending changes from Unix (LF) to Windows (CRLF) format across the entire file. No functional code modifications were made, and no security vulnerabilities were introduced or fixed. The file content remains identical in terms of logic and security posture. All existing security practices (use of `esc_html()`, `esc_attr()`, `wp_kses()`, and other WordPress escaping functions) remain unchanged and intact.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/shortcodes/crm_satisfaction_page.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/shortcodes/crm_satisfaction_page.php 2025-12-21 09:36:35.511308688 +0000@@ -1,81 +1,81 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -ob_start(); -$pid = isset( $_GET['id'] ) ? sanitize_text_field( $_GET['id'] ) : ''; -$pauthor = isset( $_GET['wsdesk_author'] ) ? sanitize_text_field( $_GET['wsdesk_author'] ) : ''; -$ticket = eh_crm_get_ticket( array( 'ticket_id' => $pid ) ); -?> -<center> - <div class="satisfaction-div wsdesk_wrapper"> - <?php - if ( $ticket ) { - $gstatus = eh_crm_get_ticketmeta( $ticket[0]['ticket_id'], 'ticket_rating' ); - if ( ! $gstatus ) { - if ( $ticket[0]['ticket_email'] === $pauthor ) { - $ticket_title = eh_crm_wpml_translations( $ticket[0]['ticket_title'], 'ticket_title', 'ticket_title' ); - echo '<h3>' . esc_html__( 'How is our Support?', 'wsdesk' ) . '</h3>'; - echo '<h4><u>Ticket (#' . esc_html( $pid ) . ') : [ ' . esc_html( $ticket_title ) . ' ]</u></h4>'; - ?> - <input type="hidden" id="satisfaction_id" value="<?php echo esc_html( $pid ); ?>"> - <input type="hidden" id="satisfaction_author" value="<?php echo esc_html( $pauthor ); ?>"> - <table class="satisfaction-thumbs"> - <tr> - <td style="width: 50%;text-align: center;"> - <div style="margin-right: 10px;"> - <input id="satisfaction-good" name="satisfaction-thumb" checked type="radio" class="glyphicon with-font with-good glyphicon-thumbs-up" value="good" /> - <label for="satisfaction-good" class="satisfaction-label"><?php esc_html_e( 'Good !', 'wsdesk' ); ?></label> - </div> - </td> - <td style="width: 50%;text-align: center;"> - <div style="margin-left: 10px;"> - <input id="satisfaction-bad" name="satisfaction-thumb" type="radio" class="glyphicon with-font with-bad glyphicon-thumbs-up" value="bad"/> - <label for="satisfaction-bad" class="satisfaction-label"><?php esc_html_e( 'Bad !', 'wsdesk' ); ?></label> - </div> - </td> - </tr> - <tr> - <td colspan="2"> - <textarea rows="5" style="width: 100%" id="satisfaction_comment"></textarea> - </td> - </tr> - <tr> - <td colspan="2" style="text-align: center"> - <button class="btn btn-primary" id="submit_satisfaction" data-loading-text="<?php esc_html_e( 'Submitting...', 'wsdesk' ); ?>"><?php esc_html_e( 'Submit', 'wsdesk' ); ?></button> - </td> - </tr> - </table> - <?php - } else { - ?> - <h1><?php esc_html_e( 'Oops!', 'wsdesk' ); ?></h1><h4><?php esc_html_e( 'Unauthorized Access!', 'wsdesk' ); ?></h4> - <?php - } - } else { - if ( $ticket[0]['ticket_email'] === $pauthor ) { - ?> - <h1><?php esc_html_e( 'Thank you', 'wsdesk' ); ?></h1><p><?php esc_html_e( 'Already took Satisfaction Survey for the ticket', 'wsdesk' ); ?>( #<?php echo esc_html( $pid ); ?> )</p> - <?php - } else { - ?> - <h1><?php esc_html_e( 'Oops!', 'wsdesk' ); ?></h1><h4><?php esc_html_e( 'Unauthorized Access!', 'wsdesk' ); ?></h4> - <?php - } - } - } else { - ?> - <h1><?php esc_html_e( 'Oops!', 'wsdesk' ); ?></h1><h4><?php esc_html_e( 'Access Denied!', 'wsdesk' ); ?></h4> - <?php - } - ?> - <br> - <?php - if ( ! defined( 'WSDESK_POWERED_SUPPORT' ) ) { - echo '<div class="powered_wsdesk"><span>' . esc_html__( 'Powered by', 'wsdesk' ) . '</span> <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" rel="nofollow">WSDesk</a></div>'; - } - ?> - </div> -</center> -<?php -return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+ob_start();+$pid = isset( $_GET['id'] ) ? sanitize_text_field( $_GET['id'] ) : '';+$pauthor = isset( $_GET['wsdesk_author'] ) ? sanitize_text_field( $_GET['wsdesk_author'] ) : '';+$ticket = eh_crm_get_ticket( array( 'ticket_id' => $pid ) );+?>+<center>+ <div class="satisfaction-div wsdesk_wrapper">+ <?php+ if ( $ticket ) {+ $gstatus = eh_crm_get_ticketmeta( $ticket[0]['ticket_id'], 'ticket_rating' );+ if ( ! $gstatus ) {+ if ( $ticket[0]['ticket_email'] === $pauthor ) {+ $ticket_title = eh_crm_wpml_translations( $ticket[0]['ticket_title'], 'ticket_title', 'ticket_title' );+ echo '<h3>' . esc_html__( 'How is our Support?', 'wsdesk' ) . '</h3>';+ echo '<h4><u>Ticket (#' . esc_html( $pid ) . ') : [ ' . esc_html( $ticket_title ) . ' ]</u></h4>';+ ?>+ <input type="hidden" id="satisfaction_id" value="<?php echo esc_html( $pid ); ?>">+ <input type="hidden" id="satisfaction_author" value="<?php echo esc_html( $pauthor ); ?>">+ <table class="satisfaction-thumbs">+ <tr>+ <td style="width: 50%;text-align: center;">+ <div style="margin-right: 10px;">+ <input id="satisfaction-good" name="satisfaction-thumb" checked type="radio" class="glyphicon with-font with-good glyphicon-thumbs-up" value="good" />+ <label for="satisfaction-good" class="satisfaction-label"><?php esc_html_e( 'Good !', 'wsdesk' ); ?></label>+ </div>+ </td>+ <td style="width: 50%;text-align: center;">+ <div style="margin-left: 10px;">+ <input id="satisfaction-bad" name="satisfaction-thumb" type="radio" class="glyphicon with-font with-bad glyphicon-thumbs-up" value="bad"/>+ <label for="satisfaction-bad" class="satisfaction-label"><?php esc_html_e( 'Bad !', 'wsdesk' ); ?></label>+ </div>+ </td>+ </tr>+ <tr>+ <td colspan="2">+ <textarea rows="5" style="width: 100%" id="satisfaction_comment"></textarea>+ </td>+ </tr>+ <tr>+ <td colspan="2" style="text-align: center">+ <button class="btn btn-primary" id="submit_satisfaction" data-loading-text="<?php esc_html_e( 'Submitting...', 'wsdesk' ); ?>"><?php esc_html_e( 'Submit', 'wsdesk' ); ?></button>+ </td>+ </tr>+ </table>+ <?php+ } else {+ ?>+ <h1><?php esc_html_e( 'Oops!', 'wsdesk' ); ?></h1><h4><?php esc_html_e( 'Unauthorized Access!', 'wsdesk' ); ?></h4>+ <?php+ }+ } else {+ if ( $ticket[0]['ticket_email'] === $pauthor ) {+ ?>+ <h1><?php esc_html_e( 'Thank you', 'wsdesk' ); ?></h1><p><?php esc_html_e( 'Already took Satisfaction Survey for the ticket', 'wsdesk' ); ?>( #<?php echo esc_html( $pid ); ?> )</p>+ <?php+ } else {+ ?>+ <h1><?php esc_html_e( 'Oops!', 'wsdesk' ); ?></h1><h4><?php esc_html_e( 'Unauthorized Access!', 'wsdesk' ); ?></h4>+ <?php+ }+ }+ } else {+ ?>+ <h1><?php esc_html_e( 'Oops!', 'wsdesk' ); ?></h1><h4><?php esc_html_e( 'Access Denied!', 'wsdesk' ); ?></h4>+ <?php+ }+ ?>+ <br>+ <?php+ if ( ! defined( 'WSDESK_POWERED_SUPPORT' ) ) {+ echo '<div class="powered_wsdesk"><span>' . esc_html__( 'Powered by', 'wsdesk' ) . '</span> <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" rel="nofollow">WSDesk</a></div>';+ }+ ?>+ </div>+</center>+<?php+return ob_get_clean();
Vulnerability Existed: no No Security Vulnerabilities Found - File Encoding Change Only Explanation: This diff shows only a line ending change (CRLF to LF conversion) with no actual code modifications. The file content remains identical across all 81 lines. No security fixes, vulnerabilities, or code logic changes are present. All existing security measures remain unchanged: - Input sanitization via `sanitize_text_field()` is maintained for `$_GET['id']` and `$_GET['wsdesk_author']` - Output escaping via `esc_html()` and `esc_html_e()` is consistent throughout - Authorization check comparing `$ticket[0]['ticket_email']` with `$pauthor` is preserved - The file structure and security controls are identical between versions 3.3.4 and 3.3.5 This appears to be a formatting/normalization update rather than a security patch.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/shortcodes/crm_support_check_request.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/shortcodes/crm_support_check_request.php 2025-12-21 09:36:35.511308688 +0000@@ -1,63 +1,63 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -ob_start(); -$selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' ); -$select_val = array(); -if ( is_array( $selected_fields ) ) { - if ( isset( $cus_fields ) && ! empty( $cus_fields ) && is_array( $cus_fields ) ) { - $select_val = array_intersect( $selected_fields, $cus_fields ); - } -} -$etitle = eh_crm_get_settingsmeta( 0, 'existing_ticket_title' ); -$etitle = eh_crm_wpml_translations( $etitle, 'title', 'title' ); -$submit = eh_crm_get_settingsmeta( 0, 'submit_ticket_button' ); -if ( ! $submit ) { - $submit = __( 'Submit Request', 'wsdesk' ); -} -$submit = eh_crm_wpml_translations( $submit, 'submit', 'submit' ); -$etitle = empty( $etitle ) ? "<h3>$etitle</h3>" : ''; -if ( empty( $cus_fields ) ) { - echo esc_html( $etitle ); - ?> -<div class="wsdesk_wrapper"> - <div class="eh_crm_support_main load_wsdesk_request_directly"> - <input type= "hidden" id="custom_fields" value ="<?php echo esc_html( json_encode( $select_val ) ); ?>"/> - <div class="support_option_choose"> - <button data-loading-text="<?php esc_html_e( 'Fetching Request Form...', 'wsdesk' ); ?>" class="btn btn-primary eh_crm_new_request eh_crm_new_request_check_request_page" onclick="jQuery('#check_request_powered_wsdesk').hide();"> - <?php echo esc_html( $submit ); ?> - </button> - <br> - <br> - </div> - - </div> - <div class="loaderDirect"></div> - <!--<div class="eh_crm_support_main l">--> -</div> - <?php - if ( ! defined( 'WSDESK_POWERED_SUPPORT' ) ) { - echo '<div id="check_request_powered_wsdesk" class="powered_wsdesk"><span>' . esc_html__( 'Powered by', 'wsdesk' ) . '</span> <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" rel="nofollow">WSDesk</a></div>'; - } -} -?> -<?php if ( isset( $cus_fields ) && ! empty( $cus_fields ) && is_array( $cus_fields ) ) { ?> -<div class="wsdesk_wrapper"> - <div class="eh_crm_support_main load_wsdesk_request_directly"> - <input type= "hidden" id="custom_fields" value ="<?php echo esc_html( json_encode( $select_val ) ); ?>"/> - <div class="support_option_choose"> - <?php echo esc_html( $etitle ); ?> - <button data-loading-text="<?php esc_html_e( 'Fetching Request Form...', 'wsdesk' ); ?>" class="btn btn-primary eh_crm_new_request" onclick="jQuery('#check_request_powered_wsdesk').hide();"> - <?php echo esc_html( $submit ); ?> - </button> - <br> - <br> - </div> - - </div> - <div class="loaderDirect"></div> -</div> -<?php } -return ob_get_clean(); -?> +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+ob_start();+$selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' );+$select_val = array();+if ( is_array( $selected_fields ) ) {+ if ( isset( $cus_fields ) && ! empty( $cus_fields ) && is_array( $cus_fields ) ) {+ $select_val = array_intersect( $selected_fields, $cus_fields );+ }+} +$etitle = eh_crm_get_settingsmeta( 0, 'existing_ticket_title' );+$etitle = eh_crm_wpml_translations( $etitle, 'title', 'title' );+$submit = eh_crm_get_settingsmeta( 0, 'submit_ticket_button' );+if ( ! $submit ) {+ $submit = __( 'Submit Request', 'wsdesk' );+}+$submit = eh_crm_wpml_translations( $submit, 'submit', 'submit' );+$etitle = empty( $etitle ) ? "<h3>$etitle</h3>" : '';+if ( empty( $cus_fields ) ) {+ echo esc_html( $etitle );+ ?>+<div class="wsdesk_wrapper">+ <div class="eh_crm_support_main load_wsdesk_request_directly">+ <input type= "hidden" id="custom_fields" value ="<?php echo esc_html( json_encode( $select_val ) ); ?>"/>+ <div class="support_option_choose"> + <button data-loading-text="<?php esc_html_e( 'Fetching Request Form...', 'wsdesk' ); ?>" class="btn btn-primary eh_crm_new_request eh_crm_new_request_check_request_page" onclick="jQuery('#check_request_powered_wsdesk').hide();">+ <?php echo esc_html( $submit ); ?>+ </button>+ <br>+ <br>+ </div>+ + </div>+ <div class="loaderDirect"></div>+ <!--<div class="eh_crm_support_main l">-->+</div>+ <?php+ if ( ! defined( 'WSDESK_POWERED_SUPPORT' ) ) {+ echo '<div id="check_request_powered_wsdesk" class="powered_wsdesk"><span>' . esc_html__( 'Powered by', 'wsdesk' ) . '</span> <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" rel="nofollow">WSDesk</a></div>';+ }+}+?>+<?php if ( isset( $cus_fields ) && ! empty( $cus_fields ) && is_array( $cus_fields ) ) { ?>+<div class="wsdesk_wrapper">+ <div class="eh_crm_support_main load_wsdesk_request_directly">+ <input type= "hidden" id="custom_fields" value ="<?php echo esc_html( json_encode( $select_val ) ); ?>"/>+ <div class="support_option_choose">+ <?php echo esc_html( $etitle ); ?>+ <button data-loading-text="<?php esc_html_e( 'Fetching Request Form...', 'wsdesk' ); ?>" class="btn btn-primary eh_crm_new_request" onclick="jQuery('#check_request_powered_wsdesk').hide();">+ <?php echo esc_html( $submit ); ?>+ </button>+ <br>+ <br>+ </div>+ + </div>+ <div class="loaderDirect"></div>+</div>+<?php }+return ob_get_clean();+?>
Based on my analysis of the provided diff, this appears to be a line-ending normalization (CRLF to LF conversion) with no actual code changes. Here is my security analysis:
---
**Vulnerability Existed: no**
**No Vulnerabilities Detected - Line Ending Change Only**
**Old Code:**
```php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
...
return ob_get_clean();
?>
```
**Fixed Code:**
```php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
...
return ob_get_clean();
?>
```
**Explanation:**
The diff shows only whitespace/line-ending changes (conversion from Windows CRLF to Unix LF line endings). The actual code logic remains identical between versions 3.3.4 and 3.3.5. No security fixes or vulnerability remediations are present in this diff. The code continues to:
- Use `esc_html()` for escaping HTML output
- Use `esc_html_e()` for escaped translation output
- Properly validate arrays with `is_array()` checks
- Use `json_encode()` safely within escaped contexts
There are no new security vulnerabilities introduced, and no existing vulnerabilities have been addressed in this update.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/shortcodes/crm_support_form_Support_Request_table.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/shortcodes/crm_support_form_Support_Request_table.php 2025-12-21 09:36:35.511308688 +0000@@ -1,56 +1,56 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -ob_start(); -$etitle = eh_crm_get_settingsmeta( 0, 'main_ticket_form_title' ); -$etitle = eh_crm_wpml_translations( $etitle, 'title', 'title' ); -$selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' ); -$select_val = array(); -if ( is_array( $selected_fields ) ) { - if ( isset( $cus_fields ) && ! empty( $cus_fields ) && is_array( $cus_fields ) ) { - $select_val = array_intersect( $selected_fields, $cus_fields ); - } -} -$ticket_id = ''; -if ( isset( $_GET['customer_ticket_num'] ) ) { - $ticket_id = sanitize_text_field( $_GET['customer_ticket_num'] ); -} elseif ( ! empty( $_GET ) ) { - foreach ( $_GET as $query_id => $query_value ) { - if ( strpos( $query_value, 'customer_ticket_num' ) != '' ) { - $ticket_id = explode( 'customer_ticket_num=', $query_value )[1]; - break; - } - } -} -if ( $ticket_id && is_user_logged_in() ) { - $ticket = eh_crm_get_ticket( array( 'ticket_id' => $ticket_id ), array( 'ticket_author', 'ticket_email' ) ); - $wcurrent_user = wp_get_current_user(); - if ( $ticket[0]['ticket_email'] == $wcurrent_user->user_email || $ticket[0]['ticket_author'] == $wcurrent_user->ID ) { - echo'<div class="eh_crm_support_main wsdesk_wrapper"> - <div class="loaderDirect"></div> - <div class="eh_crm_support_main load_wsdesk_request_ticket_directly"> - <div class="ticket_table_wrapper"> - <div class="ticket_load_content"></div> - </div> - </div> - </div>'; - } -} else { - ?> -<div class="eh_crm_support_main wsdesk_wrapper"> - <input type= "hidden" id="custom_fields" value ="<?php echo esc_html( json_encode( $select_val ) ); ?>"/> - <?php echo ( '' !== $etitle ) ? '<h3>' . esc_html( $etitle ) . '</h3>' : ''; ?> - <div class="wsdesk_wrapper"> - <div class="loaderDirect"></div> - <div class="eh_crm_support_main load_wsdesk_request_directly wsdesk_new_ticket_view"> - <div class="ticket_table_wrapper"></div> - </div> - </div> -</div> - <?php -} -if ( ! defined( 'WSDESK_POWERED_SUPPORT' ) ) { - echo '<div id="check_request_powered_wsdesk" class="powered_wsdesk"><span>' . esc_html__( 'Powered by', 'wsdesk' ) . '</span> <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" rel="nofollow">WSDesk</a></div>'; -} -return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+ob_start();+$etitle = eh_crm_get_settingsmeta( 0, 'main_ticket_form_title' );+$etitle = eh_crm_wpml_translations( $etitle, 'title', 'title' );+$selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' );+$select_val = array();+if ( is_array( $selected_fields ) ) {+ if ( isset( $cus_fields ) && ! empty( $cus_fields ) && is_array( $cus_fields ) ) {+ $select_val = array_intersect( $selected_fields, $cus_fields );+ }+}+$ticket_id = '';+if ( isset( $_GET['customer_ticket_num'] ) ) {+ $ticket_id = sanitize_text_field( $_GET['customer_ticket_num'] );+} elseif ( ! empty( $_GET ) ) {+ foreach ( $_GET as $query_id => $query_value ) {+ if ( strpos( $query_value, 'customer_ticket_num' ) != '' ) {+ $ticket_id = explode( 'customer_ticket_num=', $query_value )[1];+ break;+ }+ }+}+if ( $ticket_id && is_user_logged_in() ) {+ $ticket = eh_crm_get_ticket( array( 'ticket_id' => $ticket_id ), array( 'ticket_author', 'ticket_email' ) );+ $wcurrent_user = wp_get_current_user();+ if ( $ticket[0]['ticket_email'] == $wcurrent_user->user_email || $ticket[0]['ticket_author'] == $wcurrent_user->ID ) {+ echo'<div class="eh_crm_support_main wsdesk_wrapper"> + <div class="loaderDirect"></div>+ <div class="eh_crm_support_main load_wsdesk_request_ticket_directly">+ <div class="ticket_table_wrapper">+ <div class="ticket_load_content"></div>+ </div>+ </div>+ </div>';+ }+} else {+ ?>+<div class="eh_crm_support_main wsdesk_wrapper">+ <input type= "hidden" id="custom_fields" value ="<?php echo esc_html( json_encode( $select_val ) ); ?>"/>+ <?php echo ( '' !== $etitle ) ? '<h3>' . esc_html( $etitle ) . '</h3>' : ''; ?>+ <div class="wsdesk_wrapper"> + <div class="loaderDirect"></div>+ <div class="eh_crm_support_main load_wsdesk_request_directly wsdesk_new_ticket_view">+ <div class="ticket_table_wrapper"></div>+ </div>+ </div>+</div>+ <?php+}+if ( ! defined( 'WSDESK_POWERED_SUPPORT' ) ) {+ echo '<div id="check_request_powered_wsdesk" class="powered_wsdesk"><span>' . esc_html__( 'Powered by', 'wsdesk' ) . '</span> <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" rel="nofollow">WSDesk</a></div>';+}+return ob_get_clean();
Vulnerability Existed: no Explanation: This diff contains only whitespace changes (line ending conversion from CRLF to LF), with no actual code modifications. The security characteristics of the code remain identical between versions 3.3.4 and 3.3.5. While the underlying code does contain potential security issues (such as the unsanitized `$ticket_id` extraction from `$_GET` via string parsing on lines 21-24, and missing nonce verification for ticket access), these issues existed in both versions and were not fixed by this update. The diff itself introduces no new security fixes or vulnerabilities.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/shortcodes/crm_support_new.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/shortcodes/crm_support_new.php 2025-12-21 09:36:35.511308688 +0000@@ -1,356 +1,356 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -ob_start(); -if ( isset( $display ) && ( 'form' === $display || 'form_only' === $display ) ) { - echo '<div class="eh_crm_support_main wsdesk_wrapper">'; -} -$raiser_default = eh_crm_get_settingsmeta( 0, 'ticket_raiser' ); -$login_redirect_url = eh_crm_get_settingsmeta( 0, 'login_redirect_url' ); -$logout_redirect_url = eh_crm_get_settingsmeta( 0, 'logout_redirect_url' ); -$register_redirect_url = eh_crm_get_settingsmeta( 0, 'register_redirect_url' ); -$login_url = eh_crm_get_settingsmeta( '0', 'login_url' ); -$reg_url = eh_crm_get_settingsmeta( '0', 'reg_url' ); - -if ( is_user_logged_in() ) { - $purchase_credit_redirect_url = eh_crm_get_settingsmeta( '0', 'purchase_credit_redirect_url' ); - $set_credit_limit = eh_crm_get_settingsmeta( '0', 'set_credit_limit' ); - if ( ! $set_credit_limit ) { - $set_credit_limit = 0; - } - if ( EH_CRM_PAY_FOR_SUPPORT_STATUS ) { - $user_id = 'wsdesk_subscription_method' . get_current_user_id(); - $user_pay_for_support_data = get_option( strval( $user_id ) ); - $main_score = get_user_meta( Parent_Child_Accounts::has_parent( get_current_user_id() ), Pfs_metakey_constants::MAIN_SCORE, true ); - if ( false == $main_score || null == $main_score || '' == $main_score ) { - $main_score = 0; - } - if ( $main_score < $set_credit_limit ) { - echo '<div class="form-elements"><span>' . esc_html__( 'You do not have enough credits to raise a ticket.', 'wsdesk' ) . '</span><br><a class="btn btn-primary" href="' . esc_url( $purchase_credit_redirect_url ) . '">' . esc_html__( 'Purchase Credits', 'wsdesk' ) . '</a></div>'; - return ob_get_clean(); - } - } -} - -if ( $register_redirect_url ) { - $register_redirect_url = 'redirect_to=' . urlencode( $register_redirect_url ); -} -if ( $login_redirect_url ) { - $login_redirect_url = 'redirect_to=' . urlencode( $login_redirect_url ); -} -if ( 'registered' == $raiser_default ) { - if ( ! is_user_logged_in() ) { - $login_url = eh_crm_append_query_string_to_url( $login_url ? $login_url : wp_login_url(), $login_redirect_url ); - $reg_url = eh_crm_append_query_string_to_url( $reg_url ? $reg_url : wp_registration_url(), $register_redirect_url ); - - echo '<div class="form-elements log-in"><span>' . esc_html( get_existing_ticket_login_label() ) . '</span><br><a class="btn btn-primary" href="' . esc_url( $login_url ) . '">' . esc_html__( 'Login', 'wsdesk' ) . '</a></div>'; - echo '<div class="form-elements sign-up"><span>' . esc_html( get_existing_ticket_register_label() ) . '</span><br><a class="btn btn-primary" href="' . esc_url( $reg_url ) . '">' . esc_html__( 'Register', 'wsdesk' ) . '</a></div>'; - return ob_get_clean(); - } -} elseif ( 'guest' == $raiser_default -) { - if ( is_user_logged_in() ) { - echo '<div class="form-elements"><span>' . esc_html__( 'You must Logout to Raise Ticket', 'wsdesk' ) . '</span><br><a class="btn btn-primary" href="' . esc_url( wp_logout_url() ) . '">' . esc_html__( 'Logout', 'wsdesk' ) . '</a></div>'; - return ob_get_clean(); - } -} -$args = array( 'type' => 'field' ); -$fields = array( 'slug', 'title', 'settings_id' ); -$avail_fields = eh_crm_get_settings( $args, $fields ); -$selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' ); - -if ( empty( $selected_fields ) ) { - $selected_fields = array( 'request_email', 'request_title', 'request_description' ); -} -if ( isset( $cus_fields ) && ! empty( $cus_fields ) && is_array( $cus_fields ) ) { - $select_val = array(); - foreach ( $cus_fields as $value ) { - if ( in_array( $value, $selected_fields ) ) { - array_push( $select_val, $value ); - } - } - $selected_fields = $select_val; -} -if ( ! in_array( 'request_description', $selected_fields ) ) { - array_unshift( $selected_fields, 'request_description' ); -} -if ( ! in_array( 'request_title', $selected_fields ) ) { - array_unshift( $selected_fields, 'request_title' ); -} -if ( ! in_array( 'request_email', $selected_fields ) ) { - array_unshift( $selected_fields, 'request_email' ); -} -$input_width = eh_crm_get_settingsmeta( 0, 'input_width' ); -$utitle = eh_crm_get_settingsmeta( 0, 'new_ticket_form_title' ); - -$utitle = eh_crm_wpml_translations( $utitle, 'title', 'title' ); - -$submit = eh_crm_get_settingsmeta( 0, 'submit_ticket_button' ); - -if ( ! $submit ) { - $submit = __( 'Submit Request', 'wsdesk' ); -} - -$submit = eh_crm_wpml_translations( $submit, 'submit', 'submit' ); - -$reset = eh_crm_get_settingsmeta( 0, 'reset_ticket_button' ); - -if ( ! $reset ) { - $reset = __( 'Reset Request', 'wsdesk' ); -} - -$reset = eh_crm_wpml_translations( $reset, 'reset', 'reset' ); - -$existing = eh_crm_get_settingsmeta( 0, 'existing_ticket_button' ); -if ( ! $existing ) { - $existing = __( 'Check your Existing Request', 'wsdesk' ); -} - -$existing = eh_crm_wpml_translations( $existing, 'existing', 'existing' ); -if ( isset( $display ) && ( 'form' === $display ) ) { - echo ' - <div class="support_option_choose"> - <a href="' . esc_url( eh_get_url_by_shortcode( '[wsdesk_support display="check_request"' ) ) . '" target="_blank" data-loading-text="' . esc_html__( 'Loading your Request...', 'wsdesk' ) . '" class="btn btn-primary eh_crm_check_request" role="button"> - ' . esc_html( $existing ) . ' - </a> - </div>'; -} -echo '<div class="main_new_suppot_request_form">'; -echo '<style> - .support_form - { - width: ' . esc_html( $input_width ) . '% !important; - } - </style> <form class="support_form" id="eh_crm_ticket_form">'; -echo ( '' !== $utitle ) ? '<h3>' . esc_html( $utitle ) . '</h3>' : ''; -$urole = ''; -if ( is_user_logged_in() ) { - if ( isset( wp_get_current_user()->roles ) ) { - $wwp_roles = array( 'administrator', 'WSDesk_Agents', 'WSDesk_Supervisor' ); - foreach ( $wwp_roles as $wp_role ) { - - $urole_index = array_search( $wp_role, wp_get_current_user()->roles ); - if ( $urole_index ) { - $urole = wp_get_current_user()->roles[ $urole_index ]; - break; - } - } - } -} -for ( $i = 0; $i < count( $selected_fields ); $i++ ) { - for ( $j = 0; $j < count( $avail_fields ); $j++ ) { - $current_meta = eh_crm_get_settingsmeta( $avail_fields[ $j ]['settings_id'] ); - if ( $avail_fields[ $j ]['slug'] === $selected_fields[ $i ] && ( ! isset( $current_meta['field_visible'] ) || 'yes' === $current_meta['field_visible'] || 'ip' == $current_meta['field_type'] || in_array( $avail_fields[ $j ]['slug'], array( 'request_email', 'request_title', 'request_description' ) ) ) ) { - echo '<div class="form-elements">'; - if ( 'WSDesk_Agents' == $urole ) { - $required = ( isset( $current_meta['field_require_agent'] ) ? $current_meta['field_require_agent'] : '' ); - } elseif ( 'WSDesk_Supervisor' == $urole || 'administrator' == $urole ) { - $required = 'no'; - } else { - $required = ( isset( $current_meta['field_require'] ) ? $current_meta['field_require'] : '' ); - } - - $required = ( 'yes' === $required || in_array( $avail_fields[ $j ]['slug'], array( 'request_email', 'request_title', 'request_description' ) ) ) ? 'required' : ''; - if ( 'ip' == $current_meta['field_type'] ) { - echo '<input type="hidden" value="' . esc_html( isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : null ) . '" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" class="input_element form-control">'; - } else { - $field_title = eh_crm_wpml_translations( $avail_fields[ $j ]['title'], $avail_fields[ $j ]['settings_id'] . '_field_title', $avail_fields[ $j ]['settings_id'] . '_field_title' ); - if ( 'woo_order_id' == $selected_fields[ $i ] ) { - if ( is_user_logged_in() ) { - echo '<span>' . esc_html( $field_title ) . ' </span>'; - } else { - $required = ''; - } - } else { - echo '<span>' . esc_html( $field_title ) . ' </span>'; - } - } - echo ( 'required' === $required ) ? '<span class="input_required">*</span>' : ' <br>'; - $default_values = ( isset( $current_meta['field_default'] ) ? $current_meta['field_default'] : '' ); - switch ( $current_meta['field_type'] ) { - case 'text': - $default_values = eh_crm_wpml_translations( $default_values, $avail_fields[ $j ]['settings_id'] . '_field_default', $avail_fields[ $j ]['settings_id'] . '_field_default' ); - - $field_placeholder = eh_crm_wpml_translations( $current_meta['field_placeholder'], $avail_fields[ $j ]['settings_id'] . '_field_placeholder', $avail_fields[ $j ]['settings_id'] . '_field_placeholder' ); - echo '<input type="text" autocomplete="off" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $field_placeholder ) . '" ' . esc_html( $required ) . '>'; - break; - case 'email': - $email = ''; - if ( is_user_logged_in() && 'request_email' == $avail_fields[ $j ]['slug'] ) { - $uid = get_current_user_id(); - $user = new WP_User( $uid ); - $default_values = $user->user_email; - } - $field_placeholder = eh_crm_wpml_translations( $current_meta['field_placeholder'], $avail_fields[ $j ]['settings_id'] . '_field_placeholder', $avail_fields[ $j ]['settings_id'] . '_field_placeholder' ); - echo '<input type="email" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $field_placeholder ) . '"' . esc_html( $required ) . '>'; - break; - case 'phone': - echo '<br><span><strong>+</strong><input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $current_meta )['field_placeholder'] . '"' . esc_html( $required ) . ' style="display: inline; width: 99% !important"></span>'; - break; - case 'number': - echo '<input type="number" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $current_meta['field_placeholder'] ) . '"' . esc_html( $required ) . '>'; - break; - case 'password': - echo '<input type="password" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $current_meta['field_placeholder'] ) . '"' . esc_html( $required ) . '>'; - break; - case 'select': - $field_values = $current_meta['field_values']; - $customer_temp_altered = array(); - $return = array(); - if ( 'woo_order_id' == $selected_fields[ $i ] ) { - $uid = get_current_user_id(); - if ( 0 != $uid ) { - $customer_orders = wc_get_orders( array( 'customer_id' => $uid ) ); - if ( count( $customer_orders ) > 0 ) { - foreach ( $customer_orders as $key => $customer_order ) { - array_push( $customer_temp_altered, trim( str_replace( ' ', '', $customer_order->get_order_number() ) ) ); - } - for ( $g = 0;$g < count( $customer_temp_altered );$g++ ) { - $return[ $g ] = $customer_temp_altered[ $g ]; - } - echo '<select class="input_element form-control" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" ' . esc_html( $required ) . '>'; - echo '<option value="">' . ( isset( $current_meta['field_placeholder'] ) ? esc_html( $current_meta['field_placeholder'] ) : '-' ) . '</option>'; - foreach ( $return as $key => $val ) { - $select_default = ''; - if ( $default_values === $val ) { - $select_default = 'selected'; - } - $field_values_tranlsated = eh_crm_wpml_translations( $val, $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' ); - echo '<option value="' . esc_html( $val ) . '" ' . esc_html( $select_default ) . '>' . esc_html( $field_values_tranlsated ) . '</option>'; - } - echo '</select>'; - break; - } - } - } else { - $field_values = $current_meta['field_values']; - $field_keys = array_keys( $field_values ); - echo '<select class="input_element form-control" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" ' . esc_html( $required ) . '>'; - echo '<option value="">' . ( isset( $current_meta['field_placeholder'] ) ? esc_html( $current_meta['field_placeholder'] ) : '-' ) . '</option>'; - - $field_order = isset( $current_meta['field_order'] ) ? array_values( array_unique( $current_meta['field_order'] ) ) : ( isset( $field_keys ) ? $field_keys : array() ); - $field_order = array_intersect( $field_order, array_keys( $current_meta['field_values'] ) ); - foreach ( $field_order as $value ) { - $key = $value; - $select_default = ''; - if ( $default_values === $key ) { - $select_default = 'selected'; - } - $field_values_tranlsated = eh_crm_wpml_translations( $field_values[ $key ], $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' ); - echo '<option value="' . esc_html( $key ) . '" ' . esc_html( $select_default ) . '>' . esc_html( $field_values_tranlsated ) . '</option>'; - } - echo '</select>'; - break; - } - break; - case 'radio': - $field_values = $current_meta['field_values']; - echo '<span style="vertical-align: middle;display: block;">'; - foreach ( $field_values as $key => $value ) { - $radio_default = ''; - if ( $default_values === $key ) { - $radio_default = 'checked'; - } - $field_values_tranlsated = eh_crm_wpml_translations( $value, $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' ); - echo '<input type="radio" class="form-control" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" style="margin-top: 0;" value="' . esc_html( $key ) . '" ' . esc_html( $radio_default ) . ' ' . esc_html( $required ) . '>' . esc_html( $field_values_tranlsated ) . '<br>'; - } - echo '</span>'; - break; - case 'checkbox': - $field_values = $current_meta['field_values']; - echo '<span style="vertical-align: middle;display: block;">'; - foreach ( $field_values as $key => $value ) { - $check_default = ''; - if ( $default_values === $key ) { - $check_default = 'checked'; - } - $field_values_tranlsated = eh_crm_wpml_translations( $value, $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' ); - echo '<input type="checkbox" data-slug="' . esc_html( $selected_fields[ $i ] ) . '" data-required="' . esc_html( $required ) . '" class="form-control toggle-checkbox-required ' . esc_html( $selected_fields[ $i ] ) . '" name="' . esc_html( $selected_fields[ $i ] ) . '[]" id="' . esc_html( $selected_fields[ $i ] ) . '[]" style="margin-top: 0;" value="' . esc_html( $key ) . '" ' . esc_html( $check_default ) . ' ' . esc_html( $required ) . '> ' . esc_html( $field_values_tranlsated ) . '<br>'; - } - echo '</span>'; - break; - case 'textarea': - $default_values = eh_crm_wpml_translations( $default_values, $avail_fields[ $j ]['settings_id'] . '_field_default', $avail_fields[ $j ]['settings_id'] . '_field_default' ); - echo '<textarea name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" class="input_element form-control" ' . esc_html( $required ) . '>' . esc_html( $default_values ) . '</textarea>'; - break; - case 'date': - echo '<input type="text" autocomplete="off" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" class="input_element form-control trigger_date_jq" placeholder="' . esc_html( $current_meta['field_placeholder'] ) . '" ' . esc_html( $required ) . '>'; - break; - case 'file': - $file_type = ( 'multiple' === $current_meta['file_type'] ) ? 'multiple' : ''; - if ( 'multiple' === $file_type ) { - $multiple_required = $required; - $required = ''; - ?> - <div class="ticket_multiple_attachments_container <?php echo esc_html( $multiple_required ); ?>"> - <div class="multiple_attachments_previewer"> - <div class="multiple_attachments_previewer_item hidden"> - <span class="file_name">file_name.jpg</span> - <span class="glyphicon glyphicon-remove remove"></span> - </div> - </div> - <div class="multiple_attachments_drop_zone"> - </div> - <div class="multiple_attachments_actions"> - <button class="btn btn-primary multiple_attachments_browse_files_trigger" type="button" name="multiple_attachments_browse_files_trigger"> - <i class="glyphicon glyphicon-plus"></i> - <?php echo esc_html_e( 'Browse files', 'wsdesk' ); ?> - </button> - </div> - </div> - <?php - } - echo '<input type="file" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" ' . esc_html( $file_type ) . ' class="input_element ' . ( 'multiple' === $file_type ? ' hidden ' : '' ) . 'form-control ticket_attachment" ' . esc_html( $required ) . ' style="height: auto;">'; - break; - - case 'google_captcha': - echo '<div class="g-recaptcha" data-sitekey="' . esc_html( $current_meta['field_site_key'] ) . '"></div><div class="captcha-error"></div>'; - break; - case 'pfs_order_product': - if ( class_exists( 'WSDESK_Pay_for_Support_Subscription' ) === false ) { - break; - } - echo '<select name="pfs_order_product" id="pfs_order_product" class="input_element form-control "' . esc_html( $required ) . '>'; - $pfs_user_id = get_current_user_id(); - if ( 0 != $pfs_user_id ) { - $current_product_names = WSDESK_Pay_for_Support_Subscription::pfs_get_product_names( $pfs_user_id ); - if ( count( $current_product_names ) > 0 ) { - echo '<option value="">' . esc_html__( 'Please select a product for the ticket', 'wsdesk' ) . '</option>'; - foreach ( $current_product_names as $products ) { - echo '<option value="' . esc_html( $products['order_id'] ) . ',' . esc_html( $products['product_id'] ) . '">' . esc_html( $products['product_name'] ) . ' (order id:' . esc_html( $products['order_id'] ) . ')</option>'; - } - } - } - echo '</select>'; - if ( ! is_user_logged_in() ) { - echo '<p style="margin:0px;font-size:0.9em">' . esc_html__( 'Please login to see your orders here', 'wsdesk' ) . '</p>'; - } - break; - } - $field_description = eh_crm_wpml_translations( $current_meta['field_description'], $avail_fields[ $j ]['settings_id'] . '_field_description', $avail_fields[ $j ]['settings_id'] . '_field_description' ); - - if ( 'woo_order_id' == $selected_fields[ $i ] ) { - $uid = get_current_user_id(); - if ( 0 != $uid ) { - echo '<small>' . esc_html( $field_description ) . '</small>'; - } - } else { - echo '<small>' . esc_html( $field_description ) . '</small>'; - } - - if ( eh_crm_get_settingsmeta( 0, 'auto_suggestion' ) == 'enable' && 'request_title' == $selected_fields[ $i ] ) { - echo '<div class="auto_suggestion_posts"></div>'; - } - echo '</div><br>'; - } - } -} -echo '<button type="submit" id="crm_form_submit" class="btn btn-primary" data-loading-text="' . esc_html__( 'Submitting...', 'wsdesk' ) . '">' . esc_html( $submit ) . '</button>'; -echo '<button type="reset" class="btn btn-primary wsdesk_crm_reset_button_show_hide" style="margin-left:5px;">' . esc_html( $reset ) . '</button></form>'; -echo '</div>'; -if ( ! defined( 'WSDESK_POWERED_SUPPORT' ) ) { - echo '<div class="powered_wsdesk"><span>' . esc_html__( 'Powered by', 'wsdesk' ) . '</span> <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" rel="nofollow">WSDesk</a></div>'; -} -return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++ob_start();+if ( isset( $display ) && ( 'form' === $display || 'form_only' === $display ) ) {+ echo '<div class="eh_crm_support_main wsdesk_wrapper">';+}+$raiser_default = eh_crm_get_settingsmeta( 0, 'ticket_raiser' );+$login_redirect_url = eh_crm_get_settingsmeta( 0, 'login_redirect_url' );+$logout_redirect_url = eh_crm_get_settingsmeta( 0, 'logout_redirect_url' );+$register_redirect_url = eh_crm_get_settingsmeta( 0, 'register_redirect_url' );+$login_url = eh_crm_get_settingsmeta( '0', 'login_url' );+$reg_url = eh_crm_get_settingsmeta( '0', 'reg_url' );++if ( is_user_logged_in() ) {+ $purchase_credit_redirect_url = eh_crm_get_settingsmeta( '0', 'purchase_credit_redirect_url' );+ $set_credit_limit = eh_crm_get_settingsmeta( '0', 'set_credit_limit' );+ if ( ! $set_credit_limit ) {+ $set_credit_limit = 0;+ }+ if ( EH_CRM_PAY_FOR_SUPPORT_STATUS ) {+ $user_id = 'wsdesk_subscription_method' . get_current_user_id();+ $user_pay_for_support_data = get_option( strval( $user_id ) );+ $main_score = get_user_meta( Parent_Child_Accounts::has_parent( get_current_user_id() ), Pfs_metakey_constants::MAIN_SCORE, true );+ if ( false == $main_score || null == $main_score || '' == $main_score ) {+ $main_score = 0;+ }+ if ( $main_score < $set_credit_limit ) {+ echo '<div class="form-elements"><span>' . esc_html__( 'You do not have enough credits to raise a ticket.', 'wsdesk' ) . '</span><br><a class="btn btn-primary" href="' . esc_url( $purchase_credit_redirect_url ) . '">' . esc_html__( 'Purchase Credits', 'wsdesk' ) . '</a></div>';+ return ob_get_clean();+ }+ }+}++if ( $register_redirect_url ) {+ $register_redirect_url = 'redirect_to=' . urlencode( $register_redirect_url );+}+if ( $login_redirect_url ) {+ $login_redirect_url = 'redirect_to=' . urlencode( $login_redirect_url );+}+if ( 'registered' == $raiser_default ) {+ if ( ! is_user_logged_in() ) {+ $login_url = eh_crm_append_query_string_to_url( $login_url ? $login_url : wp_login_url(), $login_redirect_url );+ $reg_url = eh_crm_append_query_string_to_url( $reg_url ? $reg_url : wp_registration_url(), $register_redirect_url );++ echo '<div class="form-elements log-in"><span>' . esc_html( get_existing_ticket_login_label() ) . '</span><br><a class="btn btn-primary" href="' . esc_url( $login_url ) . '">' . esc_html__( 'Login', 'wsdesk' ) . '</a></div>';+ echo '<div class="form-elements sign-up"><span>' . esc_html( get_existing_ticket_register_label() ) . '</span><br><a class="btn btn-primary" href="' . esc_url( $reg_url ) . '">' . esc_html__( 'Register', 'wsdesk' ) . '</a></div>';+ return ob_get_clean();+ }+} elseif ( 'guest' == $raiser_default+) {+ if ( is_user_logged_in() ) {+ echo '<div class="form-elements"><span>' . esc_html__( 'You must Logout to Raise Ticket', 'wsdesk' ) . '</span><br><a class="btn btn-primary" href="' . esc_url( wp_logout_url() ) . '">' . esc_html__( 'Logout', 'wsdesk' ) . '</a></div>';+ return ob_get_clean();+ }+}+$args = array( 'type' => 'field' );+$fields = array( 'slug', 'title', 'settings_id' );+$avail_fields = eh_crm_get_settings( $args, $fields );+$selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' );++if ( empty( $selected_fields ) ) {+ $selected_fields = array( 'request_email', 'request_title', 'request_description' );+}+if ( isset( $cus_fields ) && ! empty( $cus_fields ) && is_array( $cus_fields ) ) {+ $select_val = array();+ foreach ( $cus_fields as $value ) {+ if ( in_array( $value, $selected_fields ) ) {+ array_push( $select_val, $value );+ }+ }+ $selected_fields = $select_val;+}+if ( ! in_array( 'request_description', $selected_fields ) ) {+ array_unshift( $selected_fields, 'request_description' );+}+if ( ! in_array( 'request_title', $selected_fields ) ) {+ array_unshift( $selected_fields, 'request_title' );+}+if ( ! in_array( 'request_email', $selected_fields ) ) {+ array_unshift( $selected_fields, 'request_email' );+}+$input_width = eh_crm_get_settingsmeta( 0, 'input_width' );+$utitle = eh_crm_get_settingsmeta( 0, 'new_ticket_form_title' );++$utitle = eh_crm_wpml_translations( $utitle, 'title', 'title' );++$submit = eh_crm_get_settingsmeta( 0, 'submit_ticket_button' );++if ( ! $submit ) {+ $submit = __( 'Submit Request', 'wsdesk' );+}++$submit = eh_crm_wpml_translations( $submit, 'submit', 'submit' );++$reset = eh_crm_get_settingsmeta( 0, 'reset_ticket_button' );++if ( ! $reset ) {+ $reset = __( 'Reset Request', 'wsdesk' );+}++$reset = eh_crm_wpml_translations( $reset, 'reset', 'reset' );++$existing = eh_crm_get_settingsmeta( 0, 'existing_ticket_button' );+if ( ! $existing ) {+ $existing = __( 'Check your Existing Request', 'wsdesk' );+}++$existing = eh_crm_wpml_translations( $existing, 'existing', 'existing' );+if ( isset( $display ) && ( 'form' === $display ) ) {+ echo '+ <div class="support_option_choose">+ <a href="' . esc_url( eh_get_url_by_shortcode( '[wsdesk_support display="check_request"' ) ) . '" target="_blank" data-loading-text="' . esc_html__( 'Loading your Request...', 'wsdesk' ) . '" class="btn btn-primary eh_crm_check_request" role="button">+ ' . esc_html( $existing ) . '+ </a>+ </div>';+}+echo '<div class="main_new_suppot_request_form">';+echo '<style>+ .support_form+ {+ width: ' . esc_html( $input_width ) . '% !important;+ }+ </style> <form class="support_form" id="eh_crm_ticket_form">';+echo ( '' !== $utitle ) ? '<h3>' . esc_html( $utitle ) . '</h3>' : '';+$urole = '';+if ( is_user_logged_in() ) {+ if ( isset( wp_get_current_user()->roles ) ) {+ $wwp_roles = array( 'administrator', 'WSDesk_Agents', 'WSDesk_Supervisor' );+ foreach ( $wwp_roles as $wp_role ) {++ $urole_index = array_search( $wp_role, wp_get_current_user()->roles );+ if ( $urole_index ) {+ $urole = wp_get_current_user()->roles[ $urole_index ];+ break;+ }+ }+ }+}+for ( $i = 0; $i < count( $selected_fields ); $i++ ) {+ for ( $j = 0; $j < count( $avail_fields ); $j++ ) {+ $current_meta = eh_crm_get_settingsmeta( $avail_fields[ $j ]['settings_id'] );+ if ( $avail_fields[ $j ]['slug'] === $selected_fields[ $i ] && ( ! isset( $current_meta['field_visible'] ) || 'yes' === $current_meta['field_visible'] || 'ip' == $current_meta['field_type'] || in_array( $avail_fields[ $j ]['slug'], array( 'request_email', 'request_title', 'request_description' ) ) ) ) {+ echo '<div class="form-elements">';+ if ( 'WSDesk_Agents' == $urole ) {+ $required = ( isset( $current_meta['field_require_agent'] ) ? $current_meta['field_require_agent'] : '' );+ } elseif ( 'WSDesk_Supervisor' == $urole || 'administrator' == $urole ) {+ $required = 'no';+ } else {+ $required = ( isset( $current_meta['field_require'] ) ? $current_meta['field_require'] : '' );+ }++ $required = ( 'yes' === $required || in_array( $avail_fields[ $j ]['slug'], array( 'request_email', 'request_title', 'request_description' ) ) ) ? 'required' : '';+ if ( 'ip' == $current_meta['field_type'] ) {+ echo '<input type="hidden" value="' . esc_html( isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : null ) . '" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" class="input_element form-control">';+ } else {+ $field_title = eh_crm_wpml_translations( $avail_fields[ $j ]['title'], $avail_fields[ $j ]['settings_id'] . '_field_title', $avail_fields[ $j ]['settings_id'] . '_field_title' );+ if ( 'woo_order_id' == $selected_fields[ $i ] ) {+ if ( is_user_logged_in() ) {+ echo '<span>' . esc_html( $field_title ) . ' </span>';+ } else {+ $required = '';+ }+ } else {+ echo '<span>' . esc_html( $field_title ) . ' </span>';+ }+ }+ echo ( 'required' === $required ) ? '<span class="input_required">*</span>' : ' <br>';+ $default_values = ( isset( $current_meta['field_default'] ) ? $current_meta['field_default'] : '' );+ switch ( $current_meta['field_type'] ) {+ case 'text':+ $default_values = eh_crm_wpml_translations( $default_values, $avail_fields[ $j ]['settings_id'] . '_field_default', $avail_fields[ $j ]['settings_id'] . '_field_default' );++ $field_placeholder = eh_crm_wpml_translations( $current_meta['field_placeholder'], $avail_fields[ $j ]['settings_id'] . '_field_placeholder', $avail_fields[ $j ]['settings_id'] . '_field_placeholder' );+ echo '<input type="text" autocomplete="off" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $field_placeholder ) . '" ' . esc_html( $required ) . '>';+ break;+ case 'email':+ $email = '';+ if ( is_user_logged_in() && 'request_email' == $avail_fields[ $j ]['slug'] ) {+ $uid = get_current_user_id();+ $user = new WP_User( $uid );+ $default_values = $user->user_email;+ }+ $field_placeholder = eh_crm_wpml_translations( $current_meta['field_placeholder'], $avail_fields[ $j ]['settings_id'] . '_field_placeholder', $avail_fields[ $j ]['settings_id'] . '_field_placeholder' );+ echo '<input type="email" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $field_placeholder ) . '"' . esc_html( $required ) . '>';+ break;+ case 'phone':+ echo '<br><span><strong>+</strong><input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $current_meta )['field_placeholder'] . '"' . esc_html( $required ) . ' style="display: inline; width: 99% !important"></span>';+ break;+ case 'number':+ echo '<input type="number" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $current_meta['field_placeholder'] ) . '"' . esc_html( $required ) . '>';+ break;+ case 'password':+ echo '<input type="password" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $current_meta['field_placeholder'] ) . '"' . esc_html( $required ) . '>';+ break;+ case 'select':+ $field_values = $current_meta['field_values'];+ $customer_temp_altered = array();+ $return = array();+ if ( 'woo_order_id' == $selected_fields[ $i ] ) {+ $uid = get_current_user_id();+ if ( 0 != $uid ) {+ $customer_orders = wc_get_orders( array( 'customer_id' => $uid ) );+ if ( count( $customer_orders ) > 0 ) {+ foreach ( $customer_orders as $key => $customer_order ) {+ array_push( $customer_temp_altered, trim( str_replace( ' ', '', $customer_order->get_order_number() ) ) );+ }+ for ( $g = 0;$g < count( $customer_temp_altered );$g++ ) {+ $return[ $g ] = $customer_temp_altered[ $g ];+ }+ echo '<select class="input_element form-control" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" ' . esc_html( $required ) . '>';+ echo '<option value="">' . ( isset( $current_meta['field_placeholder'] ) ? esc_html( $current_meta['field_placeholder'] ) : '-' ) . '</option>';+ foreach ( $return as $key => $val ) {+ $select_default = '';+ if ( $default_values === $val ) {+ $select_default = 'selected';+ }+ $field_values_tranlsated = eh_crm_wpml_translations( $val, $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' );+ echo '<option value="' . esc_html( $val ) . '" ' . esc_html( $select_default ) . '>' . esc_html( $field_values_tranlsated ) . '</option>';+ }+ echo '</select>';+ break;+ }+ }+ } else {+ $field_values = $current_meta['field_values'];+ $field_keys = array_keys( $field_values );+ echo '<select class="input_element form-control" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" ' . esc_html( $required ) . '>';+ echo '<option value="">' . ( isset( $current_meta['field_placeholder'] ) ? esc_html( $current_meta['field_placeholder'] ) : '-' ) . '</option>';++ $field_order = isset( $current_meta['field_order'] ) ? array_values( array_unique( $current_meta['field_order'] ) ) : ( isset( $field_keys ) ? $field_keys : array() );+ $field_order = array_intersect( $field_order, array_keys( $current_meta['field_values'] ) );+ foreach ( $field_order as $value ) {+ $key = $value;+ $select_default = '';+ if ( $default_values === $key ) {+ $select_default = 'selected';+ }+ $field_values_tranlsated = eh_crm_wpml_translations( $field_values[ $key ], $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' );+ echo '<option value="' . esc_html( $key ) . '" ' . esc_html( $select_default ) . '>' . esc_html( $field_values_tranlsated ) . '</option>';+ }+ echo '</select>';+ break;+ }+ break;+ case 'radio':+ $field_values = $current_meta['field_values'];+ echo '<span style="vertical-align: middle;display: block;">';+ foreach ( $field_values as $key => $value ) {+ $radio_default = '';+ if ( $default_values === $key ) {+ $radio_default = 'checked';+ }+ $field_values_tranlsated = eh_crm_wpml_translations( $value, $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' );+ echo '<input type="radio" class="form-control" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" style="margin-top: 0;" value="' . esc_html( $key ) . '" ' . esc_html( $radio_default ) . ' ' . esc_html( $required ) . '>' . esc_html( $field_values_tranlsated ) . '<br>';+ }+ echo '</span>';+ break;+ case 'checkbox':+ $field_values = $current_meta['field_values'];+ echo '<span style="vertical-align: middle;display: block;">';+ foreach ( $field_values as $key => $value ) {+ $check_default = '';+ if ( $default_values === $key ) {+ $check_default = 'checked';+ }+ $field_values_tranlsated = eh_crm_wpml_translations( $value, $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' );+ echo '<input type="checkbox" data-slug="' . esc_html( $selected_fields[ $i ] ) . '" data-required="' . esc_html( $required ) . '" class="form-control toggle-checkbox-required ' . esc_html( $selected_fields[ $i ] ) . '" name="' . esc_html( $selected_fields[ $i ] ) . '[]" id="' . esc_html( $selected_fields[ $i ] ) . '[]" style="margin-top: 0;" value="' . esc_html( $key ) . '" ' . esc_html( $check_default ) . ' ' . esc_html( $required ) . '> ' . esc_html( $field_values_tranlsated ) . '<br>';+ }+ echo '</span>';+ break;+ case 'textarea':+ $default_values = eh_crm_wpml_translations( $default_values, $avail_fields[ $j ]['settings_id'] . '_field_default', $avail_fields[ $j ]['settings_id'] . '_field_default' );+ echo '<textarea name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" class="input_element form-control" ' . esc_html( $required ) . '>' . esc_html( $default_values ) . '</textarea>';+ break;+ case 'date':+ echo '<input type="text" autocomplete="off" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" class="input_element form-control trigger_date_jq" placeholder="' . esc_html( $current_meta['field_placeholder'] ) . '" ' . esc_html( $required ) . '>';+ break;+ case 'file':+ $file_type = ( 'multiple' === $current_meta['file_type'] ) ? 'multiple' : '';+ if ( 'multiple' === $file_type ) {+ $multiple_required = $required;+ $required = '';+ ?>+ <div class="ticket_multiple_attachments_container <?php echo esc_html( $multiple_required ); ?>">+ <div class="multiple_attachments_previewer">+ <div class="multiple_attachments_previewer_item hidden">+ <span class="file_name">file_name.jpg</span>+ <span class="glyphicon glyphicon-remove remove"></span>+ </div>+ </div>+ <div class="multiple_attachments_drop_zone">+ </div>+ <div class="multiple_attachments_actions">+ <button class="btn btn-primary multiple_attachments_browse_files_trigger" type="button" name="multiple_attachments_browse_files_trigger">+ <i class="glyphicon glyphicon-plus"></i>+ <?php echo esc_html_e( 'Browse files', 'wsdesk' ); ?>+ </button>+ </div>+ </div>+ <?php+ }+ echo '<input type="file" name="' . esc_html( $selected_fields[ $i ] ) . '" id="' . esc_html( $selected_fields[ $i ] ) . '" ' . esc_html( $file_type ) . ' class="input_element ' . ( 'multiple' === $file_type ? ' hidden ' : '' ) . 'form-control ticket_attachment" ' . esc_html( $required ) . ' style="height: auto;">';+ break;++ case 'google_captcha':+ echo '<div class="g-recaptcha" data-sitekey="' . esc_html( $current_meta['field_site_key'] ) . '"></div><div class="captcha-error"></div>';+ break;+ case 'pfs_order_product':+ if ( class_exists( 'WSDESK_Pay_for_Support_Subscription' ) === false ) {+ break;+ }+ echo '<select name="pfs_order_product" id="pfs_order_product" class="input_element form-control "' . esc_html( $required ) . '>';+ $pfs_user_id = get_current_user_id();+ if ( 0 != $pfs_user_id ) {+ $current_product_names = WSDESK_Pay_for_Support_Subscription::pfs_get_product_names( $pfs_user_id );+ if ( count( $current_product_names ) > 0 ) {+ echo '<option value="">' . esc_html__( 'Please select a product for the ticket', 'wsdesk' ) . '</option>';+ foreach ( $current_product_names as $products ) {+ echo '<option value="' . esc_html( $products['order_id'] ) . ',' . esc_html( $products['product_id'] ) . '">' . esc_html( $products['product_name'] ) . ' (order id:' . esc_html( $products['order_id'] ) . ')</option>';+ }+ }+ }+ echo '</select>';+ if ( ! is_user_logged_in() ) {+ echo '<p style="margin:0px;font-size:0.9em">' . esc_html__( 'Please login to see your orders here', 'wsdesk' ) . '</p>';+ }+ break;+ }+ $field_description = eh_crm_wpml_translations( $current_meta['field_description'], $avail_fields[ $j ]['settings_id'] . '_field_description', $avail_fields[ $j ]['settings_id'] . '_field_description' );++ if ( 'woo_order_id' == $selected_fields[ $i ] ) {+ $uid = get_current_user_id();+ if ( 0 != $uid ) {+ echo '<small>' . esc_html( $field_description ) . '</small>';+ }+ } else {+ echo '<small>' . esc_html( $field_description ) . '</small>';+ }++ if ( eh_crm_get_settingsmeta( 0, 'auto_suggestion' ) == 'enable' && 'request_title' == $selected_fields[ $i ] ) {+ echo '<div class="auto_suggestion_posts"></div>';+ }+ echo '</div><br>';+ }+ }+}+echo '<button type="submit" id="crm_form_submit" class="btn btn-primary" data-loading-text="' . esc_html__( 'Submitting...', 'wsdesk' ) . '">' . esc_html( $submit ) . '</button>';+echo '<button type="reset" class="btn btn-primary wsdesk_crm_reset_button_show_hide" style="margin-left:5px;">' . esc_html( $reset ) . '</button></form>';+echo '</div>';+if ( ! defined( 'WSDESK_POWERED_SUPPORT' ) ) {+ echo '<div class="powered_wsdesk"><span>' . esc_html__( 'Powered by', 'wsdesk' ) . '</span> <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" rel="nofollow">WSDesk</a></div>';+}+return ob_get_clean();
Vulnerability Existed: no No Security Vulnerabilities Identified - File: views/shortcodes/crm_support_new.php Explanation: This diff shows only whitespace/line ending changes (CRLF to LF conversion). The actual code content remains identical between versions 3.3.4 and 3.3.5. No security fixes or new vulnerabilities were introduced. The file contains proper security practices throughout: - All user-facing output uses `esc_html()`, `esc_url()`, and `esc_html__()` for escaping - Server variables like `$_SERVER['REMOTE_ADDR']` are properly sanitized with `sanitize_text_field()` - Input validation occurs through field type checks and configuration metadata - WordPress security functions are used consistently Since this is purely a formatting change with no code modifications, there are no security vulnerabilities to analyze.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/shortcodes/crm_support_new_and_check_request.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/shortcodes/crm_support_new_and_check_request.php 2025-12-21 09:36:35.511308688 +0000@@ -1,413 +1,413 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -ob_start(); -if ( isset( $display ) && ( 'form' === $display || 'form_only' === $display ) ) { - echo '<div class="eh_crm_support_main wsdesk_wrapper">'; -} -$raiser_default = eh_crm_get_settingsmeta( 0, 'ticket_raiser' ); -$login_redirect_url = eh_crm_get_settingsmeta( 0, 'login_redirect_url' ); -$logout_redirect_url = eh_crm_get_settingsmeta( 0, 'logout_redirect_url' ); -$register_redirect_url = eh_crm_get_settingsmeta( 0, 'register_redirect_url' ); -$login_url = eh_crm_get_settingsmeta( '0', 'login_url' ); -$reg_url = eh_crm_get_settingsmeta( '0', 'reg_url' ); -if ( is_user_logged_in() ) { - $purchase_credit_redirect_url = eh_crm_get_settingsmeta( '0', 'purchase_credit_redirect_url' ); - $set_credit_limit = eh_crm_get_settingsmeta( '0', 'set_credit_limit' ); - if ( ! $set_credit_limit ) { - $set_credit_limit = 0; - } - if ( EH_CRM_PAY_FOR_SUPPORT_STATUS ) { - $user_id = 'wsdesk_subscription_method' . get_current_user_id(); - $user_pay_for_support_data = get_option( strval( $user_id ) ); - if ( isset( $user_pay_for_support_data['design_credits'] ) ) { - $user_credit = $user_pay_for_support_data['design_credits']; - } - if ( $user_credit < $set_credit_limit ) { - echo '<div class="form-elements"><span>' . esc_html__( 'You do not have enough credits to raise a ticket.', 'wsdesk' ) . '</span><br><a class="btn btn-primary" href="' . esc_url( $purchase_credit_redirect_url ) . '">' . esc_html__( 'Purchase Credits', 'wsdesk' ) . '</a></div>'; - return ob_get_clean(); - } - } -} - -if ( $register_redirect_url ) { - $register_redirect_url = '&redirect_to=' . urlencode( $register_redirect_url ); -} -if ( $login_redirect_url ) { - $login_redirect_url = '&redirect_to=' . urlencode( $login_redirect_url ); -} -if ( 'registered' == $raiser_default ) { - if ( ! is_user_logged_in() ) { - if ( $login_url ) { - $login_url = $login_url . $login_redirect_url; - } else { - $login_url = wp_login_url() . $login_redirect_url; - } - if ( $reg_url ) { - $reg_url = $reg_url . $register_redirect_url; - } else { - $reg_url = wp_registration_url() . $register_redirect_url; - } - - echo '<div class="form-elements log-in"><span>' . esc_html( get_existing_ticket_login_label() ) . '</span><br><a class="btn btn-primary" href="' . esc_url( $login_url ) . '">' . esc_html__( 'Login', 'wsdesk' ) . '</a></div>'; - echo '<div class="form-elements sign-up"><span>' . esc_html( get_existing_ticket_register_label() ) . '</span><br><a class="btn btn-primary" href="' . esc_url( $reg_url ) . '">' . esc_html__( 'Register', 'wsdesk' ) . '</a></div>'; - return ob_get_clean(); - } -} elseif ( 'guest' == $raiser_default ) { - if ( is_user_logged_in() ) { - echo '<div class="form-elements"><span>' . esc_html__( 'You must Logout to Raise Ticket', 'wsdesk' ) . '</span><br><a class="btn btn-primary" href="' . esc_url( wp_logout_url( $logout_redirect_url ) ) . '">' . esc_html__( 'Logout', 'wsdesk' ) . '</a></div>'; - return ob_get_clean(); - } -} -$args = array( 'type' => 'field' ); -$fields = array( 'slug', 'title', 'settings_id' ); -$avail_fields = eh_crm_get_settings( $args, $fields ); -$selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' ); - -if ( empty( $selected_fields ) ) { - $selected_fields = array( 'request_email', 'request_title', 'request_description' ); -} -if ( isset( $cus_fields ) && ! empty( $cus_fields ) && is_array( $cus_fields ) ) { - $select_val = array(); - foreach ( $cus_fields as $value ) { - if ( in_array( $value, $selected_fields ) ) { - array_push( $select_val, $value ); - } - } - $selected_fields = $select_val; -} -if ( ! in_array( 'request_description', $selected_fields ) ) { - array_unshift( $selected_fields, 'request_description' ); -} -if ( ! in_array( 'request_title', $selected_fields ) ) { - array_unshift( $selected_fields, 'request_title' ); -} -if ( ! in_array( 'request_email', $selected_fields ) ) { - array_unshift( $selected_fields, 'request_email' ); -} -$input_width = eh_crm_get_settingsmeta( 0, 'input_width' ); -$etitle = eh_crm_get_settingsmeta( 0, 'new_ticket_form_title' ); - -$etitle = eh_crm_wpml_translations( $etitle, 'title', 'title' ); - -$submit = eh_crm_get_settingsmeta( 0, 'submit_ticket_button' ); - -if ( ! $submit ) { - $submit = __( 'Submit Request', 'wsdesk' ); -} - -$submit = eh_crm_wpml_translations( $submit, 'submit', 'submit' ); - -$reset = eh_crm_get_settingsmeta( 0, 'reset_ticket_button' ); - -if ( ! $reset ) { - $reset = __( 'Reset Request', 'wsdesk' ); -} - -$reset = eh_crm_wpml_translations( $reset, 'reset', 'reset' ); - -$existing = eh_crm_get_settingsmeta( 0, 'existing_ticket_button' ); -if ( ! $existing ) { - $existing = __( 'Check your Existing Request', 'wsdesk' ); -} - -$existing = eh_crm_wpml_translations( $existing, 'existing', 'existing' ); -if ( isset( $display ) && ( 'form' === $display ) ) { - echo ' - <div class="support_option_choose"> - <a href="' . esc_html( eh_get_url_by_shortcode( '[wsdesk_support display="check_request"' ) ) . '" target="_blank" data-loading-text="' . esc_html__( 'Loading your Request...', 'wsdesk' ) . '" class="btn btn-primary eh_crm_check_request" role="button"> - ' . esc_html( $existing ) . ' - </a> - </div>'; -} -?> - -<div class="main_new_suppot_request_form"> - <style> - .support_form - { - width: <?php echo esc_html( $input_width ); ?>% !important; - } - </style> - <form class="support_form" id="eh_crm_ticket_form"> - -<?php -echo ( '' !== $etitle ) ? '<h3>' . esc_html( $etitle ) . '</h3>' : ''; - -$urole = ''; -if ( is_user_logged_in() ) { - if ( isset( wp_get_current_user()->roles ) ) { - $ewp_roles = array( 'administrator', 'WSDesk_Agents', 'WSDesk_Supervisor' ); - foreach ( $ewp_roles as $wp_role ) { - - $role_index = array_search( $wp_role, wp_get_current_user()->roles ); - if ( $role_index ) { - $urole = wp_get_current_user()->roles[ $role_index ]; - break; - } - } - } -} -for ( $i = 0; $i < count( $selected_fields ); $i++ ) { - for ( $j = 0; $j < count( $avail_fields ); $j++ ) { - $current_meta = eh_crm_get_settingsmeta( $avail_fields[ $j ]['settings_id'] ); - if ( $avail_fields[ $j ]['slug'] === $selected_fields[ $i ] && ( ! isset( $current_meta['field_visible'] ) || 'yes' === $current_meta['field_visible'] || 'ip' == $current_meta['field_type'] || in_array( $avail_fields[ $j ]['slug'], array( 'request_email', 'request_title', 'request_description' ) ) ) ) { - echo '<div class="form-elements">'; - if ( 'WSDesk_Agents' == $urole ) { - $required = ( isset( $current_meta['field_require_agent'] ) ? $current_meta['field_require_agent'] : '' ); - } elseif ( 'WSDesk_Supervisor' == $urole || 'administrator' == $urole ) { - $required = 'no'; - } else { - $required = ( isset( $current_meta['field_require'] ) ? $current_meta['field_require'] : '' ); - } - - $required = ( 'yes' === $required || in_array( $avail_fields[ $j ]['slug'], array( 'request_email', 'request_title', 'request_description' ) ) ) ? 'required' : ''; - if ( 'ip' == $current_meta['field_type'] ) { - echo '<input type="hidden" value="' . esc_html( isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : null ) . '" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" class="input_element form-control">'; - } else { - if ( 'request_description' != $avail_fields[ $j ]['slug'] ) { - $field_title = eh_crm_wpml_translations( $avail_fields[ $j ]['title'], $avail_fields[ $j ]['settings_id'] . '_field_title', $avail_fields[ $j ]['settings_id'] . '_field_title' ); - if ( is_user_logged_in() && 'request_email' != $avail_fields[ $j ]['slug'] && 'request_title' != $avail_fields[ $j ]['slug'] && 'request_description' != $avail_fields[ $j ]['slug'] ) { - echo '<span>' . esc_html( $field_title ) . ' </span>'; - } - } - } - if ( 'request_description' != $avail_fields[ $j ]['slug'] && 'request_email' != $avail_fields[ $j ]['slug'] && 'request_title' != $avail_fields[ $j ]['slug'] ) { - echo ( 'required' === $required ) ? '<span class="input_required">*</span>' : ' <br>'; - } - - $default_values = ( isset( $current_meta['field_default'] ) ? $current_meta['field_default'] : '' ); - - switch ( $current_meta['field_type'] ) { - case 'text': - if ( is_user_logged_in() && 'request_title' == $avail_fields[ $j ]['slug'] ) { - $default_values = eh_crm_wpml_translations( $default_values, $avail_fields[ $j ]['settings_id'] . '_field_default', $avail_fields[ $j ]['settings_id'] . '_field_default' ); - $default_values = ''; - - $field_placeholder = eh_crm_wpml_translations( $current_meta['field_placeholder'], $avail_fields[ $j ]['settings_id'] . '_field_placeholder', $avail_fields[ $j ]['settings_id'] . '_field_placeholder' ); - echo '<input type="text" autocomplete="off" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $field_placeholder ) . '" ' . esc_html( $required ) . '>'; - break; - } else { - $default_values = eh_crm_wpml_translations( $default_values, $avail_fields[ $j ]['settings_id'] . '_field_default', $avail_fields[ $j ]['settings_id'] . '_field_default' ); - - $field_placeholder = eh_crm_wpml_translations( $current_meta['field_placeholder'], $avail_fields[ $j ]['settings_id'] . '_field_placeholder', $avail_fields[ $j ]['settings_id'] . '_field_placeholder' ); - echo '<input type="text" autocomplete="off" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $field_placeholder ) . '" ' . esc_html( $required ) . '>'; - break; - } - case 'email': - $email = ''; - if ( is_user_logged_in() && 'request_email' == $avail_fields[ $j ]['slug'] ) { - $uid = get_current_user_id(); - $user = new WP_User( $uid ); - $default_values = $user->user_email; - $field_placeholder = eh_crm_wpml_translations( $current_meta['field_placeholder'], $avail_fields[ $j ]['settings_id'] . '_field_placeholder', $avail_fields[ $j ]['settings_id'] . '_field_placeholder' ); - echo '<input type="email" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $field_placeholder ) . '"' . esc_html( $required ) . ' >'; - break; - } else { - $field_placeholder = eh_crm_wpml_translations( $current_meta['field_placeholder'], $avail_fields[ $j ]['settings_id'] . '_field_placeholder', $avail_fields[ $j ]['settings_id'] . '_field_placeholder' ); - echo '<input type="email" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $field_placeholder ) . '"' . esc_html( $required ) . '>'; - break; - } - - case 'phone': - echo '<br><span><strong>+</strong><input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $current_meta['field_placeholder'] ) . '"' . esc_html( $required ) . ' style="display: inline; width: 99% !important"></span>'; - break; - case 'number': - echo '<input type="number" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $current_meta['field_placeholder'] ) . '"' . esc_html( $required ) . '>'; - break; - case 'password': - echo '<input type="password" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $current_meta['field_placeholder'] ) . '"' . esc_html( $required ) . '>'; - break; - case 'select': - $field_values = $current_meta['field_values']; - $customer_temp_altered = array(); - $return = array(); - if ( 'woo_order_id' == $selected_fields[ $i ] ) { - $uid = get_current_user_id(); - if ( 0 != $uid ) { - $customer_orders = wc_get_orders( array( 'customer_id' => $uid ) ); - if ( count( $customer_orders ) > 0 ) { - foreach ( $customer_orders as $key => $customer_order ) { - array_push( $customer_temp_altered, trim( str_replace( ' ', '', $customer_order->get_order_number() ) ) ); - } - for ( $g = 0;$g < count( $customer_temp_altered );$g++ ) { - $return[ $g ] = $customer_temp_altered[ $g ]; - } - echo '<select class="input_element form-control" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" ' . esc_html( $required ) . '>'; - echo '<option value="">' . ( isset( $current_meta['field_placeholder'] ) ? esc_html( $current_meta['field_placeholder'] ) : '-' ) . '</option>'; - foreach ( $return as $key => $val ) { - $select_default = ''; - if ( $default_values === $val ) { - $select_default = 'selected'; - } - $field_values_tranlsated = eh_crm_wpml_translations( $val, $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' ); - echo '<option value="' . esc_html( $val ) . '" ' . esc_html( $select_default ) . '>' . esc_html( $field_values_tranlsated ) . '</option>'; - } - echo '</select>'; - break; - } - } - } else { - $field_values = $current_meta['field_values']; - $field_keys = array_keys( $field_values ); - echo '<select class="input_element form-control" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" ' . esc_html( $required ) . '>'; - echo '<option value="">' . ( isset( $current_meta['field_placeholder'] ) ? esc_html( $current_meta['field_placeholder'] ) : '-' ) . '</option>'; - - $field_order = array_intersect( $field_order, array_keys( $current_meta['field_values'] ) ); - $field_order = isset( $current_meta['field_order'] ) ? array_values( array_unique( $current_meta['field_order'] ) ) : ( isset( $field_keys ) ? $field_keys : array() ); - foreach ( $field_order as $value ) { - $key = $value; - $select_default = ''; - if ( $default_values === $key ) { - $select_default = 'selected'; - } - $field_values_tranlsated = eh_crm_wpml_translations( $field_values[ $key ], $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' ); - echo '<option value="' . esc_html( $key ) . '" ' . esc_html( $select_default ) . '>' . esc_html( $field_values_tranlsated ) . '</option>'; - } - echo '</select>'; - break; - } - break; - case 'radio': - $field_values = $current_meta['field_values']; - echo '<span style="vertical-align: middle;display: block;">'; - foreach ( $field_values as $key => $value ) { - $radio_default = ''; - if ( $default_values === $key ) { - $radio_default = 'checked'; - } - $field_values_tranlsated = eh_crm_wpml_translations( $value, $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' ); - echo '<input type="radio" class="form-control" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" style="margin-top: 0;" value="' . esc_html( $key ) . '" ' . esc_html( $radio_default ) . ' ' . esc_html( $required ) . '>' . esc_html( $field_values_tranlsated ) . '<br>'; - } - echo '</span>'; - break; - case 'checkbox': - $field_values = $current_meta['field_values']; - echo '<span style="vertical-align: middle;display: block;">'; - foreach ( $field_values as $key => $value ) { - $check_default = ''; - if ( $default_values === $key ) { - $check_default = 'checked'; - } - $field_values_tranlsated = eh_crm_wpml_translations( $value, $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' ); - echo '<input type="checkbox" class="form-control" name="' . esc_attr( $selected_fields[ $i ] ) . '[]" id="' . esc_attr( $selected_fields[ $i ] ) . '[]" style="margin-top: 0;" value="' . esc_html( $key ) . '" ' . esc_html( $check_default ) . ' ' . esc_html( $required ) . '> ' . esc_html( $field_values_tranlsated ) . '<br>'; - } - echo '</span>'; - break; - case 'textarea': - if ( 'request_description' == $avail_fields[ $j ]['slug'] ) { - - $required = 'no'; - $default_values = eh_crm_wpml_translations( $default_values, $avail_fields[ $j ]['settings_id'] . '_field_default', $avail_fields[ $j ]['settings_id'] . '_field_default' ); - echo '<textarea name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" class="input_element form-control" ' . esc_html( $required ) . '>' . esc_html( $default_values ) . '</textarea>'; - } else { - $default_values = eh_crm_wpml_translations( $default_values, $avail_fields[ $j ]['settings_id'] . '_field_default', $avail_fields[ $j ]['settings_id'] . '_field_default' ); - echo '<textarea name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" class="input_element form-control" ' . esc_html( $required ) . '>' . esc_html( $default_values ) . '</textarea>'; - } - break; - case 'date': - echo '<input type="text" autocomplete="off" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" class="input_element form-control trigger_date_jq" placeholder="' . esc_html( $current_meta )['field_placeholder'] . '" ' . esc_html( $required ) . '>'; - break; - case 'file': - $file_type = ( 'multiple' === $current_meta['file_type'] ) ? 'multiple' : ''; - if ( 'multiple' === $file_type ) { - $multiple_required = $required; - $required = ''; - ?> - <div class="ticket_multiple_attachments_container <?php echo esc_html( $multiple_required ); ?>"> - <div class="multiple_attachments_previewer"> - <div class="multiple_attachments_previewer_item hidden"> - <span class="file_name">file_name.jpg</span> - <span class="glyphicon glyphicon-remove remove"></span> - </div> - </div> - <div class="multiple_attachments_drop_zone"> - </div> - <div class="multiple_attachments_actions"> - <button class="btn btn-primary multiple_attachments_browse_files_trigger" type="button" name="multiple_attachments_browse_files_trigger"> - <i class="glyphicon glyphicon-plus"></i> - <?php echo esc_html_e( 'Browse files', 'wsdesk' ); ?> - </button> - </div> - </div> - <?php - } - echo '<input type="file" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" ' . esc_html( $file_type ) . ' class="input_element ' . ( 'multiple' === $file_type ? ' hidden ' : '' ) . 'form-control ticket_attachment" ' . esc_html( $required ) . ' style="height: auto;">'; - break; - case 'google_captcha': - echo '<div class="g-recaptcha" data-sitekey="' . esc_html( $current_meta['field_site_key'] ) . '"></div><div class="captcha-error"></div>'; - break; - } - - $field_description = eh_crm_wpml_translations( $current_meta['field_description'], $avail_fields[ $j ]['settings_id'] . '_field_description', $avail_fields[ $j ]['settings_id'] . '_field_description' ); - echo '<small>' . esc_html( $field_description ) . '</small>'; - - - if ( eh_crm_get_settingsmeta( 0, 'auto_suggestion' ) == 'enable' && 'request_title' == $selected_fields[ $i ] ) { - echo '<div class="auto_suggestion_posts"></div>'; - } - echo '</div><br>'; - } - } -} -echo '<button type="button" id="crm_form_submit" class="btn btn-primary" data-loading-text="' . esc_html__( 'Submitting...', 'wsdesk' ) . '">' . esc_html( $submit ) . '</button>'; -echo '<button type="reset" class="btn btn-primary wsdesk_crm_reset_button_show_hide" style="margin-left:5px;">' . esc_html( $reset ) . '</button></form>'; -echo '</div>'; -if ( ! defined( 'WSDESK_POWERED_SUPPORT' ) ) { - echo '<div class="powered_wsdesk"><span>' . esc_html__( 'Powered by', 'wsdesk' ) . '</span> <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" rel="nofollow">WSDesk</a></div>'; -} - -$etitle = eh_crm_get_settingsmeta( 0, 'main_ticket_form_title' ); -$etitle = eh_crm_wpml_translations( $etitle, 'title', 'title' ); -$selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' ); -$select_val = array(); -if ( is_array( $selected_fields ) ) { - if ( isset( $cus_fields ) && ! empty( $cus_fields ) && is_array( $cus_fields ) ) { - $select_val = array_intersect( $selected_fields, $cus_fields ); - } -} -$ticket_id = ''; -if ( isset( $_GET['customer_ticket_num'] ) ) { - $ticket_id = sanitize_text_field( $_GET['customer_ticket_num'] ); -} elseif ( ! empty( $_GET ) ) { - foreach ( $_GET as $query_id => $query_value ) { - if ( strpos( $query_value, 'customer_ticket_num' ) != '' ) { - $ticket_id = explode( 'customer_ticket_num=', $query_value )[1]; - break; - } - } -} -if ( $ticket_id && is_user_logged_in() ) { - $ticket = eh_crm_get_ticket( array( 'ticket_id' => $ticket_id ), array( 'ticket_author', 'ticket_email' ) ); - $wcurrent_user = wp_get_current_user(); - if ( $ticket[0]['ticket_email'] == $wcurrent_user->user_email || $ticket[0]['ticket_author'] == $wcurrent_user->ID ) { - echo'<div class="eh_crm_support_main wsdesk_wrapper"> - <div class="loaderDirect"></div> - <div class="eh_crm_support_main load_wsdesk_request_ticket_directly"> - <div class="ticket_table_wrapper"> - <div class="ticket_load_content"></div> - </div> - </div> - </div>'; - } -} else { - ?> -<div class="eh_crm_support_main wsdesk_wrapper"> - <input type= "hidden" id="custom_fields" value ="<?php echo esc_html( json_encode( $select_val ) ); ?>"/> - <?php echo ( '' !== $etitle ) ? '<h3>' . esc_html( $etitle ) . '</h3>' : ''; ?> - <div class="wsdesk_wrapper"> - <div class="loaderDirect"></div> - <div class="eh_crm_support_main load_wsdesk_request_directly wsdesk_new_ticket_view"> - <div class="ticket_table_wrapper"></div> - </div> - </div> -</div> - <?php -} -if ( ! defined( 'WSDESK_POWERED_SUPPORT' ) ) { - echo '<div id="check_request_powered_wsdesk" class="powered_wsdesk"><span>' . esc_html__( 'Powered by', 'wsdesk' ) . '</span> <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" rel="nofollow">WSDesk</a></div>'; -} - -return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++ob_start();+if ( isset( $display ) && ( 'form' === $display || 'form_only' === $display ) ) {+ echo '<div class="eh_crm_support_main wsdesk_wrapper">';+}+$raiser_default = eh_crm_get_settingsmeta( 0, 'ticket_raiser' );+$login_redirect_url = eh_crm_get_settingsmeta( 0, 'login_redirect_url' );+$logout_redirect_url = eh_crm_get_settingsmeta( 0, 'logout_redirect_url' );+$register_redirect_url = eh_crm_get_settingsmeta( 0, 'register_redirect_url' );+$login_url = eh_crm_get_settingsmeta( '0', 'login_url' );+$reg_url = eh_crm_get_settingsmeta( '0', 'reg_url' );+if ( is_user_logged_in() ) {+ $purchase_credit_redirect_url = eh_crm_get_settingsmeta( '0', 'purchase_credit_redirect_url' );+ $set_credit_limit = eh_crm_get_settingsmeta( '0', 'set_credit_limit' );+ if ( ! $set_credit_limit ) {+ $set_credit_limit = 0;+ }+ if ( EH_CRM_PAY_FOR_SUPPORT_STATUS ) {+ $user_id = 'wsdesk_subscription_method' . get_current_user_id();+ $user_pay_for_support_data = get_option( strval( $user_id ) );+ if ( isset( $user_pay_for_support_data['design_credits'] ) ) {+ $user_credit = $user_pay_for_support_data['design_credits'];+ }+ if ( $user_credit < $set_credit_limit ) {+ echo '<div class="form-elements"><span>' . esc_html__( 'You do not have enough credits to raise a ticket.', 'wsdesk' ) . '</span><br><a class="btn btn-primary" href="' . esc_url( $purchase_credit_redirect_url ) . '">' . esc_html__( 'Purchase Credits', 'wsdesk' ) . '</a></div>';+ return ob_get_clean();+ }+ }+}++if ( $register_redirect_url ) {+ $register_redirect_url = '&redirect_to=' . urlencode( $register_redirect_url );+}+if ( $login_redirect_url ) {+ $login_redirect_url = '&redirect_to=' . urlencode( $login_redirect_url );+}+if ( 'registered' == $raiser_default ) {+ if ( ! is_user_logged_in() ) {+ if ( $login_url ) {+ $login_url = $login_url . $login_redirect_url;+ } else {+ $login_url = wp_login_url() . $login_redirect_url;+ }+ if ( $reg_url ) {+ $reg_url = $reg_url . $register_redirect_url;+ } else {+ $reg_url = wp_registration_url() . $register_redirect_url;+ }++ echo '<div class="form-elements log-in"><span>' . esc_html( get_existing_ticket_login_label() ) . '</span><br><a class="btn btn-primary" href="' . esc_url( $login_url ) . '">' . esc_html__( 'Login', 'wsdesk' ) . '</a></div>';+ echo '<div class="form-elements sign-up"><span>' . esc_html( get_existing_ticket_register_label() ) . '</span><br><a class="btn btn-primary" href="' . esc_url( $reg_url ) . '">' . esc_html__( 'Register', 'wsdesk' ) . '</a></div>';+ return ob_get_clean();+ }+} elseif ( 'guest' == $raiser_default ) {+ if ( is_user_logged_in() ) {+ echo '<div class="form-elements"><span>' . esc_html__( 'You must Logout to Raise Ticket', 'wsdesk' ) . '</span><br><a class="btn btn-primary" href="' . esc_url( wp_logout_url( $logout_redirect_url ) ) . '">' . esc_html__( 'Logout', 'wsdesk' ) . '</a></div>';+ return ob_get_clean();+ }+}+$args = array( 'type' => 'field' );+$fields = array( 'slug', 'title', 'settings_id' );+$avail_fields = eh_crm_get_settings( $args, $fields );+$selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' );++if ( empty( $selected_fields ) ) {+ $selected_fields = array( 'request_email', 'request_title', 'request_description' );+}+if ( isset( $cus_fields ) && ! empty( $cus_fields ) && is_array( $cus_fields ) ) {+ $select_val = array();+ foreach ( $cus_fields as $value ) {+ if ( in_array( $value, $selected_fields ) ) {+ array_push( $select_val, $value );+ }+ }+ $selected_fields = $select_val;+}+if ( ! in_array( 'request_description', $selected_fields ) ) {+ array_unshift( $selected_fields, 'request_description' );+}+if ( ! in_array( 'request_title', $selected_fields ) ) {+ array_unshift( $selected_fields, 'request_title' );+}+if ( ! in_array( 'request_email', $selected_fields ) ) {+ array_unshift( $selected_fields, 'request_email' );+}+$input_width = eh_crm_get_settingsmeta( 0, 'input_width' );+$etitle = eh_crm_get_settingsmeta( 0, 'new_ticket_form_title' );++$etitle = eh_crm_wpml_translations( $etitle, 'title', 'title' );++$submit = eh_crm_get_settingsmeta( 0, 'submit_ticket_button' );++if ( ! $submit ) {+ $submit = __( 'Submit Request', 'wsdesk' );+}++$submit = eh_crm_wpml_translations( $submit, 'submit', 'submit' );++$reset = eh_crm_get_settingsmeta( 0, 'reset_ticket_button' );++if ( ! $reset ) {+ $reset = __( 'Reset Request', 'wsdesk' );+}++$reset = eh_crm_wpml_translations( $reset, 'reset', 'reset' );++$existing = eh_crm_get_settingsmeta( 0, 'existing_ticket_button' );+if ( ! $existing ) {+ $existing = __( 'Check your Existing Request', 'wsdesk' );+}++$existing = eh_crm_wpml_translations( $existing, 'existing', 'existing' );+if ( isset( $display ) && ( 'form' === $display ) ) {+ echo '+ <div class="support_option_choose">+ <a href="' . esc_html( eh_get_url_by_shortcode( '[wsdesk_support display="check_request"' ) ) . '" target="_blank" data-loading-text="' . esc_html__( 'Loading your Request...', 'wsdesk' ) . '" class="btn btn-primary eh_crm_check_request" role="button">+ ' . esc_html( $existing ) . '+ </a>+ </div>';+}+?>++<div class="main_new_suppot_request_form">+ <style>+ .support_form+ {+ width: <?php echo esc_html( $input_width ); ?>% !important;+ }+ </style>+ <form class="support_form" id="eh_crm_ticket_form">++<?php+echo ( '' !== $etitle ) ? '<h3>' . esc_html( $etitle ) . '</h3>' : '';++$urole = '';+if ( is_user_logged_in() ) {+ if ( isset( wp_get_current_user()->roles ) ) {+ $ewp_roles = array( 'administrator', 'WSDesk_Agents', 'WSDesk_Supervisor' );+ foreach ( $ewp_roles as $wp_role ) {++ $role_index = array_search( $wp_role, wp_get_current_user()->roles );+ if ( $role_index ) {+ $urole = wp_get_current_user()->roles[ $role_index ];+ break;+ }+ }+ }+}+for ( $i = 0; $i < count( $selected_fields ); $i++ ) {+ for ( $j = 0; $j < count( $avail_fields ); $j++ ) {+ $current_meta = eh_crm_get_settingsmeta( $avail_fields[ $j ]['settings_id'] );+ if ( $avail_fields[ $j ]['slug'] === $selected_fields[ $i ] && ( ! isset( $current_meta['field_visible'] ) || 'yes' === $current_meta['field_visible'] || 'ip' == $current_meta['field_type'] || in_array( $avail_fields[ $j ]['slug'], array( 'request_email', 'request_title', 'request_description' ) ) ) ) {+ echo '<div class="form-elements">';+ if ( 'WSDesk_Agents' == $urole ) {+ $required = ( isset( $current_meta['field_require_agent'] ) ? $current_meta['field_require_agent'] : '' );+ } elseif ( 'WSDesk_Supervisor' == $urole || 'administrator' == $urole ) {+ $required = 'no';+ } else {+ $required = ( isset( $current_meta['field_require'] ) ? $current_meta['field_require'] : '' );+ }++ $required = ( 'yes' === $required || in_array( $avail_fields[ $j ]['slug'], array( 'request_email', 'request_title', 'request_description' ) ) ) ? 'required' : '';+ if ( 'ip' == $current_meta['field_type'] ) {+ echo '<input type="hidden" value="' . esc_html( isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : null ) . '" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" class="input_element form-control">';+ } else {+ if ( 'request_description' != $avail_fields[ $j ]['slug'] ) {+ $field_title = eh_crm_wpml_translations( $avail_fields[ $j ]['title'], $avail_fields[ $j ]['settings_id'] . '_field_title', $avail_fields[ $j ]['settings_id'] . '_field_title' );+ if ( is_user_logged_in() && 'request_email' != $avail_fields[ $j ]['slug'] && 'request_title' != $avail_fields[ $j ]['slug'] && 'request_description' != $avail_fields[ $j ]['slug'] ) {+ echo '<span>' . esc_html( $field_title ) . ' </span>';+ }+ }+ }+ if ( 'request_description' != $avail_fields[ $j ]['slug'] && 'request_email' != $avail_fields[ $j ]['slug'] && 'request_title' != $avail_fields[ $j ]['slug'] ) {+ echo ( 'required' === $required ) ? '<span class="input_required">*</span>' : ' <br>';+ }++ $default_values = ( isset( $current_meta['field_default'] ) ? $current_meta['field_default'] : '' );++ switch ( $current_meta['field_type'] ) {+ case 'text':+ if ( is_user_logged_in() && 'request_title' == $avail_fields[ $j ]['slug'] ) {+ $default_values = eh_crm_wpml_translations( $default_values, $avail_fields[ $j ]['settings_id'] . '_field_default', $avail_fields[ $j ]['settings_id'] . '_field_default' );+ $default_values = '';++ $field_placeholder = eh_crm_wpml_translations( $current_meta['field_placeholder'], $avail_fields[ $j ]['settings_id'] . '_field_placeholder', $avail_fields[ $j ]['settings_id'] . '_field_placeholder' );+ echo '<input type="text" autocomplete="off" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $field_placeholder ) . '" ' . esc_html( $required ) . '>';+ break;+ } else {+ $default_values = eh_crm_wpml_translations( $default_values, $avail_fields[ $j ]['settings_id'] . '_field_default', $avail_fields[ $j ]['settings_id'] . '_field_default' );++ $field_placeholder = eh_crm_wpml_translations( $current_meta['field_placeholder'], $avail_fields[ $j ]['settings_id'] . '_field_placeholder', $avail_fields[ $j ]['settings_id'] . '_field_placeholder' );+ echo '<input type="text" autocomplete="off" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $field_placeholder ) . '" ' . esc_html( $required ) . '>';+ break;+ }+ case 'email':+ $email = '';+ if ( is_user_logged_in() && 'request_email' == $avail_fields[ $j ]['slug'] ) {+ $uid = get_current_user_id();+ $user = new WP_User( $uid );+ $default_values = $user->user_email;+ $field_placeholder = eh_crm_wpml_translations( $current_meta['field_placeholder'], $avail_fields[ $j ]['settings_id'] . '_field_placeholder', $avail_fields[ $j ]['settings_id'] . '_field_placeholder' );+ echo '<input type="email" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $field_placeholder ) . '"' . esc_html( $required ) . ' >';+ break;+ } else {+ $field_placeholder = eh_crm_wpml_translations( $current_meta['field_placeholder'], $avail_fields[ $j ]['settings_id'] . '_field_placeholder', $avail_fields[ $j ]['settings_id'] . '_field_placeholder' );+ echo '<input type="email" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $field_placeholder ) . '"' . esc_html( $required ) . '>';+ break;+ }++ case 'phone':+ echo '<br><span><strong>+</strong><input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $current_meta['field_placeholder'] ) . '"' . esc_html( $required ) . ' style="display: inline; width: 99% !important"></span>';+ break;+ case 'number':+ echo '<input type="number" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $current_meta['field_placeholder'] ) . '"' . esc_html( $required ) . '>';+ break;+ case 'password':+ echo '<input type="password" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" value="' . esc_html( $default_values ) . '" class="input_element form-control" placeholder="' . esc_html( $current_meta['field_placeholder'] ) . '"' . esc_html( $required ) . '>';+ break;+ case 'select':+ $field_values = $current_meta['field_values'];+ $customer_temp_altered = array();+ $return = array();+ if ( 'woo_order_id' == $selected_fields[ $i ] ) {+ $uid = get_current_user_id();+ if ( 0 != $uid ) {+ $customer_orders = wc_get_orders( array( 'customer_id' => $uid ) );+ if ( count( $customer_orders ) > 0 ) {+ foreach ( $customer_orders as $key => $customer_order ) {+ array_push( $customer_temp_altered, trim( str_replace( ' ', '', $customer_order->get_order_number() ) ) );+ }+ for ( $g = 0;$g < count( $customer_temp_altered );$g++ ) {+ $return[ $g ] = $customer_temp_altered[ $g ];+ }+ echo '<select class="input_element form-control" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" ' . esc_html( $required ) . '>';+ echo '<option value="">' . ( isset( $current_meta['field_placeholder'] ) ? esc_html( $current_meta['field_placeholder'] ) : '-' ) . '</option>';+ foreach ( $return as $key => $val ) {+ $select_default = '';+ if ( $default_values === $val ) {+ $select_default = 'selected';+ }+ $field_values_tranlsated = eh_crm_wpml_translations( $val, $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' );+ echo '<option value="' . esc_html( $val ) . '" ' . esc_html( $select_default ) . '>' . esc_html( $field_values_tranlsated ) . '</option>';+ }+ echo '</select>';+ break;+ }+ }+ } else {+ $field_values = $current_meta['field_values'];+ $field_keys = array_keys( $field_values );+ echo '<select class="input_element form-control" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" ' . esc_html( $required ) . '>';+ echo '<option value="">' . ( isset( $current_meta['field_placeholder'] ) ? esc_html( $current_meta['field_placeholder'] ) : '-' ) . '</option>';++ $field_order = array_intersect( $field_order, array_keys( $current_meta['field_values'] ) );+ $field_order = isset( $current_meta['field_order'] ) ? array_values( array_unique( $current_meta['field_order'] ) ) : ( isset( $field_keys ) ? $field_keys : array() );+ foreach ( $field_order as $value ) {+ $key = $value;+ $select_default = '';+ if ( $default_values === $key ) {+ $select_default = 'selected';+ }+ $field_values_tranlsated = eh_crm_wpml_translations( $field_values[ $key ], $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' );+ echo '<option value="' . esc_html( $key ) . '" ' . esc_html( $select_default ) . '>' . esc_html( $field_values_tranlsated ) . '</option>';+ }+ echo '</select>';+ break;+ }+ break;+ case 'radio':+ $field_values = $current_meta['field_values'];+ echo '<span style="vertical-align: middle;display: block;">';+ foreach ( $field_values as $key => $value ) {+ $radio_default = '';+ if ( $default_values === $key ) {+ $radio_default = 'checked';+ }+ $field_values_tranlsated = eh_crm_wpml_translations( $value, $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' );+ echo '<input type="radio" class="form-control" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" style="margin-top: 0;" value="' . esc_html( $key ) . '" ' . esc_html( $radio_default ) . ' ' . esc_html( $required ) . '>' . esc_html( $field_values_tranlsated ) . '<br>';+ }+ echo '</span>';+ break;+ case 'checkbox':+ $field_values = $current_meta['field_values'];+ echo '<span style="vertical-align: middle;display: block;">';+ foreach ( $field_values as $key => $value ) {+ $check_default = '';+ if ( $default_values === $key ) {+ $check_default = 'checked';+ }+ $field_values_tranlsated = eh_crm_wpml_translations( $value, $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values', $avail_fields[ $j ]['settings_id'] . '_' . esc_html( $key ) . '_field_values' );+ echo '<input type="checkbox" class="form-control" name="' . esc_attr( $selected_fields[ $i ] ) . '[]" id="' . esc_attr( $selected_fields[ $i ] ) . '[]" style="margin-top: 0;" value="' . esc_html( $key ) . '" ' . esc_html( $check_default ) . ' ' . esc_html( $required ) . '> ' . esc_html( $field_values_tranlsated ) . '<br>';+ }+ echo '</span>';+ break;+ case 'textarea':+ if ( 'request_description' == $avail_fields[ $j ]['slug'] ) {++ $required = 'no';+ $default_values = eh_crm_wpml_translations( $default_values, $avail_fields[ $j ]['settings_id'] . '_field_default', $avail_fields[ $j ]['settings_id'] . '_field_default' );+ echo '<textarea name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" class="input_element form-control" ' . esc_html( $required ) . '>' . esc_html( $default_values ) . '</textarea>';+ } else {+ $default_values = eh_crm_wpml_translations( $default_values, $avail_fields[ $j ]['settings_id'] . '_field_default', $avail_fields[ $j ]['settings_id'] . '_field_default' );+ echo '<textarea name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" class="input_element form-control" ' . esc_html( $required ) . '>' . esc_html( $default_values ) . '</textarea>';+ }+ break;+ case 'date':+ echo '<input type="text" autocomplete="off" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" class="input_element form-control trigger_date_jq" placeholder="' . esc_html( $current_meta )['field_placeholder'] . '" ' . esc_html( $required ) . '>';+ break;+ case 'file':+ $file_type = ( 'multiple' === $current_meta['file_type'] ) ? 'multiple' : '';+ if ( 'multiple' === $file_type ) {+ $multiple_required = $required;+ $required = '';+ ?>+ <div class="ticket_multiple_attachments_container <?php echo esc_html( $multiple_required ); ?>">+ <div class="multiple_attachments_previewer">+ <div class="multiple_attachments_previewer_item hidden">+ <span class="file_name">file_name.jpg</span>+ <span class="glyphicon glyphicon-remove remove"></span>+ </div>+ </div>+ <div class="multiple_attachments_drop_zone">+ </div>+ <div class="multiple_attachments_actions">+ <button class="btn btn-primary multiple_attachments_browse_files_trigger" type="button" name="multiple_attachments_browse_files_trigger">+ <i class="glyphicon glyphicon-plus"></i>+ <?php echo esc_html_e( 'Browse files', 'wsdesk' ); ?>+ </button>+ </div>+ </div>+ <?php+ }+ echo '<input type="file" name="' . esc_attr( $selected_fields[ $i ] ) . '" id="' . esc_attr( $selected_fields[ $i ] ) . '" ' . esc_html( $file_type ) . ' class="input_element ' . ( 'multiple' === $file_type ? ' hidden ' : '' ) . 'form-control ticket_attachment" ' . esc_html( $required ) . ' style="height: auto;">';+ break;+ case 'google_captcha':+ echo '<div class="g-recaptcha" data-sitekey="' . esc_html( $current_meta['field_site_key'] ) . '"></div><div class="captcha-error"></div>';+ break;+ }++ $field_description = eh_crm_wpml_translations( $current_meta['field_description'], $avail_fields[ $j ]['settings_id'] . '_field_description', $avail_fields[ $j ]['settings_id'] . '_field_description' );+ echo '<small>' . esc_html( $field_description ) . '</small>';+++ if ( eh_crm_get_settingsmeta( 0, 'auto_suggestion' ) == 'enable' && 'request_title' == $selected_fields[ $i ] ) {+ echo '<div class="auto_suggestion_posts"></div>';+ }+ echo '</div><br>';+ }+ }+}+echo '<button type="button" id="crm_form_submit" class="btn btn-primary" data-loading-text="' . esc_html__( 'Submitting...', 'wsdesk' ) . '">' . esc_html( $submit ) . '</button>';+echo '<button type="reset" class="btn btn-primary wsdesk_crm_reset_button_show_hide" style="margin-left:5px;">' . esc_html( $reset ) . '</button></form>';+echo '</div>';+if ( ! defined( 'WSDESK_POWERED_SUPPORT' ) ) {+ echo '<div class="powered_wsdesk"><span>' . esc_html__( 'Powered by', 'wsdesk' ) . '</span> <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" rel="nofollow">WSDesk</a></div>';+}++$etitle = eh_crm_get_settingsmeta( 0, 'main_ticket_form_title' );+$etitle = eh_crm_wpml_translations( $etitle, 'title', 'title' );+$selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' );+$select_val = array();+if ( is_array( $selected_fields ) ) {+ if ( isset( $cus_fields ) && ! empty( $cus_fields ) && is_array( $cus_fields ) ) {+ $select_val = array_intersect( $selected_fields, $cus_fields );+ }+}+$ticket_id = '';+if ( isset( $_GET['customer_ticket_num'] ) ) {+ $ticket_id = sanitize_text_field( $_GET['customer_ticket_num'] );+} elseif ( ! empty( $_GET ) ) {+ foreach ( $_GET as $query_id => $query_value ) {+ if ( strpos( $query_value, 'customer_ticket_num' ) != '' ) {+ $ticket_id = explode( 'customer_ticket_num=', $query_value )[1];+ break;+ }+ }+}+if ( $ticket_id && is_user_logged_in() ) {+ $ticket = eh_crm_get_ticket( array( 'ticket_id' => $ticket_id ), array( 'ticket_author', 'ticket_email' ) );+ $wcurrent_user = wp_get_current_user();+ if ( $ticket[0]['ticket_email'] == $wcurrent_user->user_email || $ticket[0]['ticket_author'] == $wcurrent_user->ID ) {+ echo'<div class="eh_crm_support_main wsdesk_wrapper">+ <div class="loaderDirect"></div>+ <div class="eh_crm_support_main load_wsdesk_request_ticket_directly">+ <div class="ticket_table_wrapper">+ <div class="ticket_load_content"></div>+ </div>+ </div>+ </div>';+ }+} else {+ ?>+<div class="eh_crm_support_main wsdesk_wrapper">+ <input type= "hidden" id="custom_fields" value ="<?php echo esc_html( json_encode( $select_val ) ); ?>"/>+ <?php echo ( '' !== $etitle ) ? '<h3>' . esc_html( $etitle ) . '</h3>' : ''; ?>+ <div class="wsdesk_wrapper">+ <div class="loaderDirect"></div>+ <div class="eh_crm_support_main load_wsdesk_request_directly wsdesk_new_ticket_view">+ <div class="ticket_table_wrapper"></div>+ </div>+ </div>+</div>+ <?php+}+if ( ! defined( 'WSDESK_POWERED_SUPPORT' ) ) {+ echo '<div id="check_request_powered_wsdesk" class="powered_wsdesk"><span>' . esc_html__( 'Powered by', 'wsdesk' ) . '</span> <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank" rel="nofollow">WSDesk</a></div>';+}++return ob_get_clean();
Vulnerability Existed: no Explanation: This diff shows only a line ending change (CRLF to LF conversion) across the entire file. The actual PHP code content remains identical between version 3.3.4 and 3.3.5. There are no code logic changes, no new security fixes, and no vulnerabilities introduced or removed. The file structure, all function calls, output escaping with `esc_html()`, `esc_attr()`, `esc_url()`, and all security patterns remain exactly the same.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/shortcodes/crm_support_page.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/shortcodes/crm_support_page.php 2025-12-21 09:36:35.511308688 +0000@@ -1,60 +1,60 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -ob_start(); -$utitle = eh_crm_get_settingsmeta( 0, 'main_ticket_form_title' ); -$utitle = eh_crm_wpml_translations( $utitle, 'title', 'title' ); -$existing = eh_crm_get_settingsmeta( 0, 'existing_ticket_button' ); -$existing = eh_crm_wpml_translations( $existing, 'existing', 'existing' ); -$submit = eh_crm_get_settingsmeta( 0, 'submit_ticket_button' ); -$submit = eh_crm_wpml_translations( $submit, 'submit', 'submit' ); -if ( ! $submit ) { - $submit = __( 'Submit Request', 'wsdesk' ); -} -if ( ! $existing ) { - $existing = __( 'Check your Existing Request', 'wsdesk' ); -} - -$flag = false; -if ( isset( $_GET['customer_ticket_num'] ) ) { - $flag = true; -} elseif ( ! empty( $_GET ) ) { - foreach ( $_GET as $query_id => $query_value ) { - if ( strpos( $query_value, 'customer_ticket_num' ) != '' ) { - $flag = true; - break; - } - } -} -if ( $flag ) { - - echo'<div class="wsdesk_wrapper"> - <div class="loaderDirect"></div> - <div class="eh_crm_support_main load_wsdesk_request_ticket_directly"> - <div class="ticket_table_wrapper"> - <div class="ticket_load_content"></div> - </div> - </div> - </div>'; - die(); -} - -?> -<div class="eh_crm_support_main wsdesk_wrapper"> - <div class="support_option_choose"> - <?php echo ( '' !== $utitle ) ? '<h3>' . esc_html( $utitle ) . '</h3>' : ''; ?> - <button data-loading-text="<?php esc_html_e( 'Fetching Request Form...', 'wsdesk' ); ?>" class="btn btn-primary eh_crm_new_request"> - <?php echo esc_html( $submit ); ?> - </button> - <br> - <br> - <a href='<?php echo esc_url( eh_get_url_by_shortcode( '[wsdesk_support display="check_request"' ) ); ?>' target="_blank" data-loading-text="<?php esc_html_e( 'Loading your Request...', 'wsdesk' ); ?>" class="btn btn-primary eh_crm_check_request" role="button"> - <?php echo esc_html( $existing ); ?> - </a> - </div> - <div class="ticket_table_wrapper"> - </div> -</div> -<?php -return ob_get_clean(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+ob_start();+$utitle = eh_crm_get_settingsmeta( 0, 'main_ticket_form_title' );+$utitle = eh_crm_wpml_translations( $utitle, 'title', 'title' );+$existing = eh_crm_get_settingsmeta( 0, 'existing_ticket_button' );+$existing = eh_crm_wpml_translations( $existing, 'existing', 'existing' );+$submit = eh_crm_get_settingsmeta( 0, 'submit_ticket_button' );+$submit = eh_crm_wpml_translations( $submit, 'submit', 'submit' );+if ( ! $submit ) {+ $submit = __( 'Submit Request', 'wsdesk' );+}+if ( ! $existing ) {+ $existing = __( 'Check your Existing Request', 'wsdesk' );+}++$flag = false;+if ( isset( $_GET['customer_ticket_num'] ) ) {+ $flag = true;+} elseif ( ! empty( $_GET ) ) {+ foreach ( $_GET as $query_id => $query_value ) {+ if ( strpos( $query_value, 'customer_ticket_num' ) != '' ) {+ $flag = true;+ break;+ }+ }+}+if ( $flag ) {++ echo'<div class="wsdesk_wrapper">+ <div class="loaderDirect"></div>+ <div class="eh_crm_support_main load_wsdesk_request_ticket_directly">+ <div class="ticket_table_wrapper">+ <div class="ticket_load_content"></div>+ </div>+ </div>+ </div>';+ die();+}++?>+<div class="eh_crm_support_main wsdesk_wrapper">+ <div class="support_option_choose">+ <?php echo ( '' !== $utitle ) ? '<h3>' . esc_html( $utitle ) . '</h3>' : ''; ?>+ <button data-loading-text="<?php esc_html_e( 'Fetching Request Form...', 'wsdesk' ); ?>" class="btn btn-primary eh_crm_new_request">+ <?php echo esc_html( $submit ); ?>+ </button>+ <br>+ <br>+ <a href='<?php echo esc_url( eh_get_url_by_shortcode( '[wsdesk_support display="check_request"' ) ); ?>' target="_blank" data-loading-text="<?php esc_html_e( 'Loading your Request...', 'wsdesk' ); ?>" class="btn btn-primary eh_crm_check_request" role="button">+ <?php echo esc_html( $existing ); ?>+ </a>+ </div>+ <div class="ticket_table_wrapper">+ </div>+</div>+<?php+return ob_get_clean();
I've analyzed the provided code diff. This diff contains only whitespace/line ending changes (CRLF to LF conversion) with no functional code modifications. **Analysis Result:** Vulnerability Existed: no **Explanation:** The diff shows no security-relevant changes. The modifications are purely formatting: - Line ending conversions (Windows CRLF → Unix LF) - No code logic alterations - No changes to security-sensitive operations - All existing security practices remain unchanged: - `esc_html()` and `esc_url()` escaping functions remain in place - `$_GET` superglobal access patterns unchanged (potential XSS/CSRF concerns already present before and after, but not introduced by this diff) - No new vulnerable code introduced - No security fixes applied Since there are no functional code changes, there are no new vulnerabilities introduced and no existing vulnerabilities fixed in this commit.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/tickets/crm_archive_tickets.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/tickets/crm_archive_tickets.php 2025-12-21 09:36:35.511308688 +0000@@ -1,635 +1,635 @@-<?php -$time = microtime( true ); -require_once EH_CRM_MAIN_PATH . '/vendor/autoload.php'; - -use Illuminate\Support\Arr; -use WSDesk\Settings\SettingsRepository; - - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -ob_start(); -$settings = new SettingsRepository(); - -$avail_labels_wf = $settings->getLabels(); -$avail_labels_f = $settings->getFilterableLabels(); - -$avail_tags_wf = $settings->getTags(); -$avail_tags_f = $settings->getFilterableTags(); - -$avail_templates = $settings->getTemplates(); -$avail_fields = $settings->getFields(); - -$tickets_display = eh_crm_get_settingsmeta( '0', 'tickets_display' ); -if ( ! $avail_templates ) { -$avail_templates = array(); -} -$user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ); -$user_caps_default = array( 'reply_tickets', 'delete_tickets', 'manage_tickets' ); -$users_data = get_users( array( 'role__in' => $user_roles_default ) ); - -$users_data = array_map( - function ( $user ) { - return array( - 'id' => $user->ID, - 'name' => $user->display_name, - 'caps' => $user->caps, - 'email' => $user->user_email, - ); - }, - $users_data -); -$users_data = array_key_by( $users_data, 'id' ); - -$table_title = 'Archived Tickets'; -$ticket_rows = eh_crm_get_settingsmeta( 0, 'ticket_rows' ); -if ( '' == $ticket_rows ) { - $ticket_rows = 25; -} -$current_page = Arr::get( $_GET, 'page_no', 0 ); - -$offset = ( $current_page ) * $ticket_rows; -$section_tickets_id = eh_crm_get_ticket_value_count_archive( 'ticket_parent', 0, false, '', '', 'ticket_updated', 'DESC', $ticket_rows, $offset ); -$archived_ticket_ids = Arr::pluck( $section_tickets_id, 'ticket_id' ); -$archived_tickets = eh_crm_get_ticket_archive( [ 'ticket_id' => $archived_ticket_ids ] ); -$archived_tickets = false === $archived_tickets ? array() : $archived_tickets; -$archived_tickets = array_key_by( $archived_tickets, 'ticket_id' ); - -$archived_tickets_meta = eh_crm_get_ticketmeta_archive( $archived_ticket_ids ); -//dd($archived_tickets_meta); -$total_no_of_tickets = wpElexFluent()->table( 'wsdesk_archived_tickets' )->where( 'ticket_parent', 0 )->count(); - -$total_no_of_voices = wpElexFluent()->table( 'wsdesk_archived_tickets' ) - ->where( 'ticket_trash', 0 ) - ->whereIn( 'ticket_parent', $archived_ticket_ids ) - ->select( \DB::raw( 'ticket_parent, count(ticket_id) as count, ticket_category' ) ) - ->groupBy( [ 'ticket_category', 'ticket_parent' ] ) - ->get(); -$total_no_of_voices = array_map( - function ( $status ) { - return array( - 'ticket_id' => $status['ticket_parent'], - $status['ticket_category'] => $status['count'], - ); - }, - $total_no_of_voices -); -$total_no_of_voices = array_group_by( $total_no_of_voices, 'ticket_id' ); - -$total_no_of_voices = array_map( - function ( $replies ) { - return Arr::collapse( $replies ); - }, - $total_no_of_voices -); - -$eye_colors = wpElexFluent()->table( 'wsdesk_settingsmeta' ) - ->whereIn( 'settings_id', Arr::pluck( $avail_labels_wf, 'settings_id' ) ) - ->where( 'meta_key', 'label_color' ) - ->get(); - -$eye_colors = Arr::pluck( $eye_colors, 'meta_value', 'settings_id' ); - -foreach ( $avail_labels_wf as $i => $label ) { - $avail_labels_wf[ $i ]['eye_color'] = Arr::get( $eye_colors, $label['settings_id'], '' ); -} - -//$all_section_ids = eh_crm_get_ticket_value_count_archive("ticket_parent",0,false,"","","ticket_updated","DESC","",0); -$pagination_ids = array(); -//foreach ($all_section_ids as $tic) { -// array_push($pagination_ids,$tic['ticket_id']); -//} -$avail_caps = array( 'reply_tickets', 'delete_tickets', 'manage_tickets', 'manage_templates' ); -$access = array(); -$logged_user = wp_get_current_user(); -$logged_user_caps = array_keys( $logged_user->caps ); -if ( ! in_array( 'administrator', $logged_user->roles ) ) { - for ( $i = 0;$i < count( $logged_user_caps );$i++ ) { - if ( ! in_array( $logged_user_caps[ $i ], $avail_caps ) ) { - unset( $logged_user_caps[ $i ] ); - } - } - $access = $logged_user_caps; -} else { - $access = $avail_caps; -} -if ( ! isset( $_COOKIE['collapsed_views'] ) ) { - $collapsed_views = array(); -} else { - $collapsed_views = stripslashes( sanitize_text_field( $_COOKIE['collapsed_views'] ) ); - $collapsed_views = str_replace( '"', '', $collapsed_views ); - $collapsed_views = str_replace( '[', '', $collapsed_views ); - $collapsed_views = str_replace( ']', '', $collapsed_views ); - $collapsed_views = explode( ',', $collapsed_views ); -} - -$settings_meta_data = []; -$all_ticket_field_views = eh_crm_get_settingsmeta( '0', 'all_ticket_page_columns' ); -$custom_table_headers = array(); -$default_columns = array( 'id', 'requestor', 'subject', 'requested', 'assignee', 'feedback' ); -if ( false === $all_ticket_field_views ) { - $all_ticket_field_views = $default_columns; - eh_crm_update_settingsmeta( '0', 'all_ticket_page_columns', $default_columns ); -} -if ( ! empty( $all_ticket_field_views ) ) { - foreach ( $all_ticket_field_views as $all_ticket_field ) { - if ( in_array( $all_ticket_field, $default_columns ) ) { - switch ( $all_ticket_field ) { - case 'id': - array_push( $custom_table_headers, '<div class="row" style="margin-left: 0px; "># <span class="dashicons dashicons-sort sort-icon" id="id" style="margin-left: 5px;"></span></div>' ); - break; - case 'subject': - array_push( $custom_table_headers, '<div class="row">' . ucfirst( $all_ticket_field ) . '<span class="dashicons dashicons-sort sort-icon" id="subject" style="margin-left: 5px"></span></div>' ); - break; - default: - array_push( $custom_table_headers, ucfirst( $all_ticket_field ) ); - } - } else { - $fields = eh_crm_get_settings( array( 'slug' => $all_ticket_field ), 'title' ); - if ( isset( $fields[0] ) ) { - array_push( $custom_table_headers, $fields[0]['title'] ); - } - } - } -} -?> - -<div class="container"> - <div class="row" style="margin-top: 10px;"> - <div class="col-md-9" style="padding-right:0px;"> - <div class="full_row filter_div" id="dev-table-action-bar" > - <div class="filter-each"><input type="checkbox" class="ticket_select_all"></div> - <div class="filter-each" id="refresh_tickets" style="cursor:pointer;"> - <div class="ticket-refresh-button" data-placement="top" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Refresh', 'wsdesk' ); ?>"> - <span class="glyphicon glyphicon-refresh"></span> - </div> - </div> - <?php - if ( in_array( 'delete_tickets', $access ) ) { - echo '<div class="filter-each ticket-delete-btn multiple_ticket_unarchive_action" id="delete_tickets" style="display: none;"><div class="multiple_ticket_unarchive_action ticket-delete-button" data-placement="top" data-toggle="wsdesk_tooltip" title="' . esc_html__( 'Restore the ticket(s)', 'wsdesk' ) . '"><span class="glyphicon glyphicon-folder-open"></span></div></div>'; - } - ?> - - </div> - </div> - <div id="update_template_model_display"></div> - <div id="preview_template_model_display"></div> - <div class="col-md-9" id="right_bar_all_tickets" style="overflow: scroll;padding-right: 0px;width:1250px;"> - <input type="hidden" id="pagination_ids_traverse" value="<?php echo esc_html( json_encode( $pagination_ids ) ); ?>"> - <div class="panel panel-default tickets_panel" style="background-color: white;color: black"> - <div class="panel-heading" style="background-color:white;color:black"> - <h3 class="panel-title"><?php esc_html_e( $table_title, 'wsdesk' ); ?> - <span class="spinner_loader table_loader"> - <span class="bounce1"></span> - <span class="bounce2"></span> - <span class="bounce3"></span> - </span> - </h3> - <div class="pull-right"> - <span class="clickable filter" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Tickets Filter', 'wsdesk' ); ?>" data-container="body"> - <i class="glyphicon glyphicon-filter"></i> - </span> - </div> - <div class="pull-right" style="margin: -25px 0px 0px 0px;"> - <span class="text-muted"><b> - <?php - $page_number = $current_page; -echo esc_html( ( $current_page > 0 ) && ( $current_page * $ticket_rows ) <= $total_no_of_tickets ) ? esc_html( ( ( $current_page ) * $ticket_rows ) + 1 ) : esc_html( '1' ); - ?> - </b>–<b><?php echo esc_html( ( $current_page > 0 ) && ( $current_page * $ticket_rows ) <= $total_no_of_tickets ) ? esc_html( ( $current_page * $ticket_rows ) + count( $section_tickets_id ) ) : esc_html( $ticket_rows ); ?></b> of <b><?php echo esc_html( $total_no_of_tickets ); ?></b></span> - <?php - if ( $page_number >= 0 ) { - $page_number = $current_page + 1; - - $current_page = $current_page; - } - ?> - <input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" name="cur" id="current_page_n" class="btn btn-default pagination_tic" placeholder="<?php esc_html_e( $page_number, 'wsdesk' ); ?>"min=1 title="<?php esc_html_e( 'Page Number', 'wsdesk' ); ?> " - oninput="validity.valid||(value='');" style="width:65px;height:30px" /> - <div class="btn-group btn-group-sm" style="margin:1px 0px 0px 0px;"> - <?php - if ( 0 != $current_page ) { - ?> - <button type="button" class="btn btn-default pagination_tickets" id="prev" title="<?php esc_html_e( 'Previous', 'wsdesk' ); ?> <?php echo esc_html( $ticket_rows ); ?>" data-container="body"> - <span class="glyphicon glyphicon-chevron-left"></span> - </button> - <?php - } - ?> - <?php - if ( 0 == $current_page ) { - ?> - <button type="button" class="btn btn-default pagination_tick" id="pre" title="<?php esc_html_e( 'Beginning of the Page', 'wsdesk' ); ?> "style="color:#AFAFAF; " data-container="body"> - <span class="glyphicon glyphicon-chevron-left"></span> - </button> - <?php - } - ?> - <input type="hidden" id="current_page_no" value="<?php echo esc_html( $current_page ); ?>"> - <?php - //To Hide the preview and next buttons for first and lastpages of tickets - if ( ( ( $current_page * $ticket_rows ) + count( $section_tickets_id ) ) != $total_no_of_tickets ) { - ?> - <button type="button" class="btn btn-default pagination_tickets" id="next" title="<?php esc_html_e( 'Next', 'wsdesk' ); ?> <?php echo esc_html( $ticket_rows ); ?>" data-container="body"> - <span class="glyphicon glyphicon-chevron-right"></span> - </button> - <?php - } - ?> - <?php - if ( ( ( $current_page * $ticket_rows ) + count( $section_tickets_id ) ) == $total_no_of_tickets ) { - ?> - <button type="button" class="btn btn-default pagination_tick" id="nex" title="<?php esc_html_e( 'End of the Page', 'wsdesk' ); ?> "style="color:#AFAFAF; " data-container="body"> - <span class="glyphicon glyphicon-chevron-right"></span> - </button> - <?php - } - ?> - </div> - </div> - </div> - <div class="panel-body"> - <input type="text" class="form-control" id="dev-table-filter" data-action="filter" data-filters="#dev-table" placeholder="<?php esc_html_e( 'Filter Tickets', 'wsdesk' ); ?>" /> - </div> - <table class="table table-hover" id="dev-table"> - <thead> - <tr class="except_view"> - <th style="width: 1%;"></th> - <th style="width: 2%;"><?php esc_html_e( 'View', 'wsdesk' ); ?></th> - <?php - foreach ( $custom_table_headers as $value ) { - echo '<th>' . esc_html( $value ) . '</th>'; - } - ?> - </tr> - </thead> - <tbody> - <?php - if ( empty( $section_tickets_id ) ) { - echo '<tr class="except_view"> - <td colspan="12"> ' . esc_html__( 'No Tickets', 'wsdesk' ) . ' </td></tr>'; - } else { - for ( $i = 0;$i < count( $section_tickets_id );$i++ ) { - //$current = eh_crm_get_ticket_archive(array("ticket_id"=>$section_tickets_id[$i]['ticket_id'])); - $current = [ $archived_tickets[ $section_tickets_id[ $i ]['ticket_id'] ] ]; - $current_meta = $archived_tickets_meta[ $section_tickets_id[ $i ]['ticket_id'] ]; - $action_value = ''; - $assignee_value = ''; - $eye_color = ''; - for ( $j = 0;$j < count( $avail_labels_wf );$j++ ) { - if ( in_array( 'manage_tickets', $access ) ) { - $action_value .= '<li id="' . $current[0]['ticket_id'] . '"><a href="#" class="single_ticket_action" id="' . $avail_labels_wf[ $j ]['slug'] . '">' . esc_html__( 'Mark as', 'wsdesk' ) . ' ' . $avail_labels_wf[ $j ]['title'] . '</a></li>'; - - } - if ( $avail_labels_wf[ $j ]['slug'] == $current_meta['ticket_label'] ) { - $eye_color = $avail_labels_wf[ $j ]['eye_color']; - } - } - foreach ( $users_data as $user ) { - if ( in_array( 'manage_tickets', $access ) ) { - $assignee_value .= '<li id="' . $current[0]['ticket_id'] . '"><a href="#" class="single_ticket_assignee" id="' . $user['id'] . '">' . $user['name'] . '</a></li>'; - } - } - $ticket_raiser = $current[0]['ticket_email']; - $ticket_raiser_email = $current[0]['ticket_email']; - if ( 0 != $current[0]['ticket_author'] ) { - $wcurrent_user = new WP_User( $current[0]['ticket_author'] ); - $ticket_raiser = $wcurrent_user->display_name; - } - $ticket_assignee_name = array(); - $ticket_assignee_email = array(); - if ( isset( $current_meta['ticket_assignee'] ) ) { - $current_assignee = array_values( $current_meta['ticket_assignee'] ); - foreach ( $current_assignee as $assignee_id ) { - if ( isset( $users_data[ $assignee_id ] ) ) { - $ticket_assignee_name[] = $users_data[ $assignee_id ]['name']; - $ticket_assignee_email[] = $users_data[ $assignee_id ]['email']; - } - } - } - $ticket_assignee_name = empty( $ticket_assignee_name ) ? esc_html__( 'No Assignee', 'wsdesk' ) : implode( ', ', $ticket_assignee_name ); - $latest_reply_id = ''; - //$latest_reply_id = eh_crm_get_ticket_value_count_archive("ticket_category","agent_note" ,true,"ticket_parent",$current[0]['ticket_id'],'ticket_id','DESC','1'); - $latest_content = array(); - $attach = ''; - if ( ! empty( $latest_reply_id ) ) { - $latest_ticket_reply = eh_crm_get_ticket_archive( array( 'ticket_id' => $latest_reply_id[0]['ticket_id'] ) ); - $latest_content['content'] = $latest_ticket_reply[0]['ticket_content']; - $latest_content['author_email'] = $latest_ticket_reply[0]['ticket_email']; - $latest_content['reply_date'] = $latest_ticket_reply[0]['ticket_date']; - if ( 0 != $latest_ticket_reply[0]['ticket_author'] ) { - $reply_user = new WP_User( $latest_ticket_reply[0]['ticket_author'] ); - $latest_content['author_name'] = $reply_user->display_name; - } else { - $latest_content['author_name'] = esc_html__( 'Guest', 'wsdesk' ); - } - $latest_reply_meta = eh_crm_get_ticketmeta_archive( $latest_reply_id[0]['ticket_id'] ); - if ( isset( $latest_reply_meta['ticket_attachment'] ) ) { - $attach = ' | <small class="glyphicon glyphicon-pushpin"></small> <small style="opacity:0.7;"> ' . count( $latest_reply_meta['ticket_attachment'] ) . ' ' . esc_html__( 'Attachment', 'wsdesk' ) . '</small>'; - } - } else { - $latest_content['content'] = $current[0]['ticket_content']; - $latest_content['author_email'] = $current[0]['ticket_email']; - $latest_content['reply_date'] = $current[0]['ticket_date']; - if ( 0 != $current[0]['ticket_author'] ) { - $wcurrent_user = new WP_User( $current[0]['ticket_author'] ); - $latest_content['author_name'] = $wcurrent_user->display_name; - } else { - $latest_content['author_name'] = esc_html__( 'Guest', 'wsdesk' ); - } - if ( isset( $current_meta['ticket_attachment'] ) ) { - $attach = ' | <small class="glyphicon glyphicon-pushpin"></small> <small style="opacity:0.7;"> ' . count( $current_meta['ticket_attachment'] ) . ' ' . esc_html__( 'Attachment', 'wsdesk' ) . '</small>'; - } - } - $input_data = ( 'text' != $tickets_display ) ? html_entity_decode( stripslashes( $latest_content['content'] ) ) : stripslashes( $latest_content['content'] ); - $input_array[0] = '/<((html)[^>]*)>(.*)\<\/(html)>/Us'; - $input_array[1] = '/<((head)[^>]*)>(.*)\<\/(head)>/Us'; - $input_array[2] = '/<((style)[^>]*)>(.*)\<\/(style)>/Us'; - $input_array[3] = '/<((body)[^>]*)>(.*)\<\/(body)>/Us'; - $input_array[4] = '/<((form)[^>]*)>(.*)\<\/(form)>/Us'; - $input_array[5] = '/<((input)[^>]*)>(.*)\<\/(input)>/Us'; - $input_array[6] = '/<((input)[^>]*)>/Us'; - $input_array[7] = '/<((button)[^>]*)>(.*)\<\/(button)>/Us'; - $input_array[8] = '/<((iframe)[^>]*)>(.*)\<\/(iframe)>/Us'; - $input_array[9] = '/<((script)[^>]*)>(.*)\<\/(script)>/Us'; - $input_array[10] = '/<((ins)[^>]*)>(.*)\<\/(ins)>/Us'; - $output_array[0] = '<$1>$3</html>'; - $output_array[1] = '<$1>$3</head>'; - $output_array[2] = '<$1>$3</style>'; - $output_array[3] = '<$1>$3</body>'; - $output_array[4] = '<$1>$3</form>'; - $output_array[5] = '<$1>$3</input>'; - $output_array[6] = '<$1>$3</input>'; - $output_array[7] = '<$1>$3</button>'; - $output_array[8] = '<$1>$3</iframe>'; - $output_array[9] = '<$1>$3</script>'; - $output_array[10] = '<$1>$3</ins>'; - $latest_content['content'] = preg_replace( $input_array, $output_array, $input_data ); - $latest_content['content'] = str_replace( '<script>', '<script>', $latest_content['content'] ); - $ticket_tags = ''; - if ( ! empty( $avail_tags_wf ) ) { - for ( $j = 0;$j < count( $avail_tags_wf );$j++ ) { - $current_ticket_tags = ( isset( $current_meta['ticket_tags'] ) ? array_values( $current_meta['ticket_tags'] ) : array() ); - for ( $k = 0;$k < count( $current_ticket_tags );$k++ ) { - if ( $avail_tags_wf[ $j ]['slug'] == $current_ticket_tags[ $k ] ) { - $ticket_tags .= '<span class="label label-info">#' . $avail_tags_wf[ $j ]['title'] . '</span>'; - } - } - } - } - if ( isset( $current_meta['ticket_rating'] ) ) { - if ( 'great' == $current_meta['ticket_rating'] ) { - $ticket_rating = '<span class="glyphicon glyphicon-thumbs-up" style="color: green"></span>'; - } else { - $ticket_rating = '<span class="glyphicon glyphicon-thumbs-down" style="color: red"></span>'; - } - } else { - $ticket_rating = '<span class="glyphicon glyphicon-time"></span>'; - } - $reply_count = Arr::get( $total_no_of_voices, $section_tickets_id[ $i ]['ticket_id'], [] ); - - $raiser_voice = Arr::get( $reply_count, 'raiser_reply', 0 ); - $agent_voice = Arr::get( $reply_count, 'agent_reply', 0 ); - echo ' - <tr data-time="' . esc_html( microtime( true ) - $time ) . '" class="clickable ticket_row" id="' . esc_attr( $current[0]['ticket_id'] ) . '"> - <td class="except_view"><input type="checkbox" class="ticket_select_t" id="ticket_select_t" value="' . esc_html( $current[0]['ticket_id'] ) . '"></td> - <td class="except_view"><button class="btn btn-default btn-xs accordion-toggle quick_view_ticket" style="background-color: ' . esc_html( $eye_color ) . ' !important" data-toggle="collapse" data-target="#expand_' . esc_attr( $current[0]['ticket_id'] ) . '" ><span class="glyphicon glyphicon-eye-open"></span></button></td>'; - if ( ! empty( $all_ticket_field_views ) ) { - foreach ( $all_ticket_field_views as $all_ticket_field ) { - switch ( $all_ticket_field ) { - case 'id': - echo '<td>' . esc_html( $current[0]['ticket_id'] ) . '</td>'; - break; - case 'requestor': - echo '<td>' . esc_html( $ticket_raiser ) . '</td>'; - break; - case 'subject': - echo '<td class="wrap_content" data-toggle="wsdesk_tooltip" title="' . esc_html( $current[0]['ticket_title'] ) . '" data-container="body">' . esc_html( $current[0]['ticket_title'] ) . '</td>'; - break; - case 'requested': - echo '<td>' . esc_html( eh_crm_get_formatted_date( $current[0]['ticket_date'] ) ) . '</td>'; - break; - case 'assignee': - echo '<td>' . esc_html( $ticket_assignee_name ) . '</td>'; - break; - case 'feedback': - echo '<td>' . esc_html( $ticket_rating ) . '</td>'; - break; - default: - if ( ! isset( $settings_meta_data[ $all_ticket_field ]['settings'] ) ) { - $settings_meta_data[ $all_ticket_field ]['settings'] = eh_crm_get_settings( array( 'slug' => $all_ticket_field ), 'settings_id' ); - } - $current_settings_id = Arr::get( $settings_meta_data, $all_ticket_field . '.settings', [] ); - if ( ! isset( $current_settings_id[0]['settings_id'] ) ) { - break; - } - if ( ! isset( $settings_meta_data[ $all_ticket_field ]['meta'] ) ) { - $settings_meta_data[ $all_ticket_field ]['meta'] = eh_crm_get_settingsmeta( $current_settings_id[0]['settings_id'] ); - } - $current_settings_meta = Arr::get( $settings_meta_data, $all_ticket_field . '.meta', [] ); - if ( 'select' == $current_settings_meta['field_type'] ) { - if ( 'woo_order_id' == $all_ticket_field ) { - $current_settings_meta['field_type'] = 'text'; - } - } - if ( 'file' != $current_settings_meta['field_type'] && 'google_captcha' != $current_settings_meta['field_type'] ) { - switch ( $current_settings_meta['field_type'] ) { - case 'select': - case 'radio': - case 'checkbox': - $field_values = $current_settings_meta['field_values']; - if ( isset( $current_meta[ $all_ticket_field ] ) ) { - echo '<td>' . esc_html( $field_values[ $current_meta[ $all_ticket_field ] ] ) . '</td>'; - } else { -echo '<td>-</td>'; - } - break; - default: - if ( isset( $current_meta[ $all_ticket_field ] ) ) { - echo '<td>' . esc_html( $current_meta[ $all_ticket_field ] ) . '</td>'; - } else { -echo '<td>-</td>'; - } - break; - } - } - break; - } - } - } - echo '</tr> - <tr class="except_view"> - <td colspan="12" class="hiddenRow"> - <div class="accordian-body collapse" id="expand_' . esc_html( $current[0]['ticket_id'] ) . '"> - <table class="table table-striped" style="margin-bottom: 0px !important"> - <thead> - <tr> - <td colspan="12" style="white-space: normal;"> - <div style="padding:5px 0px;"> - <small class="glyphicon glyphicon-user"></small> <small style="opacity:0.7;">' . esc_html( $latest_content['author_name'] ) . '</small> - | <small class="glyphicon glyphicon-envelope"></small> <small style="opacity:0.7;">' . esc_html( $latest_content['author_email'] ) . '</small> - | <small class="glyphicon glyphicon-calendar"></small> <small style="opacity:0.7;">' . esc_html( eh_crm_get_formatted_date( $latest_content['reply_date'] ) ) . '</small> - ' . esc_html( $attach ) . ' - </div> - <hr> - <p> - ' . esc_html( $latest_content['content'] ) . ' - </p> - </td> - </tr> - <tr> - <th>' . esc_html__( 'Actions', 'wsdesk' ) . '</th> - <th>' . esc_html__( 'Assignee', 'wsdesk' ) . '</th> - <th>' . esc_html__( 'Reply Requester', 'wsdesk' ) . '</th> - <th>' . esc_html__( 'Raiser Voices', 'wsdesk' ) . '</th> - <th>' . esc_html__( 'Agent Voices', 'wsdesk' ) . '</th> - <th>' . esc_html__( 'Tags', 'wsdesk' ) . '</th> - <th>' . esc_html__( 'Source', 'wsdesk' ) . '</th> - </tr> - </thead> - <tbody> - <tr> - <td> - <div class="btn-group"> - <button type="button" class="btn btn-default dropdown-toggle single_ticket_action_button_' . esc_html( $current[0]['ticket_id'] ) . '" data-toggle="dropdown"> - ' . esc_html__( 'Actions', 'wsdesk' ) . ' <span class="caret"></span> - </button> - <ul class="dropdown-menu" role="menu"> - ' . ( ( '' != $action_value ) ? esc_html( $action_value ) : '<li style="padding: 3px 20px;">' . esc_html__( 'No Actions', 'wsdesk' ) . '</li>' ) . ' - <li class="divider"></li> - <li class="text-center"> - <small class="text-muted"> - ' . esc_html__( 'Select label to assign', 'wsdesk' ) . ' - </small> - </li> - </ul> - </div> - </td> - <td> - <div class="btn-group"> - <button type="button" class="btn btn-default dropdown-toggle single_ticket_assignee_button_' . esc_html( $current[0]['ticket_id'] ) . '" data-toggle="dropdown"> - ' . esc_html__( 'Assignee', 'wsdesk' ) . ' <span class="caret"></span> - </button> - <ul class="dropdown-menu" role="menu"> - ' . ( ( '' != $assignee_value ) ? esc_html( $assignee_value ) : '<li style="padding: 3px 20px;">' . esc_html__( 'No Assignee', 'wsdesk' ) . '</li>' ) . ' - <li class="divider"></li> - <li class="text-center"> - <small class="text-muted"> - ' . esc_html__( 'Select assignee to assign', 'wsdesk' ) . ' - </small> - </li> - </ul> - </div> - </td> - <td> - <a href="#reply_' . esc_html( $current[0]['ticket_id'] ) . '" data-toggle="modal" title="' . esc_html__( 'Compose Reply', 'wsdesk' ) . '"> - ' . esc_html( $current[0]['ticket_email'] ) . ' - </a> - </td> - <td>' . esc_html( $raiser_voice ) . '</td> - <td>' . esc_html( $agent_voice ) . '</td> - <td>' . ( ( '' != $ticket_tags ) ? esc_html( $ticket_tags ) : esc_html__( 'No Tags', 'wsdesk' ) ) . '</td> - <td>' . ( ( isset( $current_meta['ticket_source'] ) ) ? esc_html( $current_meta['ticket_source'] ) : esc_html__( 'Unknown', 'wsdesk' ) ) . '</td> - </tr> - </tbody> - </table> - <!-- Modal --> - <div aria-hidden="true" aria-labelledby="myModalLabel" role="dialog" tabindex="-1" id="reply_' . esc_attr( $current[0]['ticket_id'] ) . '" class="modal fade" style="display: none;"> - <div class="modal-dialog"> - <div class="modal-content"> - <div class="modal-header"> - <button aria-hidden="true" data-dismiss="modal" class="close" type="button">×</button> - <h4 class="modal-title">' . esc_html__( 'Ticket', 'wsdesk' ) . ' #' . esc_html( $current[0]['ticket_id'] ) . ' ' . esc_html__( 'Compose Reply', 'wsdesk' ) . '</h4> - </div> - <div class="modal-body"> - <p style="margin-top: 5px;font-size: 16px;"> - '; - if ( in_array( 'manage_tickets', $access ) ) { - echo '<input type="text" value="' . esc_html( $current[0]['ticket_title'] ) . '" id="direct_ticket_title_' . esc_html( $current[0]['ticket_id'] ) . '" class="ticket_title_editable">'; - } else { - echo esc_html( $current[0]['ticket_title'] ); - } - if ( in_array( 'reply_tickets', $access ) ) { - ?> - </p> - <div class="row" style="margin-bottom: 20px;"> - <div class="col-md-12"> - <div class="widget-area no-padding blank"> - <div class="status-upload"> - <div rows="10" cols="30" class="textarea form-control direct_reply_textarea" id="direct_reply_textarea_<?php echo esc_html( $current[0]['ticket_id'] ); ?>" name="reply_textarea_<?php echo esc_html( $current[0]['ticket_id'] ); ?>"></div> - <div class="form-group"> - <div class="input-group col-md-12"> - <span class="btn btn-primary fileinput-button"> - <i class="glyphicon glyphicon-plus"></i> - <span><?php esc_html_e( 'Attachment', 'wsdesk' ); ?></span> - <input type="file" name="direct_files" id="direct_files_<?php echo esc_html( $current[0]['ticket_id'] ); ?>" class="direct_attachment_reply" multiple=""> - </span> - <div class="btn-group pull-right"> - <button type="button" class="btn btn-primary dropdown-toggle direct_ticket_reply_action_button_<?php echo esc_html( $current[0]['ticket_id'] ); ?>" data-toggle="dropdown" aria-haswsdesk-popup="true" aria-expanded="false"> - <?php esc_html_e( 'Submit as', 'wsdesk' ); ?> <span class="caret"></span> - </button> - <ul class="dropdown-menu"> - <?php - for ( $j = 0;$j < count( $avail_labels_wf );$j++ ) { - echo '<li id="' . esc_html( $current[0]['ticket_id'] ) . '"><a href="#" class="direct_ticket_reply_action" id="' . esc_html( $avail_labels_wf[ $j ]['slug'] ) . '">' . esc_html__( 'Submit as', 'wsdesk' ) . ' ' . esc_html( $avail_labels_wf[ $j ]['title'] ) . '</a></li>'; - } - ?> - <li role="separator" class="divider"></li> - <li id="<?php echo esc_html( $current[0]['ticket_id'] ); ?>"><a href="#" class="direct_ticket_reply_action" id="note"><?php esc_html_e( 'Submit as Note', 'wsdesk' ); ?></a></li> - <li class="text-center"><small class="text-muted"><?php esc_html_e( 'Notes visible to Agents and Supervisors', 'wsdesk' ); ?></small></li> - </ul> - </div> - </div> - <div class="direct_upload_preview_files_<?php echo esc_html( $current[0]['ticket_id'] ); ?>"></div> - </div> - </div><!-- Status Upload --> - </div><!-- Widget Area --> - </div> - </div> - <?php - } else { - echo '<p>' . esc_html__( "You don't Have permisson to Reply this ticket", 'wsdesk' ) . '</p>'; - } - echo' - </div><!-- /.modal-content --> - </div><!-- /.modal-dialog --> - </div><!-- /.modal --> - </div> - </td> - </tr > - '; - } - } - ?> - </tbody> - </table> - </div> - </div> - </div> -</div> -<script>deepview();</script> -<div id="wsdesk-template-wsdesk-popup" class="wsdesk-overlay"> - <div class="wsdesk-popup"> - <h4>Available Templates</h4> - <a class="close" href="#">×</a> - <div class="content"> - <div class="wsdesk-overlay-success" style="display: none;"> - <?php esc_html_e( 'Template Added !', 'wsdesk' ); ?> - </div> - <?php - if ( ! empty( $avail_templates ) ) { - for ( $i = 0;$i < count( $avail_templates );$i++ ) { - echo '<li class="list-group-item available_template ' . esc_html( $avail_templates[ $i ]['slug'] ) . '_li" title="' . esc_html( $avail_templates[ $i ]['title'] ) . '"> <span class="truncate multiple_template_action ' . esc_html( $avail_templates[ $i ]['slug'] ) . '_head" based="bulk" id="' . esc_html( $avail_templates[ $i ]['slug'] ) . '">' . esc_html( $avail_templates[ $i ]['title'] ) . '</span>'; - if ( in_array( 'manage_templates', $access ) ) { - echo '<span class="pull-right"> <span class="glyphicon glyphicon-pencil ticket_template_edit_type" id="' . esc_html( $avail_templates[ $i ]['slug'] ) . '" data-toggle="wsdesk_tooltip" data-container="body" title="' . esc_html__( 'Edit Template', 'wsdesk' ) . '" style="margin-right:5px;cursor:pointer;font-size: large;"></span></span>'; - } - echo '</li>'; - } - } - ?> - </div> - </div> -</div> -<?php -return ob_get_clean(); +<?php+$time = microtime( true );+require_once EH_CRM_MAIN_PATH . '/vendor/autoload.php';++use Illuminate\Support\Arr;+use WSDesk\Settings\SettingsRepository;+++if ( ! defined( 'ABSPATH' ) ) {+ exit;+}+ob_start();+$settings = new SettingsRepository();++$avail_labels_wf = $settings->getLabels();+$avail_labels_f = $settings->getFilterableLabels();++$avail_tags_wf = $settings->getTags();+$avail_tags_f = $settings->getFilterableTags();++$avail_templates = $settings->getTemplates();+$avail_fields = $settings->getFields();++$tickets_display = eh_crm_get_settingsmeta( '0', 'tickets_display' );+if ( ! $avail_templates ) {+$avail_templates = array();+}+$user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' );+$user_caps_default = array( 'reply_tickets', 'delete_tickets', 'manage_tickets' );+$users_data = get_users( array( 'role__in' => $user_roles_default ) );++$users_data = array_map(+ function ( $user ) {+ return array(+ 'id' => $user->ID,+ 'name' => $user->display_name,+ 'caps' => $user->caps,+ 'email' => $user->user_email,+ );+ },+ $users_data+);+$users_data = array_key_by( $users_data, 'id' );++$table_title = 'Archived Tickets';+$ticket_rows = eh_crm_get_settingsmeta( 0, 'ticket_rows' );+if ( '' == $ticket_rows ) {+ $ticket_rows = 25;+}+$current_page = Arr::get( $_GET, 'page_no', 0 );++$offset = ( $current_page ) * $ticket_rows;+$section_tickets_id = eh_crm_get_ticket_value_count_archive( 'ticket_parent', 0, false, '', '', 'ticket_updated', 'DESC', $ticket_rows, $offset );+$archived_ticket_ids = Arr::pluck( $section_tickets_id, 'ticket_id' );+$archived_tickets = eh_crm_get_ticket_archive( [ 'ticket_id' => $archived_ticket_ids ] );+$archived_tickets = false === $archived_tickets ? array() : $archived_tickets;+$archived_tickets = array_key_by( $archived_tickets, 'ticket_id' );++$archived_tickets_meta = eh_crm_get_ticketmeta_archive( $archived_ticket_ids );+//dd($archived_tickets_meta);+$total_no_of_tickets = wpElexFluent()->table( 'wsdesk_archived_tickets' )->where( 'ticket_parent', 0 )->count();++$total_no_of_voices = wpElexFluent()->table( 'wsdesk_archived_tickets' )+ ->where( 'ticket_trash', 0 )+ ->whereIn( 'ticket_parent', $archived_ticket_ids )+ ->select( \DB::raw( 'ticket_parent, count(ticket_id) as count, ticket_category' ) )+ ->groupBy( [ 'ticket_category', 'ticket_parent' ] )+ ->get();+$total_no_of_voices = array_map(+ function ( $status ) {+ return array(+ 'ticket_id' => $status['ticket_parent'],+ $status['ticket_category'] => $status['count'],+ );+ },+ $total_no_of_voices+);+$total_no_of_voices = array_group_by( $total_no_of_voices, 'ticket_id' );++$total_no_of_voices = array_map(+ function ( $replies ) {+ return Arr::collapse( $replies );+ },+ $total_no_of_voices+);++$eye_colors = wpElexFluent()->table( 'wsdesk_settingsmeta' )+ ->whereIn( 'settings_id', Arr::pluck( $avail_labels_wf, 'settings_id' ) )+ ->where( 'meta_key', 'label_color' )+ ->get();++$eye_colors = Arr::pluck( $eye_colors, 'meta_value', 'settings_id' );++foreach ( $avail_labels_wf as $i => $label ) {+ $avail_labels_wf[ $i ]['eye_color'] = Arr::get( $eye_colors, $label['settings_id'], '' );+}++//$all_section_ids = eh_crm_get_ticket_value_count_archive("ticket_parent",0,false,"","","ticket_updated","DESC","",0);+$pagination_ids = array();+//foreach ($all_section_ids as $tic) {+// array_push($pagination_ids,$tic['ticket_id']);+//}+$avail_caps = array( 'reply_tickets', 'delete_tickets', 'manage_tickets', 'manage_templates' );+$access = array();+$logged_user = wp_get_current_user();+$logged_user_caps = array_keys( $logged_user->caps );+if ( ! in_array( 'administrator', $logged_user->roles ) ) {+ for ( $i = 0;$i < count( $logged_user_caps );$i++ ) {+ if ( ! in_array( $logged_user_caps[ $i ], $avail_caps ) ) {+ unset( $logged_user_caps[ $i ] );+ }+ }+ $access = $logged_user_caps;+} else {+ $access = $avail_caps;+}+if ( ! isset( $_COOKIE['collapsed_views'] ) ) {+ $collapsed_views = array();+} else {+ $collapsed_views = stripslashes( sanitize_text_field( $_COOKIE['collapsed_views'] ) );+ $collapsed_views = str_replace( '"', '', $collapsed_views );+ $collapsed_views = str_replace( '[', '', $collapsed_views );+ $collapsed_views = str_replace( ']', '', $collapsed_views );+ $collapsed_views = explode( ',', $collapsed_views );+}++$settings_meta_data = [];+$all_ticket_field_views = eh_crm_get_settingsmeta( '0', 'all_ticket_page_columns' );+$custom_table_headers = array();+$default_columns = array( 'id', 'requestor', 'subject', 'requested', 'assignee', 'feedback' );+if ( false === $all_ticket_field_views ) {+ $all_ticket_field_views = $default_columns;+ eh_crm_update_settingsmeta( '0', 'all_ticket_page_columns', $default_columns );+}+if ( ! empty( $all_ticket_field_views ) ) {+ foreach ( $all_ticket_field_views as $all_ticket_field ) {+ if ( in_array( $all_ticket_field, $default_columns ) ) {+ switch ( $all_ticket_field ) {+ case 'id':+ array_push( $custom_table_headers, '<div class="row" style="margin-left: 0px; "># <span class="dashicons dashicons-sort sort-icon" id="id" style="margin-left: 5px;"></span></div>' );+ break;+ case 'subject':+ array_push( $custom_table_headers, '<div class="row">' . ucfirst( $all_ticket_field ) . '<span class="dashicons dashicons-sort sort-icon" id="subject" style="margin-left: 5px"></span></div>' );+ break;+ default:+ array_push( $custom_table_headers, ucfirst( $all_ticket_field ) );+ }+ } else {+ $fields = eh_crm_get_settings( array( 'slug' => $all_ticket_field ), 'title' );+ if ( isset( $fields[0] ) ) {+ array_push( $custom_table_headers, $fields[0]['title'] );+ }+ }+ }+}+?>++<div class="container">+ <div class="row" style="margin-top: 10px;">+ <div class="col-md-9" style="padding-right:0px;">+ <div class="full_row filter_div" id="dev-table-action-bar" >+ <div class="filter-each"><input type="checkbox" class="ticket_select_all"></div>+ <div class="filter-each" id="refresh_tickets" style="cursor:pointer;">+ <div class="ticket-refresh-button" data-placement="top" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Refresh', 'wsdesk' ); ?>">+ <span class="glyphicon glyphicon-refresh"></span>+ </div>+ </div>+ <?php+ if ( in_array( 'delete_tickets', $access ) ) {+ echo '<div class="filter-each ticket-delete-btn multiple_ticket_unarchive_action" id="delete_tickets" style="display: none;"><div class="multiple_ticket_unarchive_action ticket-delete-button" data-placement="top" data-toggle="wsdesk_tooltip" title="' . esc_html__( 'Restore the ticket(s)', 'wsdesk' ) . '"><span class="glyphicon glyphicon-folder-open"></span></div></div>';+ }+ ?>++ </div>+ </div>+ <div id="update_template_model_display"></div>+ <div id="preview_template_model_display"></div>+ <div class="col-md-9" id="right_bar_all_tickets" style="overflow: scroll;padding-right: 0px;width:1250px;">+ <input type="hidden" id="pagination_ids_traverse" value="<?php echo esc_html( json_encode( $pagination_ids ) ); ?>">+ <div class="panel panel-default tickets_panel" style="background-color: white;color: black">+ <div class="panel-heading" style="background-color:white;color:black">+ <h3 class="panel-title"><?php esc_html_e( $table_title, 'wsdesk' ); ?>+ <span class="spinner_loader table_loader">+ <span class="bounce1"></span>+ <span class="bounce2"></span>+ <span class="bounce3"></span>+ </span>+ </h3>+ <div class="pull-right">+ <span class="clickable filter" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Tickets Filter', 'wsdesk' ); ?>" data-container="body">+ <i class="glyphicon glyphicon-filter"></i>+ </span>+ </div>+ <div class="pull-right" style="margin: -25px 0px 0px 0px;">+ <span class="text-muted"><b>+ <?php+ $page_number = $current_page;+echo esc_html( ( $current_page > 0 ) && ( $current_page * $ticket_rows ) <= $total_no_of_tickets ) ? esc_html( ( ( $current_page ) * $ticket_rows ) + 1 ) : esc_html( '1' );+ ?>+ </b>–<b><?php echo esc_html( ( $current_page > 0 ) && ( $current_page * $ticket_rows ) <= $total_no_of_tickets ) ? esc_html( ( $current_page * $ticket_rows ) + count( $section_tickets_id ) ) : esc_html( $ticket_rows ); ?></b> of <b><?php echo esc_html( $total_no_of_tickets ); ?></b></span>+ <?php+ if ( $page_number >= 0 ) {+ $page_number = $current_page + 1;++ $current_page = $current_page;+ }+ ?>+ <input type="number" oninput="this.value = !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null" min="0" name="cur" id="current_page_n" class="btn btn-default pagination_tic" placeholder="<?php esc_html_e( $page_number, 'wsdesk' ); ?>"min=1 title="<?php esc_html_e( 'Page Number', 'wsdesk' ); ?> "+ oninput="validity.valid||(value='');" style="width:65px;height:30px" />+ <div class="btn-group btn-group-sm" style="margin:1px 0px 0px 0px;">+ <?php+ if ( 0 != $current_page ) {+ ?>+ <button type="button" class="btn btn-default pagination_tickets" id="prev" title="<?php esc_html_e( 'Previous', 'wsdesk' ); ?> <?php echo esc_html( $ticket_rows ); ?>" data-container="body">+ <span class="glyphicon glyphicon-chevron-left"></span>+ </button>+ <?php+ }+ ?>+ <?php+ if ( 0 == $current_page ) {+ ?>+ <button type="button" class="btn btn-default pagination_tick" id="pre" title="<?php esc_html_e( 'Beginning of the Page', 'wsdesk' ); ?> "style="color:#AFAFAF; " data-container="body">+ <span class="glyphicon glyphicon-chevron-left"></span>+ </button>+ <?php+ }+ ?>+ <input type="hidden" id="current_page_no" value="<?php echo esc_html( $current_page ); ?>">+ <?php+ //To Hide the preview and next buttons for first and lastpages of tickets+ if ( ( ( $current_page * $ticket_rows ) + count( $section_tickets_id ) ) != $total_no_of_tickets ) {+ ?>+ <button type="button" class="btn btn-default pagination_tickets" id="next" title="<?php esc_html_e( 'Next', 'wsdesk' ); ?> <?php echo esc_html( $ticket_rows ); ?>" data-container="body">+ <span class="glyphicon glyphicon-chevron-right"></span>+ </button>+ <?php+ }+ ?>+ <?php+ if ( ( ( $current_page * $ticket_rows ) + count( $section_tickets_id ) ) == $total_no_of_tickets ) {+ ?>+ <button type="button" class="btn btn-default pagination_tick" id="nex" title="<?php esc_html_e( 'End of the Page', 'wsdesk' ); ?> "style="color:#AFAFAF; " data-container="body">+ <span class="glyphicon glyphicon-chevron-right"></span>+ </button>+ <?php+ }+ ?>+ </div>+ </div>+ </div>+ <div class="panel-body">+ <input type="text" class="form-control" id="dev-table-filter" data-action="filter" data-filters="#dev-table" placeholder="<?php esc_html_e( 'Filter Tickets', 'wsdesk' ); ?>" />+ </div>+ <table class="table table-hover" id="dev-table">+ <thead>+ <tr class="except_view">+ <th style="width: 1%;"></th>+ <th style="width: 2%;"><?php esc_html_e( 'View', 'wsdesk' ); ?></th>+ <?php+ foreach ( $custom_table_headers as $value ) {+ echo '<th>' . esc_html( $value ) . '</th>';+ }+ ?>+ </tr>+ </thead>+ <tbody>+ <?php+ if ( empty( $section_tickets_id ) ) {+ echo '<tr class="except_view">+ <td colspan="12"> ' . esc_html__( 'No Tickets', 'wsdesk' ) . ' </td></tr>';+ } else {+ for ( $i = 0;$i < count( $section_tickets_id );$i++ ) {+ //$current = eh_crm_get_ticket_archive(array("ticket_id"=>$section_tickets_id[$i]['ticket_id']));+ $current = [ $archived_tickets[ $section_tickets_id[ $i ]['ticket_id'] ] ];+ $current_meta = $archived_tickets_meta[ $section_tickets_id[ $i ]['ticket_id'] ];+ $action_value = '';+ $assignee_value = '';+ $eye_color = '';+ for ( $j = 0;$j < count( $avail_labels_wf );$j++ ) {+ if ( in_array( 'manage_tickets', $access ) ) {+ $action_value .= '<li id="' . $current[0]['ticket_id'] . '"><a href="#" class="single_ticket_action" id="' . $avail_labels_wf[ $j ]['slug'] . '">' . esc_html__( 'Mark as', 'wsdesk' ) . ' ' . $avail_labels_wf[ $j ]['title'] . '</a></li>';++ }+ if ( $avail_labels_wf[ $j ]['slug'] == $current_meta['ticket_label'] ) {+ $eye_color = $avail_labels_wf[ $j ]['eye_color'];+ }+ }+ foreach ( $users_data as $user ) {+ if ( in_array( 'manage_tickets', $access ) ) {+ $assignee_value .= '<li id="' . $current[0]['ticket_id'] . '"><a href="#" class="single_ticket_assignee" id="' . $user['id'] . '">' . $user['name'] . '</a></li>';+ }+ }+ $ticket_raiser = $current[0]['ticket_email'];+ $ticket_raiser_email = $current[0]['ticket_email'];+ if ( 0 != $current[0]['ticket_author'] ) {+ $wcurrent_user = new WP_User( $current[0]['ticket_author'] );+ $ticket_raiser = $wcurrent_user->display_name;+ }+ $ticket_assignee_name = array();+ $ticket_assignee_email = array();+ if ( isset( $current_meta['ticket_assignee'] ) ) {+ $current_assignee = array_values( $current_meta['ticket_assignee'] );+ foreach ( $current_assignee as $assignee_id ) {+ if ( isset( $users_data[ $assignee_id ] ) ) {+ $ticket_assignee_name[] = $users_data[ $assignee_id ]['name'];+ $ticket_assignee_email[] = $users_data[ $assignee_id ]['email'];+ }+ }+ }+ $ticket_assignee_name = empty( $ticket_assignee_name ) ? esc_html__( 'No Assignee', 'wsdesk' ) : implode( ', ', $ticket_assignee_name );+ $latest_reply_id = '';+ //$latest_reply_id = eh_crm_get_ticket_value_count_archive("ticket_category","agent_note" ,true,"ticket_parent",$current[0]['ticket_id'],'ticket_id','DESC','1');+ $latest_content = array();+ $attach = '';+ if ( ! empty( $latest_reply_id ) ) {+ $latest_ticket_reply = eh_crm_get_ticket_archive( array( 'ticket_id' => $latest_reply_id[0]['ticket_id'] ) );+ $latest_content['content'] = $latest_ticket_reply[0]['ticket_content'];+ $latest_content['author_email'] = $latest_ticket_reply[0]['ticket_email'];+ $latest_content['reply_date'] = $latest_ticket_reply[0]['ticket_date'];+ if ( 0 != $latest_ticket_reply[0]['ticket_author'] ) {+ $reply_user = new WP_User( $latest_ticket_reply[0]['ticket_author'] );+ $latest_content['author_name'] = $reply_user->display_name;+ } else {+ $latest_content['author_name'] = esc_html__( 'Guest', 'wsdesk' );+ }+ $latest_reply_meta = eh_crm_get_ticketmeta_archive( $latest_reply_id[0]['ticket_id'] );+ if ( isset( $latest_reply_meta['ticket_attachment'] ) ) {+ $attach = ' | <small class="glyphicon glyphicon-pushpin"></small> <small style="opacity:0.7;"> ' . count( $latest_reply_meta['ticket_attachment'] ) . ' ' . esc_html__( 'Attachment', 'wsdesk' ) . '</small>';+ }+ } else {+ $latest_content['content'] = $current[0]['ticket_content'];+ $latest_content['author_email'] = $current[0]['ticket_email'];+ $latest_content['reply_date'] = $current[0]['ticket_date'];+ if ( 0 != $current[0]['ticket_author'] ) {+ $wcurrent_user = new WP_User( $current[0]['ticket_author'] );+ $latest_content['author_name'] = $wcurrent_user->display_name;+ } else {+ $latest_content['author_name'] = esc_html__( 'Guest', 'wsdesk' );+ }+ if ( isset( $current_meta['ticket_attachment'] ) ) {+ $attach = ' | <small class="glyphicon glyphicon-pushpin"></small> <small style="opacity:0.7;"> ' . count( $current_meta['ticket_attachment'] ) . ' ' . esc_html__( 'Attachment', 'wsdesk' ) . '</small>';+ }+ }+ $input_data = ( 'text' != $tickets_display ) ? html_entity_decode( stripslashes( $latest_content['content'] ) ) : stripslashes( $latest_content['content'] );+ $input_array[0] = '/<((html)[^>]*)>(.*)\<\/(html)>/Us';+ $input_array[1] = '/<((head)[^>]*)>(.*)\<\/(head)>/Us';+ $input_array[2] = '/<((style)[^>]*)>(.*)\<\/(style)>/Us';+ $input_array[3] = '/<((body)[^>]*)>(.*)\<\/(body)>/Us';+ $input_array[4] = '/<((form)[^>]*)>(.*)\<\/(form)>/Us';+ $input_array[5] = '/<((input)[^>]*)>(.*)\<\/(input)>/Us';+ $input_array[6] = '/<((input)[^>]*)>/Us';+ $input_array[7] = '/<((button)[^>]*)>(.*)\<\/(button)>/Us';+ $input_array[8] = '/<((iframe)[^>]*)>(.*)\<\/(iframe)>/Us';+ $input_array[9] = '/<((script)[^>]*)>(.*)\<\/(script)>/Us';+ $input_array[10] = '/<((ins)[^>]*)>(.*)\<\/(ins)>/Us';+ $output_array[0] = '<$1>$3</html>';+ $output_array[1] = '<$1>$3</head>';+ $output_array[2] = '<$1>$3</style>';+ $output_array[3] = '<$1>$3</body>';+ $output_array[4] = '<$1>$3</form>';+ $output_array[5] = '<$1>$3</input>';
Vulnerability Existed: no This diff represents a line-ending normalization (converting CRLF to LF or vice versa), not a code change. All 635 lines are identical in content—only the line endings have changed. Since no actual code has been modified, no security vulnerabilities were introduced, fixed, or removed. The file remains functionally identical with the same security posture before and after this change.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/tickets/crm_archive_tickets_v2.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/tickets/crm_archive_tickets_v2.php 2025-12-21 09:36:35.511308688 +0000@@ -1,468 +1,468 @@-<?php - -use Illuminate\Support\Arr; -use WSDesk\Settings\SettingsItem; -use WSDesk\Settings\SettingsRepository; -use WSDesk\Tickets\TicketRepository; - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -$repo = new TicketRepository(); -$settings = new SettingsRepository(); - -$ticket_filters_with_count = $repo->get_available_views(); - -$avail_labels_wf = array_values( $settings->getLabels() ); -$avail_labels_f = array_values( $settings->getFilterableLabels() ); - -$avail_tags_wf = array_values( $settings->getTags() ); -$avail_tags_f = array_values( $settings->getFilterableTags() ); -$avail_templates = array_values( $settings->getTemplates() ); - -$available_views_f = $settings->getFilterableViews(); -$selected_views = eh_crm_get_settingsmeta( 0, 'selected_views' ); - -if ( ! $avail_templates ) { - $avail_templates = array(); -} -$user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ); -$user_caps_default = array( 'reply_tickets', 'delete_tickets', 'manage_tickets' ); -$users = get_users( - array( - 'role__in' => $user_roles_default, - 'orderby' => 'display_name', - ) -); -$users_data = array(); - -$users_data = array_map( - function ( $user ) { - $users_data['id'] = $user->ID; - $users_data['name'] = $user->display_name; - $users_data['caps'] = $user->caps; - $users_data['email'] = $user->user_email; - return $users_data ; - }, - $users -); - -/**** - * Ticket Filters - */ -$ticket_filters_with_count = array_map( - function ( $filter ) use ( $avail_labels_f, $avail_tags_f, $available_views_f, $users_data, $selected_views ) { - if ( 'Labels' === $filter['title'] ) { - $filter['items'] = $avail_labels_f; - } - - if ( 'Tags' === $filter['title'] ) { - $filter['items'] = $avail_tags_f; - } - - if ( 'Views' === $filter['title'] ) { - $filter['items'] = array_filter( - $available_views_f, - function ( $view ) use ( $selected_views ) { - return \Illuminate\Support\Str::startsWith( $view['slug'], 'view_' ) && in_array( $view['slug'], $selected_views , true ); - } - ); - - $filter['items'] = Arr::sort( - $filter['items'], - function ( $view ) use ( $selected_views ) { - return array_search( $view['slug'], $selected_views, true ); - } - ); - - } - - if ( 'Agents' === $filter['title'] ) { - $filter['items'] = array_map( - function ( $user ) { - return array( - 'slug' => $user['id'], - 'title' => $user['name'], - ); - }, - $users_data - ); - $filter['items'][] = array( - 'slug' => 'null', - 'title' => 'Unassigned', - ); - } - - if ( 'Users' === $filter['title'] ) { - $filter['items'] = array( - array( - 'slug' => 'registered', - 'title' => 'Registered Users', - ), - array( - 'slug' => 'guest', - 'title' => 'Guest Users', - ), - ); - } - - return $filter; - }, - $ticket_filters_with_count -); - -$avail_fields = array_values( $settings->getFields() ); -$active_fields = eh_crm_get_settingsmeta( '0', 'selected_fields' ); -$all_tickets_page_columns = eh_crm_get_settingsmeta( '0', 'all_ticket_page_columns' ); - -// TODO: Sort based on the all_tickets_page_columns -$columns = []; -foreach ( $avail_fields as $key => $field ) { - if ( strpos( $field['slug'], 'request_' ) !== 0 && in_array( $field['slug'], $active_fields, true ) && in_array( $field['slug'], $all_tickets_page_columns , true ) ) { - $field = new SettingsItem( $field ); - $columns[] = [ - 'data' => $field['slug'], - 'field_type' => $field->get_meta()->get( 'field_type' ), - 'title' => $field['title'], - ]; - } -} - -$active_fields = array_map( - function ( $f ) { - return str_replace( 'request_', 'ticket_', $f ); - }, - $active_fields -); - -$avail_caps = array( 'reply_tickets', 'delete_tickets', 'manage_tickets', 'manage_templates' ); -$access = array(); -$logged_user = wp_get_current_user(); - -if ( ! in_array( 'administrator', $logged_user->roles , true ) ) { - $access = array_intersect( $avail_caps, $logged_user->caps ); -} else { - $access = $avail_caps; -} - -// ob_start(); - -?> -<div class="container"> - <div class="row" style="margin-top: 10px;"> - <div class="col-md-12"> - <div class="full_row filter_div" id="dev-table-action-bar" > - <div class="filter-each"><input type="checkbox" class="ticket_select_all"></div> - <div class="filter-each" id="refresh_tickets" style="cursor:pointer;"> - <div class="ticket-refresh-button" data-placement="top" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Refresh', 'wsdesk' ); ?>"> - <span class="glyphicon glyphicon-refresh"></span> - </div> - </div> - <?php - if ( in_array( 'delete_tickets', $access ) ) { - echo '<div class="filter-each ticket-delete-btn multiple_ticket_unarchive_action" id="delete_tickets" style="display: none;"><div class="ticket-delete-button" data-placement="top" data-toggle="wsdesk_tooltip" title="' . esc_html__( 'Restore the ticket(s)', 'wsdesk' ) . '"><span class="glyphicon glyphicon-folder-open"></span></div></div>'; - } - ?> - - </div> - </div> - </div> - <div class="row" style="margin-top: 10px;"> - - <div class="col-md-12" style="padding-right:0px;"> - <input type="hidden" name="view_type"/> - <input type="hidden" name="view_slug"/> - <div class="panel panel-default" > - <div class="panel-body"> - <table class="table" id="archive_tickets_table_v2"> - </table> - </div> - </div> - </div> - </div> -</div> -<script> -(function (){ - //window.onload = initDataTable; - dt_columns = <?php echo json_encode( $columns ); ?>; - dt_page_columns = <?php echo json_encode( array_values( $all_tickets_page_columns ) ); ?>; - var agents = <?php echo json_encode( $users_data ); ?>; - var tags = <?php echo json_encode( $avail_tags_wf ); ?>; - var actions = <?php echo json_encode( $avail_labels_wf ); ?>; - templates = <?php echo json_encode( $avail_templates ); ?>; - accesses = <?php echo json_encode( array_values( $access ) ); ?>; - dt_available_fields = <?php echo json_encode( array_values( $avail_fields ) ); ?>; - dt_active_fields = <?php echo json_encode( array_values( $active_fields ) ); ?>; - - for (var i = 0;i < dt_columns.length; i++) { - dt_columns[i].orderable = false; - dt_columns[i].render = function (data, type, row, meta) { - if (meta.settings.aoColumns[meta.col].field_type === 'file' && row.ticket_attachment) { - return row.ticket_attachment; - } - - return data || '-'; - } - } - - var stop = false; - function tryNavigateToEloberateTab(ticket_id) { - var tab = jQuery('ul.elaborate li#tab_' + ticket_id); - if (tab.length === 0) { - return false; - } - - - if(jQuery("ul.collapse_ul > li#tab_" + ticket_id).length!=0) - { - jQuery('.elaborate > li').last().before(ticket_id); - collapse_tab(); - } - tab.children('a').click(); - return true; - } - - window.loadSingleTicketTab = function (ticket_id) { - if (stop || tryNavigateToEloberateTab(ticket_id)) { - return false; - } - - jQuery(".table_loader").css("display", "inline"); - stop = true; - jQuery.ajax({ - type: 'post', - url: ajaxurl, - data: { - action: 'eh_crm_ticket_single_view_archive', - ticket_id: ticket_id, - nonce: js_obj.nonce, - pagination_id : jQuery("#pagination_ids_traverse").val() - }, - success: function (data) { - jQuery(".table_loader").css("display", "none"); - var parse = jQuery.parseJSON(data); - var tab_head = '<li role="presentation" class="visible_tab ticket_tab_open" id="tab_' + ticket_id + '" style="min-width:200px;">' + parse.tab_head + '</li>'; - var tab_content = '<div class="tab-pane new-style-tab-pane" id="tab_content_' + ticket_id + '">' + parse.tab_content + '</div>'; - jQuery('.elaborate > li').last().before(tab_head); - jQuery('.tab-content').append(tab_content); - trigger_load_single_ticket(ticket_id); - jQuery('.visible_tab a#tab_content_a_'+ticket_id).click(); - // setURLFunc(ticket_id); - collapse_tab(); - stop = false; - }, - error: function (jqXHR, textStatus, errorThrown) { - console.log(textStatus, errorThrown); - } - }); - }; - - jQuery('#archive_tickets_table_v2').on('click', 'a.ticket_row_item', function (e) { - e.preventDefault(); - loadSingleTicketTab(this.innerText); - }); - jQuery('#archive_tickets_table_v2').on('deselect.dt', function () { - jQuery('#delete_tickets').hide(); - dtFilter.selectAll = false; - - if (jQuery(this).find('tr.selected .select-checkbox').length || dtFilter.selectAll) { - jQuery('#delete_tickets').show(); - } - - }); - jQuery('#archive_tickets_table_v2').on('xhr.dt', function (e, settings, json) { - // jQuery('[data-toggle="wsdesk_tooltip"]').wstooltip({trigger : 'hover'}); - if (dtFilter.selectAll) { - setTimeout(() => { - dtTable.rows().select(); - }, 400); - } else { - const selectBtn = jQuery('#selectCurrentPageRows'); - if (selectBtn.prop('checked')) { - selectBtn.click(); - } - } - }); - jQuery('#archive_tickets_table_v2').on('select.dt', function () { - jQuery('#delete_tickets').show(); - }); - - window.toggleRowSelection = function (selected) { - selected ? dtTable.rows().select() : dtTable.rows().deselect(); - dtFilter.ticket_id = selected ? dtTable.column(2).data() : []; - } - - function generateTicketCountView(views) { - var html = ''; - views.forEach(function (view) { - var viewDom = document.createElement('div'); - //viewDom.id = view.title; - - var header = document.createElement('h4'); - header.innerText = view.title; - viewDom.append(header); - - var list = document.createElement('ul'); - list.id = view.title.toLowerCase(); - list.className = "nav nav-pills nav-stacked side-bar-filter"; - - view.data.forEach(function (item) { - list.innerHTML += '<li data-slug="'+item.slug+'" id="view_item_'+item.slug+'"><a href="#"><span class="view_item_count badge pull-right"></span>'+item.title+'</a></li>'; - }); - - viewDom.append(list); - viewDom.innerHTML += '<hr />'; - document.getElementById('ticket_views_count').append(viewDom); - }); - } - - jQuery('#all_tickets_v2_left_bar').on('click', 'ul li', function (e) { - e.preventDefault(); - dtFilter.view = {}; - var view = jQuery(this).parent().attr('id'); - dtFilter.view[view] = []; - - dtFilter.view[view].push(this.getAttribute('data-slug')); - if (this.getAttribute('id') === 'view_item_all_tickets') { - dtTable.rows().deselect(); - reset_dtfilter(); - loadCount(); - } - - if (this.getAttribute('data-slug') && this.getAttribute('data-slug').indexOf('view_') === 0 ) { - loadCount({views_only: dtFilter.view}); - } - - updateFilterActiveStatus(); - dtTable.draw(); - - }); - - function getChildRowHtml(data) { - data.last_message = data.last_message || { - display_name: 'admin', - ticket_email: data.ticket_email, - ticket_date: data.ticket_date, - ticket_content: data.ticket_content - }; - var html = '<div >'; - html += '<div style="padding:5px 0px;">' + - '<small class="glyphicon glyphicon-user"></small> <small style="opacity:0.7;">'+ data.last_message.display_name +'</small>' + - '| <small class="glyphicon glyphicon-envelope"></small> <small style="opacity:0.7;">'+ data.last_message.ticket_email +'</small>' + - '| <small class="glyphicon glyphicon-calendar"></small> <small style="opacity:0.7;">'+ data.last_message.ticket_date +'</small>' + - '</div>'; - - html += '<hr>'; - html += '<p>' + data.last_message.ticket_content + '</p>'; - - html += '<table class="table table-striped">'; - html += '<thead>'; - html += '<tr>'+ - '<th>Actions</th>'+ - '<th>Assignee</th>'+ - '<th>Reply Requester</th>'+ - '<th>Raiser Voices</th>'+ - '<th>Agent Voices</th>'+ - '<th>Tags</th>'+ - '<th>Source</th>'+ - '</tr>'; - html += '</thead>'; - html += '<tbody>'; - html += '<tr>'+ - '<td>'+ getActionBtnDropdown(data) +'</td>'+ - '<td>'+ getAssingeesBtnDropdown(data) +'</td>'+ - '<td><a href="#reply_'+data.ticket_id+'" data-toggle="modal" title="<?php echo esc_html__( 'Compose Reply', 'wsdesk' ); ?>">' + - data.ticket_email + - '</a></td>'+ - '<td>'+ (data.reply_count.raiser_reply || 0) +'</td>'+ - '<td>'+ (data.reply_count.agent_reply || 0) +'</td>'+ - '<th>'+ getTagsLabel(data.ticket_tags) +'</th>'+ - '<td>'+ data.ticket_source +'</td>'+ - '</tr>'; - html += '</tbody>'; - html += '</div>'; - - return html; - } - - function getActionBtnDropdown(data, isMultiAction) { - var html = '<div class="btn-group '+(isMultiAction ? 'ml-1': '')+'">'+ - '<button disabled type="button" '+ (isMultiAction ? 'disabled' : '') +' class="btn btn-default dropdown-toggle '+(isMultiAction ? 'mulitple_ticket_action_button' : '')+'" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">'+ - 'Action <span class="caret"></span>'+ - '</button>'+ - '<ul class="dropdown-menu">'+ - actions.map(function (action) { - return '<li id="'+ data.ticket_id +'">'+ - '<a href="#" class="' +(isMultiAction ? '' : 'single_ticket_action_button')+ '" data-ticket_id="'+data.ticket_id+'" data-action="'+action.slug+'" id="'+action.slug+'">Mark as '+action.title+'</a>'+ - '</li>'; - }).join('') + - '<li role="separator" class="divider"></li>'; - if (isMultiAction) { - html +='<li><a href="#" data-action="archive_tickets">Archive Tickets</a></li>'; - } else { - html += '<li class="text-center"><small class="text-muted text-sm">Select label to assign</small></li>'; - } - html+= '</ul>'+ - '</div>'; - - return html; - } - function getAssingeesBtnDropdown(data) { - var html = '<div class="btn-group">'+ - '<button disabled type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">'+ - 'Assignee <span class="caret"></span>'+ - '</button>'+ - '<ul class="dropdown-menu">'+ - agents.map(function (assignee) { - return '<li id="'+ data.ticket_id +'">'+ - '<a href="#" class="single_ticket_assignee" id="'+assignee.id+'">'+assignee.name+'</a>'+ - '</li>'; - }).join('') + - '<li role="separator" class="divider"></li>'+ - '<li class="text-center"><small class="text-muted text-sm">Select assignee to assign</small></li>'+ - '</ul>'+ - '</div>'; - - return html; - } - - function getTagsLabel(slugs) { - if (!slugs) return ''; - - slugs = Object.values(slugs); - - var filteredSlugs = tags.filter(function (tag) { - return slugs.indexOf(tag.slug) > -1; - }); - - return filteredSlugs.map(function (tag) { - return '<span class="label label-info">#' + tag.title + '</span>'; - }).join(' '); - } - - jQuery('#archive_tickets_table_v2').on('click', 'button.btn_quick_view_ticket', function () { - var row = dtTable.row(jQuery(this).parents('tr')); - var icon = jQuery(this).find('span'); - - if (row.child.isShown()) { - row.child.hide(); - jQuery(icon).removeClass('glyphicon-eye-close'); - jQuery(icon).addClass('glyphicon-eye-open'); - } else { - row.child(getChildRowHtml(row.data())).show(); - jQuery(icon).removeClass('glyphicon-eye-open'); - jQuery(icon).addClass('glyphicon-eye-close'); - } - }); - jQuery('#all_tickets_tab_header').click(function () { - if (jQuery(this).parent().hasClass('active') === false) { - loadCount(); - dtTable.draw(); - } - }); - -})(); -</script> -<?php -// return ob_get_clean(); +<?php++use Illuminate\Support\Arr;+use WSDesk\Settings\SettingsItem;+use WSDesk\Settings\SettingsRepository;+use WSDesk\Tickets\TicketRepository;++if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++$repo = new TicketRepository();+$settings = new SettingsRepository();++$ticket_filters_with_count = $repo->get_available_views();++$avail_labels_wf = array_values( $settings->getLabels() );+$avail_labels_f = array_values( $settings->getFilterableLabels() );++$avail_tags_wf = array_values( $settings->getTags() );+$avail_tags_f = array_values( $settings->getFilterableTags() );+$avail_templates = array_values( $settings->getTemplates() );++$available_views_f = $settings->getFilterableViews();+$selected_views = eh_crm_get_settingsmeta( 0, 'selected_views' );++if ( ! $avail_templates ) {+ $avail_templates = array();+}+$user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' );+$user_caps_default = array( 'reply_tickets', 'delete_tickets', 'manage_tickets' );+$users = get_users(+ array(+ 'role__in' => $user_roles_default,+ 'orderby' => 'display_name',+ )+);+$users_data = array();++$users_data = array_map(+ function ( $user ) {+ $users_data['id'] = $user->ID;+ $users_data['name'] = $user->display_name;+ $users_data['caps'] = $user->caps;+ $users_data['email'] = $user->user_email;+ return $users_data ;+ },+ $users+);++/****+ * Ticket Filters+ */+$ticket_filters_with_count = array_map(+ function ( $filter ) use ( $avail_labels_f, $avail_tags_f, $available_views_f, $users_data, $selected_views ) {+ if ( 'Labels' === $filter['title'] ) {+ $filter['items'] = $avail_labels_f;+ }++ if ( 'Tags' === $filter['title'] ) {+ $filter['items'] = $avail_tags_f;+ }++ if ( 'Views' === $filter['title'] ) {+ $filter['items'] = array_filter(+ $available_views_f,+ function ( $view ) use ( $selected_views ) {+ return \Illuminate\Support\Str::startsWith( $view['slug'], 'view_' ) && in_array( $view['slug'], $selected_views , true );+ }+ );++ $filter['items'] = Arr::sort(+ $filter['items'],+ function ( $view ) use ( $selected_views ) {+ return array_search( $view['slug'], $selected_views, true );+ }+ );++ }++ if ( 'Agents' === $filter['title'] ) {+ $filter['items'] = array_map(+ function ( $user ) {+ return array(+ 'slug' => $user['id'],+ 'title' => $user['name'],+ );+ },+ $users_data+ );+ $filter['items'][] = array(+ 'slug' => 'null',+ 'title' => 'Unassigned',+ );+ }++ if ( 'Users' === $filter['title'] ) {+ $filter['items'] = array(+ array(+ 'slug' => 'registered',+ 'title' => 'Registered Users',+ ),+ array(+ 'slug' => 'guest',+ 'title' => 'Guest Users',+ ),+ );+ }++ return $filter;+ },+ $ticket_filters_with_count+);++$avail_fields = array_values( $settings->getFields() );+$active_fields = eh_crm_get_settingsmeta( '0', 'selected_fields' );+$all_tickets_page_columns = eh_crm_get_settingsmeta( '0', 'all_ticket_page_columns' );++// TODO: Sort based on the all_tickets_page_columns+$columns = [];+foreach ( $avail_fields as $key => $field ) {+ if ( strpos( $field['slug'], 'request_' ) !== 0 && in_array( $field['slug'], $active_fields, true ) && in_array( $field['slug'], $all_tickets_page_columns , true ) ) {+ $field = new SettingsItem( $field );+ $columns[] = [+ 'data' => $field['slug'],+ 'field_type' => $field->get_meta()->get( 'field_type' ),+ 'title' => $field['title'],+ ];+ }+}++$active_fields = array_map(+ function ( $f ) {+ return str_replace( 'request_', 'ticket_', $f );+ },+ $active_fields+);++$avail_caps = array( 'reply_tickets', 'delete_tickets', 'manage_tickets', 'manage_templates' );+$access = array();+$logged_user = wp_get_current_user();++if ( ! in_array( 'administrator', $logged_user->roles , true ) ) {+ $access = array_intersect( $avail_caps, $logged_user->caps );+} else {+ $access = $avail_caps;+}++// ob_start();++?>+<div class="container">+ <div class="row" style="margin-top: 10px;">+ <div class="col-md-12">+ <div class="full_row filter_div" id="dev-table-action-bar" >+ <div class="filter-each"><input type="checkbox" class="ticket_select_all"></div>+ <div class="filter-each" id="refresh_tickets" style="cursor:pointer;">+ <div class="ticket-refresh-button" data-placement="top" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Refresh', 'wsdesk' ); ?>">+ <span class="glyphicon glyphicon-refresh"></span>+ </div>+ </div>+ <?php+ if ( in_array( 'delete_tickets', $access ) ) {+ echo '<div class="filter-each ticket-delete-btn multiple_ticket_unarchive_action" id="delete_tickets" style="display: none;"><div class="ticket-delete-button" data-placement="top" data-toggle="wsdesk_tooltip" title="' . esc_html__( 'Restore the ticket(s)', 'wsdesk' ) . '"><span class="glyphicon glyphicon-folder-open"></span></div></div>';+ }+ ?>++ </div>+ </div>+ </div>+ <div class="row" style="margin-top: 10px;">++ <div class="col-md-12" style="padding-right:0px;">+ <input type="hidden" name="view_type"/>+ <input type="hidden" name="view_slug"/>+ <div class="panel panel-default" >+ <div class="panel-body">+ <table class="table" id="archive_tickets_table_v2">+ </table>+ </div>+ </div>+ </div>+ </div>+</div>+<script>+(function (){+ //window.onload = initDataTable;+ dt_columns = <?php echo json_encode( $columns ); ?>;+ dt_page_columns = <?php echo json_encode( array_values( $all_tickets_page_columns ) ); ?>;+ var agents = <?php echo json_encode( $users_data ); ?>;+ var tags = <?php echo json_encode( $avail_tags_wf ); ?>;+ var actions = <?php echo json_encode( $avail_labels_wf ); ?>;+ templates = <?php echo json_encode( $avail_templates ); ?>;+ accesses = <?php echo json_encode( array_values( $access ) ); ?>;+ dt_available_fields = <?php echo json_encode( array_values( $avail_fields ) ); ?>;+ dt_active_fields = <?php echo json_encode( array_values( $active_fields ) ); ?>;++ for (var i = 0;i < dt_columns.length; i++) {+ dt_columns[i].orderable = false;+ dt_columns[i].render = function (data, type, row, meta) {+ if (meta.settings.aoColumns[meta.col].field_type === 'file' && row.ticket_attachment) {+ return row.ticket_attachment;+ }++ return data || '-';+ }+ }++ var stop = false;+ function tryNavigateToEloberateTab(ticket_id) {+ var tab = jQuery('ul.elaborate li#tab_' + ticket_id);+ if (tab.length === 0) {+ return false;+ }+++ if(jQuery("ul.collapse_ul > li#tab_" + ticket_id).length!=0)+ {+ jQuery('.elaborate > li').last().before(ticket_id);+ collapse_tab();+ }+ tab.children('a').click();+ return true;+ }++ window.loadSingleTicketTab = function (ticket_id) {+ if (stop || tryNavigateToEloberateTab(ticket_id)) {+ return false;+ }++ jQuery(".table_loader").css("display", "inline");+ stop = true;+ jQuery.ajax({+ type: 'post',+ url: ajaxurl,+ data: {+ action: 'eh_crm_ticket_single_view_archive',+ ticket_id: ticket_id,+ nonce: js_obj.nonce,+ pagination_id : jQuery("#pagination_ids_traverse").val()+ },+ success: function (data) {+ jQuery(".table_loader").css("display", "none");+ var parse = jQuery.parseJSON(data);+ var tab_head = '<li role="presentation" class="visible_tab ticket_tab_open" id="tab_' + ticket_id + '" style="min-width:200px;">' + parse.tab_head + '</li>';+ var tab_content = '<div class="tab-pane new-style-tab-pane" id="tab_content_' + ticket_id + '">' + parse.tab_content + '</div>';+ jQuery('.elaborate > li').last().before(tab_head);+ jQuery('.tab-content').append(tab_content);+ trigger_load_single_ticket(ticket_id);+ jQuery('.visible_tab a#tab_content_a_'+ticket_id).click();+ // setURLFunc(ticket_id);+ collapse_tab();+ stop = false;+ },+ error: function (jqXHR, textStatus, errorThrown) {+ console.log(textStatus, errorThrown);+ }+ });+ };++ jQuery('#archive_tickets_table_v2').on('click', 'a.ticket_row_item', function (e) {+ e.preventDefault();+ loadSingleTicketTab(this.innerText);+ });+ jQuery('#archive_tickets_table_v2').on('deselect.dt', function () {+ jQuery('#delete_tickets').hide();+ dtFilter.selectAll = false;++ if (jQuery(this).find('tr.selected .select-checkbox').length || dtFilter.selectAll) {+ jQuery('#delete_tickets').show();+ }++ });+ jQuery('#archive_tickets_table_v2').on('xhr.dt', function (e, settings, json) {+ // jQuery('[data-toggle="wsdesk_tooltip"]').wstooltip({trigger : 'hover'});+ if (dtFilter.selectAll) {+ setTimeout(() => {+ dtTable.rows().select();+ }, 400);+ } else {+ const selectBtn = jQuery('#selectCurrentPageRows');+ if (selectBtn.prop('checked')) {+ selectBtn.click();+ }+ }+ });+ jQuery('#archive_tickets_table_v2').on('select.dt', function () {+ jQuery('#delete_tickets').show();+ });++ window.toggleRowSelection = function (selected) {+ selected ? dtTable.rows().select() : dtTable.rows().deselect();+ dtFilter.ticket_id = selected ? dtTable.column(2).data() : [];+ }++ function generateTicketCountView(views) {+ var html = '';+ views.forEach(function (view) {+ var viewDom = document.createElement('div');+ //viewDom.id = view.title;++ var header = document.createElement('h4');+ header.innerText = view.title;+ viewDom.append(header);++ var list = document.createElement('ul');+ list.id = view.title.toLowerCase();+ list.className = "nav nav-pills nav-stacked side-bar-filter";++ view.data.forEach(function (item) {+ list.innerHTML += '<li data-slug="'+item.slug+'" id="view_item_'+item.slug+'"><a href="#"><span class="view_item_count badge pull-right"></span>'+item.title+'</a></li>';+ });++ viewDom.append(list);+ viewDom.innerHTML += '<hr />';+ document.getElementById('ticket_views_count').append(viewDom);+ });+ }++ jQuery('#all_tickets_v2_left_bar').on('click', 'ul li', function (e) {+ e.preventDefault();+ dtFilter.view = {};+ var view = jQuery(this).parent().attr('id');+ dtFilter.view[view] = [];++ dtFilter.view[view].push(this.getAttribute('data-slug'));+ if (this.getAttribute('id') === 'view_item_all_tickets') {+ dtTable.rows().deselect();+ reset_dtfilter();+ loadCount();+ }++ if (this.getAttribute('data-slug') && this.getAttribute('data-slug').indexOf('view_') === 0 ) {+ loadCount({views_only: dtFilter.view});+ }++ updateFilterActiveStatus();+ dtTable.draw();++ });++ function getChildRowHtml(data) {+ data.last_message = data.last_message || {+ display_name: 'admin',+ ticket_email: data.ticket_email,+ ticket_date: data.ticket_date,+ ticket_content: data.ticket_content+ };+ var html = '<div >';+ html += '<div style="padding:5px 0px;">' ++ '<small class="glyphicon glyphicon-user"></small> <small style="opacity:0.7;">'+ data.last_message.display_name +'</small>' ++ '| <small class="glyphicon glyphicon-envelope"></small> <small style="opacity:0.7;">'+ data.last_message.ticket_email +'</small>' ++ '| <small class="glyphicon glyphicon-calendar"></small> <small style="opacity:0.7;">'+ data.last_message.ticket_date +'</small>' ++ '</div>';++ html += '<hr>';+ html += '<p>' + data.last_message.ticket_content + '</p>';++ html += '<table class="table table-striped">';+ html += '<thead>';+ html += '<tr>'++ '<th>Actions</th>'++ '<th>Assignee</th>'++ '<th>Reply Requester</th>'++ '<th>Raiser Voices</th>'++ '<th>Agent Voices</th>'++ '<th>Tags</th>'++ '<th>Source</th>'++ '</tr>';+ html += '</thead>';+ html += '<tbody>';+ html += '<tr>'++ '<td>'+ getActionBtnDropdown(data) +'</td>'++ '<td>'+ getAssingeesBtnDropdown(data) +'</td>'++ '<td><a href="#reply_'+data.ticket_id+'" data-toggle="modal" title="<?php echo esc_html__( 'Compose Reply', 'wsdesk' ); ?>">' ++ data.ticket_email ++ '</a></td>'++ '<td>'+ (data.reply_count.raiser_reply || 0) +'</td>'++ '<td>'+ (data.reply_count.agent_reply || 0) +'</td>'++ '<th>'+ getTagsLabel(data.ticket_tags) +'</th>'++ '<td>'+ data.ticket_source +'</td>'++ '</tr>';+ html += '</tbody>';+ html += '</div>';++ return html;+ }++ function getActionBtnDropdown(data, isMultiAction) {+ var html = '<div class="btn-group '+(isMultiAction ? 'ml-1': '')+'">'++ '<button disabled type="button" '+ (isMultiAction ? 'disabled' : '') +' class="btn btn-default dropdown-toggle '+(isMultiAction ? 'mulitple_ticket_action_button' : '')+'" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">'++ 'Action <span class="caret"></span>'++ '</button>'++ '<ul class="dropdown-menu">'++ actions.map(function (action) {+ return '<li id="'+ data.ticket_id +'">'++ '<a href="#" class="' +(isMultiAction ? '' : 'single_ticket_action_button')+ '" data-ticket_id="'+data.ticket_id+'" data-action="'+action.slug+'" id="'+action.slug+'">Mark as '+action.title+'</a>'++ '</li>';+ }).join('') ++ '<li role="separator" class="divider"></li>';+ if (isMultiAction) {+ html +='<li><a href="#" data-action="archive_tickets">Archive Tickets</a></li>';+ } else {+ html += '<li class="text-center"><small class="text-muted text-sm">Select label to assign</small></li>';+ }+ html+= '</ul>'++ '</div>';++ return html;+ }+ function getAssingeesBtnDropdown(data) {+ var html = '<div class="btn-group">'++ '<button disabled type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">'++ 'Assignee <span class="caret"></span>'++ '</button>'++ '<ul class="dropdown-menu">'++ agents.map(function (assignee) {+ return '<li id="'+ data.ticket_id +'">'++ '<a href="#" class="single_ticket_assignee" id="'+assignee.id+'">'+assignee.name+'</a>'++ '</li>';+ }).join('') ++ '<li role="separator" class="divider"></li>'++ '<li class="text-center"><small class="text-muted text-sm">Select assignee to assign</small></li>'++ '</ul>'++ '</div>';++ return html;+ }++ function getTagsLabel(slugs) {+ if (!slugs) return '';++ slugs = Object.values(slugs);++ var filteredSlugs = tags.filter(function (tag) {+ return slugs.indexOf(tag.slug) > -1;+ });++ return filteredSlugs.map(function (tag) {+ return '<span class="label label-info">#' + tag.title + '</span>';+ }).join(' ');+ }++ jQuery('#archive_tickets_table_v2').on('click', 'button.btn_quick_view_ticket', function () {+ var row = dtTable.row(jQuery(this).parents('tr'));+ var icon = jQuery(this).find('span');++ if (row.child.isShown()) {+ row.child.hide();+ jQuery(icon).removeClass('glyphicon-eye-close');+ jQuery(icon).addClass('glyphicon-eye-open');+ } else {+ row.child(getChildRowHtml(row.data())).show();+ jQuery(icon).removeClass('glyphicon-eye-open');+ jQuery(icon).addClass('glyphicon-eye-close');+ }+ });+ jQuery('#all_tickets_tab_header').click(function () {+ if (jQuery(this).parent().hasClass('active') === false) {+ loadCount();+ dtTable.draw();+ }+ });++})();+</script>+<?php+// return ob_get_clean();
Vulnerability Existed: no This diff shows only line ending changes (from CRLF to LF or similar whitespace normalization) with no actual code modifications. The content and logic of the PHP/JavaScript file remains identical between versions 3.3.4 and 3.3.5. There are no security fixes or vulnerabilities introduced/removed in this change, as no functional code has been altered.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/tickets/crm_tickets_v2_all.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/tickets/crm_tickets_v2_all.php 2025-12-21 09:36:35.511308688 +0000@@ -1,762 +1,762 @@-<?php - -use Illuminate\Support\Arr; -use WSDesk\Settings\SettingsItem; -use WSDesk\Settings\SettingsRepository; -use WSDesk\Tickets\TicketRepository; - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -$repo = new TicketRepository(); -$settings = new SettingsRepository(); - -$ticket_filters_with_count = $repo->get_available_views(); - -$avail_labels_wf = array_values( $settings->getLabels() ); -$avail_labels_f = array_values( $settings->getFilterableLabels() ); - -$avail_tags_wf = array_values( $settings->getTags() ); -$avail_tags_f = array_values( $settings->getFilterableTags() ); -$avail_templates = array_values( $settings->getTemplates() ); - -$available_views_f = $settings->getFilterableViews(); -$selected_views = eh_crm_get_settingsmeta( 0, 'selected_views' ); - -if ( ! $avail_templates ) { - $avail_templates = array(); -} -$user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' ); -$user_caps_default = array( 'reply_tickets', 'delete_tickets', 'manage_tickets' ); -$users_filter = - array( - 'role__in' => $user_roles_default, - 'orderby' => 'display_name', - ); -if ( wsdesk_can_access_other_tickets() === false ) { - $users_filter['include'] = array( get_current_user_id() ); -} - -$users = get_users( - $users_filter -); -$users_data = array(); - -$users_data = array_map( - function ( $user ) { - $users_data['id'] = $user->ID; - $users_data['name'] = $user->display_name; - $users_data['caps'] = $user->caps; - $users_data['email'] = $user->user_email; - return $users_data ; - }, - $users -); - -/**** - * Ticket Filters - */ -$ticket_filters_with_count = array_map( - function ( $filter ) use ( $avail_labels_f, $avail_tags_f, $available_views_f, $users_data, $selected_views ) { - if ( 'Labels' === $filter['title'] ) { - $filter['items'] = $avail_labels_f; - } - - if ( 'Tags' === $filter['title'] ) { - $filter['items'] = $avail_tags_f; - } - - if ( 'Views' === $filter['title'] ) { - $filter['items'] = array_filter( - $available_views_f, - function ( $view ) use ( $selected_views, $filter ) { - return \Illuminate\Support\Str::startsWith( $view['slug'], 'view_' ) && in_array( $view['slug'], $selected_views , true ) && in_array( $view['slug'], Arr::get( $filter, 'data', array() ), true ); - } - ); - - $filter['items'] = Arr::sort( - $filter['items'], - function ( $view ) use ( $selected_views ) { - return array_search( $view['slug'], $selected_views, true ); - } - ); - - } - - if ( 'Agents' === $filter['title'] ) { - $filter['items'] = array_map( - function ( $user ) { - return array( - 'slug' => $user['id'], - 'title' => $user['name'], - ); - }, - $users_data - ); - $filter['items'][] = array( - 'slug' => 'null', - 'title' => 'Unassigned', - ); - } - - if ( 'Users' === $filter['title'] ) { - $filter['items'] = array( - array( - 'slug' => 'registered', - 'title' => 'Registered Users', - ), - array( - 'slug' => 'guest', - 'title' => 'Guest Users', - ), - ); - } - - return $filter; - }, - $ticket_filters_with_count -); - -$avail_fields = array_values( $settings->getFields() ); -$active_fields = eh_crm_get_settingsmeta( '0', 'selected_fields' ); -$active_fields = is_array( $active_fields ) ? $active_fields : array( $active_fields ); -$all_tickets_page_columns = wsdesk_get_all_tickets_page_fields(); - -// TODO: Sort based on the all_tickets_page_columns -$columns = []; -foreach ( $avail_fields as $key => $field ) { - if ( strpos( $field['slug'], 'request_' ) !== 0 && in_array( $field['slug'], $active_fields, true ) && in_array( $field['slug'], $all_tickets_page_columns , true ) ) { - $field = new SettingsItem( $field ); - $columns[] = [ - 'data' => $field['slug'], - 'field_type' => $field->get_meta()->get( 'field_type' ), - 'title' => $field['title'], - ]; - } -} - -$active_fields = array_map( - function ( $f ) { - return str_replace( 'request_', 'ticket_', $f ); - }, - $active_fields -); - -$avail_caps = array( 'reply_tickets', 'delete_tickets', 'manage_tickets', 'manage_templates' ); -$access = array(); -$logged_user = wp_get_current_user(); - -if ( ! in_array( 'administrator', $logged_user->roles , true ) ) { - - $access = array_intersect( $avail_caps, array_keys( $logged_user->caps ) ); -} else { - $access = $avail_caps; -} - -// ob_start(); - -?> -<div class="container"> - <div class="row" style="margin-top: 10px;"> - <div class="col-md-3" id="all_tickets_v2_left_bar" style="max-height: 100vh;overflow: auto;overflow-x: hidden;min-height: 100px;"> - <ul class="nav nav-pills nav-stacked side-bar-filter" id="v2_all_tickets_section"> - <li class="active" id="view_item_all_tickets"><a href="#" id="all"><span class="badge pull-right"><?php echo esc_html( $repo->count() ); ?></span> <?php esc_html_e( 'All Tickets', 'wsdesk' ); ?> <?php require 'eh_crm_table_loader.php'; ?></a></li> - </ul> - <hr> - <div id="ticket_views_count"> - <?php - if ( is_array( $ticket_filters_with_count ) && ! empty( $ticket_filters_with_count ) && isset( $ticket_filters_with_count ) ) { - foreach ( $ticket_filters_with_count as $view ) { - ?> - <div > - <h4><?php echo esc_html__( $view['title'], 'wsdesk' ); ?></h4> - <ul class="nav nav-pills nav-stacked side-bar-filter" id="<?php echo esc_html( strtolower( $view['title'] ) ); ?>"> - <?php foreach ( $view['items'] as $item ) { ?> - <li data-slug="<?php echo esc_html( $item['slug'] ); ?>" id="view_item_<?php echo esc_html( $item['slug'] ); ?>"><a href="#" id="all"><span class="badge pull-right">...</span> <?php echo esc_html__( $item['title'], 'wsdesk' ); ?></a></li> - <?php } ?> - </ul> - <hr /> - </div> - <?php - } - } - ?> - </div> - </div> - - <div class="col-md-9" style="padding-right:0px;"> - <input type="hidden" name="view_type"/> - <input type="hidden" name="view_slug"/> - <div class="panel panel-default" > - <div class="panel-body"> - <table class="table" id="all_tickets_table_v2"> - </table> - </div> - </div> - </div> - </div> -</div> - <div class="modal fade" id="edit_tickets_modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> - <div class="modal-dialog" role="document"> - <div class="modal-content"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> - <h4 class="modal-title" style="padding-left: 15px;"><?php esc_html_e( 'Edit', 'wsdesk' ); ?> <span class="number_of_tickets"></span> <?php esc_html_e( 'Ticket', 'wsdesk' ); ?>(s)</h4> - <input type="hidden" name="ticket_ids" id="edit_ticket_ids" value=""> - <input type="hidden" name="ticket_select_all" id="edit_ticket_select_all" value=""> - </div> - <div class="modal-body"> - <div class="row"> - <div class="col-md-4 left-modal-body"> - <div class="row bulk-edit-row"> - <label class="edit_tickets_label"><?php esc_html__( 'Assignee', 'wsdesk' ); ?></label> - <select id="assignee_ticket_edit" class="form-control" aria-describedby="helpBlock" multiple="multiple"> - <?php - foreach ( $users_data as $i => $user ) { - if ( in_array( 'administrator', array_keys( $users_data[ $i ]['caps'] ), true ) ) { - ?> - <option value="<?php echo esc_html( $user['id'] ); ?>"> - <?php echo esc_html( $user['name'] ) . ' | ' . esc_html__( 'Administrator', 'wsdesk' ); ?> - </option> - <?php - } elseif ( in_array( 'WSDesk_Supervisor', array_keys( $users_data[ $i ]['caps'] ), true ) ) { - ?> - <option value="<?php echo esc_html( $user['id'] ); ?>"> - <?php echo esc_html( $user['name'] ) . ' | ' . esc_html__( 'Supervisor', 'wsdesk' ); ?> - </option> - <?php - } elseif ( in_array( 'WSDesk_Agents', array_keys( $users_data[ $i ]['caps'] ) , true ) ) { - ?> - <option value="<?php echo esc_html( $user['id'] ); ?>"> - <?php echo esc_html( $user['name'] ) . ' | ' . esc_html__( 'Agent', 'wsdesk' ); ?> - </option> - <?php - } - } - ?> - </select> - </div> - <div class="row bulk-edit-row"> - <label class="edit_tickets_label"><?php esc_html__( 'Labels', 'wdesk' ); ?></label> - <select id="label_ticket_edit" class="form-control" aria-describedby="helpBlock"> - <option value=''> <?php echo esc_html__( 'Select Status', 'wsdesk' ); ?> </option> - <?php - foreach ( $avail_labels_f as $label ) { - ?> - <option value="<?php echo esc_html( $label['slug'] ); ?>"> - <?php echo esc_html( $label['title'] ); ?> - </option> - <?php - } - ?> - </select> - </div> - <div class="row bulk-edit-row"> - <label class="edit_tickets_label"> <?php esc_html__( 'Tags', 'wsdesk' ); ?></label> - <select id="tags_ticket_edit" class="form-control" aria-describedby="helpBlock" multiple="multiple"> - <?php - foreach ( $avail_tags_f as $tag_item ) { - ?> - <option value="<?php echo esc_html( $tag_item['slug'] ); ?>"> - <?php echo esc_html( $tag_item['title'] ); ?> - </option> - <?php - } - ?> - </select> - </div> - <center> - <button type="button" class="btn btn-primary" id="bulk_edit_save"><?php echo esc_html__( 'Save Properties', 'wsdesk' ); ?></button> - </center> - </div> - <div class="col-md-7 right-modal-body"> - <div class="row bulk-edit-row"> - <label class="edit_tickets_label"><?php esc_html_e( 'Subject' , 'wsdesk' ); ?></label> - <input type="text" placeholder="<?php esc_html_e( 'No Change', 'wsdesk' ); ?>" id="title_ticket_edit" class="form-control"> - </div> - <div class="row bulk-edit-row"> - <label class="edit_tickets_label"><?php esc_html_e( 'Bulk Reply', 'wsdesk' ); ?></label> - <div class="textarea" style="width: 100% !important; height: 200px;" class="reply_textarea" id="reply_textarea_edit" name="reply_textarea_edit"></div> - </div> - <div class="row bulk-edit-row"> - <span class="btn btn-primary fileinput-button"> - <i class="glyphicon glyphicon-plus"></i> - <span><?php esc_html_e( 'Attachment', 'wsdesk' ); ?></span> - <input type="file" name="files" id="files_edit" class="attachment_reply" media="all" multiple=""> - </span> - <span class="glyphicon glyphicon-info-sign" style="color:lightgray;font-size:x-small;vertical-align:baseline;" data-toggle="wsdesk_tooltip" title="<?php esc_html_e( 'Text in the body of the reply is mandatory to submit attachemnts.', 'wsdesk' ); ?>" data-container="body"></span> - </div> - <div class="row"> - <div class="upload_preview_edit"></div> - </div> - </div> - </div> - </div> - <div class="modal-footer"> - <button type="button" class="btn btn-default" data-dismiss="modal"><?php esc_html_e( 'Close', 'wsdesk' ); ?></button> - <button type="button" class="btn btn-primary" id="bulk_edit_submit"><?php esc_html_e( 'Submit', 'wsdesk' ); ?></button> - </div> - </div> - </div> - </div> - - <div class="modal fade" id="new_template_model" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> - <div class="modal-dialog" role="document"> - <div class="modal-content"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> - <h4 class="modal-title"><?php esc_html_e( 'New Template', 'wsdesk' ); ?></h4> - </div> - <div class="modal-body"> - <p style="margin-top: 5px;font-size: 16px;"> - <label for=""><small><?php esc_html_e( 'Template title to identify', 'wsdesk' ); ?></small></label> - <input type="text" placeholder="<?php esc_html_e( 'Enter Title', 'wsdesk' ); ?>" class="form-control template_title_editable" id="new_template_title"> - </p> - <div class="panel-group" id="email_auto_role" style="margin-bottom: 10px !important;"> - <div class="panel panel-default"> - <div class="panel-heading collapsed" style="padding:10px;cursor: pointer;" data-toggle="collapse" data-parent="#email_auto_role" data-target="#content_email_auto"> - <span class ="email-reply-toggle"></span> - <h4 class="panel-title"> - <?php esc_html_e( 'Code for template', 'wsdesk' ); ?> - </h4> - </div> - <div id="content_email_auto" class="panel-collapse collapse"> - <div class="panel-body"> - <div class="col-md-12"> - <div class="row"> - <div class="col-md-3"> - <?php esc_html_e( '[name]', 'wsdesk' ); ?> - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To insert ticket raiser name in the template', 'wsdesk' ); ?> - </div> - </div> - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - <?php esc_html_e( '[id]', 'wsdesk' ); ?> - </div> - <div class="col-md-9"> - <?php esc_html_e( 'To insert ticket number in the template', 'wsdesk' ); ?> - </div> - </div> - <?php - $selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' ); - if ( empty( $selected_fields ) ) { - $selected_fields = array(); - } - foreach ( $avail_fields as $field ) { - if ( 'google_captcha' === $field['slug'] || ! in_array( $field['slug'], $selected_fields ) ) { - continue; - } - echo ' - <span class="crm-divider"></span> - <div class="row"> - <div class="col-md-3"> - [' . esc_html( $field['slug'] ) . '] - </div> - <div class="col-md-9"> - ' . esc_html__( 'To insert ', 'wsdesk' ) . ' ' . esc_html( $field['title'] ) . ' ' . esc_html__( 'field value in the template', 'wsdesk' ) . ' - </div> - </div>'; - } - ?> - </div> - </div> - </div> - </div> - </div> - <div class="textarea" style="height: 100px" id="new_template_content"></div> - </div> - <div class="modal-footer"> - <button type="button" class="btn btn-default" data-dismiss="modal"><?php esc_html_e( 'Close', 'wsdesk' ); ?></button> - <button type="button" class="btn btn-primary" id="create_new_template"><?php esc_html_e( 'Create', 'wsdesk' ); ?></button> - </div> - </div> - </div> - </div> - <div id="update_template_model_display"></div> - <div id="preview_template_model_display"></div> -<script> -(function (){ - //window.onload = initDataTable; - dt_columns = <?php echo json_encode( $columns ); ?>; - dt_page_columns = <?php echo json_encode( array_values( $all_tickets_page_columns ) ); ?>; - var agents = <?php echo json_encode( $users_data ); ?>; - var tags = <?php echo json_encode( $avail_tags_wf ); ?>; - var actions = <?php echo json_encode( $avail_labels_wf ); ?>; - templates = <?php echo json_encode( $avail_templates ); ?>; - accesses = <?php echo json_encode( array_values( $access ) ); ?>; - dt_available_fields = <?php echo json_encode( array_values( $avail_fields ) ); ?>; - dt_active_fields = <?php echo json_encode( array_values( $active_fields ) ); ?>; - - for (var i = 0;i < dt_columns.length; i++) { - dt_columns[i].orderable = false; - dt_columns[i].render = function (data, type, row, meta) { - if (meta.settings.aoColumns[meta.col].field_type === 'file' && row.ticket_attachment) { - return row.ticket_attachment; - } - - return data || '-'; - } - } - - var stop = false; - function tryNavigateToEloberateTab(ticket_id) { - var tab = jQuery('ul.elaborate li#tab_' + ticket_id); - if (tab.length === 0) { - return false; - } - - - if(jQuery("ul.collapse_ul > li#tab_" + ticket_id).length!=0) - { - jQuery('.elaborate > li').last().before(ticket_id); - collapse_tab(); - } - tab.children('a').click(); - return true; - } - - window.loadSingleTicketTab = function (ticket_id) { - if (stop || tryNavigateToEloberateTab(ticket_id)) { - return false; - } - - jQuery(".table_loader").css("display", "inline"); - stop = true; - jQuery.ajax({ - type: 'post', - url: ajaxurl, - data: { - action: 'eh_crm_ticket_single_view', - ticket_id: ticket_id, - nonce: js_obj.nonce, - pagination_id : jQuery("#pagination_ids_traverse").val() - }, - success: function (data) { - jQuery(".table_loader").css("display", "none"); - var parse = jQuery.parseJSON(data); - var tab_head = '<li role="presentation" class="visible_tab ticket_tab_open" id="tab_' + ticket_id + '" style="min-width:200px;">' + parse.tab_head + '</li>'; - var tab_content = '<div class="tab-pane new-style-tab-pane" id="tab_content_' + ticket_id + '">' + parse.tab_content + '</div>'; - jQuery('.elaborate > li').last().before(tab_head); - jQuery('.tab-content').append(tab_content); - trigger_load_single_ticket(ticket_id); - jQuery('.visible_tab a#tab_content_a_'+ticket_id).click(); - // setURLFunc(ticket_id); - collapse_tab(); - stop = false; - }, - error: function (jqXHR, textStatus, errorThrown) { - } - }); - }; - - jQuery('#all_tickets_table_v2').on('click', 'a.ticket_row_item', function (e) { - e.preventDefault(); - loadSingleTicketTab(this.innerText); - }); - jQuery('#all_tickets_table_v2').on('deselect.dt', function () { - dtFilter.selectAll = false; - - var selectedRows = dtTable.rows({selected: true}).data(); - - if (selectedRows.length !== 0) { - return false; - } - - dtTable.button(3).disable(); - dtTable.button(4).disable(); - jQuery('.mulitple_ticket_action_button, #reply_template_button').attr('disabled', true); - jQuery('#selectCurrentPageRows').prop('checked', false); - jQuery('button.buttons-select-all').removeClass('hidden') - jQuery('button.buttons-select-none').addClass('hidden') - }); - jQuery('#all_tickets_table_v2').on('xhr.dt', function (e, settings, json) { - - if (!dtFilter.view.views) { - var activeItem = jQuery('.side-bar-filter').find('li.active'); - if (activeItem.attr('id') !== 'view_item_all_tickets') { - activeItem.find('span.badge').text(json.recordsFiltered); - } - } else { - setTimeout(function () { - jQuery('#all_tickets_table_v2').find('thead > tr').find('th[class^=sorting]').removeClass('sorting sorting_asc sorting_desc'); - }, 500); - } - - // jQuery('[data-toggle="wsdesk_tooltip"]').wstooltip({trigger : 'hover'}); - if (dtFilter.view.views ) { - dtTable.rowGroup().enable(); - } else { - dtTable.rowGroup().disable(); - } - - if (dtFilter.selectAll) { - setTimeout(() => { - dtTable.rows().select(); - }, 400); - } else { - const selectBtn = jQuery('#selectCurrentPageRows'); - if (selectBtn.prop('checked')) { - selectBtn.click(); - } - } - }); - jQuery('#all_tickets_table_v2').on('select.dt', function () { - if (User().can('delete_tickets')) { - dtTable.button(3).enable(); - } - if (User().can('manage_tickets')) { - dtTable.button(4).enable(); - jQuery('.mulitple_ticket_action_button').attr('disabled', false); - } - if (User().can('reply_tickets')) { - jQuery('#reply_template_button').attr('disabled', false); - } - jQuery('button.buttons-select-all').addClass('hidden') - jQuery('button.buttons-select-none').removeClass('hidden') - }); - jQuery('#all_tickets_table_v2').on('preInit.dt', function () { - jQuery('#all_tickets_advanced_filters').append('' + - '<div class="col-md-3">'+ - '<div class="form-group">'+ - '<label>Ticket ID</label>'+ - '<input class="form-control" name="ticket_id" placeholder="Ticket ID"/>'+ - '</div>'+ - '</div>'+ - '<div class="col-md-3">'+ - '<div class="form-group">'+ - '<label>Requestor</label>'+ - '<input class="form-control" name="requestor" placeholder="Requestor Email"/>'+ - '</div>'+ - '</div>'+ - '<div class="col-md-3">'+ - '<div class="form-group">'+ - '<label>Subject</label>'+ - '<input class="form-control" name="subject" placeholder="Subject"/>'+ - '</div>'+ - '</div>'+ - '<div class="col-md-3 text-right">'+ - '<label></label>'+ - '<br>'+ - '<button class="btn btn-primary" id="all_tickets_advanced_filters_submit">Filter</button>'+ - '</div>'+ - ''); - jQuery('#all_tickets_action_buttons').append(getActionBtnDropdown({}, true)); - jQuery('#all_tickets_action_buttons').append(getTemplatesBtn()); - }); - - jQuery('#all_tickets_table_v2').on('init.dt', function () { - jQuery('#all_tickets_advanced_filters').on('click', 'button#all_tickets_advanced_filters_submit', function () { - dtTable.draw(); - }); - jQuery('button.buttons-select-all').removeClass('hidden') - jQuery('button.buttons-select-none').addClass('hidden') - }); - window.toggleRowSelection = function (selected) { - selected ? dtTable.rows().select() : dtTable.rows().deselect(); - dtFilter.ticket_id = selected ? dtTable.column(2).data() : []; - } - - function generateTicketCountView(views) { - var html = ''; - views.forEach(function (view) { - var viewDom = document.createElement('div'); - //viewDom.id = view.title; - - var header = document.createElement('h4'); - header.innerText = view.title; - viewDom.append(header); - - var list = document.createElement('ul'); - list.id = view.title.toLowerCase(); - list.className = "nav nav-pills nav-stacked side-bar-filter"; - - view.data.forEach(function (item) { - list.innerHTML += '<li data-slug="'+item.slug+'" id="view_item_'+item.slug+'"><a href="#"><span class="view_item_count badge pull-right"></span>'+item.title+'</a></li>'; - }); - - viewDom.append(list); - viewDom.innerHTML += '<hr />'; - document.getElementById('ticket_views_count').append(viewDom); - }); - } - - jQuery('#all_tickets_v2_left_bar').on('click', 'ul li', function (e) { - e.preventDefault(); - dtFilter.view = {}; - var view = jQuery(this).parent().attr('id'); - dtFilter.view[view] = []; - - dtFilter.view[view].push(this.getAttribute('data-slug')); - if (this.getAttribute('id') === 'view_item_all_tickets') { - dtTable.rows().deselect(); - reset_dtfilter(); - loadCount(); - } - - if (this.getAttribute('data-slug') && this.getAttribute('data-slug').indexOf('view_') === 0 ) { - loadCount({views_only: dtFilter.view}); - } - - updateFilterActiveStatus(); - dtTable.draw(); - - if (window.history) { - const newUrl = new URL(window.location); - - const filter = getTicketsFilter(); - newUrl.searchParams.set('filter', crypto_enc(JSON.stringify(filter))); - - window.history.pushState(filter, '', newUrl); - } - }); - - function getChildRowHtml(data) { - data.last_message = data.last_message || { - display_name: 'admin', - ticket_email: data.ticket_email, - ticket_date: data.ticket_date, - ticket_content: data.ticket_content - }; - var html = '<div >'; - html += '<div style="padding:5px 0px;">' + - '<small class="glyphicon glyphicon-user"></small> <small style="opacity:0.7;">'+ data.last_message.display_name +'</small>' + - '| <small class="glyphicon glyphicon-envelope"></small> <small style="opacity:0.7;">'+ data.last_message.ticket_email +'</small>' + - '| <small class="glyphicon glyphicon-calendar"></small> <small style="opacity:0.7;">'+ data.last_message.ticket_date +'</small>' + - '</div>'; - - html += '<hr>'; - html += '<p>' + data.last_message.ticket_content + '</p>'; - - html += '<table class="table table-striped">'; - html += '<thead>'; - html += '<tr>'+ - '<th>Actions</th>'+ - '<th>Assignee</th>'+ - '<th>Reply Requester</th>'+ - '<th>Raiser Voices</th>'+ - '<th>Agent Voices</th>'+ - '<th>Tags</th>'+ - '<th>Source</th>'+ - '</tr>'; - html += '</thead>'; - html += '<tbody>'; - html += '<tr>'+ - '<td>'+ ( User().can('manage_tickets') ? getActionBtnDropdown(data) : getActionBtnDropdown(data, true)) +'</td>'+ - '<td>'+ ( User().can('manage_tickets') ? getAssingeesBtnDropdown(data) : getAssingeesBtnDropdown(data, true)) +'</td>'+ - '<td><a href="#reply_'+data.ticket_id+'" data-toggle="modal" title="<?php echo esc_html__( 'Compose Reply', 'wsdesk' ); ?>">' + - data.ticket_email + - '</a></td>'+ - '<td>'+ (data.reply_count.raiser_reply || 0) +'</td>'+ - '<td>'+ (data.reply_count.agent_reply || 0) +'</td>'+ - '<th>'+ getTagsLabel(data.ticket_tags) +'</th>'+ - '<td>'+ data.ticket_source +'</td>'+ - '</tr>'; - html += '</tbody>'; - html += '</div>'; - - return html; - } - - function getActionBtnDropdown(data, isMultiAction) { - var html = '<div class="btn-group '+(isMultiAction ? 'ml-1': '')+'">'+ - '<button type="button" '+ (isMultiAction ? 'disabled' : '') +' class="btn btn-default dropdown-toggle '+(isMultiAction ? 'mulitple_ticket_action_button' : '')+'" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">'+ - 'Action <span class="caret"></span>'+ - '</button>'+ - '<ul class="dropdown-menu">'+ - actions.map(function (action) { - return '<li id="'+ data.ticket_id +'">'+ - '<a href="#" class="' +(isMultiAction ? '' : 'single_ticket_action_button')+ '" data-ticket_id="'+data.ticket_id+'" data-action="'+action.slug+'" id="'+action.slug+'">Mark as '+action.title+'</a>'+ - '</li>'; - }).join(''); - if (isMultiAction) { - } else { - html += '<li role="separator" class="divider"></li>'; - html += '<li class="text-center"><small class="text-muted text-sm">Select label to assign</small></li>'; - } - html+= '</ul>'+ - '</div>'; - - return html; - } - function getAssingeesBtnDropdown(data, isDisabled) { - var html = '<div class="btn-group '+(isDisabled ? 'ml-1': '')+'">'+ - '<button type="button" '+ (isDisabled ? 'disabled' : '') +' class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">'+ - 'Assignee <span class="caret"></span>'+ - '</button>'+ - '<ul class="dropdown-menu">'+ - agents.map(function (assignee) { - return '<li id="'+ data.ticket_id +'">'+ - '<a href="#" class="single_ticket_assignee" id="'+assignee.id+'">'+assignee.name+'</a>'+ - '</li>'; - }).join('') + - '<li role="separator" class="divider"></li>'+ - '<li class="text-center"><small class="text-muted text-sm">Select assignee to assign</small></li>'+ - '</ul>'+ - '</div>'; - - return html; - } - - function getTagsLabel(slugs) { - if (!slugs) return ''; - - slugs = Object.values(slugs); - - var filteredSlugs = tags.filter(function (tag) { - return slugs.indexOf(tag.slug) > -1; - }); - - return filteredSlugs.map(function (tag) { - return '<span class="label label-info">#' + tag.title + '</span>'; - }).join(' '); - } - - jQuery('#all_tickets_table_v2').on('click', 'button.btn_quick_view_ticket', function () { - var row = dtTable.row(jQuery(this).parents('tr')); - var icon = jQuery(this).find('span'); - - if (row.child.isShown()) { - row.child.hide(); - jQuery(icon).removeClass('glyphicon-eye-close'); - jQuery(icon).addClass('glyphicon-eye-open'); - } else { - row.child(getChildRowHtml(row.data())).show(); - jQuery(icon).removeClass('glyphicon-eye-open'); - jQuery(icon).addClass('glyphicon-eye-close'); - } - }); - jQuery('#all_tickets_tab_header').click(function () { - if (jQuery(this).parent().hasClass('active') === false) { - loadCount(); - dtTable.draw(); - } - }); - - jQuery(document).on('click', '.ticket_action_refresh', function () { - const ticket_id = jQuery(this).data('id'); - jQuery.ajax({ - type: 'post', - url: ajaxurl, - data: { - action: 'eh_crm_ticket_single_view', - ticket_id: ticket_id, - nonce: js_obj.nonce, - pagination_id : jQuery("#pagination_ids_traverse").val() - }, - success: function (data) { - jQuery(".table_loader").css("display", "none"); - var parse = jQuery.parseJSON(data); - jQuery('#tab_content_' + ticket_id).html(parse.tab_content); - trigger_load_single_ticket(ticket_id); - collapse_tab(); - },}); - }); - -})(); -</script> -<?php -// return ob_get_clean(); +<?php++use Illuminate\Support\Arr;+use WSDesk\Settings\SettingsItem;+use WSDesk\Settings\SettingsRepository;+use WSDesk\Tickets\TicketRepository;++if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++$repo = new TicketRepository();+$settings = new SettingsRepository();++$ticket_filters_with_count = $repo->get_available_views();++$avail_labels_wf = array_values( $settings->getLabels() );+$avail_labels_f = array_values( $settings->getFilterableLabels() );++$avail_tags_wf = array_values( $settings->getTags() );+$avail_tags_f = array_values( $settings->getFilterableTags() );+$avail_templates = array_values( $settings->getTemplates() );++$available_views_f = $settings->getFilterableViews();+$selected_views = eh_crm_get_settingsmeta( 0, 'selected_views' );++if ( ! $avail_templates ) {+ $avail_templates = array();+}+$user_roles_default = array( 'WSDesk_Agents', 'WSDesk_Supervisor', 'administrator' );+$user_caps_default = array( 'reply_tickets', 'delete_tickets', 'manage_tickets' );+$users_filter =+ array(+ 'role__in' => $user_roles_default,+ 'orderby' => 'display_name',+ );+if ( wsdesk_can_access_other_tickets() === false ) {+ $users_filter['include'] = array( get_current_user_id() );+}++$users = get_users(+ $users_filter+);+$users_data = array();++$users_data = array_map(+ function ( $user ) {+ $users_data['id'] = $user->ID;+ $users_data['name'] = $user->display_name;+ $users_data['caps'] = $user->caps;+ $users_data['email'] = $user->user_email;+ return $users_data ;+ },+ $users+);++/****+ * Ticket Filters+ */+$ticket_filters_with_count = array_map(+ function ( $filter ) use ( $avail_labels_f, $avail_tags_f, $available_views_f, $users_data, $selected_views ) {+ if ( 'Labels' === $filter['title'] ) {+ $filter['items'] = $avail_labels_f;+ }++ if ( 'Tags' === $filter['title'] ) {+ $filter['items'] = $avail_tags_f;+ }++ if ( 'Views' === $filter['title'] ) {+ $filter['items'] = array_filter(+ $available_views_f,+ function ( $view ) use ( $selected_views, $filter ) {+ return \Illuminate\Support\Str::startsWith( $view['slug'], 'view_' ) && in_array( $view['slug'], $selected_views , true ) && in_array( $view['slug'], Arr::get( $filter, 'data', array() ), true );+ }+ );++ $filter['items'] = Arr::sort(+ $filter['items'],+ function ( $view ) use ( $selected_views ) {+ return array_search( $view['slug'], $selected_views, true );+ }+ );++ }++ if ( 'Agents' === $filter['title'] ) {+ $filter['items'] = array_map(+ function ( $user ) {+ return array(+ 'slug' => $user['id'],+ 'title' => $user['name'],+ );+ },+ $users_data+ );+ $filter['items'][] = array(+ 'slug' => 'null',+ 'title' => 'Unassigned',+ );+ }++ if ( 'Users' === $filter['title'] ) {+ $filter['items'] = array(+ array(+ 'slug' => 'registered',+ 'title' => 'Registered Users',+ ),+ array(+ 'slug' => 'guest',+ 'title' => 'Guest Users',+ ),+ );+ }++ return $filter;+ },+ $ticket_filters_with_count+);++$avail_fields = array_values( $settings->getFields() );+$active_fields = eh_crm_get_settingsmeta( '0', 'selected_fields' );+$active_fields = is_array( $active_fields ) ? $active_fields : array( $active_fields );+$all_tickets_page_columns = wsdesk_get_all_tickets_page_fields();++// TODO: Sort based on the all_tickets_page_columns+$columns = [];+foreach ( $avail_fields as $key => $field ) {+ if ( strpos( $field['slug'], 'request_' ) !== 0 && in_array( $field['slug'], $active_fields, true ) && in_array( $field['slug'], $all_tickets_page_columns , true ) ) {+ $field = new SettingsItem( $field );+ $columns[] = [+ 'data' => $field['slug'],+ 'field_type' => $field->get_meta()->get( 'field_type' ),+ 'title' => $field['title'],+ ];+ }+}++$active_fields = array_map(+ function ( $f ) {+ return str_replace( 'request_', 'ticket_', $f );+ },+ $active_fields+);++$avail_caps = array( 'reply_tickets', 'delete_tickets', 'manage_tickets', 'manage_templates' );+$access = array();+$logged_user = wp_get_current_user();++if ( ! in_array( 'administrator', $logged_user->roles , true ) ) {++ $access = array_intersect( $avail_caps, array_keys( $logged_user->caps ) );+} else {+ $access = $avail_caps;+}++// ob_start();++?>+<div class="container">+ <div class="row" style="margin-top: 10px;">+ <div class="col-md-3" id="all_tickets_v2_left_bar" style="max-height: 100vh;overflow: auto;overflow-x: hidden;min-height: 100px;">+ <ul class="nav nav-pills nav-stacked side-bar-filter" id="v2_all_tickets_section">+ <li class="active" id="view_item_all_tickets"><a href="#" id="all"><span class="badge pull-right"><?php echo esc_html( $repo->count() ); ?></span> <?php esc_html_e( 'All Tickets', 'wsdesk' ); ?> <?php require 'eh_crm_table_loader.php'; ?></a></li>+ </ul>+ <hr>+ <div id="ticket_views_count">+ <?php+ if ( is_array( $ticket_filters_with_count ) && ! empty( $ticket_filters_with_count ) && isset( $ticket_filters_with_count ) ) {+ foreach ( $ticket_filters_with_count as $view ) {+ ?>+ <div >+ <h4><?php echo esc_html__( $view['title'], 'wsdesk' ); ?></h4>+ <ul class="nav nav-pills nav-stacked side-bar-filter" id="<?php echo esc_html( strtolower( $view['title'] ) ); ?>">+ <?php foreach ( $view['items'] as $item ) { ?>+ <li data-slug="<?php echo esc_html( $item['slug'] ); ?>" id="view_item_<?php echo esc_html( $item['slug'] ); ?>"><a href="#" id="all"><span class="badge pull-right">...</span> <?php echo esc_html__( $item['title'], 'wsdesk' ); ?></a></li>+ <?php } ?>+ </ul>+ <hr />+ </div>+ <?php+ }+ }+ ?>+ </div>+ </div>++ <div class="col-md-9" style="padding-right:0px;">+ <input type="hidden" name="view_type"/>+ <input type="hidden" name="view_slug"/>+ <div class="panel panel-default" >+ <div class="panel-body">+ <table class="table" id="all_tickets_table_v2">+ </table>+ </div>+ </div>+ </div>+ </div>+</div>+ <div class="modal fade" id="edit_tickets_modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">+ <div class="modal-dialog" role="document">+ <div class="modal-content">+ <div class="modal-header">+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>+ <h4 class="modal-title" style="padding-left: 15px;"><?php esc_html_e( 'Edit', 'wsdesk' ); ?> <span class="number_of_tickets"></span> <?php esc_html_e( 'Ticket', 'wsdesk' ); ?>(s)</h4>+ <input type="hidden" name="ticket_ids" id="edit_ticket_ids" value="">+ <input type="hidden" name="ticket_select_all" id="edit_ticket_select_all" value="">+ </div>+ <div class="modal-body">+ <div class="row">+ <div class="col-md-4 left-modal-body">+ <div class="row bulk-edit-row">+ <label class="edit_tickets_label"><?php esc_html__( 'Assignee', 'wsdesk' ); ?></label>+ <select id="assignee_ticket_edit" class="form-control" aria-describedby="helpBlock" multiple="multiple">+ <?php+ foreach ( $users_data as $i => $user ) {+ if ( in_array( 'administrator', array_keys( $users_data[ $i ]['caps'] ), true ) ) {+ ?>+ <option value="<?php echo esc_html( $user['id'] ); ?>">+ <?php echo esc_html( $user['name'] ) . ' | ' . esc_html__( 'Administrator', 'wsdesk' ); ?>+ </option>+ <?php+ } elseif ( in_array( 'WSDesk_Supervisor', array_keys( $users_data[ $i ]['caps'] ), true ) ) {+ ?>+ <option value="<?php echo esc_html( $user['id'] ); ?>">+ <?php echo esc_html( $user['name'] ) . ' | ' . esc_html__( 'Supervisor', 'wsdesk' ); ?>+ </option>+ <?php+ } elseif ( in_array( 'WSDesk_Agents', array_keys( $users_data[ $i ]['caps'] ) , true ) ) {+ ?>+ <option value="<?php echo esc_html( $user['id'] ); ?>">+ <?php echo esc_html( $user['name'] ) . ' | ' . esc_html__( 'Agent', 'wsdesk' ); ?>+ </option>+ <?php+ }
Analyzing the provided diff... The diff shows a file with only line ending changes (CRLF to LF conversion). The content remains identical between versions 3.3.4 and 3.3.5, with no actual code modifications. --- **Vulnerability Existed: no** **No security vulnerabilities detected** **Old Code** All lines contain identical PHP/JavaScript code with CRLF line endings **Fixed Code** All lines contain identical PHP/JavaScript code with LF line endings **Explanation:** This diff represents a line ending normalization (CRLF → LF) with zero actual code changes. No security fixes, patches, or modifications were introduced. The file content remains functionally identical, so no vulnerabilities were introduced or fixed. This is purely a formatting/whitespace change common in version control standardization.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/tickets/eh_crm_table_loader.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/tickets/eh_crm_table_loader.php 2025-12-21 09:36:35.511308688 +0000@@ -1,5 +1,5 @@-<span class="spinner_loader table_loader"> - <span class="bounce1"></span> - <span class="bounce2"></span> - <span class="bounce3"></span> +<span class="spinner_loader table_loader">+ <span class="bounce1"></span>+ <span class="bounce2"></span>+ <span class="bounce3"></span> </span>\ No newline at end of file
Vulnerability Existed: no Explanation: This diff contains only whitespace changes (indentation normalization). No code logic, functionality, or security-relevant content has been modified. The file remains an HTML template with static span elements used for displaying a loading spinner animation. There are no: - Input validation changes - Authentication/authorization modifications - SQL queries or database interactions - External data handling - API endpoint changes - Cryptographic operations - File operations - Command execution This is purely a formatting/style change with no security implications.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/tickets/wsdesk_print.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/tickets/wsdesk_print.php 2025-12-21 09:36:35.511308688 +0000@@ -1,557 +1,557 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -class WSDesk_Print { - public $ticket_id; - public function __construct() { - if ( current_user_can( 'activate_plugins' ) || current_user_can( 'crm_role' ) ) { - add_action( 'admin_menu', array( $this, 'wsdesk_print_admin_menus' ), 100 ); - add_action( 'admin_init', array( $this, 'wsdesk_print_setup' ) ); - } - } - - public function wsdesk_print_admin_menus() { - if ( isset( $_GET['ticket'] ) && isset( $_GET['master'] ) ) { - $this->ticket_id = sanitize_text_field( $_GET['ticket'] ); - $current = eh_crm_get_ticket( - array( - 'ticket_id' => $this->ticket_id, - 'ticket_parent' => 0, - ) - ); - if ( $current && md5( $current[0]['ticket_email'] ) == $_GET['master'] ) { - add_dashboard_page( '', '', 'read', 'wsdesk_print', '' ); - } - } - } - - public function wsdesk_print_setup() { - if ( empty( $_GET['page'] ) || 'wsdesk_print' !== $_GET['page'] ) { - return; - } - wp_enqueue_style( 'wp-admin' ); - wp_enqueue_style( 'jquery' ); - ob_start(); - $this->print_header(); - $this->print_content(); - $this->print_footer(); - exit; - } - public function print_header() { - ?> - <!DOCTYPE html> - <html <?php language_attributes(); ?>> - <head> - <meta name="viewport" content="width=device-width" /> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <title><?php esc_html_e( 'WSDesk › Print #' . $this->ticket_id, 'wsdesk' ); ?></title> - <?php - wp_enqueue_style( 'ticket-css', EH_CRM_MAIN_CSS . 'crm_tickets.css', '', EH_CRM_VERSION ); - wp_enqueue_style( 'new-ticket-css', EH_CRM_MAIN_CSS . 'new-style.css', '', EH_CRM_VERSION ); - wp_enqueue_style( 'bootstrap-css', EH_CRM_MAIN_CSS . 'bootstrap.css', '', EH_CRM_VERSION ); - wp_enqueue_style( 'boot-css', EH_CRM_MAIN_CSS . 'boot.css', '', EH_CRM_VERSION ); - wp_enqueue_style( 'print-css', EH_CRM_MAIN_CSS . 'print.css', '', EH_CRM_VERSION ); - ?> - <?php - /** - * Fire an action hook for admin print styles - * - * @since 3.1.2 - * - */ - do_action( 'admin_print_styles' ); - ?> - <script type="text/javascript"> - var ajaxurl = '<?php echo esc_url( admin_url( 'admin-ajax.php', 'relative' ) ); ?>'; - </script> - </head> - <body class="wsdesk_wrapper" id="print_body"> - <div class="Ws-content-detail-full" style="width:100%;"> - <div class="rightPanel" style="border-left: 0px !important;width:100%;"> - <?php - } - public function print_footer() { - ?> - </div> - </div> - <div class="footer"> - <div class="copyright"><div class="powered_wsdesk"><?php esc_html_e( 'Powered by', 'wsdesk' ); ?> WSDesk</div></div> - </div> - <?php - wp_print_scripts( 'jquery' ); - ?> - <script> - jQuery( document ).ready(function() { - jQuery('.get_attachement_image').each(function(){ - var img = jQuery(this).css('background-image'); - img = img.substring(img.indexOf('url("')+5,img.indexOf('")')); - var html = '<img class="img-upload clickable" style="width:50px" src="'+img+'">'; - jQuery(this).html(html); - }); - window.print(); - }); - </script> - </body> - </html> - <?php - } - public function print_content() { - $current = eh_crm_get_ticket( array( 'ticket_id' => $this->ticket_id ) ); - $current_meta = eh_crm_get_ticketmeta( $this->ticket_id ); - $avail_fields = eh_crm_get_settings( array( 'type' => 'field' ), array( 'slug', 'title', 'settings_id' ) ); - $selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' ); - $avail_tags = eh_crm_get_settings( array( 'type' => 'tag' ), array( 'slug', 'title', 'settings_id' ) ); - $avail_labels = eh_crm_get_settings( array( 'type' => 'label' ), array( 'slug', 'title', 'settings_id' ) ); - $raiser_name = ''; - $raiser_email = $current[0]['ticket_email']; - if ( 0 != $current[0]['ticket_author'] ) { - $raiser_obj = new WP_User( $current[0]['ticket_author'] ); - $raiser_name = $raiser_obj->display_name; - } else { - $raiser_name = 'Guest'; - } - $ticket_label = ''; - $eye_color = ''; - for ( $j = 0;$j < count( $avail_labels );$j++ ) { - if ( $avail_labels[ $j ]['slug'] == $current_meta['ticket_label'] ) { - $ticket_label = $avail_labels[ $j ]['title']; - } - if ( $avail_labels[ $j ]['slug'] == $current_meta['ticket_label'] ) { - $eye_color = eh_crm_get_settingsmeta( $avail_labels[ $j ]['settings_id'], 'label_color' ); - } - } - $logged_user = wp_get_current_user(); - $logged_user_caps = array_keys( $logged_user->caps ); - $avail_caps = array( 'reply_tickets', 'delete_tickets', 'manage_tickets', 'manage_templates' ); - $access = array(); - if ( ! in_array( 'administrator', $logged_user->roles ) ) { - for ( $i = 0;$i < count( $logged_user_caps );$i++ ) { - if ( ! in_array( $logged_user_caps[ $i ], $avail_caps ) ) { - unset( $logged_user_caps[ $i ] ); - } - } - $access = $logged_user_caps; - } else { - $access = $avail_caps; - } - $users_data = get_users( array( 'role__in' => array( 'administrator', 'WSDesk_Agents', 'WSDesk_Supervisor' ) ) ); - $users = array(); - for ( $i = 0; $i < count( $users_data ); $i++ ) { - $current_user = $users_data[ $i ]; - $temp = array(); - $roles = $current_user->roles; - foreach ( $roles as $value ) { - $current_role = $value; - $temp[ $i ] = ucfirst( str_replace( '_', ' ', $current_role ) ); - } - $users[ implode( ' & ', $temp ) ][ $current_user->ID ] = $current_user->data->display_name; - } - $assignee = ( isset( $current_meta['ticket_assignee'] ) ? $current_meta['ticket_assignee'] : array() ); - $assignee_name = array(); - if ( '' !== $assignee ) { - foreach ( $users as $key => $value ) { - foreach ( $value as $id => $name ) { - if ( in_array( $id, $assignee ) ) { - array_push( $assignee_name, $name ); - } - } - } - } - $cc = ( isset( $current_meta['ticket_cc'] ) ? $current_meta['ticket_cc'] : array() ); - $cc_selected = array(); - if ( ! empty( $cc ) ) { - foreach ( $cc as $key => $value ) { - array_push( $cc_selected, $value ); - } - } - $bcc_selected = array(); - $bcc = ( isset( $current_meta['ticket_bcc'] ) ? $current_meta['ticket_bcc'] : array() ); - if ( ! empty( $bcc ) ) { - foreach ( $bcc as $key => $value ) { - array_push( $bcc_selected, $value ); - } - } - $ticket_tags = ( isset( $current_meta['ticket_tags'] ) ? $current_meta['ticket_tags'] : array() ); - $tags_selected = array(); - if ( '' !== $ticket_tags && ! empty( $avail_tags ) ) { - for ( $i = 0;$i < count( $avail_tags );$i++ ) { - if ( in_array( $avail_tags[ $i ]['slug'], $ticket_tags ) ) { - array_push( $tags_selected, $avail_tags[ $i ]['title'] ); - } - } - } - ?> - <div class="rightPanelHeader"> - <div class="leftFreeSpace"> - <div class="tictxt"> - <p style="margin-top: 5px;font-size: 20px;"> - <?php - echo '#' . esc_html( $this->ticket_id ) . ' '; - echo esc_html( $current[0]['ticket_title'] ); - ?> - - </p> - <p style="margin-top: 5px;" class="info"> - <i class="glyphicon glyphicon-user"></i> by - <?php - echo '<span>' . esc_html( $current[0]['ticket_email'] ) . '</span>'; - ?> - | <i class="glyphicon glyphicon-calendar"></i> <?php echo esc_html( eh_crm_get_formatted_date( $current[0]['ticket_date'] ) ); ?> - </p> - <p style="margin-top: 5px;" class="info"> - <i class="glyphicon glyphicon-comment"></i> - <?php - $raiser_voice = eh_crm_get_ticket_value_count( 'ticket_parent', $this->ticket_id, false, 'ticket_category', 'raiser_reply' ); - echo count( $raiser_voice ) . ' ' . esc_html__( 'Raiser Voice', 'wsdesk' ); - ?> - | <i class="glyphicon glyphicon-bullhorn"></i> - <?php - $agent_voice = eh_crm_get_ticket_value_count( 'ticket_parent', $this->ticket_id, false, 'ticket_category', 'agent_reply' ); - echo count( $agent_voice ) . ' ' . esc_html__( 'Agent Voice', 'wsdesk' ); - ?> - | <i class="glyphicon glyphicon-star"></i> Rating : <?php echo ( isset( $current_meta['ticket_rating'] ) ? esc_html( ucfirst( $current_meta['ticket_rating'] ) ) : esc_html__( 'None', 'wsdesk' ) ); ?> - </p> - <br> - <?php - if ( EH_CRM_WOO_STATUS ) { - $woo_orders = eh_crm_get_settingsmeta( 0, 'woo_order_tickets' ); - $woo_access = eh_crm_get_settingsmeta( 0, 'woo_order_access' ); - $woo_price = eh_crm_get_settingsmeta( 0, 'woo_order_price' ); - $role = ''; - if ( in_array( 'administrator', $logged_user->roles ) ) { - $role = 'administrator'; - } elseif ( in_array( 'WSDesk_Supervisor', $logged_user->roles ) ) { - $role = 'WSDesk_Supervisor'; - } elseif ( in_array( 'WSDesk_Agents', $logged_user->roles ) ) { - $role = 'WSDesk_Agents'; - } - if ( 'enable' == $woo_orders && in_array( $role, $woo_access ) ) { - $raiser_id = $current[0]['ticket_author']; - if ( 0 == $raiser_id ) { - $user = get_user_by( 'email', $current[0]['ticket_email'] ); - if ( $user ) { - $raiser_id = $user->ID; - } - } - $customer_orders = array(); - if ( 0 != $raiser_id ) { - $customer_orders = get_posts( - array( - 'orderby' => 'ID', - 'numberposts' => -1, - 'meta_key' => '_customer_user', - 'meta_value' => $raiser_id, - 'post_type' => wc_get_order_types(), - 'post_status' => array_keys( wc_get_order_statuses() ), - 'fields' => 'ids', - ) - ); - } - if ( ! empty( $customer_orders ) ) { - $order_id_url = array(); - $total_amount = 0; - $order_count = count( $customer_orders ); - $count = 0; - $cou = 0; - foreach ( $customer_orders as $order ) { - $order_data = wc_get_order( $order ); - if ( $order_data->get_status() == 'completed' ) { - $total_amount += $order_data->get_total(); - } - if ( $cou < 5 ) { - array_push( $order_id_url, '#' . $order ); - $cou++; - } - } - echo '<p style="margin-top: 5px;" class="info"><i class="glyphicon glyphicon-shopping-cart"></i> ' . esc_html__( 'Total Orders', 'wsdesk' ) . ' : ' . esc_html( $order_count ) . ' | ' . esc_html__( 'Recent Order', 'wsdesk' ) . ' : [ ' . esc_html( implode( ', ', $order_id_url ) ) . ' ]'; - if ( 'enable' == $woo_price || 'administrator' == $role ) { - echo ' | ' . esc_html__( 'Total Purchase', 'wsdesk' ) . ' : ' . esc_html( get_woocommerce_currency_symbol() ) . esc_html( $total_amount ) . ' ' . esc_html( get_woocommerce_currency() ); - } - echo '</p>'; - } else { - ?> - <p style="margin-top: 5px;" class="info"> - <i class="glyphicon glyphicon-shopping-cart"></i> <?php esc_html_e( 'Total Orders', 'wsdesk' ); ?> : 0 | <?php esc_html_e( 'Recent Order', 'wsdesk' ); ?> : <?php esc_html_e( 'None', 'wsdesk' ); ?> | <?php esc_html_e( 'Total Purchase', 'wsdesk' ); ?> : <?php echo esc_html( get_woocommerce_currency_symbol() ) . '0 ' . esc_html( get_woocommerce_currency() ); ?> - </p> - <?php - } - } - } - ?> - </div> - </div> - </div> - <div class="media-print"> - <div class="media-bod"> - <div class="table-container"> - <table class="print_table" style="border-right: 1px solid lightgray;"> - <tr> - <td> - <h5><?php esc_html_e( 'Status', 'wsdesk' ); ?></h5> - </td> - <td class="center-td"> - : - </td> - <td> - <h5><span style="color: <?php echo esc_html( $eye_color ); ?>;"><?php echo esc_html( $ticket_label ); ?> </span></h5> - </td> - </tr> - <tr> - <td> - <h5><?php esc_html_e( 'Assignee', 'wsdesk' ); ?></h5> - </td> - <td class="center-td"> - : - </td> - <td> - <h5> - <?php - if ( ! empty( $assignee_name ) ) { -echo esc_html( implode( ', ', $assignee_name ) ); - } else { - echo '-';} - ?> - </h5> - </td> - </tr> - <tr> - <td> - <h5><?php esc_html_e( 'Tags', 'wsdesk' ); ?></h5> - </td> - <td class="center-td"> - : - </td> - <td> - <h5> - <?php - if ( ! empty( $tags_selected ) ) { -echo esc_html( implode( ', ', $tags_selected ) ); - } else { - echo '-';} - ?> - </h5> - </td> - </tr> - <?php - if ( ! empty( $cc_selected ) ) { - ?> - <tr> - <td> - <h5><?php esc_html_e( 'Cc', 'wsdesk' ); ?></h5> - </td> - <td class="center-td"> - : - </td> - <td> - <h5><?php echo esc_html( implode( ', ', $cc_selected ) ); ?></h5> - </td> - </tr> - <?php - } - if ( ! empty( $cc_selected ) ) { - ?> - <tr> - <td> - <h5><?php esc_html_e( 'Bcc', 'wsdesk' ); ?></h5> - </td> - <td class="center-td"> - : - </td> - <td> - <h5><?php echo esc_html( implode( ', ', $bcc_selected ) ); ?></h5> - </td> - </tr> - <?php - } - ?> - </table> - <table class="print_table" style="margin-left:20px;"> - <?php - for ( $i = 0; $i < count( $selected_fields ); $i++ ) { - for ( $j = 3; $j < count( $avail_fields ); $j++ ) { - if ( $avail_fields[ $j ]['slug'] == $selected_fields[ $i ] ) { - $field_ticket_value = ( isset( $current_meta[ $avail_fields[ $j ]['slug'] ] ) ? $current_meta[ $avail_fields[ $j ]['slug'] ] : '-' ); - $current_settings_meta = eh_crm_get_settingsmeta( $avail_fields[ $j ]['settings_id'] ); - if ( 'file' != $current_settings_meta['field_type'] && 'google_captcha' != $current_settings_meta['field_type'] ) { - switch ( $current_settings_meta['field_type'] ) { - case 'text': - case 'date': - case 'email': - case 'number': - case 'password': - case 'textarea': - case 'phone': - echo '<tr> - <td> - <h5>' . esc_html( $avail_fields[ $j ]['title'] ) . '</h5> - </td> - <td class="center-td"> - : - </td> - <td> - <h5>' . esc_html( $field_ticket_value ) . '</h5> - </td> - </tr>'; - break; - case 'select': - case 'radio': - $gen_val = array(); - $field_values = $current_settings_meta['field_values']; - foreach ( $field_values as $key => $value ) { - if ( $key == $field_ticket_value ) { - array_push( $gen_val, $value ); - } - } - echo '<tr> - <td> - <h5>' . esc_html( $avail_fields[ $j ]['title'] ) . '</h5> - </td> - <td class="center-td"> - : - </td> - <td> - <h5>' . ( ( ! empty( $gen_val ) ) ? esc_html( implode( ', ', $gen_val ) ) : '-' ) . '</h5> - </td> - </tr>'; - break; - case 'checkbox': - $gen_val = array(); - $field_values = $current_settings_meta['field_values']; - $field_ticket_value = is_array( $field_ticket_value ) ? $field_ticket_value : array(); - foreach ( $field_values as $key => $value ) { - if ( in_array( $key, $field_ticket_value ) ) { - array_push( $gen_val, $value ); - } - } - echo '<tr> - <td> - <h5>' . esc_html( $avail_fields[ $j ]['title'] ) . '</h5> - </td> - <td class="center-td"> - : - </td> - <td> - <h5>' . ( ( ! empty( $gen_val ) ) ? esc_html( implode( ', ', $gen_val ) ) : '-' ) . '</h5> - </td> - </tr>'; - break; - } - } - } - } - } - ?> - </table> - </div> - </div> - </div> - <?php - $reply_id = eh_crm_get_ticket_value_count( 'ticket_parent', $this->ticket_id, false, '', '', 'ticket_updated', 'DESC' ); - array_push( $reply_id, array( 'ticket_id' => $this->ticket_id ) ); - for ( $s = 0;$s < count( $reply_id );$s++ ) { - $reply_ticket = eh_crm_get_ticket( array( 'ticket_id' => $reply_id[ $s ]['ticket_id'] ) ); - $reply_ticket_meta = eh_crm_get_ticketmeta( $reply_id[ $s ]['ticket_id'] ); - $replier_name = ''; - $replier_email = $reply_ticket[0]['ticket_email']; - $replier_pic = ''; - if ( 0 != $reply_ticket[0]['ticket_author'] ) { - $replier_obj = new WP_User( $reply_ticket[0]['ticket_author'] ); - $replier_name = $replier_obj->display_name; - $replier_pic = get_avatar_url( $reply_ticket[0]['ticket_author'], array( 'size' => 50 ) ); - } else { - $replier_name = 'Guest'; - $replier_pic = get_avatar_url( $reply_ticket[0]['ticket_email'], array( 'size' => 50 ) ); - } - $attachment = ''; - if ( isset( $reply_ticket_meta['ticket_attachment'] ) ) { - $reply_att = $reply_ticket_meta['ticket_attachment']; - $attachment = '<div>'; - for ( $at = 0;$at < count( $reply_att );$at++ ) { - $current_att = $reply_att[ $at ]; - $att_ext = pathinfo( $current_att, PATHINFO_EXTENSION ); - if ( empty( $att_ext ) ) { - $att_ext = ''; - } - $att_name = pathinfo( $current_att, PATHINFO_FILENAME ); - $img_ext = array( 'jpg', 'jpeg', 'png', 'gif' ); - if ( in_array( strtolower( $att_ext ), $img_ext ) ) { - $attachment .= '<img class="img-upload clickable" style="width:200px" title="' . $att_name . '" src="' . $current_att . '">'; - } else { - $check_file_ext = array( 'doc', 'docx', 'pdf', 'xml', 'csv', 'xlsx', 'xls', 'txt', 'zip' ); - if ( in_array( $att_ext, $check_file_ext ) ) { - $attachment .= '<div class="' . $att_ext . ' get_attachement_image"></div>'; - } else { - $attachment .= '<div class="unknown_type get_attachement_image"></div>'; - } - } - } - $attachment .= '</div>'; - } - $color = ''; - switch ( $reply_ticket[0]['ticket_category'] ) { - case 'satisfaction_survey': - if ( 'great' == $current_meta['ticket_rating'] ) { - $color = 'background-color: #88fcb6 !important'; - } else { - $color = 'background-color: #f7aba5 !important'; - } - break; - case 'agent_note': - $color = 'background-color: aliceblue!important'; - break; - default: - break; - } - echo '<div class="conversation_each" style="' . esc_html( $color ) . '"> - <div class="leftFreeSpace"> - <div class="icon"><img src="' . esc_url( $replier_pic ) . '" style="border-radius: 25px;"></div> - <h3>' . esc_html( $replier_name ) . '</h3> - <h4>' . esc_html( $replier_email ) . ' | ' . esc_html( eh_crm_get_formatted_date( $reply_ticket[0]['ticket_date'] ) ) . ' </h4> - ' . ( ( 'satisfaction_survey' === $reply_ticket[0]['ticket_category'] ) ? '<b>' . esc_html__( 'Satisfaction Comment', 'wsdesk' ) . '</b><br>' : '' ) . ' - <p>'; - echo esc_html( stripslashes( $reply_ticket[0]['ticket_content'] ) ); - echo '</p>'; - if ( isset( $reply_ticket_meta['ticket_attachment'] ) ) { - $reply_att = $reply_ticket_meta['ticket_attachment']; - ?> - <div> - <?php - for ( $at = 0;$at < count( $reply_att );$at++ ) { - $current_att = $reply_att[ $at ]; - $att_ext = pathinfo( $current_att, PATHINFO_EXTENSION ); - if ( empty( $att_ext ) ) { - $att_ext = ''; - } - $att_name = pathinfo( $current_att, PATHINFO_FILENAME ); - $img_ext = array( 'jpg', 'jpeg', 'png', 'gif' ); - if ( in_array( strtolower( $att_ext ), $img_ext ) ) { - ?> - <img class="img-upload clickable" style="width:200px" title='<?php echo esc_html( $att_name ); ?>' src='<?php echo esc_html( $current_att ); ?>'>'; - <?php - } else { - $check_file_ext = array( 'doc', 'docx', 'pdf', 'xml', 'csv', 'xlsx', 'xls', 'txt', 'zip' ); - if ( in_array( $att_ext, $check_file_ext ) ) { - ?> - <div class='<?php echo esc_html( $att_ext ); ?> get_attachement_image'></div>; - <?php - } else { - ?> - <div class='unknown_type get_attachement_image'></div>; - <?php - } - } - } - ?> - </div> - <?php - } - ?> - </div> - </div> - <?php - } - } -} -new WSDesk_Print(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++class WSDesk_Print {+ public $ticket_id;+ public function __construct() {+ if ( current_user_can( 'activate_plugins' ) || current_user_can( 'crm_role' ) ) {+ add_action( 'admin_menu', array( $this, 'wsdesk_print_admin_menus' ), 100 );+ add_action( 'admin_init', array( $this, 'wsdesk_print_setup' ) );+ }+ }++ public function wsdesk_print_admin_menus() {+ if ( isset( $_GET['ticket'] ) && isset( $_GET['master'] ) ) {+ $this->ticket_id = sanitize_text_field( $_GET['ticket'] );+ $current = eh_crm_get_ticket(+ array(+ 'ticket_id' => $this->ticket_id, + 'ticket_parent' => 0,+ ) + );+ if ( $current && md5( $current[0]['ticket_email'] ) == $_GET['master'] ) {+ add_dashboard_page( '', '', 'read', 'wsdesk_print', '' );+ }+ }+ }++ public function wsdesk_print_setup() {+ if ( empty( $_GET['page'] ) || 'wsdesk_print' !== $_GET['page'] ) {+ return;+ }+ wp_enqueue_style( 'wp-admin' );+ wp_enqueue_style( 'jquery' );+ ob_start();+ $this->print_header();+ $this->print_content();+ $this->print_footer();+ exit;+ }+ public function print_header() {+ ?>+ <!DOCTYPE html>+ <html <?php language_attributes(); ?>>+ <head>+ <meta name="viewport" content="width=device-width" />+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />+ <title><?php esc_html_e( 'WSDesk › Print #' . $this->ticket_id, 'wsdesk' ); ?></title>+ <?php + wp_enqueue_style( 'ticket-css', EH_CRM_MAIN_CSS . 'crm_tickets.css', '', EH_CRM_VERSION );+ wp_enqueue_style( 'new-ticket-css', EH_CRM_MAIN_CSS . 'new-style.css', '', EH_CRM_VERSION );+ wp_enqueue_style( 'bootstrap-css', EH_CRM_MAIN_CSS . 'bootstrap.css', '', EH_CRM_VERSION );+ wp_enqueue_style( 'boot-css', EH_CRM_MAIN_CSS . 'boot.css', '', EH_CRM_VERSION );+ wp_enqueue_style( 'print-css', EH_CRM_MAIN_CSS . 'print.css', '', EH_CRM_VERSION );+ ?>+ <?php + /**+ * Fire an action hook for admin print styles+ *+ * @since 3.1.2+ * + */+ do_action( 'admin_print_styles' ); + ?>+ <script type="text/javascript">+ var ajaxurl = '<?php echo esc_url( admin_url( 'admin-ajax.php', 'relative' ) ); ?>';+ </script>+ </head>+ <body class="wsdesk_wrapper" id="print_body">+ <div class="Ws-content-detail-full" style="width:100%;">+ <div class="rightPanel" style="border-left: 0px !important;width:100%;">+ <?php+ }+ public function print_footer() {+ ?>+ </div>+ </div>+ <div class="footer">+ <div class="copyright"><div class="powered_wsdesk"><?php esc_html_e( 'Powered by', 'wsdesk' ); ?> WSDesk</div></div>+ </div>+ <?php+ wp_print_scripts( 'jquery' );+ ?>+ <script>+ jQuery( document ).ready(function() {+ jQuery('.get_attachement_image').each(function(){+ var img = jQuery(this).css('background-image');+ img = img.substring(img.indexOf('url("')+5,img.indexOf('")'));+ var html = '<img class="img-upload clickable" style="width:50px" src="'+img+'">';+ jQuery(this).html(html);+ });+ window.print();+ });+ </script>+ </body>+ </html>+ <?php+ }+ public function print_content() {+ $current = eh_crm_get_ticket( array( 'ticket_id' => $this->ticket_id ) );+ $current_meta = eh_crm_get_ticketmeta( $this->ticket_id );+ $avail_fields = eh_crm_get_settings( array( 'type' => 'field' ), array( 'slug', 'title', 'settings_id' ) );+ $selected_fields = eh_crm_get_settingsmeta( 0, 'selected_fields' );+ $avail_tags = eh_crm_get_settings( array( 'type' => 'tag' ), array( 'slug', 'title', 'settings_id' ) );+ $avail_labels = eh_crm_get_settings( array( 'type' => 'label' ), array( 'slug', 'title', 'settings_id' ) );+ $raiser_name = '';+ $raiser_email = $current[0]['ticket_email'];+ if ( 0 != $current[0]['ticket_author'] ) {+ $raiser_obj = new WP_User( $current[0]['ticket_author'] );+ $raiser_name = $raiser_obj->display_name;+ } else {+ $raiser_name = 'Guest';+ }+ $ticket_label = '';+ $eye_color = '';+ for ( $j = 0;$j < count( $avail_labels );$j++ ) {+ if ( $avail_labels[ $j ]['slug'] == $current_meta['ticket_label'] ) {+ $ticket_label = $avail_labels[ $j ]['title'];+ }+ if ( $avail_labels[ $j ]['slug'] == $current_meta['ticket_label'] ) {+ $eye_color = eh_crm_get_settingsmeta( $avail_labels[ $j ]['settings_id'], 'label_color' );+ }+ }+ $logged_user = wp_get_current_user();+ $logged_user_caps = array_keys( $logged_user->caps );+ $avail_caps = array( 'reply_tickets', 'delete_tickets', 'manage_tickets', 'manage_templates' );+ $access = array();+ if ( ! in_array( 'administrator', $logged_user->roles ) ) {+ for ( $i = 0;$i < count( $logged_user_caps );$i++ ) {+ if ( ! in_array( $logged_user_caps[ $i ], $avail_caps ) ) {+ unset( $logged_user_caps[ $i ] );+ }+ }+ $access = $logged_user_caps;+ } else {+ $access = $avail_caps;+ }+ $users_data = get_users( array( 'role__in' => array( 'administrator', 'WSDesk_Agents', 'WSDesk_Supervisor' ) ) );+ $users = array();+ for ( $i = 0; $i < count( $users_data ); $i++ ) {+ $current_user = $users_data[ $i ];+ $temp = array();+ $roles = $current_user->roles;+ foreach ( $roles as $value ) {+ $current_role = $value;+ $temp[ $i ] = ucfirst( str_replace( '_', ' ', $current_role ) );+ }+ $users[ implode( ' & ', $temp ) ][ $current_user->ID ] = $current_user->data->display_name;+ }+ $assignee = ( isset( $current_meta['ticket_assignee'] ) ? $current_meta['ticket_assignee'] : array() );+ $assignee_name = array();+ if ( '' !== $assignee ) {+ foreach ( $users as $key => $value ) {+ foreach ( $value as $id => $name ) {+ if ( in_array( $id, $assignee ) ) {+ array_push( $assignee_name, $name );+ }+ } + }+ }+ $cc = ( isset( $current_meta['ticket_cc'] ) ? $current_meta['ticket_cc'] : array() );+ $cc_selected = array();+ if ( ! empty( $cc ) ) {+ foreach ( $cc as $key => $value ) {+ array_push( $cc_selected, $value );+ }+ }+ $bcc_selected = array();+ $bcc = ( isset( $current_meta['ticket_bcc'] ) ? $current_meta['ticket_bcc'] : array() );+ if ( ! empty( $bcc ) ) {+ foreach ( $bcc as $key => $value ) {+ array_push( $bcc_selected, $value );+ }+ }+ $ticket_tags = ( isset( $current_meta['ticket_tags'] ) ? $current_meta['ticket_tags'] : array() );+ $tags_selected = array();+ if ( '' !== $ticket_tags && ! empty( $avail_tags ) ) {+ for ( $i = 0;$i < count( $avail_tags );$i++ ) {+ if ( in_array( $avail_tags[ $i ]['slug'], $ticket_tags ) ) {+ array_push( $tags_selected, $avail_tags[ $i ]['title'] );+ } + }+ }+ ?>+ <div class="rightPanelHeader">+ <div class="leftFreeSpace">+ <div class="tictxt">+ <p style="margin-top: 5px;font-size: 20px;">+ <?php+ echo '#' . esc_html( $this->ticket_id ) . ' ';+ echo esc_html( $current[0]['ticket_title'] );+ ?>+ + </p>+ <p style="margin-top: 5px;" class="info">+ <i class="glyphicon glyphicon-user"></i> by+ <?php+ echo '<span>' . esc_html( $current[0]['ticket_email'] ) . '</span>';+ ?>+ | <i class="glyphicon glyphicon-calendar"></i> <?php echo esc_html( eh_crm_get_formatted_date( $current[0]['ticket_date'] ) ); ?>+ </p>+ <p style="margin-top: 5px;" class="info">+ <i class="glyphicon glyphicon-comment"></i>+ <?php+ $raiser_voice = eh_crm_get_ticket_value_count( 'ticket_parent', $this->ticket_id, false, 'ticket_category', 'raiser_reply' );+ echo count( $raiser_voice ) . ' ' . esc_html__( 'Raiser Voice', 'wsdesk' ); + ?>+ | <i class="glyphicon glyphicon-bullhorn"></i>+ <?php+ $agent_voice = eh_crm_get_ticket_value_count( 'ticket_parent', $this->ticket_id, false, 'ticket_category', 'agent_reply' );+ echo count( $agent_voice ) . ' ' . esc_html__( 'Agent Voice', 'wsdesk' );+ ?>+ | <i class="glyphicon glyphicon-star"></i> Rating : <?php echo ( isset( $current_meta['ticket_rating'] ) ? esc_html( ucfirst( $current_meta['ticket_rating'] ) ) : esc_html__( 'None', 'wsdesk' ) ); ?>+ </p>+ <br>+ <?php+ if ( EH_CRM_WOO_STATUS ) {+ $woo_orders = eh_crm_get_settingsmeta( 0, 'woo_order_tickets' );+ $woo_access = eh_crm_get_settingsmeta( 0, 'woo_order_access' );+ $woo_price = eh_crm_get_settingsmeta( 0, 'woo_order_price' );+ $role = '';+ if ( in_array( 'administrator', $logged_user->roles ) ) {+ $role = 'administrator';+ } elseif ( in_array( 'WSDesk_Supervisor', $logged_user->roles ) ) {+ $role = 'WSDesk_Supervisor';+ } elseif ( in_array( 'WSDesk_Agents', $logged_user->roles ) ) {+ $role = 'WSDesk_Agents';+ }+ if ( 'enable' == $woo_orders && in_array( $role, $woo_access ) ) {+ $raiser_id = $current[0]['ticket_author'];+ if ( 0 == $raiser_id ) {+ $user = get_user_by( 'email', $current[0]['ticket_email'] );+ if ( $user ) {+ $raiser_id = $user->ID;+ }+ }+ $customer_orders = array();+ if ( 0 != $raiser_id ) {+ $customer_orders = get_posts(+ array(+ 'orderby' => 'ID',+ 'numberposts' => -1,+ 'meta_key' => '_customer_user',+ 'meta_value' => $raiser_id,+ 'post_type' => wc_get_order_types(),+ 'post_status' => array_keys( wc_get_order_statuses() ),+ 'fields' => 'ids',+ )+ );+ }+ if ( ! empty( $customer_orders ) ) {+ $order_id_url = array();+ $total_amount = 0;+ $order_count = count( $customer_orders );+ $count = 0;+ $cou = 0;+ foreach ( $customer_orders as $order ) {+ $order_data = wc_get_order( $order );+ if ( $order_data->get_status() == 'completed' ) {+ $total_amount += $order_data->get_total();+ }+ if ( $cou < 5 ) {+ array_push( $order_id_url, '#' . $order );+ $cou++;+ }+ }+ echo '<p style="margin-top: 5px;" class="info"><i class="glyphicon glyphicon-shopping-cart"></i> ' . esc_html__( 'Total Orders', 'wsdesk' ) . ' : ' . esc_html( $order_count ) . ' | ' . esc_html__( 'Recent Order', 'wsdesk' ) . ' : [ ' . esc_html( implode( ', ', $order_id_url ) ) . ' ]';+ if ( 'enable' == $woo_price || 'administrator' == $role ) {+ echo ' | ' . esc_html__( 'Total Purchase', 'wsdesk' ) . ' : ' . esc_html( get_woocommerce_currency_symbol() ) . esc_html( $total_amount ) . ' ' . esc_html( get_woocommerce_currency() );+ }+ echo '</p>';+ } else {+ ?>+ <p style="margin-top: 5px;" class="info">+ <i class="glyphicon glyphicon-shopping-cart"></i> <?php esc_html_e( 'Total Orders', 'wsdesk' ); ?> : 0 | <?php esc_html_e( 'Recent Order', 'wsdesk' ); ?> : <?php esc_html_e( 'None', 'wsdesk' ); ?> | <?php esc_html_e( 'Total Purchase', 'wsdesk' ); ?> : <?php echo esc_html( get_woocommerce_currency_symbol() ) . '0 ' . esc_html( get_woocommerce_currency() ); ?>+ </p>+ <?php+ }+ }+ }+ ?>+ </div>+ </div>+ </div>+ <div class="media-print">+ <div class="media-bod">+ <div class="table-container">+ <table class="print_table" style="border-right: 1px solid lightgray;">+ <tr>+ <td>+ <h5><?php esc_html_e( 'Status', 'wsdesk' ); ?></h5>+ </td>+ <td class="center-td">+ :+ </td>+ <td>+ <h5><span style="color: <?php echo esc_html( $eye_color ); ?>;"><?php echo esc_html( $ticket_label ); ?> </span></h5>+ </td>+ </tr>+ <tr>+ <td>+ <h5><?php esc_html_e( 'Assignee', 'wsdesk' ); ?></h5>+ </td>+ <td class="center-td">+ :+ </td>+ <td>+ <h5>+ <?php + if ( ! empty( $assignee_name ) ) {+echo esc_html( implode( ', ', $assignee_name ) );+ } else {+ echo '-';} + ?>+ </h5>+ </td>+ </tr>+ <tr>+ <td>+ <h5><?php esc_html_e( 'Tags', 'wsdesk' ); ?></h5>+ </td>+ <td class="center-td">+ :+ </td>+ <td>+ <h5>+ <?php + if ( ! empty( $tags_selected ) ) {+echo esc_html( implode( ', ', $tags_selected ) );+ } else {+ echo '-';} + ?>+ </h5>+ </td>+ </tr>+ <?php+ if ( ! empty( $cc_selected ) ) {+ ?>+ <tr>+ <td>+ <h5><?php esc_html_e( 'Cc', 'wsdesk' ); ?></h5>+ </td>+ <td class="center-td">+ :+ </td>+ <td>+ <h5><?php echo esc_html( implode( ', ', $cc_selected ) ); ?></h5>+ </td>+ </tr>+ <?php+ }+ if ( ! empty( $cc_selected ) ) {+ ?>+ <tr>+ <td>+ <h5><?php esc_html_e( 'Bcc', 'wsdesk' ); ?></h5>+ </td>+ <td class="center-td">+ :+ </td>+ <td>+ <h5><?php echo esc_html( implode( ', ', $bcc_selected ) ); ?></h5>+ </td>+ </tr>+ <?php+ }+ ?>+ </table>+ <table class="print_table" style="margin-left:20px;">+ <?php + for ( $i = 0; $i < count( $selected_fields ); $i++ ) {+ for ( $j = 3; $j < count( $avail_fields ); $j++ ) {+ if ( $avail_fields[ $j ]['slug'] == $selected_fields[ $i ] ) {+ $field_ticket_value = ( isset( $current_meta[ $avail_fields[ $j ]['slug'] ] ) ? $current_meta[ $avail_fields[ $j ]['slug'] ] : '-' );+ $current_settings_meta = eh_crm_get_settingsmeta( $avail_fields[ $j ]['settings_id'] );+ if ( 'file' != $current_settings_meta['field_type'] && 'google_captcha' != $current_settings_meta['field_type'] ) {+ switch ( $current_settings_meta['field_type'] ) {+ case 'text':+ case 'date':+ case 'email':+ case 'number':+ case 'password':+ case 'textarea':+ case 'phone':+ echo '<tr>+ <td>+ <h5>' . esc_html( $avail_fields[ $j ]['title'] ) . '</h5>+ </td>+ <td class="center-td">+ :+ </td>+ <td>+ <h5>' . esc_html( $field_ticket_value ) . '</h5>+ </td>+ </tr>';+ break;+ case 'select':+ case 'radio':+ $gen_val = array();+ $field_values = $current_settings_meta['field_values'];+ foreach ( $field_values as $key => $value ) {+ if ( $key == $field_ticket_value ) {+ array_push( $gen_val, $value );+ }+ }+ echo '<tr>+ <td>+ <h5>' . esc_html( $avail_fields[ $j ]['title'] ) . '</h5>+ </td>+ <td class="center-td">+ :+ </td>+ <td>+ <h5>' . ( ( ! empty( $gen_val ) ) ? esc_html( implode( ', ', $gen_val ) ) : '-' ) . '</h5>+ </td>+ </tr>';+ break;+ case 'checkbox':+ $gen_val = array();+ $field_values = $current_settings_meta['field_values'];+ $field_ticket_value = is_array( $field_ticket_value ) ? $field_ticket_value : array();+ foreach ( $field_values as $key => $value ) {+ if ( in_array( $key, $field_ticket_value ) ) {+ array_push( $gen_val, $value );+ }+ }+ echo '<tr>+ <td>+ <h5>' . esc_html( $avail_fields[ $j ]['title'] ) . '</h5>+ </td>+ <td class="center-td">+ :+ </td>+ <td>+ <h5>' . ( ( ! empty( $gen_val ) ) ? esc_html( implode( ', ', $gen_val ) ) : '-' ) . '</h5>+ </td>+ </tr>';+ break;+ }
# Security Analysis Results This diff shows a line-ending normalization (converting from Windows CRLF to Unix LF) across the entire file. The actual code logic remains identical. ## Finding: **Vulnerability Existed: no** Improper Neutralization of Input During Web Page Generation - CWE-79 - views/tickets/wsdesk_print.php - Line 482 (and other locations) **Old Code:** ```php <img class="img-upload clickable" style="width:200px" title="' . $att_name . '" src="' . $current_att . '">'; ``` **Fixed Code:** ```php <img class="img-upload clickable" style="width:200px" title='<?php echo esc_html( $att_name ); ?>' src='<?php echo esc_html( $current_att ); ?>'>'; ``` **Explanation:** Despite this being purely a line-ending normalization diff, the actual codebase does contain XSS vulnerabilities that exist in BOTH versions. The old code concatenates user-controlled data (`$att_name` and `$current_att`) directly into HTML attributes without proper escaping. However, since the diff shows identical functional code with only whitespace changes, **no security fix is present in this particular diff**. The vulnerabilities remain unfixed in version 3.3.5. The file should use `esc_attr()` for HTML attributes instead of `esc_html()`, and `esc_url()` for the src attribute.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
--- cache/elex-helpdesk-customer-support-ticket-system_3.3.4/views/welcome/welcome.php 2025-12-21 09:35:59.585075764 +0000+++ cache/elex-helpdesk-customer-support-ticket-system_3.3.5/views/welcome/welcome.php 2025-12-21 09:36:35.515308936 +0000@@ -1,573 +1,573 @@-<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -class WSDesk_Setup_Wizard { - private $step = ''; - private $steps = array(); - public function __construct() { - if ( current_user_can( 'activate_plugins' ) ) { - add_action( 'admin_menu', array( $this, 'wsdesk_admin_menus' ) ); - add_action( 'admin_init', array( $this, 'wsdesk_setup_wizard' ) ); - } - update_option( 'wsdesk_setup_wizard', 'shown' ); - } - - public function wsdesk_admin_menus() { - add_dashboard_page( '', '', 'manage_options', 'wsdesk-setup', '' ); - } - - /** - * Show the setup wizard. - */ - public function wsdesk_setup_wizard() { - if ( empty( $_GET['page'] ) || 'wsdesk-setup' !== $_GET['page'] ) { - return; - } - $default_steps = array( - 'introduction' => array( - 'name' => esc_html__( 'Start', 'wsdesk' ), - 'view' => array( $this, 'wsdesk_setup_introduction' ), - 'handler' => '', - ), - 'pages' => array( - 'name' => esc_html__( 'Support Setup', 'wsdesk' ), - 'view' => array( $this, 'wsdesk_setup_pages' ), - 'handler' => array( $this, 'wsdesk_setup_pages_save' ), - ), - 'fields' => array( - 'name' => esc_html__( 'Ticket Fields', 'wsdesk' ), - 'view' => array( $this, 'wsdesk_setup_fields' ), - 'handler' => '', - ), - 'email' => array( - 'name' => esc_html__( 'Email Client', 'wsdesk' ), - 'view' => array( $this, 'wsdesk_setup_email' ), - 'handler' => '', - ), - 'agents' => array( - 'name' => esc_html__( 'WSDesk Agents', 'wsdesk' ), - 'view' => array( $this, 'wsdesk_setup_agents' ), - 'handler' => '', - ), - 'next_steps' => array( - 'name' => esc_html__( 'Ready!', 'wsdesk' ), - 'view' => array( $this, 'wsdesk_setup_ready' ), - 'handler' => '', - ), - ); - $this->steps = $default_steps; - $this->step = isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : 'introduction'; - if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_GET['_wpnonce'] ), 'wsdesk-setup' ) ) { - die; - } - if ( ! empty( $_POST['save_step'] ) && isset( $this->steps[ $this->step ]['handler'] ) ) { - call_user_func( $this->steps[ $this->step ]['handler'], $this ); - } - wp_register_script( 'material-bootstrap-wizard', EH_CRM_MAIN_JS . 'welcome/material-bootstrap-wizard.js', '', EH_CRM_VERSION ); - wp_register_script( 'bootstrap', EH_CRM_MAIN_JS . 'bootstrap.js', '', EH_CRM_VERSION ); - wp_register_script( 'jquery.bootstrap', EH_CRM_MAIN_JS . 'welcome/jquery.bootstrap.js', '', EH_CRM_VERSION ); - wp_register_script( 'jquery.validate.min', EH_CRM_MAIN_JS . 'welcome/jquery.validate.min.js', '', EH_CRM_VERSION ); - wp_enqueue_style( 'wp-admin' ); - wp_enqueue_style( 'jquery' ); - $page = ( isset( $_GET['page'] ) ? sanitize_text_field( $_GET['page'] ) : '' ); - if ( 'wsdesk-setup' == $page ) { - wp_register_script( 'dialog', EH_CRM_MAIN_JS . 'dialog.js', '', EH_CRM_VERSION ); - wp_enqueue_style( 'dialog', EH_CRM_MAIN_CSS . 'dialog.css', '', EH_CRM_VERSION ); - wp_enqueue_style( 'select2', EH_CRM_MAIN_CSS . 'select2.css', '', EH_CRM_VERSION ); - wp_register_script( 'select2', EH_CRM_MAIN_JS . 'select2.js', '', EH_CRM_VERSION ); - if ( 'fields' === $this->step ) { - wp_register_script( 'crm_settings', EH_CRM_MAIN_JS . 'crm_settings.js', '', EH_CRM_VERSION ); - $js_var = eh_crm_js_translation_obj( 'settings' ); - wp_localize_script( 'crm_settings', 'js_obj', $js_var ); - wp_enqueue_style( 'crm_settings', EH_CRM_MAIN_CSS . 'crm_settings.css', '', EH_CRM_VERSION ); - wp_enqueue_script( 'jquery-ui-datepicker' ); - wp_enqueue_style( 'jquery-ui' , EH_CRM_MAIN_CSS . 'jquery-ui.css', '', EH_CRM_VERSION ); - wp_register_script( 'dragDrop', EH_CRM_MAIN_JS . 'DragDrop.js', '', EH_CRM_VERSION ); - } - if ( 'agents' === $this->step ) { - wp_register_script( 'crm_agents', EH_CRM_MAIN_JS . 'crm_agents.js', '', EH_CRM_VERSION ); - wp_enqueue_style( 'crm_agents', EH_CRM_MAIN_CSS . 'crm_agents.css', '', EH_CRM_VERSION ); - $js_var = eh_crm_js_translation_obj( 'agents' ); - wp_localize_script( 'crm_agents', 'js_obj', $js_var ); - } - if ( 'email' === $this->step ) { - wp_register_script( 'crm_email', EH_CRM_MAIN_JS . 'crm_email.js', '', EH_CRM_VERSION ); - wp_enqueue_style( 'crm_email', EH_CRM_MAIN_CSS . 'crm_email.css', '', EH_CRM_VERSION ); - $js_var = eh_crm_js_translation_obj( 'email' ); - wp_localize_script( 'crm_email', 'js_obj', $js_var ); - } - } - ob_start(); - $this->setup_wizard_header(); - if ( 'introduction' != $this->step ) { - $this->setup_wizard_steps(); - } - $this->setup_wizard_content(); - $this->setup_wizard_footer(); - exit; - } - public function get_next_step_link( $step = '' ) { - if ( ! $step ) { - $step = $this->step; - } - - $keys = array_keys( $this->steps ); - if ( end( $keys ) === $step ) { - return admin_url(); - } - - $step_index = array_search( $step, $keys ); - if ( false === $step_index ) { - return ''; - } - - return add_query_arg( 'step', $keys[ $step_index + 1 ] ); - } - - /** - * Setup Wizard Header. - */ - public function setup_wizard_header() { - ?> - <!DOCTYPE html> - <html <?php language_attributes(); ?>> - <head> - <meta name="viewport" content="width=device-width" /> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <title><?php esc_html_e( 'WSDesk › Setup Wizard', 'wsdesk' ); ?></title> - <?php - wp_enqueue_style( 'setup-css', EH_CRM_MAIN_CSS . 'welcome/setup.css', '', EH_CRM_VERSION ); - wp_enqueue_style( 'wsdesk_bootstrap-css2', EH_CRM_MAIN_CSS . 'welcome/bootstrap.min.css', '', EH_CRM_VERSION ); - wp_enqueue_style( 'wsdesk_bootstrap-css3', EH_CRM_MAIN_CSS . 'bootstrap.css', '', EH_CRM_VERSION ); - wp_enqueue_style( 'wsdesk_bootstrap-css1', EH_CRM_MAIN_CSS . 'welcome/boot.css', '', EH_CRM_VERSION ); - wp_enqueue_style( 'material-bootstrap-wizard-css1', EH_CRM_MAIN_CSS . 'welcome/material-bootstrap-wizard.css', '', EH_CRM_VERSION ); - ?> - <?php - /** - * Fire an action hook for admin print styles - * - * @since 3.1.2 - * - */ - do_action( 'admin_print_styles' ); - ?> - <?php - /** - * Fire an action hook for admin head - * - * @since 3.1.2 - * - */ - do_action( 'admin_head' ); - ?> - <script type="text/javascript"> - var ajaxurl = '<?php echo esc_url( admin_url( 'admin-ajax.php', 'relative' ) ); ?>'; - </script> - </head> - <body style="background-color:#f1f1f1 !important;"> - <center> - <div class="logo" style="margin-bottom:20px;"> - <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank"> - <img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'wsdesk.png' ); ?>"> - </a> - </div> - <a href="<?php echo esc_url( admin_url() ); ?>" ><?php esc_html_e( 'Return to the WordPress Dashboard', 'wsdesk' ); ?></a> - </center> - <div class="container" style="margin-bottom:30px;"> - <div class="row"> - <div class="col-sm-10 col-sm-offset-1"> - - <div class="wizard-container" style="padding-top: 30px !important"> - <div class="setup-wsdesk-card wizard-card" data-color="red" id="wizard"> - <?php - switch ( $this->step ) { - case 'introduction': - ?> - <div class="wizard-header" style="padding-bottom:10px !important;margin-top:20px !important;"> - <h1 class="wizard-title" style="font-weight: bold;"> - <?php esc_html_e( 'Thank you for choosing WSDesk to power your online support!', 'wsdesk' ); ?> - </h1> - </div> - <?php - - break; - case 'next_steps': - ?> - <div class="wizard-header"> - <h3 class="wizard-title" style="font-weight: bold;"> - <?php esc_html_e( 'Your helpdesk is ready!', 'wsdesk' ); ?> - </h3> - </div> - <?php - break; - default: - ?> - <div class="wizard-header"> - <h3 class="wizard-title" style="font-weight: bold;"> - <?php esc_html_e( 'WSDesk - Quick Setup Wizard', 'wsdesk' ); ?> - </h3> - </div> - <?php - break; - } - ?> - <?php - } - - /** - * Setup Wizard Footer. - */ - public function setup_wizard_footer() { - ?> - </div> - </div> - </div> - </div> - </div> - <?php - if ( 'fields' === $this->step ) { - wp_print_scripts( 'jquery-ui-datepicker' ); - } - wp_print_scripts( 'jquery' ); - wp_print_scripts( 'bootstrap' ); - wp_print_scripts( 'dialog' ); - wp_print_scripts( 'jquery.bootstrap' ); - wp_print_scripts( 'material-bootstrap-wizard' ); - wp_print_scripts( 'jquery.validate.min' ); - if ( 'fields' === $this->step ) { - wp_print_scripts( 'crm_settings' ); - wp_print_scripts( 'dragDrop' ); - } - wp_print_scripts( 'select2' ); - if ( 'agents' === $this->step ) { - wp_print_scripts( 'crm_agents' ); - } - if ( 'email' === $this->step ) { - wp_print_scripts( 'crm_email' ); - } - ?> - </body> - </html> - <?php - } - - /** - * Output the steps. - */ - public function setup_wizard_steps() { - $ouput_steps = $this->steps; - array_shift( $ouput_steps ); - ?> - <div class="wizard-navigation"> - <ul> - <?php foreach ( $ouput_steps as $step_key => $step ) : ?> - <li style="margin-bottom: 0px !important;" class=" - <?php - if ( $step_key === $this->step ) { - echo 'active'; - } elseif ( array_search( $this->step, array_keys( $this->steps ) ) > array_search( $step_key, array_keys( $this->steps ) ) ) { - echo 'done'; - } - ?> - "> - <a href="#<?php echo esc_html( $step_key ); ?>" style="pointer-events:none;" data-toggle="tab"><?php echo esc_attr_e( $step['name'] ); ?></a> - </li> - <?php endforeach; ?> - </ul> - </div> - <?php - } - - public function setup_wizard_content() { - echo '<div class="tab-content wsdesk-setup-content"><div class="loader"></div>'; - call_user_func( $this->steps[ $this->step ]['view'], $this ); - echo '</div>'; - } - - public function wsdesk_setup_introduction() { - ?> - <center> - <p><?php echo wp_kses_post( 'This quick setup wizard will help you configure the basic settings. <br/><strong>It’s completely optional and shouldn’t take longer.</strong>' ); ?></p> - <p><?php esc_html_e( 'No time right now? If you don’t want to go through the wizard, you can skip and configure it later under settings.', 'wsdesk' ); ?></p> - <p> - <a href="<?php echo esc_url( admin_url( 'admin.php?page=wsdesk_tickets' ) ); ?>" class="btn btn-default wsdesk-setup-actions"><?php esc_html_e( 'Not right now', 'wsdesk' ); ?></a> - <a href="<?php echo esc_url( $this->get_next_step_link() ); ?>" class="btn-info btn wsdesk-setup-actions"><?php esc_html_e( 'Let\'s setup now!', 'wsdesk' ); ?></a> - </p> - </center> - <?php - } - - public function wsdesk_setup_pages() { - ?> - <center> - <div style="margin-top:10px;"> - <form method="post"> - <p style="margin: 0 0 15px;"><?php printf( esc_html__( 'Set your support page title, email ID and ticket starting ticket ID.', 'wsdesk' ), esc_url( admin_url( 'edit.php?post_type=page' ) ) ); ?></p> - <div class="row"> - <div class="col-sm-12"> - <div class="col-sm-6"> - <div class="input-group" style="width:90%"> - <div class="form-group1" style="margin:0px !important;"> - <span class="input-group-addon" style="padding: 6px 15px 10px !important;"> - <span class="glyphicon glyphicon-envelope" style="font-size: 35px;"></span> - </span> - <label for="support_email" style="color:black;"><?php esc_html_e( 'WSDesk Support Email', 'wsdesk' ); ?></label> - <br> - <label for="support_email"><small><?php esc_html_e( 'The email ID which is used for support responses', 'wsdesk' ); ?></small></label> - <br> - <input name="support_email" id="support_email" type="email" class="form-control1" style="font-size: 20px;height: 40px;width:80%;" placeholder="[email protected]"> - </div> - </div> - </div> - <div class="col-sm-6"> - <div class="input-group" style="width:90%"> - <div class="form-group1" style="margin:0px !important;"> - <span class="input-group-addon" style="padding: 6px 15px 10px !important;"> - <span class="glyphicon glyphicon-list-alt" style="font-size: 35px;"></span> - </span> - <label for="page_name" style="color:black;"><?php esc_html_e( 'Starting Ticket ID', 'wsdesk' ); ?></label> - <br> - <label for="page_name"><small><?php esc_html_e( 'You can set your first Ticket\'s ID here.', 'wsdesk' ); ?></small></label> - <br> - <input name="ticket_id" id="ticket_id" type="text" class="form-control1" style="font-size: 20px;width:80%;height: 40px;" placeholder="<?php esc_html_e( 'Default Ticket ID is 1', 'wsdesk' ); ?>"> - </div> - </div> - </div> - </div> - </div> - <div class="row"> - <div class="col-sm-4"> - <div class="input-group" style="width:90%"> - <div class="form-group1" style="margin:0px !important;"> - <span class="input-group-addon" style="padding: 6px 15px 10px !important;"> - <span class="glyphicon glyphicon-headphones" style="font-size: 35px;"></span> - </span> - <label for="page_name" style="color:black;"><?php esc_html_e( 'WSDesk Support Page Title', 'wsdesk' ); ?></label> - <br> - <label for="page_name"><small><?php esc_html_e( 'Title which will be displayed on your site', 'wsdesk' ); ?></small></label> - <br> - <input name="page_name" id="page_name" type="text" class="form-control1" style="font-size: 20px;width:80%;height: 40px;" placeholder="<?php esc_html_e( 'Enter page title', 'wsdesk' ); ?>"> - </div> - </div> - </div> - <div class="col-sm-4"> - <div class="input-group" style="width:90%"> - <div class="form-group1" style="margin:0px !important;"> - <span class="input-group-addon" style="padding: 6px 15px 10px !important;"> - <span class="glyphicon glyphicon-headphones" style="font-size: 35px;"></span> - </span> - <label for="page_name" style="color:black;"><?php esc_html_e( 'WSDesk Individual Ticket Page Title', 'wsdesk' ); ?></label> - <br> - <label for="page_name"><small><?php esc_html_e( 'Title which will be displayed on your site', 'wsdesk' ); ?></small></label> - <br> - <input name="single_ticket_page_name" id="page_name" type="text" class="form-control1" style="font-size: 20px;width:80%;height: 40px;" placeholder="<?php esc_html_e( 'Enter page title', 'wsdesk' ); ?>"> - </div> - </div> - </div> - <div class="col-sm-4"> - <div class="input-group" style="width:90%"> - <div class="form-group1" style="margin:0px !important;"> - <span class="input-group-addon" style="padding: 6px 15px 10px !important;"> - <span class="glyphicon glyphicon-headphones" style="font-size: 35px;"></span> - </span> - <label for="page_name" style="color:black;"><?php esc_html_e( 'WSDesk Existing Ticket Page Title', 'wsdesk' ); ?></label> - <br> - <label for="page_name"><small><?php esc_html_e( 'Title which will be displayed on your site', 'wsdesk' ); ?></small></label> - <br> - <input name="existing_ticket_page_name" id="page_name" type="text" class="form-control1" style="font-size: 20px;width:80%;height: 40px;" placeholder="<?php esc_html_e( 'Enter page title', 'wsdesk' ); ?>"> - </div> - </div> - </div> - </div> - <div class="pull-right" style="margin-top: 15px;"> - <p style="padding: 0px 20px;"> - <a href="<?php echo esc_url( $this->get_next_step_link() ); ?>" class="btn-default btn wsdesk-setup-actions"><?php esc_html_e( 'Skip this step', 'wsdesk' ); ?></a> - <input type="submit" class="btn-info btn wsdesk-setup-actions" value="<?php esc_attr_e( 'Save & Continue', 'wsdesk' ); ?>" name="save_step"/> - <?php wp_nonce_field( 'wsdesk-setup' ); ?> - </p> - </div> - </form> - </div> - </center> - <?php - } - - public function wsdesk_setup_pages_save() { - check_admin_referer( 'wsdesk-setup' ); - global $wpdb; - $table_name = $wpdb->prefix . 'wsdesk_tickets'; - $name = ( isset( $_POST['page_name'] ) ) ? sanitize_text_field( $_POST['page_name'] ) : esc_html__( 'Support', 'wsdesk' ); - $single_ticket_page_name = ( isset( $_POST['single_ticket_page_name'] ) ) ? sanitize_text_field( $_POST['single_ticket_page_name'] ) : esc_html__( 'Single Ticket View', 'wsdesk' ); - $existing_ticket_page_name = ( isset( $_POST['existing_ticket_page_name'] ) ) ? sanitize_text_field( $_POST['existing_ticket_page_name'] ) : esc_html__( 'Existing Tickets', 'wsdesk' ); - - $email = ( isset( $_POST['support_email'] ) ) ? sanitize_text_field( $_POST['support_email'] ) : ''; - $ticket_id = ( isset( $_POST['ticket_id'] ) && is_numeric( $_POST['ticket_id'] ) ) ? sanitize_text_field( $_POST['ticket_id'] ) : ''; - $post = array( - 'comment_status' => 'closed', - 'ping_status' => 'closed', - 'post_author' => get_current_user_id(), - 'post_content' => '[wsdesk_support display="form"]', - 'post_status' => 'publish', - 'post_title' => $name, - 'post_type' => 'page', - ); - $newvalue = wp_insert_post( $post, false ); - if ( ! is_wp_error( $newvalue ) ) { - update_option( 'wsdesk_support_page', $newvalue ); - } - - $post['post_content'] = '[wsdesk_support display="form_support_request_table"]'; - $post['post_title'] = $single_ticket_page_name; - $newvalue = wp_insert_post( $post, false ); - - $post['post_content'] = '[wsdesk_support display="check_request"]'; - $post['post_title'] = $existing_ticket_page_name; - $newvalue = wp_insert_post( $post, false ); - - eh_crm_update_settingsmeta( 0, 'support_reply_email', $email ); - if ( '' != $ticket_id ) { - $wpdb->get_var( $wpdb->prepare( "ALTER TABLE {$wpdb->prefix}wsdesk_tickets AUTO_INCREMENT = %d", $ticket_id ) ); - } - wp_redirect( esc_url_raw( $this->get_next_step_link() ) ); - exit; - } - - /** - * Locale settings. - */ - public function wsdesk_setup_fields() { - ?> - <div class="row" style="margin-top:15px;"> - <div class="col-md-12"> - <center> - <h2><?php esc_html_e( 'Configure your support form fields', 'wsdesk' ); ?></h2> - </center> - </div> - </div> - <div class="tab-pane" id="ticket_fields_tab" style="display: block;"> - <?php include EH_CRM_MAIN_VIEWS . 'settings/crm_settings_fields.php' ; ?> - </div> - <div class="row"> - <div class="col-md-12" style="margin-left:15px;"> - <small><?php esc_html_e( 'Save your changes before going to next step.', 'wsdesk' ); ?></small> - </div> - </div> - <div class="row"> - <div class="col-md-6 col-sm-offset-3"> - <div class="alert alert-success" style="display: none" role="alert"> - <div id="success_alert_text"></div> - </div> - <div class="alert alert-danger" style="display: none" role="alert"> - <div id="danger_alert_text"></div> - </div> - </div> - <span class="crm-divider"></span> - <center> - <div class="pull-right" style="margin-top: 15px;"> - <p style="padding: 0px 20px;"> - <a href="<?php echo esc_url( $this->get_next_step_link() ); ?>" class="btn btn-default"><?php esc_html_e( 'Skip this step', 'wsdesk' ); ?></a> - <a href="<?php echo esc_url( $this->get_next_step_link() ); ?>" class="btn btn-info"><?php esc_html_e( 'Continue', 'wsdesk' ); ?></a> - </p> - </div> - </center> - </div> - <?php - } - - /** - * Shipping and taxes. - */ - public function wsdesk_setup_email() { - ?> - <div class="row" style="margin-top:15px;"> - <div class="col-md-12"> - <center> - <h2><?php esc_html_e( 'Configure your Email client to create tickets', 'wsdesk' ); ?></h2> - </center> - </div> - </div> - <div class="tab-pane col-sm-offset-2 col-sm-8" id="imap_setup_tab" style="display: block;"> - <?php include EH_CRM_MAIN_VIEWS . 'email/crm_imap_setup.php' ; ?> - </div> - <div class="row"> - <div class="col-md-6 col-sm-offset-3"> - <div class="alert alert-success" style="display: none" role="alert"> - <div id="success_alert_text"></div> - </div> - <div class="alert alert-danger" style="display: none" role="alert"> - <div id="danger_alert_text"></div> - </div> - </div> - <span class="crm-divider"></span> - <center> - <div class="pull-right" style="margin-top: 15px;"> - <p style="padding: 0px 20px;"> - <a href="<?php echo esc_url( $this->get_next_step_link() ); ?>" class="btn btn-default"><?php esc_html_e( 'Skip this step', 'wsdesk' ); ?></a> - <a href="<?php echo esc_url( $this->get_next_step_link() ); ?>" class="btn btn-info"><?php esc_html_e( 'Continue', 'wsdesk' ); ?></a> - </p> - </div> - </center> - </div> - <?php - } - - public function wsdesk_setup_agents() { - ?> - <div class="row" style="margin-top:15px;"> - <div class="col-md-12"> - <center> - <h2><?php esc_html_e( 'Setup your support agents to handle tickets', 'wsdesk' ); ?></h2> - </center> - </div> - </div> - <div class="tab-pane col-sm-12" style="display: block;"> - <?php include EH_CRM_MAIN_VIEWS . 'agents/crm_agents_main.php' ; ?> - </div> - <div class="row"> - <span class="crm-divider"></span> - <center> - <div class="pull-right" style="margin-top: 15px;"> - <p style="padding: 0px 20px;"> - <a href="<?php echo esc_url( $this->get_next_step_link() ); ?>" class="btn btn-default"><?php esc_html_e( 'Skip this step', 'wsdesk' ); ?></a> - <a href="<?php echo esc_url( $this->get_next_step_link() ); ?>" class="btn btn-info"><?php esc_html_e( 'Continue', 'wsdesk' ); ?></a> - </p> - </div> - </center> - </div> - - <?php - } - - /** - * Final step. - */ - public function wsdesk_setup_ready() { - $page = get_option( 'wsdesk_support_page' ); - $support_url = get_permalink( $page ); - ?> - <div class="row" style="margin:20px 0px;"> - <div class="col-sm-12" style="background-color:#f5f5f5;padding: 10px;"> - <div class="col-sm-3" style="text-align:center;"> - <label><?php esc_html_e( 'Configure your Helpdesk', 'wsdesk' ); ?></label><br> - <a class="btn btn-primary btn-lg" href="<?php echo esc_url( admin_url( 'admin.php?page=wsdesk_settings' ) ); ?>"><?php esc_html_e( 'Go to Settings', 'wsdesk' ); ?></a> - </div> - <div class="col-sm-3" style="text-align:center;"> - <label><?php esc_html_e( 'Get started with your first ticket', 'wsdesk' ); ?></label><br> - <a class="btn btn-primary btn-lg" href="<?php echo esc_url( $support_url ); ?>"><?php esc_html_e( 'Create a ticket!', 'wsdesk' ); ?></a> - </div> - <div class="col-sm-6"> - <ul> - <li style="font-size:15px;margin-bottom: 10px;"><span class="glyphicon glyphicon-link"></span> <a style="cursor:pointer;" href="https://elextensions.com/documentation/#wsdesk-wordpress-helpdesk-plugin" target="_blank"><?php esc_html_e( 'WSDesk Documentation', 'wsdesk' ); ?></a></li> - <li style="font-size:15px;margin-bottom: 10px;"><span class="glyphicon glyphicon-link"></span> <a style="cursor:pointer;" href="https://elextensions.com/knowledge-base/set-up-google-oauth-individual-gmail-account-google-oauth-credentials-wsdesk/" target="_blank"><?php esc_html_e( 'Read how to setup Google OAuth.', 'wsdesk' ); ?></a></li> - <li style="font-size:15px;margin-bottom: 10px;"><span class="glyphicon glyphicon-link"></span> <a style="cursor:pointer;" href="https://elextensions.com/knowledge-base/steps-import-tickets-zendesk-wsdesk/" target="_blank"><?php esc_html_e( 'How to import tickets from Zendesk?', 'wsdesk' ); ?></a></li> - </ul> - </div> - </div> - </div> - <?php - } -} - -new WSDesk_Setup_Wizard(); +<?php+if ( ! defined( 'ABSPATH' ) ) {+ exit;+}++class WSDesk_Setup_Wizard {+ private $step = '';+ private $steps = array();+ public function __construct() {+ if ( current_user_can( 'activate_plugins' ) ) {+ add_action( 'admin_menu', array( $this, 'wsdesk_admin_menus' ) );+ add_action( 'admin_init', array( $this, 'wsdesk_setup_wizard' ) );+ }+ update_option( 'wsdesk_setup_wizard', 'shown' );+ }++ public function wsdesk_admin_menus() {+ add_dashboard_page( '', '', 'manage_options', 'wsdesk-setup', '' );+ }++ /**+ * Show the setup wizard.+ */+ public function wsdesk_setup_wizard() {+ if ( empty( $_GET['page'] ) || 'wsdesk-setup' !== $_GET['page'] ) {+ return;+ }+ $default_steps = array(+ 'introduction' => array(+ 'name' => esc_html__( 'Start', 'wsdesk' ),+ 'view' => array( $this, 'wsdesk_setup_introduction' ),+ 'handler' => '',+ ),+ 'pages' => array(+ 'name' => esc_html__( 'Support Setup', 'wsdesk' ),+ 'view' => array( $this, 'wsdesk_setup_pages' ),+ 'handler' => array( $this, 'wsdesk_setup_pages_save' ),+ ),+ 'fields' => array(+ 'name' => esc_html__( 'Ticket Fields', 'wsdesk' ),+ 'view' => array( $this, 'wsdesk_setup_fields' ),+ 'handler' => '',+ ),+ 'email' => array(+ 'name' => esc_html__( 'Email Client', 'wsdesk' ),+ 'view' => array( $this, 'wsdesk_setup_email' ),+ 'handler' => '',+ ),+ 'agents' => array(+ 'name' => esc_html__( 'WSDesk Agents', 'wsdesk' ),+ 'view' => array( $this, 'wsdesk_setup_agents' ),+ 'handler' => '',+ ),+ 'next_steps' => array(+ 'name' => esc_html__( 'Ready!', 'wsdesk' ),+ 'view' => array( $this, 'wsdesk_setup_ready' ),+ 'handler' => '',+ ),+ );+ $this->steps = $default_steps;+ $this->step = isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : 'introduction';+ if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_GET['_wpnonce'] ), 'wsdesk-setup' ) ) {+ die;+ }+ if ( ! empty( $_POST['save_step'] ) && isset( $this->steps[ $this->step ]['handler'] ) ) {+ call_user_func( $this->steps[ $this->step ]['handler'], $this );+ }+ wp_register_script( 'material-bootstrap-wizard', EH_CRM_MAIN_JS . 'welcome/material-bootstrap-wizard.js', '', EH_CRM_VERSION );+ wp_register_script( 'bootstrap', EH_CRM_MAIN_JS . 'bootstrap.js', '', EH_CRM_VERSION );+ wp_register_script( 'jquery.bootstrap', EH_CRM_MAIN_JS . 'welcome/jquery.bootstrap.js', '', EH_CRM_VERSION );+ wp_register_script( 'jquery.validate.min', EH_CRM_MAIN_JS . 'welcome/jquery.validate.min.js', '', EH_CRM_VERSION );+ wp_enqueue_style( 'wp-admin' );+ wp_enqueue_style( 'jquery' );+ $page = ( isset( $_GET['page'] ) ? sanitize_text_field( $_GET['page'] ) : '' );+ if ( 'wsdesk-setup' == $page ) {+ wp_register_script( 'dialog', EH_CRM_MAIN_JS . 'dialog.js', '', EH_CRM_VERSION );+ wp_enqueue_style( 'dialog', EH_CRM_MAIN_CSS . 'dialog.css', '', EH_CRM_VERSION );+ wp_enqueue_style( 'select2', EH_CRM_MAIN_CSS . 'select2.css', '', EH_CRM_VERSION );+ wp_register_script( 'select2', EH_CRM_MAIN_JS . 'select2.js', '', EH_CRM_VERSION );+ if ( 'fields' === $this->step ) {+ wp_register_script( 'crm_settings', EH_CRM_MAIN_JS . 'crm_settings.js', '', EH_CRM_VERSION );+ $js_var = eh_crm_js_translation_obj( 'settings' );+ wp_localize_script( 'crm_settings', 'js_obj', $js_var );+ wp_enqueue_style( 'crm_settings', EH_CRM_MAIN_CSS . 'crm_settings.css', '', EH_CRM_VERSION );+ wp_enqueue_script( 'jquery-ui-datepicker' );+ wp_enqueue_style( 'jquery-ui' , EH_CRM_MAIN_CSS . 'jquery-ui.css', '', EH_CRM_VERSION );+ wp_register_script( 'dragDrop', EH_CRM_MAIN_JS . 'DragDrop.js', '', EH_CRM_VERSION );+ }+ if ( 'agents' === $this->step ) {+ wp_register_script( 'crm_agents', EH_CRM_MAIN_JS . 'crm_agents.js', '', EH_CRM_VERSION );+ wp_enqueue_style( 'crm_agents', EH_CRM_MAIN_CSS . 'crm_agents.css', '', EH_CRM_VERSION );+ $js_var = eh_crm_js_translation_obj( 'agents' );+ wp_localize_script( 'crm_agents', 'js_obj', $js_var );+ }+ if ( 'email' === $this->step ) {+ wp_register_script( 'crm_email', EH_CRM_MAIN_JS . 'crm_email.js', '', EH_CRM_VERSION );+ wp_enqueue_style( 'crm_email', EH_CRM_MAIN_CSS . 'crm_email.css', '', EH_CRM_VERSION );+ $js_var = eh_crm_js_translation_obj( 'email' );+ wp_localize_script( 'crm_email', 'js_obj', $js_var );+ }+ }+ ob_start();+ $this->setup_wizard_header();+ if ( 'introduction' != $this->step ) {+ $this->setup_wizard_steps();+ }+ $this->setup_wizard_content();+ $this->setup_wizard_footer();+ exit;+ }+ public function get_next_step_link( $step = '' ) {+ if ( ! $step ) {+ $step = $this->step;+ }++ $keys = array_keys( $this->steps );+ if ( end( $keys ) === $step ) {+ return admin_url();+ }++ $step_index = array_search( $step, $keys );+ if ( false === $step_index ) {+ return '';+ }++ return add_query_arg( 'step', $keys[ $step_index + 1 ] );+ }++ /**+ * Setup Wizard Header.+ */+ public function setup_wizard_header() {+ ?>+ <!DOCTYPE html>+ <html <?php language_attributes(); ?>>+ <head>+ <meta name="viewport" content="width=device-width" />+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />+ <title><?php esc_html_e( 'WSDesk › Setup Wizard', 'wsdesk' ); ?></title>+ <?php+ wp_enqueue_style( 'setup-css', EH_CRM_MAIN_CSS . 'welcome/setup.css', '', EH_CRM_VERSION );+ wp_enqueue_style( 'wsdesk_bootstrap-css2', EH_CRM_MAIN_CSS . 'welcome/bootstrap.min.css', '', EH_CRM_VERSION );+ wp_enqueue_style( 'wsdesk_bootstrap-css3', EH_CRM_MAIN_CSS . 'bootstrap.css', '', EH_CRM_VERSION );+ wp_enqueue_style( 'wsdesk_bootstrap-css1', EH_CRM_MAIN_CSS . 'welcome/boot.css', '', EH_CRM_VERSION );+ wp_enqueue_style( 'material-bootstrap-wizard-css1', EH_CRM_MAIN_CSS . 'welcome/material-bootstrap-wizard.css', '', EH_CRM_VERSION );+ ?>+ <?php+ /**+ * Fire an action hook for admin print styles+ *+ * @since 3.1.2+ * + */+ do_action( 'admin_print_styles' ); + ?>+ <?php + /**+ * Fire an action hook for admin head+ *+ * @since 3.1.2+ * + */+ do_action( 'admin_head' );+ ?>+ <script type="text/javascript">+ var ajaxurl = '<?php echo esc_url( admin_url( 'admin-ajax.php', 'relative' ) ); ?>';+ </script>+ </head>+ <body style="background-color:#f1f1f1 !important;">+ <center>+ <div class="logo" style="margin-bottom:20px;">+ <a href="https://elextensions.com/plugin/wsdesk-wordpress-support-desk-plugin/" target="_blank">+ <img src="<?php echo esc_url( EH_CRM_MAIN_IMG . 'wsdesk.png' ); ?>">+ </a>+ </div>+ <a href="<?php echo esc_url( admin_url() ); ?>" ><?php esc_html_e( 'Return to the WordPress Dashboard', 'wsdesk' ); ?></a>+ </center>+ <div class="container" style="margin-bottom:30px;">+ <div class="row">+ <div class="col-sm-10 col-sm-offset-1">++ <div class="wizard-container" style="padding-top: 30px !important">+ <div class="setup-wsdesk-card wizard-card" data-color="red" id="wizard">+ <?php+ switch ( $this->step ) {+ case 'introduction':+ ?>+ <div class="wizard-header" style="padding-bottom:10px !important;margin-top:20px !important;">+ <h1 class="wizard-title" style="font-weight: bold;">+ <?php esc_html_e( 'Thank you for choosing WSDesk to power your online support!', 'wsdesk' ); ?>+ </h1>+ </div>+ <?php++ break;+ case 'next_steps':+ ?>+ <div class="wizard-header">+ <h3 class="wizard-title" style="font-weight: bold;">+ <?php esc_html_e( 'Your helpdesk is ready!', 'wsdesk' ); ?>+ </h3>+ </div>+ <?php+ break;+ default:+ ?>+ <div class="wizard-header">+ <h3 class="wizard-title" style="font-weight: bold;">+ <?php esc_html_e( 'WSDesk - Quick Setup Wizard', 'wsdesk' ); ?>+ </h3>+ </div>+ <?php+ break;+ }+ ?>+ <?php+ }++ /**+ * Setup Wizard Footer.+ */+ public function setup_wizard_footer() {+ ?>+ </div>+ </div>+ </div>+ </div>+ </div>+ <?php+ if ( 'fields' === $this->step ) {+ wp_print_scripts( 'jquery-ui-datepicker' );+ }+ wp_print_scripts( 'jquery' );+ wp_print_scripts( 'bootstrap' );+ wp_print_scripts( 'dialog' );+ wp_print_scripts( 'jquery.bootstrap' );+ wp_print_scripts( 'material-bootstrap-wizard' );+ wp_print_scripts( 'jquery.validate.min' );+ if ( 'fields' === $this->step ) {+ wp_print_scripts( 'crm_settings' );+ wp_print_scripts( 'dragDrop' );+ }+ wp_print_scripts( 'select2' );+ if ( 'agents' === $this->step ) {+ wp_print_scripts( 'crm_agents' );+ }+ if ( 'email' === $this->step ) {+ wp_print_scripts( 'crm_email' );+ }+ ?>+ </body>+ </html>+ <?php+ }++ /**+ * Output the steps.+ */+ public function setup_wizard_steps() {+ $ouput_steps = $this->steps;+ array_shift( $ouput_steps );+ ?>+ <div class="wizard-navigation">+ <ul>+ <?php foreach ( $ouput_steps as $step_key => $step ) : ?>+ <li style="margin-bottom: 0px !important;" class="+ <?php+ if ( $step_key === $this->step ) {+ echo 'active';+ } elseif ( array_search( $this->step, array_keys( $this->steps ) ) > array_search( $step_key, array_keys( $this->steps ) ) ) {+ echo 'done';+ }+ ?>+ ">+ <a href="#<?php echo esc_html( $step_key ); ?>" style="pointer-events:none;" data-toggle="tab"><?php echo esc_attr_e( $step['name'] ); ?></a>+ </li>+ <?php endforeach; ?>+ </ul>+ </div>+ <?php+ }++ public function setup_wizard_content() {+ echo '<div class="tab-content wsdesk-setup-content"><div class="loader"></div>';+ call_user_func( $this->steps[ $this->step ]['view'], $this );+ echo '</div>';+ }++ public function wsdesk_setup_introduction() {+ ?>+ <center>+ <p><?php echo wp_kses_post( 'This quick setup wizard will help you configure the basic settings. <br/><strong>It’s completely optional and shouldn’t take longer.</strong>' ); ?></p>+ <p><?php esc_html_e( 'No time right now? If you don’t want to go through the wizard, you can skip and configure it later under settings.', 'wsdesk' ); ?></p>+ <p>+ <a href="<?php echo esc_url( admin_url( 'admin.php?page=wsdesk_tickets' ) ); ?>" class="btn btn-default wsdesk-setup-actions"><?php esc_html_e( 'Not right now', 'wsdesk' ); ?></a>+ <a href="<?php echo esc_url( $this->get_next_step_link() ); ?>" class="btn-info btn wsdesk-setup-actions"><?php esc_html_e( 'Let\'s setup now!', 'wsdesk' ); ?></a>+ </p>+ </center>+ <?php+ }++ public function wsdesk_setup_pages() {+ ?>+ <center>+ <div style="margin-top:10px;">+ <form method="post">+ <p style="margin: 0 0 15px;"><?php printf( esc_html__( 'Set your support page title, email ID and ticket starting ticket ID.', 'wsdesk' ), esc_url( admin_url( 'edit.php?post_type=page' ) ) ); ?></p>+ <div class="row">+ <div class="col-sm-12">+ <div class="col-sm-6">+ <div class="input-group" style="width:90%">+ <div class="form-group1" style="margin:0px !important;">+ <span class="input-group-addon" style="padding: 6px 15px 10px !important;">+ <span class="glyphicon glyphicon-envelope" style="font-size: 35px;"></span>+ </span>+ <label for="support_email" style="color:black;"><?php esc_html_e( 'WSDesk Support Email', 'wsdesk' ); ?></label>+ <br>+ <label for="support_email"><small><?php esc_html_e( 'The email ID which is used for support responses', 'wsdesk' ); ?></small></label>+ <br>+ <input name="support_email" id="support_email" type="email" class="form-control1" style="font-size: 20px;height: 40px;width:80%;" placeholder="[email protected]">+ </div>+ </div>+ </div>+ <div class="col-sm-6">+ <div class="input-group" style="width:90%">+ <div class="form-group1" style="margin:0px !important;">+ <span class="input-group-addon" style="padding: 6px 15px 10px !important;">+ <span class="glyphicon glyphicon-list-alt" style="font-size: 35px;"></span>+ </span>+ <label for="page_name" style="color:black;"><?php esc_html_e( 'Starting Ticket ID', 'wsdesk' ); ?></label>+ <br>+ <label for="page_name"><small><?php esc_html_e( 'You can set your first Ticket\'s ID here.', 'wsdesk' ); ?></small></label>+ <br>+ <input name="ticket_id" id="ticket_id" type="text" class="form-control1" style="font-size: 20px;width:80%;height: 40px;" placeholder="<?php esc_html_e( 'Default Ticket ID is 1', 'wsdesk' ); ?>">+ </div>+ </div>+ </div>+ </div>+ </div>+ <div class="row">+ <div class="col-sm-4">+ <div class="input-group" style="width:90%">+ <div class="form-group1" style="margin:0px !important;">+ <span class="input-group-addon" style="padding: 6px 15px 10px !important;">+ <span class="glyphicon glyphicon-headphones" style="font-size: 35px;"></span>+ </span>+ <label for="page_name" style="color:black;"><?php esc_html_e( 'WSDesk Support Page Title', 'wsdesk' ); ?></label>+ <br>+ <label for="page_name"><small><?php esc_html_e( 'Title which will be displayed on your site', 'wsdesk' ); ?></small></label>+ <br>+ <input name="page_name" id="page_name" type="text" class="form-control1" style="font-size: 20px;width:80%;height: 40px;" placeholder="<?php esc_html_e( 'Enter page title', 'wsdesk' ); ?>">+ </div>+ </div>+ </div>+ <div class="col-sm-4">+ <div class="input-group" style="width:90%">+ <div class="form-group1" style="margin:0px !important;">+ <span class="input-group-addon" style="padding: 6px 15px 10px !important;">+ <span class="glyphicon glyphicon-headphones" style="font-size: 35px;"></span>+ </span>+ <label for="page_name" style="color:black;"><?php esc_html_e( 'WSDesk Individual Ticket Page Title', 'wsdesk' ); ?></label>+ <br>+ <label for="page_name"><small><?php esc_html_e( 'Title which will be displayed on your site', 'wsdesk' ); ?></small></label>+ <br>+ <input name="single_ticket_page_name" id="page_name" type="text" class="form-control1" style="font-size: 20px;width:80%;height: 40px;" placeholder="<?php esc_html_e( 'Enter page title', 'wsdesk' ); ?>">+ </div>+ </div>+ </div>+ <div class="col-sm-4">+ <div class="input-group" style="width:90%">+ <div class="form-group1" style="margin:0px !important;">+ <span class="input-group-addon" style="padding: 6px 15px 10px !important;">+ <span class="glyphicon glyphicon-headphones" style="font-size: 35px;"></span>+ </span>+ <label for="page_name" style="color:black;"><?php esc_html_e( 'WSDesk Existing Ticket Page Title', 'wsdesk' ); ?></label>+ <br>+ <label for="page_name"><small><?php esc_html_e( 'Title which will be displayed on your site', 'wsdesk' ); ?></small></label>+ <br>+ <input name="existing_ticket_page_name" id="page_name" type="text" class="form-control1" style="font-size: 20px;width:80%;height: 40px;" placeholder="<?php esc_html_e( 'Enter page title', 'wsdesk' ); ?>">+ </div>+ </div>+ </div>+ </div>+ <div class="pull-right" style="margin-top: 15px;">+ <p style="padding: 0px 20px;">+ <a href="<?php echo esc_url( $this->get_next_step_link() ); ?>" class="btn-default btn wsdesk-setup-actions"><?php esc_html_e( 'Skip this step', 'wsdesk' ); ?></a>+ <input type="submit" class="btn-info btn wsdesk-setup-actions" value="<?php esc_attr_e( 'Save & Continue', 'wsdesk' ); ?>" name="save_step"/>+ <?php wp_nonce_field( 'wsdesk-setup' ); ?>+ </p>+ </div>+ </form>+ </div>+ </center>+ <?php+ }++ public function wsdesk_setup_pages_save() {+ check_admin_referer( 'wsdesk-setup' );+ global $wpdb;+ $table_name = $wpdb->prefix . 'wsdesk_tickets';+ $name = ( isset( $_POST['page_name'] ) ) ? sanitize_text_field( $_POST['page_name'] ) : esc_html__( 'Support', 'wsdesk' );+ $single_ticket_page_name = ( isset( $_POST['single_ticket_page_name'] ) ) ? sanitize_text_field( $_POST['single_ticket_page_name'] ) : esc_html__( 'Single Ticket View', 'wsdesk' );+ $existing_ticket_page_name = ( isset( $_POST['existing_ticket_page_name'] ) ) ? sanitize_text_field( $_POST['existing_ticket_page_name'] ) : esc_html__( 'Existing Tickets', 'wsdesk' );++ $email = ( isset( $_POST['support_email'] ) ) ? sanitize_text_field( $_POST['support_email'] ) : '';+ $ticket_id = ( isset( $_POST['ticket_id'] ) && is_numeric( $_POST['ticket_id'] ) ) ? sanitize_text_field( $_POST['ticket_id'] ) : '';+ $post = array(+ 'comment_status' => 'closed',+ 'ping_status' => 'closed',+ 'post_author' => get_current_user_id(),+ 'post_content' => '[wsdesk_support display="form"]',+ 'post_status' => 'publish',+ 'post_title' => $name,+ 'post_type' => 'page',+ );+ $newvalue = wp_insert_post( $post, false );+ if ( ! is_wp_error( $newvalue ) ) {+ update_option( 'wsdesk_support_page', $newvalue );+ }++ $post['post_content'] = '[wsdesk_support display="form_support_request_table"]';+ $post['post_title'] = $single_ticket_page_name;+ $newvalue = wp_insert_post( $post, false );+
I'll analyze this diff for security vulnerabilities. Vulnerability Existed: no Explanation: This diff consists entirely of line ending changes (converting from CRLF to LF line endings). The file content itself remains functionally identical - no code logic, security controls, or input handling has changed. While the file contains some security practices (use of `sanitize_text_field()`, `check_admin_referer()`, `wp_verify_nonce()`, `esc_url()`, `esc_html_e()`, `esc_attr_e()`, and `wp_nonce_field()`), this particular diff does not modify any of that code. The only changes are: - Line ending normalization from Windows (CRLF) to Unix (LF) format - No functional code changes - No modifications to input validation, escaping, authorization, or sanitization logic Therefore, no security vulnerabilities were introduced or fixed in this diff.
The ELEX WordPress HelpDesk & Customer Ticketing System plugin for WordPress is vulnerable to Stored Cross-Site Scripting via ticket subjects in all versions up to, and including, 3.3.4 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.