PluginProbe
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services / 8.8.1
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services v8.8.1
8.8.1 8.8.0 8.7.9 8.7.8 8.7.7 8.7.6 8.7.5 8.7.4 8.7.3 8.7.2 8.7.1 8.7.0 8.6.9 8.6.8 8.6.7 8.6.6 8.6.5 8.6.4 8.6.2 8.6.1 8.6.0 8.5.9 8.5.8 8.5.7 8.5.6 All 537 releases
← All changes | includes/chat-sessions/wpbot-chat-sessions.php +156 -96 8.6.6 → 8.8.1 View file →
@@ -49,74 +49,110 @@
49 49
50 50 // ─── Admin Menu ───────────────────────────────────────────────────────────────
51 51 add_action( 'admin_menu', 'qcwp_chat_session_menu_fnc_free' );
52 52
53 -function qcwp_chat_session_menu_fnc_free() {
53 + function qcwp_chat_session_menu_fnc_free() {
54 + // All menu registration is now handled by chatbot (qcld-wpwbot.php)
55 + // We no longer register submenus here to keep the sidebar clean.
56 + }
54 57
55 - $capability = function_exists( 'qcld_wpbot_get_menu_capability' ) ? qcld_wpbot_get_menu_capability( 'sessions' ) : 'manage_options';
58 + function qc_wpbot_cs_tabbed_wrapper() {
59 + $active_tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : 'sessions';
56 60
57 - if ( current_user_can( $capability ) ) {
61 + $tabs = array(
62 + 'sessions' => array(
63 + 'label' => __( 'Chat Sessions', 'wpbot-chat-history' ),
64 + 'icon' => 'dashicons-format-chat',
65 + ),
66 + 'not-answered' => array(
67 + 'label' => __( 'Questions Not Answered', 'wpbot-chat-history' ),
68 + 'icon' => 'dashicons-editor-help',
69 + ),
70 + 'ai-insight' => array(
71 + 'label' => __( 'AI Insight', 'wpbot-chat-history' ),
72 + 'icon' => 'dashicons-lightbulb',
73 + ),
74 + );
58 75
59 - add_menu_page(
60 - 'WPBot - Sessions & Analytics',
61 - 'WPBot - Sessions & Analytics',
62 - $capability,
63 - 'wbcs-botsessions-page',
64 - 'qc_wpbot_cs_menu_page_callback_func',
65 - 'dashicons-chart-bar',
66 - '9'
67 - );
76 + if ( function_exists( 'qcpdcs_is_woowbot_active' ) && qcpdcs_is_woowbot_active() ) {
77 + $tabs['woowbot-sessions'] = array(
78 + 'label' => __( 'ChatBot Sessions', 'wpbot-chat-history' ),
79 + 'icon' => 'dashicons-cart',
80 + );
81 + }
68 82
69 - add_submenu_page(
70 - 'wbcs-botsessions-page',
71 - 'Questions Not Answered',
72 - 'Questions Not Answered',
73 - $capability,
74 - 'wbcs-botsessions-notansweredpage',
75 - 'qcld_wpbot_not_answered_question'
76 - );
83 + ?>
84 + <div class="wrap qcld-main-wrapper qcld-chat-sessions-wrap">
85 + <h1 style="display:none"><?php esc_html_e( 'Chat Sessions', 'wpbot-chat-history' ); ?></h1>
77 86
78 - add_submenu_page(
79 - 'wbcs-botsessions-page',
80 - 'AI Insight',
81 - 'AI Insight',
82 - $capability,
83 - 'wbcs-schedule-session-reporting',
84 - 'qcld_wpbot_schedule_session_reporting'
85 - );
87 + <div class="qcld-wp-chatbot-wrap-header">
88 + <div class="qcld-wp-chatbot-wrap-header-logo">
89 + <a href="#" class="qcld-wp-chatbot-wrap-site__logo">
90 + <img src="<?php echo esc_url( QCLD_wpCHATBOT_IMG_URL . '/chatbot.png' ); ?>" alt="WPBot"> WPBot Control Panel
91 + </a>
92 + <p><strong>Core Version:</strong> v<?php echo esc_html( QCLD_wpCHATBOT_VERSION ); ?></p>
93 + </div>
94 + <ul class="qcld-wp-chatbot-wrap-version-wrapper">
95 + <li>
96 + <a class="wpchatbot-Upgrade" href="https://www.wpbot.pro/" target="_blank"><?php esc_html_e( 'Upgrade To Pro', 'chatbot' ); ?></a>
97 + </li>
98 + </ul>
99 + </div>
100 +
101 + <div class="qcld-wp-chatbot-wrap-header_inn qcld-chat-sessions-header">
102 + <div class="qcld-wp-chatbot-wrap-header_inn_heading">
103 + <h1 class="wp-heading-inline"><?php esc_html_e( 'Sessions & Analytics', 'wpbot-chat-history' ); ?></h1>
104 + </div>
105 + <nav class="nav-tab-wrapper qcld-chat-sessions-tabs">
106 + <?php foreach ( $tabs as $tab_id => $tab ) : ?>
107 + <a href="<?php echo esc_url( admin_url( 'admin.php?page=wbcs-botsessions-page&tab=' . rawurlencode( $tab_id ) ) ); ?>" class="nav-tab <?php echo $active_tab === $tab_id ? 'nav-tab-active' : ''; ?>">
108 + <span class="dashicons <?php echo esc_attr( $tab['icon'] ); ?>"></span>
109 + <span><?php echo esc_html( $tab['label'] ); ?></span>
110 + </a>
111 + <?php endforeach; ?>
112 + </nav>
113 + </div>
114 +
115 + <div class="qcld-chat-sessions-tab-content">
116 + <?php
117 + switch ( $active_tab ) {
118 + case 'not-answered':
119 + if ( function_exists( 'qcld_wpbot_not_answered_question' ) ) {
120 + qcld_wpbot_not_answered_question();
121 + }
122 + break;
123 + case 'ai-insight':
124 + if ( function_exists( 'qcld_wpbot_schedule_session_reporting' ) ) {
125 + qcld_wpbot_schedule_session_reporting();
126 + }
127 + break;
128 + case 'woowbot-sessions':
129 + if ( function_exists( 'woowbot_cs_menu_page_callback_func' ) ) {
130 + woowbot_cs_menu_page_callback_func();
131 + }
132 + break;
133 + case 'sessions':
134 + default:
135 + if ( function_exists( 'qc_wpbot_cs_menu_page_callback_func' ) ) {
136 + qc_wpbot_cs_menu_page_callback_func();
137 + }
138 + break;
139 + }
140 + ?>
141 + </div>
142 + </div>
143 + <?php
86 144 }
87 -}
88 145
89 146 // ─── Admin Scripts & Styles ───────────────────────────────────────────────────
90 147 add_action( 'admin_enqueue_scripts', 'qcld_wb_chatbot_session_admin_scripts_free' );
91 148
92 149 function qcld_wb_chatbot_session_admin_scripts_free( $hook ) {
93 - // WordPress generates hook suffixes as follows:
94 - // top-level page → toplevel_page_{slug}
95 - // sub-pages → {parent-menu-title}_page_{slug} (title, lowercased, spaces→hyphens)
96 - // Our parent title is "WPBot Sessions & Analytics" → "wpbot-sessions-analytics"
97 - $session_hooks = array(
98 - 'toplevel_page_wbcs-botsessions-page',
99 - 'wpbot-sessions-analytics_page_wbcs-botsessions-notansweredpage',
100 - 'wpbot-sessions-analytics_page_wbcs-botsessions-reports',
101 - 'wpbot-sessions-analytics_page_wbcs-schedule-session-reporting',
102 - );
103 - $is_session_page = false;
104 - foreach ( $session_hooks as $session_hook ) {
105 - if ( strpos( $hook, $session_hook ) !== false || ( isset( $_GET['page'] ) && $_GET['page'] === str_replace( 'toplevel_page_', '', $session_hook ) ) ) {
106 - $is_session_page = true;
107 - break;
150 + // Only enqueue on our specific sessions page
151 + if ( ! isset( $_GET['page'] ) || 'wbcs-botsessions-page' !== $_GET['page'] ) {
152 + return;
108 153 }
109 - }
110 -
111 - if ( isset( $_GET['page'] ) && in_array( $_GET['page'], array( 'wbcs-botsessions-page', 'wbcs-botsessions-notansweredpage', 'wbcs-botsessions-reports', 'wbcs-schedule-session-reporting' ) ) ) {
112 - $is_session_page = true;
113 - }
114 154
115 - if ( ! $is_session_page ) {
116 - return;
117 - }
118 -
119 155 wp_register_style( 'qlcd-wp-bootstrap-cs', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'css/qlcd-wp-bootstrap.css', array(), QCLD_wpCHATBOT_VERSION, 'screen' );
120 156 wp_enqueue_style( 'qlcd-wp-bootstrap-cs' );
121 157
122 158 wp_register_style( 'qlcd-wp-bootstrap-icons-cs', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'css/qlcd-wp-bootstrap-icons.css', array(), QCLD_wpCHATBOT_VERSION, 'screen' );
@@ -127,8 +163,11 @@
127 163
128 164 wp_register_style( 'qlcd-wp-session-style-cs', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'reports/view/assets/style.css', array(), QCLD_wpCHATBOT_VERSION, 'screen' );
129 165 wp_enqueue_style( 'qlcd-wp-session-style-cs' );
130 166
167 + wp_register_style( 'qcld-wp-chatbot-history-style', QCLD_CHATBOT_FREE_SESSION_PLUGIN_URL . 'css/history-style.css', array( 'qlcd-wp-chatbot-admin-style' ), QCLD_wpCHATBOT_VERSION, 'screen' );
168 + wp_enqueue_style( 'qcld-wp-chatbot-history-style' );
169 +
131 170 // SweetAlert2 — used by admin.js for Swal.fire() and Swal.showLoading()
132 171 wp_register_script( 'qcld-wp-chatbot-sweetalrt-cs', QCLD_wpCHATBOT_PLUGIN_URL . 'js/sweetalrt.js', array( 'jquery' ), QCLD_wpCHATBOT_VERSION, true );
133 172 wp_enqueue_script( 'qcld-wp-chatbot-sweetalrt-cs' );
134 173
@@ -365,9 +404,9 @@
365 404 ?>
366 405 </div>
367 406
368 407
369 - <form id="wpcs_form_sessions" action="<?php echo esc_url( $mainurl ); ?>" method="POST" style="width:98%">
408 + <form id="wpcs_form_sessions" action="<?php echo esc_url( $mainurl ); ?>" method="POST">
370 409 <?php wp_nonce_field( 'wpcs_bulk_action' ); ?>
371 410 <input type="hidden" name="wpbot_session_remove" />
372 411
373 412 <?php if ( ! empty( $result ) ) : ?>
@@ -424,9 +463,9 @@
424 463 foreach ( $users as $user ) {
425 464 $sessions[] = wpbot_conversations_export( $user );
426 465 }
427 466 }
428 - qcld_wpbot_chatsession_download_send_headers( 'wpbot_chatsession_' . date( 'Y-m-d' ) . '.csv' );
467 + qcld_wpbot_chatsession_download_send_headers( 'wpbot_chatsession_' . gmdate( 'Y-m-d' ) . '.csv' );
429 468 print wpbot_chatsession_array2csv( $sessions ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- raw CSV download, escaping would corrupt the file.
430 469 exit;
431 470 }
432 471
@@ -440,9 +479,9 @@
440 479 foreach ( $userids as $userid ) {
441 480 $user = $wpdb->get_row( $wpdb->prepare( "SELECT wu.`id`, wu.`session_id`, wu.`name`, wu.`email`, wu.`date`, wu.`phone`, wu.`interaction`, wc.`conversation` FROM $tableuser1 as wu, $tableconversation1 as wc WHERE 1 AND wu.id = wc.user_id AND wu.id = %d", $userid ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
442 481 $sessions[] = wpbot_conversations_export( $user );
443 482 }
444 - qcld_wpbot_chatsession_download_send_headers( 'wpbot_chatsession_' . date( 'Y-m-d' ) . '.csv' );
483 + qcld_wpbot_chatsession_download_send_headers( 'wpbot_chatsession_' . gmdate( 'Y-m-d' ) . '.csv' );
445 484 print wpbot_chatsession_array2csv( $sessions ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- raw CSV download, escaping would corrupt the file.
446 485 exit;
447 486 }
448 487
@@ -498,10 +537,22 @@
498 537 $message = sanitize_text_field( $_POST['data']['message'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
499 538 $to = sanitize_email( $_POST['data']['to'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
500 539
501 540 global $wpdb;
502 - $tableuser = $wpdb->prefix . 'wpbot_user';
503 - $user_exists = $wpdb->get_var( $wpdb->prepare( 'SELECT id FROM %i WHERE email = %s LIMIT 1', $tableuser, $to ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
541 + $tableuser = $wpdb->prefix . 'wpbot_user';
542 + $table_sql = esc_sql( $tableuser );
543 + $cache_key = 'wpbot_user_email_' . md5( $to );
544 + $user_exists = wp_cache_get( $cache_key, 'wpbot' );
545 + if ( false === $user_exists ) {
546 + $user_exists = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
547 + $wpdb->prepare(
548 + 'SELECT id FROM `' . $table_sql . '` WHERE email = %s LIMIT 1', // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
549 + $to
550 + )
551 + );
552 + wp_cache_set( $cache_key, $user_exists, 'wpbot', 60 );
553 + }
554 +
504 555 $admin_email = get_option('admin_email');
505 556 if ( ! $user_exists && $to !== $admin_email ) {
506 557 wp_send_json( array( 'status' => 'fail', 'message' => 'Invalid recipient address. Email must be a stored session email or admin email.' ) );
507 558 }
@@ -550,21 +601,14 @@
550 601
551 602 $tableuser = $wpdb->prefix . 'wpbot_user'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
552 603 $tableconversation = $wpdb->prefix . 'wpbot_conversation'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
553 604
554 - $allowed_html = array_merge(
555 - wp_kses_allowed_html( 'post' ),
556 - array(
557 - 'div' => array( 'class' => true, 'id' => true, 'style' => true, 'data-*' => true ),
558 - 'span' => array( 'class' => true, 'id' => true, 'style' => true, 'data-*' => true ),
559 - 'ul' => array( 'class' => true ),
560 - 'li' => array( 'class' => true ),
561 - 'img' => array( 'src' => true, 'alt' => true, 'class' => true, 'style' => true ),
562 - )
563 - );
564 - $raw_conversation = isset( $_POST['conversation'] ) ? wp_unslash( $_POST['conversation'] ) : '';
565 - $clean_conversation = wp_kses( $raw_conversation, $allowed_html );
566 - $conversation = qcld_wpbot_input_validation( $clean_conversation ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
605 + // SECURITY FIX: Pass raw (decoded) input to qcld_wpbot_input_validation(), which now
606 + // correctly runs html_entity_decode() BEFORE wp_kses(). Previously, wp_kses() ran first
607 + // on entity-encoded input (&lt;img onerror=...&gt;), saw inert text, and passed it through.
608 + // html_entity_decode() then revived the executable markup after sanitization had already run.
609 + $raw_conversation = isset( $_POST['conversation'] ) ? wp_unslash( $_POST['conversation'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
610 + $conversation = qcld_wpbot_input_validation( $raw_conversation ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
567 611 $email = isset( $_POST['email'] ) ? sanitize_email( $_POST['email'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
568 612 $phone = isset( $_POST['phone'] ) ? sanitize_text_field( $_POST['phone'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
569 613 $name = isset( $_POST['name'] ) ? sanitize_text_field( $_POST['name'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
570 614 $session_id = isset( $_POST['session_id'] ) ? sanitize_text_field( $_POST['session_id'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
@@ -860,9 +904,17 @@
860 904 $email_from = get_option( 'qlcd_wp_chatbot_from_email' );
861 905 $result = $wpdb->get_row( $wpdb->prepare( "SELECT c.*, u.email, u.name, u.session_id as user_session_id FROM $tableconversation AS c LEFT JOIN $tableuser AS u ON c.user_id = u.id WHERE c.user_id = %d", $session_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
862 906 if ( ! empty( $result ) ) {
863 907 $result->email_from = $email_from;
864 - $result->status = 'success';
908 + $result->status = 'success';
909 +
910 + // SECURITY FIX: The stored conversation is entity-encoded (htmlspecialchars output).
911 + // Decode it and re-sanitize with wp_kses before returning to the admin UI.
912 + // This guarantees admin.js always receives clean, safe HTML — no onerror/onclick can survive.
913 + if ( isset( $result->conversation ) ) {
914 + $decoded = html_entity_decode( (string) $result->conversation, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
915 + $result->conversation = wp_kses( $decoded, wpbot_get_safe_conversation_tags() );
916 + }
865 917 }
866 918 echo wp_json_encode( $result );
867 919 wp_die();
868 920 }
@@ -990,18 +1042,21 @@
990 1042
991 1043 $api_key = get_option( 'open_ai_api_key' );
992 1044 $engines = get_option( 'openai_engines' );
993 1045 $post_fields = array( 'model' => $engines, 'input' => $gptkeyword );
994 - $header = array( 'Content-Type: application/json', 'Authorization: Bearer ' . $api_key );
995 1046
996 - $ch = curl_init();
997 - curl_setopt( $ch, CURLOPT_URL, 'https://api.openai.com/v1/responses' );
998 - curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
999 - curl_setopt( $ch, CURLOPT_POST, 1 );
1000 - curl_setopt( $ch, CURLOPT_POSTFIELDS, wp_json_encode( $post_fields ) );
1001 - curl_setopt( $ch, CURLOPT_HTTPHEADER, $header );
1002 - $result = curl_exec( $ch );
1003 - curl_close( $ch );
1047 + $api_response = wp_remote_post(
1048 + 'https://api.openai.com/v1/responses',
1049 + array(
1050 + 'headers' => array(
1051 + 'Content-Type' => 'application/json',
1052 + 'Authorization' => 'Bearer ' . $api_key,
1053 + ),
1054 + 'body' => wp_json_encode( $post_fields ),
1055 + 'timeout' => 60,
1056 + )
1057 + );
1058 + $result = is_wp_error( $api_response ) ? '' : wp_remote_retrieve_body( $api_response );
1004 1059
1005 1060 $mess = json_decode( $result );
1006 1061 if ( ! empty( $mess->error ) ) {
1007 1062 wp_send_json( array( 'status' => 'error', 'icon' => 'error', 'msg' => esc_html( $mess->error->code ), 'response' => esc_html( $mess->error->message ) ) );
@@ -1074,13 +1129,13 @@
1074 1129 add_action( 'admin_post_wpbot_conversations.csv', 'wpbot_conversations_csv_export_free' );
1075 1130
1076 1131 function wpbot_conversations_csv_export_free() {
1077 1132 if ( ! current_user_can( 'manage_options' ) ) {
1078 - wp_die( esc_html__( 'Unauthorized', 'wpbot' ) );
1133 + wp_die( esc_html__( 'Unauthorized', 'chatbot' ) );
1079 1134 }
1080 1135
1081 1136 if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'wpbot_conversations_csv' ) ) {
1082 - wp_die( esc_html__( 'Security check failed.', 'wpbot' ) );
1137 + wp_die( esc_html__( 'Security check failed.', 'chatbot' ) );
1083 1138 }
1084 1139
1085 1140 global $wpdb;
1086 1141 $tableuser = $wpdb->prefix . 'wpbot_user'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
@@ -1094,9 +1149,9 @@
1094 1149 if ( ! empty( $result ) ) {
1095 1150 $data[] = array( 'User Name', $userinfo->name );
1096 1151 $data[] = array( 'User Email', $userinfo->email );
1097 1152 $data[] = array( 'Session ID', $userinfo->session_id );
1098 - $data[] = array( 'Date', date( 'M,d,Y h:i:s A', strtotime( $userinfo->date ) ) );
1153 + $data[] = array( 'Date', gmdate( 'M,d,Y h:i:s A', strtotime( $userinfo->date ) ) );
1099 1154 $data[] = array( 'Bot Message', 'User Message' );
1100 1155 $messages = qcld_wpch_conversation_extract( htmlspecialchars_decode( $result->conversation ) );
1101 1156 foreach ( $messages as $message ) {
1102 1157 if ( isset( $message['bot'] ) && trim( $message['bot'] ) != '' ) {
@@ -1106,9 +1161,9 @@
1106 1161 $data[] = array( '', str_replace( '&nbsp;', ' ', trim( $message['user'] ) ) );
1107 1162 }
1108 1163 }
1109 1164 }
1110 - qcld_wpbot_chatsession_download_send_headers( $userinfo->name . '_wpbot_chatsession_' . date( 'Y-m-d' ) . '.csv' );
1165 + qcld_wpbot_chatsession_download_send_headers( $userinfo->name . '_wpbot_chatsession_' . gmdate( 'Y-m-d' ) . '.csv' );
1111 1166 print wpbot_chatsession_array2csv( $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- raw CSV download, escaping would corrupt the file.
1112 1167 }
1113 1168
1114 1169 if ( ! function_exists( 'wpbot_conversations_export' ) ) {
@@ -1118,9 +1173,9 @@
1118 1173 if ( ! empty( $user ) ) {
1119 1174 $messages = qcld_wpch_conversation_extract( htmlspecialchars_decode( $user->conversation ) );
1120 1175 $dataArray = array(
1121 1176 'Session ID' => $user->session_id,
1122 - 'Date' => date( 'M,d,Y h:i:s A', strtotime( $user->date ) ),
1177 + 'Date' => gmdate( 'M,d,Y h:i:s A', strtotime( $user->date ) ),
1123 1178 'User Name' => $user->name,
1124 1179 'User Email' => $user->email,
1125 1180 );
1126 1181 $conversations = '';
@@ -1155,8 +1210,9 @@
1155 1210 if ( ! function_exists( 'wpbot_chatsession_array2csv' ) ) {
1156 1211 function wpbot_chatsession_array2csv( array &$array ) {
1157 1212 if ( count( $array ) == 0 ) { return null; }
1158 1213 ob_start();
1214 + // phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_fopen, WordPress.WP.AlternativeFunctions.file_system_operations_fputs, WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- php://output memory stream for CSV export.
1159 1215 $df = fopen( 'php://output', 'w' );
1160 1216 fputs( $df, chr( 0xEF ) . chr( 0xBB ) . chr( 0xBF ) ); // UTF-8 BOM
1161 1217 foreach ( $array as $data ) {
1162 1218 fputcsv( $df, array_keys( $data ), ',', '"', '\\' );
@@ -1165,8 +1221,9 @@
1165 1221 foreach ( $array as $row ) {
1166 1222 fputcsv( $df, $row, ',', '"', '\\' );
1167 1223 }
1168 1224 fclose( $df );
1225 + // phpcs:enable WordPress.WP.AlternativeFunctions.file_system_operations_fopen, WordPress.WP.AlternativeFunctions.file_system_operations_fputs, WordPress.WP.AlternativeFunctions.file_system_operations_fclose
1169 1226 return ob_get_clean();
1170 1227 }
1171 1228 }
1172 1229
@@ -1217,9 +1274,9 @@
1217 1274 if ( ! function_exists( 'qcld_wpsession_wp_cron_schedule_free' ) ) {
1218 1275 function qcld_wpsession_wp_cron_schedule_free( $schedules ) {
1219 1276 $schedules['session_schedules'] = array(
1220 1277 'interval' => ( get_option( 'qcld_wbsession_corn_interval' ) != null ) ? get_option( 'qcld_wbsession_corn_interval' ) : 86400,
1221 - 'display' => esc_attr( 'Session min', 'wpchatbot' ),
1278 + 'display' => esc_attr__( 'Session min', 'chatbot' ),
1222 1279 );
1223 1280 return $schedules;
1224 1281 }
1225 1282 }
@@ -1259,18 +1316,21 @@
1259 1316
1260 1317 $api_key = get_option( 'open_ai_api_key' );
1261 1318 $engines = get_option( 'openai_engines' );
1262 1319 $post_fields = array( 'model' => $engines, 'input' => $gptkeyword );
1263 - $header = array( 'Content-Type: application/json', 'Authorization: Bearer ' . $api_key );
1264 1320
1265 - $ch = curl_init();
1266 - curl_setopt( $ch, CURLOPT_URL, 'https://api.openai.com/v1/responses' );
1267 - curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
1268 - curl_setopt( $ch, CURLOPT_POST, 1 );
1269 - curl_setopt( $ch, CURLOPT_POSTFIELDS, wp_json_encode( $post_fields ) );
1270 - curl_setopt( $ch, CURLOPT_HTTPHEADER, $header );
1271 - $result = curl_exec( $ch );
1272 - curl_close( $ch );
1321 + $api_response = wp_remote_post(
1322 + 'https://api.openai.com/v1/responses',
1323 + array(
1324 + 'headers' => array(
1325 + 'Content-Type' => 'application/json',
1326 + 'Authorization' => 'Bearer ' . $api_key,
1327 + ),
1328 + 'body' => wp_json_encode( $post_fields ),
1329 + 'timeout' => 60,
1330 + )
1331 + );
1332 + $result = is_wp_error( $api_response ) ? '' : wp_remote_retrieve_body( $api_response );
1273 1333
1274 1334 $mess = json_decode( $result );
1275 1335 $msg = isset( $mess->output[0]->content[0]->text ) ? $mess->output[0]->content[0]->text : ( isset( $mess->output[1]->content[0]->text ) ? $mess->output[1]->content[0]->text : 'No response from OpenAI.' );
1276 1336 $msg = preg_replace( "/\r\n|\r|\n/", '<br/>', $msg );