# mxchat-basic/2.2.0/includes/class-mxchat-utils.php

MxChat – AI Chatbot &amp; Content Generation for WordPress, version 2.2.0. 197 lines.

- Page: https://pluginprobe.com/plugins/mxchat-basic/2.2.0/code/includes/class-mxchat-utils.php
- Raw: https://pluginprobe.com/plugins/mxchat-basic/2.2.0/raw/includes/class-mxchat-utils.php
- Modified: 2025-05-11T12:51:58+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/mxchat-basic/2.2.0/code/includes/class-mxchat-utils.php#L10-L20`.

```php
<?php
if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly
}

class MxChat_Utils {

/**
 * Submit or update content (and its embedding) in the database.
 *
 * If the source_url already exists, update that row.
 * Otherwise, insert a new row.
 *
 * @param string $content    The content to be embedded.
 * @param string $source_url The source URL of the content.
 * @param string $api_key    The API key used for generating embeddings.
 * @return bool|string True on success, error message on failure
 */
public static function submit_content_to_db($content, $source_url, $api_key) {
    global $wpdb;
    $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
    
    error_log('[MXCHAT-DB] Starting database submission for URL: ' . $source_url);
    error_log('[MXCHAT-DB] Content length: ' . strlen($content) . ' bytes');
    
    // Sanitize the source URL
    $source_url = esc_url_raw($source_url);
    
    // Use wpdb's prepare to ensure content is properly escaped for database
    $prepared_content = $wpdb->prepare('%s', $content);
    // Remove the quotes that wpdb->prepare adds
    $safe_content = substr($prepared_content, 1, -1);
    
    // Additional content safety measures
    $safe_content = wp_check_invalid_utf8($safe_content);
    $safe_content = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $safe_content);
    
    // Generate the embedding using the API key
    $embedding_vector = self::generate_embedding($content, $api_key);
    
    if (!is_array($embedding_vector)) {
        error_log('[MXCHAT-DB] Error: Embedding generation failed');
        return false;
    }
    
    error_log('[MXCHAT-DB] Embedding generated successfully');
    
    $embedding_vector_serialized = maybe_serialize($embedding_vector);
    error_log('[MXCHAT-DB] Serialized embedding length: ' . strlen($embedding_vector_serialized) . ' bytes');
    
    // Check if a row already exists for this URL
    $existing_id = $wpdb->get_var(
        $wpdb->prepare(
            "SELECT id FROM {$table_name} WHERE source_url = %s LIMIT 1",
            $source_url
        )
    );
    
    // Progressive fallback mechanism for problematic content
    $attempt = 1;
    $max_attempts = 3;
    $current_content = $safe_content;
    $result = false;
    
    while ($attempt <= $max_attempts && $result === false) {
        try {
            if ($existing_id) {
                error_log('[MXCHAT-DB] Found existing entry (ID: ' . $existing_id . '). Updating... (Attempt ' . $attempt . ')');
                
                // Update the existing row
                $result = $wpdb->update(
                    $table_name,
                    array(
                        'url'              => $source_url,
                        'article_content'  => $current_content,
                        'embedding_vector' => $embedding_vector_serialized,
                        'source_url'       => $source_url,
                        'timestamp'        => current_time('mysql'),
                    ),
                    array('id' => $existing_id),
                    array('%s','%s','%s','%s','%s'),
                    array('%d')
                );
            } else {
                error_log('[MXCHAT-DB] No existing entry found. Inserting new row... (Attempt ' . $attempt . ')');
                error_log('[MXCHAT-DB] Content sample: ' . substr($current_content, 0, 1000));
                
                // Insert a new row
                $result = $wpdb->insert(
                    $table_name,
                    array(
                        'url'              => $source_url,
                        'article_content'  => $current_content,
                        'embedding_vector' => $embedding_vector_serialized,
                        'source_url'       => $source_url,
                        'timestamp'        => current_time('mysql'),
                    ),
                    array('%s','%s','%s','%s','%s')
                );
            }
            
            if ($result === false) {
                error_log('[MXCHAT-DB] Database operation failed (Attempt ' . $attempt . '): ' . $wpdb->last_error);
                
                // Progressively apply more aggressive sanitization on failure
                if ($attempt === 1) {
                    // First fallback: Use a more aggressive character filter and shorten
                    $current_content = preg_replace('/[^\p{L}\p{N}\s.,;:!?()-]/u', '', $current_content);
                    $current_content = substr($current_content, 0, 50000);
                } else if ($attempt === 2) {
                    // Second fallback: Keep only alphanumeric and basic punctuation, shorten further
                    $current_content = preg_replace('/[^a-zA-Z0-9\s.,;:!?()-]/u', '', $current_content);
                    $current_content = substr($current_content, 0, 30000);
                }
                
                $attempt++;
            }
        } catch (Exception $e) {
            error_log('[MXCHAT-DB] Exception during database operation: ' . $e->getMessage());
            $attempt++;
        }
    }
    
    if ($result === false) {
        error_log('[MXCHAT-DB] All database operation attempts failed');
        return false;
    }
    
    error_log('[MXCHAT-DB] Database operation completed successfully (Attempt ' . ($attempt - 1) . ')');
    return true;
}

/**
* Generate an embedding for the given text using the specified API key.
*
* @param string $text    The text to be embedded.
* @param string $api_key The API key used for generating embeddings.
* @return array|null     The embedding vector or null on failure.
*/
private static function generate_embedding($text, $api_key) {
   // Get options and selected model
   $options = get_option('mxchat_options');
   $selected_model = $options['embedding_model'] ?? 'text-embedding-ada-002';
   
   // Determine endpoint and API key based on model
   if (strpos($selected_model, 'voyage') === 0) {
       $endpoint = 'https://api.voyageai.com/v1/embeddings';
       $api_key = $options['voyage_api_key'] ?? '';
   } else {
       $endpoint = 'https://api.openai.com/v1/embeddings';
       // Use the passed API key for OpenAI
   }

   // Prepare request body
   $request_body = [
       'input' => $text,
       'model' => $selected_model
   ];

   // Add output_dimension for voyage-3-large
   if ($selected_model === 'voyage-3-large') {
       $request_body['output_dimension'] = 2048;
   }

   $args = [
       'body'        => wp_json_encode($request_body),
       'headers'     => [
           'Content-Type'  => 'application/json',
           'Authorization' => 'Bearer ' . $api_key,
       ],
       'timeout'     => 60,
       'redirection' => 5,
       'blocking'    => true,
       'httpversion' => '1.0',
       'sslverify'   => true,
   ];

   $response = wp_remote_post($endpoint, $args);
   
   if (is_wp_error($response)) {
       error_log('Error generating embedding: ' . $response->get_error_message());
       return null;
   }

   $response_body = json_decode(wp_remote_retrieve_body($response), true);
   
   if (isset($response_body['data'][0]['embedding']) && is_array($response_body['data'][0]['embedding'])) {
       return $response_body['data'][0]['embedding'];
   } else {
       error_log('Invalid response received from embedding API: ' . wp_json_encode($response_body));
       return null;
   }
}
    
    
}

```
