Your project should not use deprecated PHP features 2

More information: https://insight.symfony.com/what-we-analyse/php.use_deprecated_function

  1. return true;
  2. }
  3. $finfo = finfo_open(FILEINFO_MIME_TYPE);
  4. $mimeType = finfo_file($finfo, $filePath);
  5. finfo_close($finfo);
    finfo_close() has been deprecated in PHP 8.5 and will be removed from PHP in the next major version.
    Time to fix: about 2 hours
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. // Define allowed MIME types based on configured extensions
  7. $allowedMimeTypes = [
  8. // Images
  9. 'image/jpeg' => ['jpg', 'jpeg'],
  1. curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
  2. }
  3. $response = curl_exec($ch);
  4. $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  5. curl_close($ch);
    curl_close() has been deprecated in PHP 8.5 and will be removed from PHP in the next major version.
    Time to fix: about 2 hours
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. if ($response === false) {
  7. return ['error' => ['message' => 'Stripe API request failed (curl).']];
  8. }

Your project uses non-strict array lookups

More information: https://insight.symfony.com/what-we-analyse/php.strict_array_lookup

  1. // Check if detected MIME type matches expected extension
  2. foreach ($allowedMimeTypes as $mime => $extensions) {
  3. if ($mimeType === $mime) {
  4. $fileExtension = $this->getExtension();
  5. return in_array($fileExtension, $extensions);
    in_array() should be called with the third parameter set to true to enable strict comparison and avoid type juggling bugs.
    Time to fix: about 15 minutes
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. }
  7. }
  8. // If MIME type not in whitelist, reject
  9. return false;
  • gyakutsuki

    no included

Your project should not use insecure random number functions

More information: https://insight.symfony.com/what-we-analyse/php.use_insecure_random_function

  1. // Fallback: use multiple sources of entropy
  2. // This should never happen on PHP 7.0+ but provides safety
  3. $fallback = hash('sha256',
  4. uniqid('antispam_', true) .
  5. microtime(true) .
  6. mt_rand() .
    The function mt_rand() is not cryptographically secure. Use random_int() or random_bytes() instead.
    Time to fix: about 2 hours
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. (function_exists('random_bytes') ? bin2hex(random_bytes(16)) : '')
  8. );
  9. trigger_error(
  10. 'Failed to generate cryptographically secure secret, using fallback. Error: ' . $e->getMessage(),

Your project should use dedicated PHP string functions 63

More information: https://insight.symfony.com/what-we-analyse/php.use_string_function

  1. if (strpos($error, 'Hybrid result missing') !== false) {
  2. return "I couldn't complete your request because some of the required information is missing. Please try breaking your question into smaller parts or asking about something else.";
  3. }
  4. // Pattern: "Empty response"
  5. if (strpos($error, 'empty') !== false || strpos($error, 'Empty') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return "I couldn't find any results for your query. The information you're looking for might not be available in the system yet. Please try rephrasing your question or asking about something else.";
  7. }
  8. }
  9. // Default fallback message
  1. // Semantic results MUST have sources OR data, unless it's a valid LLM/memory fallback
  2. if (!$hasSources) {
  3. $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
  4. $isLLMFallback = $hasTextResponse && (
  5. strpos($sourceType, 'llm') !== false ||
  6. strpos($sourceType, 'general knowledge') !== false ||
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. strpos($sourceType, 'conversation') !== false ||
  8. strpos($sourceType, 'memory') !== false
  9. );
  10. if (!$isLLMFallback) {
  1. private function generateUserFriendlyErrorMessage(array $errors): string
  2. {
  3. // Check for common error patterns and generate appropriate messages
  4. foreach ($errors as $error) {
  5. // Pattern: "Semantic result missing sources and data"
  6. if (strpos($error, 'Semantic result missing sources and data') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. return "I couldn't find any information about that in the database. The requested content (like terms and conditions) may not be available yet. Please try asking about something else or contact support to add this content.";
  8. }
  9. // Pattern: "Analytics result missing data"
  10. if (strpos($error, 'Analytics result missing data') !== false) {
  1. if (!$hasSources) {
  2. $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
  3. $isLLMFallback = $hasTextResponse && (
  4. strpos($sourceType, 'llm') !== false ||
  5. strpos($sourceType, 'general knowledge') !== false ||
  6. strpos($sourceType, 'conversation') !== false ||
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. strpos($sourceType, 'memory') !== false
  8. );
  9. if (!$isLLMFallback) {
  10. $sourcesStatus = isset($finalResult['sources']) ? 'empty' : 'not set';
  1. if (strpos($error, 'Analytics result missing data') !== false) {
  2. return "I couldn't retrieve the requested data. This might be because there are no records matching your query, or the data hasn't been entered yet. Please try a different query or check if the data exists.";
  3. }
  4. // Pattern: "Hybrid result missing"
  5. if (strpos($error, 'Hybrid result missing') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return "I couldn't complete your request because some of the required information is missing. Please try breaking your question into smaller parts or asking about something else.";
  7. }
  8. // Pattern: "Empty response"
  9. if (strpos($error, 'empty') !== false || strpos($error, 'Empty') !== false) {
  1. // Semantic results MUST have sources OR data, unless it's a valid LLM/memory fallback
  2. if (!$hasSources) {
  3. $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
  4. $isLLMFallback = $hasTextResponse && (
  5. strpos($sourceType, 'llm') !== false ||
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. strpos($sourceType, 'general knowledge') !== false ||
  7. strpos($sourceType, 'conversation') !== false ||
  8. strpos($sourceType, 'memory') !== false
  9. );
  1. $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
  2. $isLLMFallback = $hasTextResponse && (
  3. strpos($sourceType, 'llm') !== false ||
  4. strpos($sourceType, 'general knowledge') !== false ||
  5. strpos($sourceType, 'conversation') !== false ||
  6. strpos($sourceType, 'memory') !== false
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. );
  8. if (!$isLLMFallback) {
  9. $sourcesStatus = isset($finalResult['sources']) ? 'empty' : 'not set';
  10. $dataStatus = isset($finalResult['data']) ? 'empty' : 'not set';
  1. if (strpos($error, 'Semantic result missing sources and data') !== false) {
  2. return "I couldn't find any information about that in the database. The requested content (like terms and conditions) may not be available yet. Please try asking about something else or contact support to add this content.";
  3. }
  4. // Pattern: "Analytics result missing data"
  5. if (strpos($error, 'Analytics result missing data') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return "I couldn't retrieve the requested data. This might be because there are no records matching your query, or the data hasn't been entered yet. Please try a different query or check if the data exists.";
  7. }
  8. // Pattern: "Hybrid result missing"
  9. if (strpos($error, 'Hybrid result missing') !== false) {
  1. // Check if goals contain contradictory terms
  2. foreach ($contradictions as $pair) {
  3. $has1in1 = strpos($goal1, $pair[0]) !== false;
  4. $has2in1 = strpos($goal1, $pair[1]) !== false;
  5. $has1in2 = strpos($goal2, $pair[0]) !== false;
  6. $has2in2 = strpos($goal2, $pair[1]) !== false;
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. // If obj1 has first term and obj2 has second term (or vice versa)
  8. if (($has1in1 && $has2in2) || ($has2in1 && $has1in2)) {
  9. // Check if they're operating on similar subjects
  10. $similarity = $this->calculateSimilarity($obj1, $obj2);
  1. 'optimize' => ['optimize', 'improve', 'enhance', 'tune']
  2. ];
  3. foreach ($operationPatterns as $operation => $keywords) {
  4. foreach ($keywords as $keyword) {
  5. if (strpos($text, $keyword) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $operations[] = $operation;
  7. break;
  8. }
  9. }
  10. }
  1. ['grow', 'shrink']
  2. ];
  3. // Check if goals contain contradictory terms
  4. foreach ($contradictions as $pair) {
  5. $has1in1 = strpos($goal1, $pair[0]) !== false;
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $has2in1 = strpos($goal1, $pair[1]) !== false;
  7. $has1in2 = strpos($goal2, $pair[0]) !== false;
  8. $has2in2 = strpos($goal2, $pair[1]) !== false;
  9. // If obj1 has first term and obj2 has second term (or vice versa)
  1. 'database', 'table', 'index', 'query', 'cache', 'memory',
  2. 'file', 'log', 'configuration', 'setting', 'registry'
  3. ];
  4. foreach ($resourceKeywords as $keyword) {
  5. if (strpos($text, $keyword) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $resources[] = $keyword;
  7. }
  8. }
  9. return array_unique($resources);
  1. ];
  2. // Check if goals contain contradictory terms
  3. foreach ($contradictions as $pair) {
  4. $has1in1 = strpos($goal1, $pair[0]) !== false;
  5. $has2in1 = strpos($goal1, $pair[1]) !== false;
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $has1in2 = strpos($goal2, $pair[0]) !== false;
  7. $has2in2 = strpos($goal2, $pair[1]) !== false;
  8. // If obj1 has first term and obj2 has second term (or vice versa)
  9. if (($has1in1 && $has2in2) || ($has2in1 && $has1in2)) {
  1. // Check if goals contain contradictory terms
  2. foreach ($contradictions as $pair) {
  3. $has1in1 = strpos($goal1, $pair[0]) !== false;
  4. $has2in1 = strpos($goal1, $pair[1]) !== false;
  5. $has1in2 = strpos($goal2, $pair[0]) !== false;
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $has2in2 = strpos($goal2, $pair[1]) !== false;
  7. // If obj1 has first term and obj2 has second term (or vice versa)
  8. if (($has1in1 && $has2in2) || ($has2in1 && $has1in2)) {
  9. // Check if they're operating on similar subjects
  1. if (strpos($errorLower, 'syntax') !== false) {
  2. return "There was a SQL syntax error. Try rephrasing your query or using a simpler time period.";
  3. }
  4. if (strpos($errorLower, 'permission') !== false || strpos($errorLower, 'access') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  5. return "You may not have permission to access the required data. Contact your administrator.";
  6. }
  7. if (strpos($errorLower, 'timeout') !== false) {
  8. return "The query took too long. Try a shorter time range or simpler aggregation.";
  1. if (strpos($errorLower, 'table') !== false) {
  2. return "The required table for {$temporalPeriod} aggregation may not exist. Verify your database structure.";
  3. }
  4. if (strpos($errorLower, 'syntax') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  5. return "There was a SQL syntax error. Try rephrasing your query or using a simpler time period.";
  6. }
  7. if (strpos($errorLower, 'permission') !== false || strpos($errorLower, 'access') !== false) {
  8. return "You may not have permission to access the required data. Contact your administrator.";
  1. private function determineSuggestedActionForSqlError(string $errorMessage, string $temporalPeriod): string
  2. {
  3. $errorLower = strtolower($errorMessage);
  4. // Check for common error patterns
  5. if (strpos($errorLower, 'column') !== false || strpos($errorLower, 'field') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return "The database may not have the required columns for {$temporalPeriod} aggregation. Try a different time period or check your data schema.";
  7. }
  8. if (strpos($errorLower, 'table') !== false) {
  9. return "The required table for {$temporalPeriod} aggregation may not exist. Verify your database structure.";
  1. // Check for common error patterns
  2. if (strpos($errorLower, 'column') !== false || strpos($errorLower, 'field') !== false) {
  3. return "The database may not have the required columns for {$temporalPeriod} aggregation. Try a different time period or check your data schema.";
  4. }
  5. if (strpos($errorLower, 'table') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return "The required table for {$temporalPeriod} aggregation may not exist. Verify your database structure.";
  7. }
  8. if (strpos($errorLower, 'syntax') !== false) {
  9. return "There was a SQL syntax error. Try rephrasing your query or using a simpler time period.";
  1. if (strpos($errorLower, 'permission') !== false || strpos($errorLower, 'access') !== false) {
  2. return "You may not have permission to access the required data. Contact your administrator.";
  3. }
  4. if (strpos($errorLower, 'timeout') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  5. return "The query took too long. Try a shorter time range or simpler aggregation.";
  6. }
  7. // Default suggestion
  8. return "Try rephrasing your query or using a different temporal period. If the problem persists, contact support.";
  1. // Format: ['table' => 'column']
  2. $table = $key;
  3. $column = $value;
  4. } else {
  5. // Format: ['table.column']
  6. if (strpos($value, '.') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. list($table, $column) = explode('.', $value, 2);
  8. } else {
  9. // Cannot validate without table context
  10. if ($this->debug) {
  11. error_log("SchemaValidator: Column '{$value}' has no table context");
  1. // Display mode badges
  2. $badges = [];
  3. foreach ($modesUsed as $mode) {
  4. $badge = '';
  5. if (strpos($mode, 'mode_a') !== false || strpos($mode, 'ai_overview') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $badge = "🤖 " . $this->language->getDef('text_rag_mode_ai_overview');
  7. } elseif (strpos($mode, 'mode_d') !== false || strpos($mode, 'amazon') !== false) {
  8. $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
  9. } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
  10. $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
  1. $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
  2. } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
  3. $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
  4. } elseif (strpos($mode, 'mode_c') !== false || strpos($mode, 'rag') !== false) {
  5. $badge = "🔍 " . $this->language->getDef('text_rag_mode_rag_scraping');
  6. } elseif (strpos($mode, 'mode_e') !== false || strpos($mode, 'google_trends') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. $badge = "📈 " . $this->language->getDef('text_rag_mode_google_trends');
  8. }
  9. if (!empty($badge)) {
  10. $badges[] = "<span class='badge badge-primary' style='margin-right: 10px; padding: 8px 12px; font-size: 0.9em;'>{$badge}</span>";
  1. if (isset($metadata['engines_used']) && is_array($metadata['engines_used'])) {
  2. $modesUsed = $metadata['engines_used'];
  3. $isHybrid = count($modesUsed) > 1;
  4. } elseif (isset($metadata['mode_type'])) {
  5. $modesUsed = [$metadata['mode_type']];
  6. $isHybrid = (strpos($metadata['mode_type'], 'hybrid') !== false);
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. }
  8. // Display hybrid label if applicable
  9. if ($isHybrid) {
  10. $output .= "<strong>" . $this->language->getDef('text_rag_hybrid_search') . "</strong><br>";
  1. foreach ($modesUsed as $mode) {
  2. $badge = '';
  3. if (strpos($mode, 'mode_a') !== false || strpos($mode, 'ai_overview') !== false) {
  4. $badge = "🤖 " . $this->language->getDef('text_rag_mode_ai_overview');
  5. } elseif (strpos($mode, 'mode_d') !== false || strpos($mode, 'amazon') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
  7. } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
  8. $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
  9. } elseif (strpos($mode, 'mode_c') !== false || strpos($mode, 'rag') !== false) {
  10. $badge = "🔍 " . $this->language->getDef('text_rag_mode_rag_scraping');
  1. $badge = "🤖 " . $this->language->getDef('text_rag_mode_ai_overview');
  2. } elseif (strpos($mode, 'mode_d') !== false || strpos($mode, 'amazon') !== false) {
  3. $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
  4. } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
  5. $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
  6. } elseif (strpos($mode, 'mode_c') !== false || strpos($mode, 'rag') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. $badge = "🔍 " . $this->language->getDef('text_rag_mode_rag_scraping');
  8. } elseif (strpos($mode, 'mode_e') !== false || strpos($mode, 'google_trends') !== false) {
  9. $badge = "📈 " . $this->language->getDef('text_rag_mode_google_trends');
  10. }
  1. if (strpos($mode, 'mode_a') !== false || strpos($mode, 'ai_overview') !== false) {
  2. $badge = "🤖 " . $this->language->getDef('text_rag_mode_ai_overview');
  3. } elseif (strpos($mode, 'mode_d') !== false || strpos($mode, 'amazon') !== false) {
  4. $badge = "🛒 " . $this->language->getDef('text_rag_mode_amazon_shopping');
  5. } elseif (strpos($mode, 'mode_b') !== false || strpos($mode, 'shopping') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $badge = "🛒 " . $this->language->getDef('text_rag_mode_shopping');
  7. } elseif (strpos($mode, 'mode_c') !== false || strpos($mode, 'rag') !== false) {
  8. $badge = "🔍 " . $this->language->getDef('text_rag_mode_rag_scraping');
  9. } elseif (strpos($mode, 'mode_e') !== false || strpos($mode, 'google_trends') !== false) {
  10. $badge = "📈 " . $this->language->getDef('text_rag_mode_google_trends');
  1. return "year {$matches[2]}";
  2. }
  3. // Check for relative time patterns
  4. foreach (self::RELATIVE_TIME_PATTERNS as $pattern => $range) {
  5. if (strpos($query, $pattern) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return $range;
  7. }
  8. }
  9. return null;
  1. public static function extractBaseMetric(string $query): ?string
  2. {
  3. $query = strtolower($query);
  4. foreach (self::FINANCIAL_METRICS as $pattern => $metric) {
  5. if (strpos($query, $pattern) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return $metric;
  7. }
  8. }
  9. return null;
  1. $lowerQuery = strtolower($query);
  2. $needsContext = false;
  3. foreach ($contextualKeywords as $keyword) {
  4. if (strpos($lowerQuery, $keyword) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  5. $needsContext = true;
  6. break;
  7. }
  8. }
  1. 'as an ai',
  2. 'i\'m an ai'
  3. ];
  4. foreach ($genericPhrases as $phrase) {
  5. if (strpos($response, $phrase) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $validationErrors[] = "Response contains generic LLM phrase indicating lack of knowledge";
  7. return false;
  8. }
  9. }
  1. // Check if source type is valid (case-insensitive, partial match)
  2. $sourceType = strtolower($sourceAttr['source_type']);
  3. $isValidSource = false;
  4. foreach ($validSourceTypes as $validType) {
  5. if (strpos($sourceType, strtolower($validType)) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $isValidSource = true;
  7. break;
  8. }
  9. }
  1. ];
  2. // If extension has defined magic bytes, validate them
  3. if (isset($magicBytes[$extension])) {
  4. foreach ($magicBytes[$extension] as $magic) {
  5. if (strpos($bytes, $magic) === 0) {
    Consider replacing strpos() with str_starts_with() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return true;
  7. }
  8. }
  9. return false;
  10. }
  1. // Simple contradiction check
  2. $s1Lower = strtolower($statement1);
  3. $s2Lower = strtolower($statement2);
  4. // Check for negation patterns
  5. if (strpos($s1Lower, 'not') !== false && strpos($s2Lower, 'not') === false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return true;
  7. }
  8. return false;
  9. }
  1. }
  2. // Check for relative time patterns
  3. $relativePatterns = self::getRelativeTimePatterns();
  4. foreach ($relativePatterns as $pattern => $range) {
  5. if (strpos($query, $pattern) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return $range;
  7. }
  8. }
  9. // Check for date range patterns (e.g., "from January to March")
  • gyakutsuki

    not included
  1. $tableName = $metadata['source_table'];
  2. // Remove prefix and _embedding suffix
  3. $prefix = CLICSHOPPING::getConfig('db_table_prefix');
  4. if (strpos($tableName, $prefix) === 0) {
    Consider replacing strpos() with str_starts_with() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  5. $tableName = substr($tableName, strlen($prefix));
  6. }
  7. $tableName = str_replace('_embedding', '', $tableName);
  8. $tableName = str_replace('_', ' ', $tableName);
  9. $docName = ucwords($tableName);
  • gyakutsuki

    not included
  1. */
  2. private function categorizeError(string $errorMessage): string
  3. {
  4. $message = strtolower($errorMessage);
  5. if (strpos($message, 'database') !== false || strpos($message, 'sql') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return 'database';
  7. }
  8. if (strpos($message, 'timeout') !== false || strpos($message, 'time out') !== false) {
  9. return 'timeout';
  10. }
  1. return 'timeout';
  2. }
  3. if (strpos($message, 'memory') !== false) {
  4. return 'memory';
  5. }
  6. if (strpos($message, 'validation') !== false || strpos($message, 'invalid') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. return 'validation';
  8. }
  9. if (strpos($message, 'classification') !== false || strpos($message, 'intent') !== false) {
  10. return 'classification';
  11. }
  1. return 'memory';
  2. }
  3. if (strpos($message, 'validation') !== false || strpos($message, 'invalid') !== false) {
  4. return 'validation';
  5. }
  6. if (strpos($message, 'classification') !== false || strpos($message, 'intent') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. return 'classification';
  8. }
  9. if (strpos($message, 'api') !== false || strpos($message, 'gpt') !== false) {
  10. return 'api';
  11. }
  1. return 'database';
  2. }
  3. if (strpos($message, 'timeout') !== false || strpos($message, 'time out') !== false) {
  4. return 'timeout';
  5. }
  6. if (strpos($message, 'memory') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. return 'memory';
  8. }
  9. if (strpos($message, 'validation') !== false || strpos($message, 'invalid') !== false) {
  10. return 'validation';
  11. }
  1. return 'validation';
  2. }
  3. if (strpos($message, 'classification') !== false || strpos($message, 'intent') !== false) {
  4. return 'classification';
  5. }
  6. if (strpos($message, 'api') !== false || strpos($message, 'gpt') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. return 'api';
  8. }
  9. return 'unknown';
  10. }
  1. $message = strtolower($errorMessage);
  2. if (strpos($message, 'database') !== false || strpos($message, 'sql') !== false) {
  3. return 'database';
  4. }
  5. if (strpos($message, 'timeout') !== false || strpos($message, 'time out') !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return 'timeout';
  7. }
  8. if (strpos($message, 'memory') !== false) {
  9. return 'memory';
  10. }
  1. $text = strtolower("$reason $comment");
  2. foreach ($keywords as $type => $words) {
  3. foreach ($words as $word) {
  4. if (strpos($text, $word) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  5. return $type;
  6. }
  7. }
  8. }
  1. return $rawResult['text_response'];
  2. }
  3. }
  4. // Priority 5: Use finalResponse if available (but not if it's the JSON fallback)
  5. if (!empty($finalResponse) && strpos($finalResponse, 'Résultat:') === false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return $finalResponse;
  7. }
  8. return '';
  9. }
  1. }
  2. }
  3. // Priority 4: Check if rawResult has 'text_response' field (but not if it's the JSON fallback)
  4. if (isset($rawResult['text_response']) && !empty($rawResult['text_response'])) {
  5. if (strpos($rawResult['text_response'], 'Résultat:') === false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return $rawResult['text_response'];
  7. }
  8. }
  9. // Priority 5: Use finalResponse if available (but not if it's the JSON fallback)
  1. // If it's an array, search for the response
  2. if (is_array($executionResult)) {
  3. if (isset($executionResult['text_response']) && !empty($executionResult['text_response'])) {
  4. // Check if text_response is NOT the JSON fallback
  5. if (strpos($executionResult['text_response'], 'Résultat:') === false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return $executionResult['text_response'];
  7. }
  8. }
  9. if (isset($executionResult['response']) && !empty($executionResult['response'])) {
  1. // 🔍 DEBUG: Log prompt loading verification
  2. if ($this->debug) {
  3. error_log("[INFO : ANALYSE] [UnifiedQueryAnalyzer] Prompt Loading Verification:");
  4. error_log(" Prompt length: " . strlen($prompt) . " characters");
  5. error_log(" Prompt preview (first 200 chars): " . substr($prompt, 0, 200) . "...");
  6. error_log(" Query in prompt: " . (strpos($prompt, $query) !== false ? 'YES' : 'NO'));
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. }
  8. // Single GPT call for everything
  9. // Use Gpt::getGptResponse() instead of non-existent complete() method
  1. if ($this->debug) {
  2. error_log("UnifiedQueryAnalyzer: Built prompt from language file sections");
  3. error_log("UnifiedQueryAnalyzer: Query to analyze: {$query}");
  4. error_log("UnifiedQueryAnalyzer: Total prompt length: " . strlen($prompt) . " characters");
  5. error_log("UnifiedQueryAnalyzer: Prompt contains query: " . (strpos($prompt, $query) !== false ? 'YES' : 'NO'));
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. }
  7. return $prompt;
  8. }
  1. return "year {$matches[2]}";
  2. }
  3. // Check for relative time patterns
  4. foreach (self::RELATIVE_TIME_PATTERNS as $pattern => $range) {
  5. if (strpos($query, $pattern) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return $range;
  7. }
  8. }
  9. return null;
  • gyakutsuki

    not included
  1. public static function extractBaseMetric(string $query): ?string
  2. {
  3. $query = strtolower($query);
  4. foreach (self::FINANCIAL_METRICS as $pattern => $metric) {
  5. if (strpos($query, $pattern) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return $metric;
  7. }
  8. }
  9. return null;
  • gyakutsuki

    not included
  1. * @return string Escaped value
  2. */
  3. private function escapeCsvValue(string $value): string
  4. {
  5. // Escape quotes and wrap in quotes if contains comma, quote, or newline
  6. if (strpos($value, ',') !== false || strpos($value, '"') !== false || strpos($value, "\n") !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. return '"' . str_replace('"', '""', $value) . '"';
  8. }
  9. return $value;
  10. }
  1. {
  2. $query = strtolower($query);
  3. $detected = [];
  4. foreach (SuperlativePatterns::$superlativeKeywords as $pattern) {
  5. if (strpos($query, $pattern) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $detected[] = $pattern;
  7. }
  8. }
  9. return $detected;
  • gyakutsuki

    not included
  1. public static function hasSuperlativePattern(string $query): bool
  2. {
  3. $query = strtolower($query);
  4. foreach (SuperlativePatterns::$superlativeKeywords as $pattern) {
  5. if (strpos($query, $pattern) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return true;
  7. }
  8. }
  9. return false;
  • gyakutsuki

    not included
  1. // Fallback to source_table if no name found
  2. if ($docName === null && isset($metadata['source_table'])) {
  3. $tableName = $metadata['source_table'];
  4. // Remove prefix and _embedding suffix
  5. $prefix = defined('CLICSHOPPING_DB_TABLE_PREFIX') ? CLICSHOPPING_DB_TABLE_PREFIX : 'clic_';
  6. if (strpos($tableName, $prefix) === 0) {
    Consider replacing strpos() with str_starts_with() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. $tableName = substr($tableName, strlen($prefix));
  8. }
  9. $tableName = str_replace('_embedding', '', $tableName);
  10. $tableName = str_replace('_', ' ', $tableName);
  11. $docName = ucwords($tableName);
  1. return $entityType;
  2. }
  3. // Remove table prefix if present
  4. $prefix = CLICSHOPPING::getConfig('db_table_prefix');
  5. if (!empty($prefix) && strpos($tableName, $prefix) === 0) {
    Consider replacing strpos() with str_starts_with() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $tableName = substr($tableName, strlen($prefix));
  7. }
  8. // Remove '_embedding' suffix if present
  9. $tableName = str_replace('_embedding', '', $tableName);
  1. }
  2. $keywords[] = $entityType;
  3. $keywords[] = str_replace('_', ' ', $entityType);
  4. if (substr($entityType, -3) === 'ies') {
    Consider replacing substr() with str_ends_with() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  5. $keywords[] = substr($entityType, 0, -3) . 'y';
  6. } elseif (substr($entityType, -1) === 's') {
  7. $keywords[] = substr($entityType, 0, -1);
  8. } else {
  9. $keywords[] = $entityType . 's';
  1. * @return bool
  2. */
  3. private function hasKeyword(string $text, array $keywords): bool
  4. {
  5. foreach ($keywords as $keyword) {
  6. if (strpos($text, $keyword) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. return true;
  8. }
  9. }
  10. return false;
  11. }
  1. $keywords[] = $entityType;
  2. $keywords[] = str_replace('_', ' ', $entityType);
  3. if (substr($entityType, -3) === 'ies') {
  4. $keywords[] = substr($entityType, 0, -3) . 'y';
  5. } elseif (substr($entityType, -1) === 's') {
    Consider replacing substr() with str_ends_with() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $keywords[] = substr($entityType, 0, -1);
  7. } else {
  8. $keywords[] = $entityType . 's';
  9. }
  10. }
  1. // Propose permission level always requires approval for write actions
  2. if ($permissionLevel === self::PERMISSION_PROPOSE) {
  3. $writeActions = ['create', 'update', 'delete', 'modify', 'propose'];
  4. foreach ($writeActions as $writeAction) {
  5. if (strpos($action, $writeAction) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return true;
  7. }
  8. }
  9. }
  1. $table = $matches[1];
  2. }
  3. // Ajouter le préfixe si nécessaire
  4. $prefix = CLICSHOPPING::getConfig('db_prefix');
  5. if (!empty($prefix) && strpos($table, $prefix) !== 0) {
    Consider replacing strpos() with str_starts_with() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $table = $prefix . $table;
  7. }
  8. return trim($table, '`"\'');
  9. }
  1. {
  2. $query = strtolower($query);
  3. $metrics = self::getMetricsPatterns();
  4. foreach ($metrics as $pattern => $metric) {
  5. if (strpos($query, $pattern) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. return $metric;
  7. }
  8. }
  9. return null;
  • gyakutsuki

    not included
  1. * @param string $sql The SQL query
  2. * @return bool True if comments found
  3. */
  4. private function hasComments(string $sql): bool
  5. {
  6. return preg_match('/--/', $sql) || preg_match('/\/\*/', $sql);
    Consider replacing preg_match() with str_contains() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. }
  8. /**
  9. * Check if query contains UNION statement.
  10. *
  1. if (isset($metadata['source_table']) && !empty($metadata['source_table'])) {
  2. $tableName = $metadata['source_table'];
  3. // Remove prefix and _embedding suffix
  4. $prefix = CLICSHOPPING::getConfig('db_table_prefix');
  5. if (!empty($prefix) && strpos($tableName, $prefix) === 0) {
    Consider replacing strpos() with str_starts_with() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $tableName = substr($tableName, strlen($prefix));
  7. }
  8. $tableName = str_replace('_embedding', '', $tableName);
  9. // Convert to readable format (e.g., "pages_manager_description" -> "Pages Manager Description")
  • gyakutsuki

    not included
  1. public function __construct(EmbeddingGeneratorInterface $embeddingGenerator, string $tableName = 'rag_embeddings')
  2. {
  3. $this->embeddingGenerator = $embeddingGenerator;
  4. $prefix = CLICSHOPPING::getConfig('db_table_prefix');
  5. if (!empty($prefix) && strpos($tableName, $prefix) === 0) {
    Consider replacing strpos() with str_starts_with() for improved readability.
    Time to fix: about 1 hour
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $this->tableName = $tableName;
  7. } else {
  8. $this->tableName = $prefix . $tableName;
  9. }
  • gyakutsuki

    not included

Your project uses legacy callable syntax instead of first-class callable syntax 3

More information: https://insight.symfony.com/what-we-analyse/php.use_first_class_callable_syntax

  1. // Escape foreign key name for SQL injection protection
  2. $escaped_fk_name = self::prepareIdentifier($name);
  3. // Escape column names in foreign key definition
  4. $escaped_cols = array_map([self::class, 'prepareIdentifier'], $fields['col']);
  5. $escaped_ref_cols = array_map([self::class, 'prepareIdentifier'], $fields['ref_col']);
    Use the first-class callable syntax ($this->method(...))
    Time to fix: about 15 minutes
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. // Escape reference table name
  7. $escaped_ref_table = self::prepareIdentifier($fields['ref_table']);
  8. $row = ' FOREIGN KEY ' . $escaped_fk_name . ' (' . implode(', ', $escaped_cols) . ') REFERENCES ' . (isset($prefix) && (!isset($fields['prefix']) || ($fields['prefix'] != 'false')) ? $prefix : '') . $escaped_ref_table . '(' . implode(', ', $escaped_ref_cols) . ')';
  1. foreach ($schema['foreign'] as $name => $fields) {
  2. // Escape foreign key name for SQL injection protection
  3. $escaped_fk_name = self::prepareIdentifier($name);
  4. // Escape column names in foreign key definition
  5. $escaped_cols = array_map([self::class, 'prepareIdentifier'], $fields['col']);
    Use the first-class callable syntax ($this->method(...))
    Time to fix: about 15 minutes
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  6. $escaped_ref_cols = array_map([self::class, 'prepareIdentifier'], $fields['ref_col']);
  7. // Escape reference table name
  8. $escaped_ref_table = self::prepareIdentifier($fields['ref_table']);
  1. // Build a mapping of table names (without prefix) to entity types
  2. $tableToEntityType = [];
  3. foreach ($allTables as $fullTableName) {
  4. $entityType = $registry->getEntityTypeForTable($fullTableName);
  5. // Remove prefix and _embedding suffix to get base table name
  6. $tableName = str_replace([$prefix, '_embedding'], '', $fullTableName);
    Use the first-class callable syntax ($this->method(...))
    Time to fix: about 15 minutes
    Read doc Permalink Copy Prompt
    Last edited by clicshopping
  7. $tableToEntityType[$tableName] = $entityType;
  8. }
  9. // Pattern 1: FROM {table_name}
  10. if (preg_match('/FROM\s+(?:\w+\.)?(\w+)/i', $query, $matches)) {