Your project should not commit sensitive files to the repository
- Read doc
- Data leak
- Critical
More information: https://insight.symfony.com/what-we-analyse/git.sensitive_file_committed
-
Core/ClicShopping/External
- vendor
- CommonCurrencies.json
- PasswordHash.php
-
cacert.pem
The sensitive file
cacert.pemis committed to the repository and may expose credentials or private keys. - cert_key_pem_paypal.txt
- update-cacert.sh
Your project uses dangerous command injection functions 16
- Read doc
- Security
- Critical
More information: https://insight.symfony.com/what-we-analyse/php.use_command_injection_function
- }
- if (isset($_POST['download'])) {
- switch ($compress) {
- case 'gzip':
- exec(LOCAL_EXE_GZIP . ' ' . $backup_directory . $backup_file);
- $backup_file .= '.gz';
- break;
- case 'zip':
- exec(LOCAL_EXE_ZIP . ' -j ' . $backup_directory . $backup_file . '.zip ' . $backup_directory . $backup_file);
- unlink($backup_directory . $backup_file);
- case 'gzip':
- exec(LOCAL_EXE_GZIP . ' ' . $backup_directory . $backup_file);
- $backup_file .= '.gz';
- break;
- case 'zip':
- exec(LOCAL_EXE_ZIP . ' -j ' . $backup_directory . $backup_file . '.zip ' . $backup_directory . $backup_file);
- unlink($backup_directory . $backup_file);
- $backup_file .= '.zip';
- }
- header('Content-type: application/x-octet-stream');
- exit;
- } else {
- switch ($compress) {
- case 'gzip':
- exec(LOCAL_EXE_GZIP . ' ' . $backup_directory . $backup_file);
- break;
- case 'zip':
- exec(LOCAL_EXE_ZIP . ' -j ' . $backup_directory . $backup_file . '.zip ' . $backup_directory . $backup_file);
- unlink($backup_directory . $backup_file);
- }
- switch ($compress) {
- case 'gzip':
- exec(LOCAL_EXE_GZIP . ' ' . $backup_directory . $backup_file);
- break;
- case 'zip':
- exec(LOCAL_EXE_ZIP . ' -j ' . $backup_directory . $backup_file . '.zip ' . $backup_directory . $backup_file);
- unlink($backup_directory . $backup_file);
- }
- $CLICSHOPPING_MessageStack->add(CLICSHOPPING::getDef('success_database_saved'), 'success');
- }
- $restore_from = $restore_file;
- $remove_raw = false;
- break;
- case '.gz':
- $restore_from = substr($restore_file, 0, -3);
- exec(LOCAL_EXE_GUNZIP . ' ' . $restore_file . ' -c > ' . $restore_from);
- $remove_raw = true;
- break;
- case 'zip':
- $restore_from = substr($restore_file, 0, -4);
- exec(LOCAL_EXE_UNZIP . ' ' . $restore_file . ' -d ' . $backup_directory);
- exec(LOCAL_EXE_GUNZIP . ' ' . $restore_file . ' -c > ' . $restore_from);
- $remove_raw = true;
- break;
- case 'zip':
- $restore_from = substr($restore_file, 0, -4);
- exec(LOCAL_EXE_UNZIP . ' ' . $restore_file . ' -d ' . $backup_directory);
- $remove_raw = true;
- }
- if (isset($restore_from) && is_file($restore_from) && filesize($restore_from) > 15000) {
- $fd = fopen($restore_from, 'rb');
- 2 => ["pipe", "w"] // stderr
- ];
- $this->logger->info('Starting MCP server process', ['command' => $command]);
- $this->process = proc_open($command, $descriptorspec, $this->pipes);
- if (!is_resource($this->process)) {
- $this->logger->error('Failed to start MCP server process', ['command' => $command]);
- throw new McpConnectionException('Failed to start MCP server process');
- }
- $CLICSHOPPING_Db = Registry::get('Db');
- $Qdate = $CLICSHOPPING_Db->query('select now() as datetime');
- try {
- [$system, $host, $kernel] = preg_split('/[\s,]+/', @exec('uname -a'), 5);
- } catch (\Throwable $e) {
- $system = $host = $kernel = 'unavailable';
- }
- try {
- } catch (\Throwable $e) {
- $system = $host = $kernel = 'unavailable';
- }
- try {
- $uptime = @exec('uptime');
- } catch (\Throwable $e) {
- $uptime = 'unavailable';
- }
- try {
- if (!self::checkExecEnabled()) {
- return false;
- }
- $cmd = 'cd ' . escapeshellarg(self::$root) . ' && composer --no-ansi --no-interaction show 2>/dev/null';
- exec($cmd, $output, $return);
- return $return === 0;
- }
- /**
- if (is_null($library) || !self::checkExecute()) {
- return false;
- }
- $cmd = 'cd ' . escapeshellarg(self::$root) . ' && composer show ' . escapeshellarg($library) . ' 2>/dev/null';
- exec($cmd, $output, $return);
- return $return === 0;
- }
- /**
- * Verifies if the necessary conditions for executing commands are met.
- if (!self::checkExecute() || is_null($library)) {
- return false;
- }
- $cmd = 'cd ' . escapeshellarg(self::$root) . ' && composer show ' . escapeshellarg($library) . ' 2>/dev/null';
- exec($cmd, $output, $return);
- if ($return === 0 && !empty($output)) {
- // Recherche la ligne contenant la version
- foreach ($output as $line) {
- if (str_starts_with($line, 'versions')) {
- if ($library !== null) {
- $cmd .= ' ' . escapeshellarg($library);
- }
- $cmd .= ' 2>&1';
- exec($cmd, $output, $return);
- // Retourne toute la sortie pour plus d'informations, ou une chaîne vide si rien
- return !empty($output) ? implode("\n", $output) : '';
- }
- if (!self::checkExecute() || is_null($library)) {
- return false;
- }
- $cmd = 'cd ' . escapeshellarg(self::$root) . ' && composer require ' . escapeshellarg($library) . ' 2>&1';
- exec($cmd, $output, $return);
- return !empty($output) ? implode("\n", $output) : '';
- }
- /**
- if (!self::checkExecute() || is_null($library)) {
- return '';
- }
- $cmd = 'cd ' . escapeshellarg(self::$root) . ' && composer remove ' . escapeshellarg($library) . ' 2>&1';
- exec($cmd, $output, $return);
- return !empty($output) ? implode("\n", $output) : '';
- }
- /**
- if (!self::checkExecute()) {
- return '';
- }
- $cmd = 'cd ' . escapeshellarg(self::$root) . ' && composer clearcache 2>&1';
- exec($cmd, $output, $return);
- // Retourne toute la sortie pour plus d'informations, ou une chaîne vide si rien
- return !empty($output) ? implode("\n", $output) : '';
- }
- }
Your project uses non-strict array lookups 296
- Read doc
- Reliability
- Major
More information: https://insight.symfony.com/what-we-analyse/php.strict_array_lookup
- */
- public static function checkExecEnabled(): bool
- {
- $disabled = explode(', ', ini_get('disable_functions'));
- return !in_array('exec', $disabled);
- }
- /**
- * Checks if Composer is installed and accessible in the current environment.
- *
- exit;
- }
- // Validate feedback_type
- $validTypes = ['positive', 'negative', 'correction'];
- if (!in_array($input['feedback_type'], $validTypes)) {
- echo json_encode([
- 'success' => false,
- 'error' => 'feedback_type must be one of: ' . implode(', ', $validTypes)
- ]);
- exit;
- $errors = [];
- // ============================================================================
- // 1. Reset Translation Cache
- // ============================================================================
- if (in_array('translations', $cacheTypes)) {
- try {
- $translationCache = new TranslationCache();
- // Count files before
- $cacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Translation/';
- }
- // ============================================================================
- // 3. Reset Classification Cache
- // ============================================================================
- if (in_array('classification', $cacheTypes)) {
- try {
- $classificationCache = new ClassificationCache();
- // Get stats before
- $statsBefore = $classificationCache->getStatistics();
- }
- // ============================================================================
- // 3. Reset Database Query Cache
- // ============================================================================
- if (in_array('database', $cacheTypes)) {
- try {
- $db = Registry::get('Db');
- $prefix = CLICSHOPPING::getConfig('db_table_prefix');
- // Count entries before
- }
- // ============================================================================
- // 4. Reset Schema Query Cache (TASK 5 - ITEM 1)
- // ============================================================================
- if (in_array('schema', $cacheTypes)) {
- try {
- // Count schema cache files before (new location)
- $schemaCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/SchemaQuery/';
- $filesBefore = 0;
- }
- // ============================================================================
- // 5. Reset Intent Classification Cache (TASK 5.1.7.6)
- // ============================================================================
- if (in_array('intent', $cacheTypes)) {
- try {
- // Count intent cache files before (new location - all files)
- $intentCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Intent/';
- $filesBefore = 0;
- }
- // ============================================================================
- // 6. Reset Ambiguity Cache (TASK 4 - Cache Migration)
- // ============================================================================
- if (in_array('ambiguity', $cacheTypes)) {
- try {
- // Count ambiguity cache files before (new location - all files)
- $ambiguityCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Ambiguity/';
- $filesBefore = 0;
- }
- // ============================================================================
- // 7. Reset Translation Ambiguity Cache
- // ============================================================================
- if (in_array('translation_ambiguity', $cacheTypes)) {
- try {
- // Count translation ambiguity cache files before (new location)
- $translationAmbiguityCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Translation/';
- $filesBefore = 0;
- }
- // ============================================================================
- // 8. Reset Context Cache
- // ============================================================================
- if (in_array('context', $cacheTypes)) {
- try {
- // Count context cache files before (new location)
- $contextCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Context/';
- $filesBefore = 0;
- }
- // ============================================================================
- // 8.5. Reset Memory Cache (file-based)
- // ============================================================================
- if (in_array('memory', $cacheTypes)) {
- try {
- $memoryCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Memory/';
- $filesBefore = 0;
- if (is_dir($memoryCacheDir)) {
- }
- // ============================================================================
- // 9. Reset Embedding Cache
- // ============================================================================
- if (in_array('embedding', $cacheTypes)) {
- try {
- // Count embedding cache files before (new location)
- $embeddingCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Embedding/';
- $filesBefore = 0;
- }
- // ============================================================================
- // 10. Reset EmbeddingSearch Cache
- // ============================================================================
- if (in_array('embedding_search', $cacheTypes)) {
- try {
- // Count embedding search cache files before (new location)
- $embeddingSearchCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/EmbeddingSearch/';
- $filesBefore = 0;
- }
- // ============================================================================
- // 11. Reset Hybrid Query Cache (TASK 8: Multi-temporal query caching)
- // ============================================================================
- if (in_array('hybrid', $cacheTypes)) {
- try {
- // Count hybrid cache files before
- $hybridCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Hybrid/';
- $filesBefore = 0;
- }
- // ============================================================================
- // 12. Reset Semantic Query Cache (TASK 8: Multi-temporal query caching)
- // ============================================================================
- if (in_array('semantic', $cacheTypes)) {
- try {
- // Count hybrid cache files before
- $semanticCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Semantic/';
- $filesBefore = 0;
- }
- // ============================================================================
- // 13. Reset Embeddings Cache (PHASE 2 - NewVector cache)
- // ============================================================================
- if (in_array('embeddings', $cacheTypes)) {
- try {
- $embeddingsCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Embeddings/';
- $filesBefore = 0;
- if (is_dir($embeddingsCacheDir)) {
- }
- // ============================================================================
- // 14. Reset SQL Query Cache (PHASE 4)
- // ============================================================================
- if (in_array('sql', $cacheTypes)) {
- try {
- $sqlCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/SQL/';
- $filesBefore = 0;
- if (is_dir($sqlCacheDir)) {
- }
- // ============================================================================
- // 15. Reset Security Cache
- // ============================================================================
- if (in_array('security', $cacheTypes)) {
- try {
- $securityCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Security/';
- $filesBefore = 0;
- if (is_dir($securityCacheDir)) {
- }
- // ============================================================================
- // 16. Reset Reputation Cache
- // ============================================================================
- if (in_array('reputation', $cacheTypes)) {
- try {
- $reputationCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Reputation/';
- $filesBefore = 0;
- if (is_dir($reputationCacheDir)) {
- }
- // ============================================================================
- // 17. Reset Config Cache
- // ============================================================================
- if (in_array('config', $cacheTypes)) {
- try {
- $configCacheDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Work/Cache/Rag/Config/';
- $filesBefore = 0;
- if (is_dir($configCacheDir)) {
- unset($this->storage[$scopedKey]);
- unset($this->metadata[$scopedKey]);
- // Remove from the scope's key list
- $scopeKeys = $this->scopes[$this->currentScope] ?? [];
- $index = array_search($scopedKey, $scopeKeys);
- if ($index !== false) {
- array_splice($this->scopes[$this->currentScope], $index, 1);
- }
- // Use higher priority
- $priorities = ['low' => 1, 'medium' => 2, 'high' => 3, 'critical' => 4];
- $priority1 = $priorities[$obj1->getPriority()];
- $priority2 = $priorities[$obj2->getPriority()];
- $combinedPriority = array_search(max($priority1, $priority2), $priorities);
- // Estimate combined time (not just sum, as there may be synergies)
- $estimatedTime = (int)(($obj1->getEstimatedCompletionTime() + $obj2->getEstimatedCompletionTime()) * 0.8);
- return [
- private function translateMonthName(string $monthName, string $languageCode): string
- {
- $englishMonths = ['January', 'February', 'March', 'April', 'May', 'June',
- 'July', 'August', 'September', 'October', 'November', 'December'];
- $monthIndex = array_search(ucfirst(strtolower($monthName)), $englishMonths);
- if ($monthIndex === false) {
- return $monthName; // Return as-is if not found
- }
- $targetMonths = $this->getMonthNames($languageCode);
- if ($field === $idColumn) {
- return true;
- }
- // Exclude system timestamp fields
- if (in_array($field, ['created_at', 'updated_at', 'deleted_at'])) {
- return false;
- }
- // Get column type
- $type = $columnTypes[$field] ?? 'string';
- // Get column type
- $type = $columnTypes[$field] ?? 'string';
- // Include numeric columns (for aggregation)
- if (in_array($type, ['int', 'bigint', 'smallint', 'decimal', 'float', 'double'])) {
- return true;
- }
- // Include date/timestamp columns (for temporal analysis)
- if (in_array($type, ['date', 'datetime', 'timestamp', 'time'])) {
- if (in_array($type, ['int', 'bigint', 'smallint', 'decimal', 'float', 'double'])) {
- return true;
- }
- // Include date/timestamp columns (for temporal analysis)
- if (in_array($type, ['date', 'datetime', 'timestamp', 'time'])) {
- return true;
- }
- // Include text columns (for filtering and grouping)
- if (in_array($type, ['varchar', 'char', 'text', 'enum'])) {
- if (in_array($type, ['date', 'datetime', 'timestamp', 'time'])) {
- return true;
- }
- // Include text columns (for filtering and grouping)
- if (in_array($type, ['varchar', 'char', 'text', 'enum'])) {
- return true;
- }
- // Exclude everything else (binary, blob, json, etc.)
- return false;
- // Prefer 'normalized'; fall back to 'normalized_value' for forward-compat
- $scoreDescription = (float) ($factor['normalized'] ?? $factor['normalized_value'] ?? 0.0);
- }
- }
- $finalQuadrant = in_array($quadrant, ['Q1', 'Q2', 'Q3', 'Q4']) ? $quadrant : 'Q_intermediate';
- return [
- 'quadrant' => $finalQuadrant,
- 'score_x' => (float) ($scoreXResult['score'] ?? 0.0),
- 'score_y' => (float) ($scoreYResult['score'] ?? 0.0),
- $fields = DoctrineOrm::getTableColumns($tableName);
- // Exclude only ID and system timestamp fields
- return array_values(array_filter($fields, function($field) use ($idColumn) {
- return $field !== $idColumn
- && !in_array($field, ['created_at', 'updated_at', 'deleted_at']);
- }));
- } catch (\Exception $e) {
- return [];
- }
- $words = preg_split('/[\s,.:;!?"()]+/u', mb_strtolower($onlyText), -1, PREG_SPLIT_NO_EMPTY);
- $grammar = $this->grammar();
- $counts = [];
- foreach ($words as $w) {
- $w = preg_replace('/[^\p{L}\p{N}\-]/u', '', $w);
- if (mb_strlen($w) > 2 && !in_array($w, $grammar)) {
- $counts[$w] = ($counts[$w] ?? 0) + 1;
- }
- }
- arsort($counts);
- $report['wordcountmax'] = array_slice($counts, 0, 8, true);
- $productData = $this->getProductData($productId);
- if ($productData && !$productData['in_stock']) {
- $messages[] = [
- 'type' => 'error',
- 'code' => 'out_of_stock',
- 'param' => '$.line_items[' . array_search($lineItem, $lineItems) . ']',
- 'content_type' => 'plain',
- 'content' => 'Produit ' . $productData['title'] . ' temporairement indisponible'
- ];
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_ECOMMERCE_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_ECOMMERCE_INSTALLED', implode(';', $installed));
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_ECOMMERCE_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_ECOMMERCE_INSTALLED', implode(';', $installed));
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_ECOMMERCE_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_ECOMMERCE_INSTALLED', implode(';', $installed));
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_ECOMMERCE_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_ECOMMERCE_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_PRODUCTS_ARCHIVE_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_PRODUCTS_ARCHIVE_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- // make sure no duplicate category IDs exist which could lock the server in a loop
- $tmp_array = [];
- $n = count($cPath_array);
- for ($i = 0; $i < $n; $i++) {
- if (!in_array($cPath_array[$i], $tmp_array)) {
- $tmp_array[] = $cPath_array[$i];
- }
- }
- return $tmp_array;
- $category_name = $this->getCategoryTreeTitle($category['name']);
- $categories_url = $this->getCategoryTreeUrl($category_link);
- if (($this->follow_cpath === true) && in_array($category_id, $this->cpath_array)) {
- $link_title = $this->cpath_start_string . $category_name . $this->cpath_end_string;
- } else {
- $link_title = $category_name;
- }
- $result .= $this->parent_end_string;
- }
- if (isset($this->_data[$category_id]) && (($this->max_level == '0') || ($this->max_level > $level + 1))) {
- if ($this->follow_cpath === true) {
- if (in_array($category_id, $this->cpath_array)) {
- $result .= $this->_buildBranch($category_id, $level + 1);
- }
- } else {
- $result .= $this->_buildBranch($category_id, $level + 1);
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_PRODUCTS_CATEGORIES_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_PRODUCTS_CATEGORIES_INSTALLED', implode(';', $installed));
- $categories_id = HTML::sanitize($this->Id);
- $new_parent_id = HTML::sanitize($this->moveToCategoryID);
- $path = explode('_', $this->categoriesAdmin->getGeneratedCategoryPathIds($new_parent_id));
- if (\in_array($this->Id, $path)) {
- $CLICSHOPPING_MessageStack->add($this->app->getDef('error_cannot_move_directory_to_parent'), 'error');
- $this->app->redirect('Categories&cPath=' . $this->cPath . '&cID=' . $categories_id);
- } else {
- $sql_array = [
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_MANUFACTURERS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_MANUFACTURERS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CATALOG_PRODUCTS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CATALOG_PRODUCTS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_PRODUCTS_ATTRIBUTES_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_PRODUCTS_ATTRIBUTES_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_SUPPLIERS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_SUPPLIERS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_EMAIL_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_EMAIL_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_NEWSLETTER_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_NEWSLETTER_INSTALLED', implode(';', $installed));
- } else {
- $chosen = [];
- foreach ($_POST['chosen'] as $id) {
- if (is_numeric($id) && !\in_array($id, $chosen)) {
- $chosen[] = $id;
- }
- }
- $ids = array_map(function ($k) {
- }
- } else {
- $chosen = [];
- foreach ($_POST['chosen'] as $id) {
- if (is_numeric($id) && !\in_array($id, $chosen)) {
- $chosen[] = $id;
- }
- }
- $ids = array_map(function ($k) {
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- $allowed = array_map(function ($v) {
- return basename($v, '.php');
- }, glob(CLICSHOPPING::BASE_DIR . 'Apps/Communication/Newsletter/Module/ClicShoppingAdmin/Newsletter/*.php'));
- if (!\in_array($newsletter_module, $allowed)) {
- $CLICSHOPPING_MessageStack->add($CLICSHOPPING_Newsletter->getDef('error_newsletter_module_not_exists'), 'danger');
- $newsletter_error = true;
- }
- if ($newsletters_accept_file == 'on') {
- $allowed = array_map(function ($v) {
- return basename($v, '.php');
- }, glob(CLICSHOPPING::BASE_DIR . 'Apps/Communication/Newsletter/Module/ClicShoppingAdmin/Newsletter/*.php'));
- if (!\in_array($newsletter_module, $allowed)) {
- $CLICSHOPPING_MessageStack->add($CLICSHOPPING_Newsletter->getDef('error_newsletter_module_not_exists'), 'danger');
- $newsletter_error = true;
- }
- if ($newsletters_accept_file == 'on') {
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_PAGE_MANAGER_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_PAGE_MANAGER_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_ADMINISTRATORS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_ADMINISTRATORS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- foreach ($Qips as $allowedIp) {
- $ip = $allowedIp['ip'];
- if ($ip === '127.0.0.1' || $ip === 'localhost') {
- if (in_array($clientIp, ['127.0.0.1', '::1'])) {
- self::logSecurityEvent('Localhost access granted', [
- 'api_id' => $api_id,
- 'client_ip' => $clientIp
- ]);
- */
- public static function isLocalEnvironment(): bool
- {
- $ip = HTTP::getIpAddress();
- if (in_array($ip, ['127.0.0.1', '::1'])) {
- return true;
- }
- $serverName = $_SERVER['SERVER_NAME'] ?? '';
- $host = $_SERVER['HTTP_HOST'] ?? '';
- }
- $method = strtoupper($_SERVER["REQUEST_METHOD"]);
- $allowedMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'];
- if (!in_array($method, $allowedMethods)) {
- throw new Exception("Invalid HTTP method: " . $method);
- }
- return $method;
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_API_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_API_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CACHE_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CACHE_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- foreach ($models as $model) {
- $modelId = $model['id'];
- $provider = $model['provider'] ?? 'openai'; // Default to openai if missing
- // Validate provider name
- if (!in_array($provider, $validProviders)) {
- if (defined('CLICSHOPPING_APP_CHATGPT_CH_DEBUG') && CLICSHOPPING_APP_CHATGPT_CH_DEBUG === 'True') {
- error_log("WARNING: Invalid provider '$provider' for model '$modelId'. Using 'openai' as default.");
- }
- $provider = 'openai';
- }
- 'open-mistral-nemo',
- 'open-codestral-mamba',
- 'mistral-moderation-latest'
- ];
- if (empty($model) || !in_array($model, $valid_models)) {
- $model = 'mistral-large-latest';
- }
- $config = new MistralAIChat();
- $config->apiKey = $api_key;
- }
- // Validate type is one of expected values
- if (isset($response['type'])) {
- $validTypes = ['analytics', 'semantic', 'web_search', 'hybrid', 'error', 'clarification'];
- if (!in_array($response['type'], $validTypes)) {
- $warnings[] = "Unexpected type value: {$response['type']}";
- }
- }
- return [
- if ($productData && !$productData['in_stock']) {
- $messages[] = [
- 'type' => 'error',
- 'code' => 'out_of_stock',
- 'text' => 'Produit ' . $productData['title'] . ' temporairement indisponible',
- 'path' => '$.line_items[' . array_search($lineItem, $lineItems) . ']'
- ];
- }
- }
- // Add promotional messages
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CHATGPT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CHATGPT_INSTALLED', implode(';', $installed));
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CHATGPT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CHATGPT_INSTALLED', implode(';', $installed));
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CHATGPT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CHATGPT_INSTALLED', implode(';', $installed));
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CHATGPT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CHATGPT_INSTALLED', implode(';', $installed));
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CHATGPT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CHATGPT_INSTALLED', implode(';', $installed));
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CHATGPT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CHATGPT_INSTALLED', implode(';', $installed));
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CHATGPT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CHATGPT_INSTALLED', implode(';', $installed));
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CHATGPT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CHATGPT_INSTALLED', implode(';', $installed));
- exit;
- }
- // Validate feedback_type
- $validTypes = ['positive', 'negative', 'correction'];
- if (!in_array($input['feedback_type'], $validTypes)) {
- echo json_encode([
- 'success' => false,
- 'error' => 'feedback_type must be one of: ' . implode(', ', $validTypes)
- ]);
- exit;
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_COUNTRIES_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_COUNTRIES_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CURRENCY_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CURRENCY_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_LANGUES_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_LANGUES_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- }
- foreach (glob(CLICSHOPPING::getConfig('dir_root', 'ClicShoppingAdmin') . 'Core/languages/*', GLOB_ONLYDIR) as $dir) {
- $code = basename($dir);
- if (array_search($code, array_column($directories, 'id')) === false) {
- $directories[] = ['id' => $code,
- 'text' => $code
- ];
- }
- }
- }
- foreach (glob(CLICSHOPPING::getConfig('dir_root', 'ClicShoppingAdmin') . 'Core/languages/*', GLOB_ONLYDIR) as $dir) {
- $code = basename($dir);
- if (array_search($code, array_column($directories, 'id')) === false) {
- $directories[] = ['id' => $code,
- 'text' => $code
- ];
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_MODULES_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_MODULES_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- $module->install();
- $modules_installed = explode(';', \constant($module_key));
- if (!\in_array($class . $file_extension, $modules_installed)) {
- $modules_installed[] = $class . $file_extension;
- }
- Registry::get('Db')->save('configuration', ['configuration_value' => implode(';', $modules_installed)],
- ['configuration_key' => $module_key]
- $module->remove();
- $modules_installed = explode(';', \constant($module_key));
- if (\in_array($class . $file_extension, $modules_installed)) {
- unset($modules_installed[array_search($class . $file_extension, $modules_installed)]);
- }
- Registry::get('Db')->save('configuration', ['configuration_value' => implode(';', $modules_installed)],
- ['configuration_key' => $module_key]
- $module->remove();
- $modules_installed = explode(';', \constant($module_key));
- if (\in_array($class . $file_extension, $modules_installed)) {
- unset($modules_installed[array_search($class . $file_extension, $modules_installed)]);
- }
- Registry::get('Db')->save('configuration', ['configuration_value' => implode(';', $modules_installed)],
- ['configuration_key' => $module_key]
- );
- if ($dir = @dir($module_directory)) {
- while ($file = $dir->read()) {
- if (!is_dir($module_directory . $file)) {
- if (substr($file, strrpos($file, '.')) == $file_extension) {
- if (isset($_GET['list']) && ($_GET['list'] == 'new')) {
- if (!\in_array($file, $modules_installed)) {
- $directory_array[] = $file;
- }
- } else {
- if (\in_array($file, $modules_installed)) {
- $directory_array[] = $file;
- if (isset($_GET['list']) && ($_GET['list'] == 'new')) {
- if (!\in_array($file, $modules_installed)) {
- $directory_array[] = $file;
- }
- } else {
- if (\in_array($file, $modules_installed)) {
- $directory_array[] = $file;
- } else {
- $new_modules_counter++;
- }
- }
- }
- if (isset($appModuleType)) {
- foreach (Apps::getModules($appModuleType) as $k => $v) {
- if (isset($_GET['list']) && ($_GET['list'] == 'new')) {
- if (!\in_array($k, $modules_installed)) {
- $directory_array[] = $k;
- }
- } else {
- if (\in_array($k, $modules_installed)) {
- $directory_array[] = $k;
- if (isset($_GET['list']) && ($_GET['list'] == 'new')) {
- if (!\in_array($k, $modules_installed)) {
- $directory_array[] = $k;
- }
- } else {
- if (\in_array($k, $modules_installed)) {
- $directory_array[] = $k;
- } else {
- $new_modules_counter++;
- }
- }
- if ($dir = @dir($module_directory)) {
- while ($file = $dir->read()) {
- if (!is_dir($module_directory . $file)) {
- if (substr($file, strrpos($file, '.')) === $file_extension) {
- if (isset($_GET['list']) && ($_GET['list'] == 'new')) {
- if (!\in_array($file, $modules_installed)) {
- $directory_array[] = $file;
- }
- } else {
- if (\in_array($file, $modules_installed)) {
- $directory_array[] = $file;
- if (isset($_GET['list']) && ($_GET['list'] == 'new')) {
- if (!\in_array($file, $modules_installed)) {
- $directory_array[] = $file;
- }
- } else {
- if (\in_array($file, $modules_installed)) {
- $directory_array[] = $file;
- } else {
- $new_modules_counter++;
- }
- }
- }
- if (isset($appModuleType)) {
- foreach (Apps::getModules($appModuleType) as $k => $v) {
- if (isset($_GET['list']) && ($_GET['list'] == 'new')) {
- if (!\in_array($k, $modules_installed)) {
- $directory_array[] = $k;
- }
- } else {
- if (\in_array($k, $modules_installed)) {
- $directory_array[] = $k;
- if (isset($_GET['list']) && ($_GET['list'] == 'new')) {
- if (!\in_array($k, $modules_installed)) {
- $directory_array[] = $k;
- }
- } else {
- if (\in_array($k, $modules_installed)) {
- $directory_array[] = $k;
- } else {
- $new_modules_counter++;
- }
- }
- <tr>
- <td><?php echo $module->title; ?></td>
- <td class="text-start"><?php echo $module->group; ?></td>
- <td class="text-end">
- <?php
- if (\in_array($module->code . $file_extension, $modules_installed) && is_numeric($module->sort_order)) {
- echo $module->sort_order;
- }
- ?>
- </td>
- <td class="text-center">
- $Qcheck = $CLICSHOPPING_Db->get('configuration', 'configuration_value', ['configuration_key' => 'TEMPLATE_BLOCK_GROUPS']);
- if ($Qcheck->fetch() !== false) {
- $tbgroups_array = explode(';', $Qcheck->value('configuration_value'));
- if (!\in_array($module_type, $tbgroups_array)) {
- $tbgroups_array[] = $module_type;
- sort($tbgroups_array);
- $CLICSHOPPING_Db->save('configuration', [
- 'configuration_value' => implode(';', $tbgroups_array),
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_ORDERS_STATUS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_ORDERS_STATUS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_ORDERS_STATUS_INVOICE_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_ORDERS_STATUS_INVOICE_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_PROUCTS_LENGTH_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_PROUCTS_LENGTH_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_PRODUCTS_QUANTITY_UNIT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_PRODUCTS_QUANTITY_UNIT_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_SETTINGS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_SETTINGS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_TAX_CLASS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_TAX_CLASS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_TAX_GEO_ZONES_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_TAX_GEO_ZONES_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_TAX_RATES_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_TAX_RATES_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_TEMPLATE_EMAIL_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_TEMPLATE_EMAIL_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_WEIGHT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_WEIGHT_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_ZONES_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_ZONES_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CUSTOMERS_INFO_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CUSTOMERS_INFO_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CUSTOMERS_GDPR_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CUSTOMERS_GDPR_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CUSTOMERS_GROUPS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CUSTOMERS_GROUPS_INSTALLED', implode(';', $installed));
- for ($i = 0, $n = \count($include_modules); $i < $n; $i++) {
- if (str_contains($include_modules[$i]['class'], '\\')) {
- Registry::set('Payment_' . str_replace('\\', '_', $include_modules[$i]['class']), new $include_modules[$i]['file']);
- $module = Registry::get('Payment_' . str_replace('\\', '_', $include_modules[$i]['class']));
- if (($cInfo->customers_group_id != 0) && (\in_array($module->code, $payments_unallowed))) {
- $content .= '<div class="row">';
- $content .= '<div class="col-md-5">';
- $content .= '<div class="form-group row">';
- $content .= '<div class="col-md-12">';
- $content .= '<span class="col-md-1"><i class="bi-check text-success"></i></span>';
- for ($i = 0, $n = \count($include_modules); $i < $n; $i++) {
- if (str_contains($include_modules[$i]['class'], '\\')) {
- Registry::set('Shipping_' . str_replace('\\', '_', $include_modules[$i]['class']), new $include_modules[$i]['file']);
- $module = Registry::get('Shipping_' . str_replace('\\', '_', $include_modules[$i]['class']));
- if (($cInfo->customers_group_id != 0) && (\in_array($module->code, $shipping_unallowed))) {
- $content .= '<div class="col-md-12">';
- $content .= '<span class="col-md-1"><i class="bi-check text-success"></i></span>';
- $content .= '<span class="col-md-3">' . $module->title . '</span>';
- $content .= '</div>';
- } elseif ($cInfo->customers_group_id != 0 && !\in_array($module->code, $shipping_unallowed)) {
- if (($cInfo->customers_group_id != 0) && (\in_array($module->code, $shipping_unallowed))) {
- $content .= '<div class="col-md-12">';
- $content .= '<span class="col-md-1"><i class="bi-check text-success"></i></span>';
- $content .= '<span class="col-md-3">' . $module->title . '</span>';
- $content .= '</div>';
- } elseif ($cInfo->customers_group_id != 0 && !\in_array($module->code, $shipping_unallowed)) {
- $content .= '<div class="col-md-12">';
- $content .= '<span class="col-md-1"><i class="bi-check text-danger"></i></span>';
- $content .= '<span class="col-md-3">' . $module->title . '</span>';
- $content .= '</div>';
- } elseif ($cInfo->customers_group_id == 0) {
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- <div class="form-group row">
- <div class="col-md-12">
- <ul class="list-group-slider list-group-flush">
- <li class="list-group-item-slider">
- <label class="switch">
- <?php echo HTML::checkboxField('payment_unallowed[' . $i . ']', $module->code, (\in_array($module->code, $payments_unallowed)) ? true : false, 'class="success"'); ?>
- <span class="slider"></span>
- </label>
- </li>
- <span class="text-slider"><?php echo $module->title; ?></span>
- </ul>
- <div class="form-group row">
- <div class="col-md-12">
- <ul class="list-group-slider list-group-flush">
- <li class="list-group-item-slider">
- <label class="switch">
- <?php echo HTML::checkboxField('shipping_unallowed[' . $i . ']', $module->code, (\in_array($module->code, $shipping_unallowed)) ? true : false, 'class="success"'); ?>
- <span class="slider"></span>
- </label>
- </li>
- <span class="text-slider"><?php echo $module->title; ?></span>
- </ul>
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CUSTOMERS_MEMBERS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CUSTOMERS_MEMBERS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_REVIEWS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_REVIEWS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_BANNER_MANAGER_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_BANNER_MANAGER_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_PRODUCTS_FAVORITES_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_PRODUCTS_FAVORITES_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_PRODUCTS_FEATURED_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_PRODUCTS_FEATURED_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_PRODUCTS_PRODUCT_RECOMMENDATIONS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_PRODUCTS_PRODUCT_RECOMMENDATIONS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_SEO_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_SEO_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_PRODUCTS_SPECIALS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_PRODUCTS_SPECIALS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_ORDER_TOTAL_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_ORDER_TOTAL_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_ORDER_TOTAL_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_ORDER_TOTAL_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_ORDER_TOTAL_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_ORDER_TOTAL_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_ORDER_TOTAL_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_ORDER_TOTAL_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- {
- if (!$this->isEnabled()) {
- return $this->skip($this->app->getDef('skip_module_disabled'));
- }
- if (!in_array($invoice_status, [self::STATUS_INVOICE, self::STATUS_CANCEL, self::STATUS_CREDIT_NOTE])) {
- return $this->skip($this->app->getDef('skip_status_not_actionable') . ' (' . $invoice_status . ')');
- }
- if ($this->isAlreadySent($order_id)) {
- return $this->skip($this->app->getDef('skip_already_sent') . ' #' . $order_id);
- $msg = $this->app->getDef('error_oauth2_failed') . ' #' . $order_id;
- $this->writeOrderHistory($order_id, '[ERROR] ' . $msg, false);
- return $this->failure($msg);
- }
- $doc_type = in_array($invoice_status, [self::STATUS_CANCEL, self::STATUS_CREDIT_NOTE]) ? self::TYPE_CREDIT_NOTE : self::TYPE_INVOICE;
- $payload = $this->buildPayload($order_id, $customer, $info, $products, $totals, $doc_type);
- if ($payload === null) {
- $msg = $this->app->getDef('error_payload_failed');
- $this->writeOrderHistory($order_id, '[ERROR] ' . $msg, false);
- // Extract totals from the order totals array
- $ht = $tva = $ttc = 0.0;
- foreach ($totals as $t) {
- $val = (float)str_replace(',', '.', preg_replace('/[^0-9.,\-]/', '', strip_tags($t['text'] ?? '0')));
- $c = $t['class'] ?? '';
- if (in_array($c, ['ot_subtotal', 'ST'])) $ht = $val;
- if (in_array($c, ['ot_tax', 'TX'])) $tva = $val;
- if (in_array($c, ['ot_total', 'TO'])) $ttc = $val;
- }
- // Fallback: compute HT from product lines if ot_subtotal not found
- $ht = $tva = $ttc = 0.0;
- foreach ($totals as $t) {
- $val = (float)str_replace(',', '.', preg_replace('/[^0-9.,\-]/', '', strip_tags($t['text'] ?? '0')));
- $c = $t['class'] ?? '';
- if (in_array($c, ['ot_subtotal', 'ST'])) $ht = $val;
- if (in_array($c, ['ot_tax', 'TX'])) $tva = $val;
- if (in_array($c, ['ot_total', 'TO'])) $ttc = $val;
- }
- // Fallback: compute HT from product lines if ot_subtotal not found
- if ($ht == 0.0) {
- foreach ($totals as $t) {
- $val = (float)str_replace(',', '.', preg_replace('/[^0-9.,\-]/', '', strip_tags($t['text'] ?? '0')));
- $c = $t['class'] ?? '';
- if (in_array($c, ['ot_subtotal', 'ST'])) $ht = $val;
- if (in_array($c, ['ot_tax', 'TX'])) $tva = $val;
- if (in_array($c, ['ot_total', 'TO'])) $ttc = $val;
- }
- // Fallback: compute HT from product lines if ot_subtotal not found
- if ($ht == 0.0) {
- foreach ($products as $p) {
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_ORDERS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_ORDERS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- if ((int)$check['orders_status_invoice'] === $new_invoice_status) {
- return;
- }
- // Only process actionable statuses
- if (!in_array($new_invoice_status, [
- EInvoiceService::STATUS_INVOICE,
- EInvoiceService::STATUS_CANCEL,
- EInvoiceService::STATUS_CREDIT_NOTE,
- ])) {
- return;
- ?>
- <span class="badge bg-success"><?php echo $CLICSHOPPING_Orders->getDef('badge_transmitted'); ?></span>
- <span class="text-success small"><?php echo $CLICSHOPPING_Orders->getDef('text_transmitted_notice'); ?></span>
- <?php
- } elseif (!in_array($current_invoice_status_id, [EInvoiceService::STATUS_INVOICE, EInvoiceService::STATUS_CANCEL, EInvoiceService::STATUS_CREDIT_NOTE])) {
- ?>
- <span class="badge bg-warning text-dark"><?php echo $CLICSHOPPING_Orders->getDef('badge_pending'); ?></span>
- <span class="text-muted small"><?php echo $CLICSHOPPING_Orders->getDef('text_pending_notice'); ?></span>
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_PRODUCTS_RETURN_ORDERS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_PRODUCTS_RETURN_ORDERS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_PAYMENT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_PAYMENT_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_PAYMENT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_PAYMENT_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_PAYMENT_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_PAYMENT_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_STATS_PRODUCTS_NOTIFICATION_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_STATS_PRODUCTS_NOTIFICATION_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_SHIPPING_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_SHIPPING_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_SHIPPING_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_SHIPPING_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- $CLICSHOPPING_Language = Registry::get('Language');
- $module = HTML::sanitize(str_replace(' ', '', $module));
- if (defined('MODULE_ACTION_RECORDER_INSTALLED') && !is_null(MODULE_ACTION_RECORDER_INSTALLED)) {
- if (!is_null($module) && in_array($module . '.' . substr(CLICSHOPPING::getIndex(), (strrpos(CLICSHOPPING::getIndex(), '.') + 1)), explode(';', MODULE_ACTION_RECORDER_INSTALLED))) {
- if (!class_exists($module)) {
- if (is_file($CLICSHOPPING_Template->getModuleDirectory() . '/action_recorder/' . $module . '.' . substr(CLICSHOPPING::getIndex(), (strrpos(CLICSHOPPING::getIndex(), '.') + 1)))) {
- $CLICSHOPPING_Language->loadDefinitions('modules/action_recorder/' . $module);
- include($CLICSHOPPING_Template->getModuleDirectory() . '/action_recorder/' . $module . '.' . substr(CLICSHOPPING::getIndex(), (strrpos(CLICSHOPPING::getIndex(), '.') + 1)));
- } else {
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_ACTIONS_RECORDER_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_ACTIONS_RECORDER_INSTALLED', implode(';', $installed));
- $modules_array[] = $Qmodules->value('module');
- }
- $expired_entries = 0;
- if (isset($_GET['module']) && \in_array($_GET['module'], $modules_array)) {
- $get_module_class = $CLICSHOPPING_ActionsRecorderClass->getClassModule($_GET['module']);
- if (\is_object($get_module_class)) {
- $expired_entries += $get_module_class->expireEntries();
- } else {
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- echo HTML::form('search', $CLICSHOPPING_ActionsRecorder->link('ActionsRecorder'), 'post', '', ['session_id' => true]);
- echo HTML::selectField('module', $modules_list_array, null, 'onchange="this.form.submit();"');
- ?>
- </span>
- <span class="col-md-1 text-end">
- <?php echo HTML::button($CLICSHOPPING_ActionsRecorder->getDef('button_reset'), null, $CLICSHOPPING_ActionsRecorder->link('ActionsRecorder&Expire' . (isset($_POST['module']) && \in_array($_POST['module'], $modules_array) ? '&module=' . $_POST['module'] : '')), 'danger'); ?>
- </span>
- </div>
- </form>
- </div>
- </div>
- </thead>
- <tbody>
- <?php
- $filter = [];
- if (isset($_POST['module']) && \in_array($_POST['module'], $modules_array)) {
- $filter[] = 'module = :module';
- }
- if (isset($_POST['search']) && !empty($_POST['search'])) {
- $filter[] = 'identifier like :identifier';
- $sql_query .= ' order by date_added desc limit :page_set_offset, :page_set_max_results';
- $Qactions = $CLICSHOPPING_ActionsRecorder->db->prepare($sql_query);
- if (!empty($filter)) {
- if (isset($_POST['module']) && \in_array($_POST['module'], $modules_array)) {
- $Qactions->bindValue(':module', $_POST['module']);
- }
- if (isset($_POST['search']) && !empty($_POST['search'])) {
- $Qactions->bindValue(':identifier', '%' . $_POST['search'] . '%');
- <div class="row">
- <div class="col-md-12">
- <div
- class="col-md-6 float-start pagenumber hidden-xs TextDisplayNumberOfLink"><?php echo $Qactions->getPageSetLabel($CLICSHOPPING_ActionsRecorder->getDef('text_display_number_of_link')); ?></div>
- <div
- class="float-end text-end"> <?php echo $Qactions->getPageSetLinks((isset($_POST['module']) && \in_array($_POST['module'], $modules_array) && \is_object($GLOBALS[$_POST['module']]) ? 'module=' . $_POST['module'] : null) . '&' . (isset($_POST['search']) && !empty($_POST['search']) ? 'search=' . $_POST['search'] : null)); ?></div>
- </div>
- </div>
- </div>
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_ADMINISTRATOR_MENU_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_ADMINISTRATOR_MENU_INSTALLED', implode(';', $installed));
- if (isset($this->Id) && ($this->Id != $this->moveToCategoryID)) {
- $new_parent_id = $this->moveToCategoryID;
- $path = explode('_', AdministratorMenu::getGeneratedAdministratorMenuPathIds($new_parent_id));
- if (\in_array($this->Id, $path)) {
- $CLICSHOPPING_MessageStack->add($this->app->getDef('error_cannot_move_directory_to_parent'), 'error');
- $this->app->redirect('AdministratorMenu&cPath=' . (int)$this->cPath . '&cID=' . (int)$this->Id);
- } else {
- $this->app->db->save('administrator_menu', [
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_APPS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_APPS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_BACKUP_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_BACKUP_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- $dir = dir($backup_directory);
- $contents = [];
- while ($file = $dir->read()) {
- if (!is_dir($backup_directory . $file) && \in_array(substr($file, -3), array('zip', 'sql', '.gz'))) {
- $contents[] = $file;
- }
- }
- sort($contents);
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_CRONJOB_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_CRONJOB_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_DATA_BASE_TABLES_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_DATA_BASE_TABLES_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- ['id' => 'utf8',
- 'text' => $CLICSHOPPING_DataBaseTables->getDef('action_utf8_conversion')
- ]);
- if (isset($_POST['action'])) {
- if (\in_array($_POST['action'], array('check', 'analyze', 'optimize', 'repair', 'utf8'))) {
- if (isset($_POST['id']) && \is_array($_POST['id']) && !empty($_POST['id'])) {
- $tables = Database::getDtTables();
- foreach ($_POST['id'] as $key => $value) {
- if (!\in_array($value, $tables)) {
- if (\in_array($_POST['action'], array('check', 'analyze', 'optimize', 'repair', 'utf8'))) {
- if (isset($_POST['id']) && \is_array($_POST['id']) && !empty($_POST['id'])) {
- $tables = Database::getDtTables();
- foreach ($_POST['id'] as $key => $value) {
- if (!\in_array($value, $tables)) {
- unset($_POST['id'][$key]);
- }
- }
- if (!empty($_POST['id'])) {
- while ($Qaction->fetch()) {
- $table_data[] = [
- ($table != $current_table) ? HTML::outputProtected($table) : '',
- $Qaction->valueProtected('Msg_type'),
- $Qaction->valueProtected('Msg_text'),
- ($table != $current_table) ? HTML::checkboxField('id[]', $table, isset($_POST['id']) && \in_array($table, $_POST['id'])) : ''
- ];
- $current_table = $table;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_DEFINE_LANGUAGE_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_DEFINE_LANGUAGE_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- $file_array = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory_selected));
- foreach ($file_array as $filename => $current) {
- $fileInfo = pathinfo($current->getFileName());
- if (array_key_exists('extension', $fileInfo) && in_array($fileInfo['extension'], $fileTypes)) {
- $found[] = $current->getFileName();
- }
- }
- if ($found) { // Check the $found array is not empty
- $file_array = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($filename_selected));
- foreach ($file_array as $filename => $current) {
- $fileInfo = pathinfo($current->getFileName());
- if (array_key_exists('extension', $fileInfo) && in_array($fileInfo['extension'], $fileTypes)) {
- $found[] = $current->getFileName();
- }
- }
- if ($found) { // Check the $found array is not empty
- $file_array = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($template_directory));
- foreach ($file_array as $filename => $current) {
- $fileInfo = pathinfo($current->getFileName());
- if (array_key_exists('extension', $fileInfo) && in_array($fileInfo['extension'], $fileTypes)) {
- $found[] = $current->getFileName();
- }
- }
- if ($found) { // Check the $found array is not empty
- /* if empty error is produced : Fatal error: Uncaught exception 'RuntimeException'*/
- foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($template_directory)) as $filename => $current) {
- $fileInfo = pathinfo($current->getFileName());
- if (array_key_exists('extension', $fileInfo) && \in_array($fileInfo['extension'], $fileTypes)) {
- $found[] = $current->getFileName();
- }
- }
- if ($found) { // Check the $found array is not empty
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_EDIT_DESIGN_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_EDIT_DESIGN_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_EDIT_LOG_ERROR_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_EDIT_LOG_ERROR_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- * @param array $checks An array of check results, each with a 'status' key.
- * @return string The overall status: 'error', 'warning', or 'healthy'.
- */
- private function determineOverallStatus(array $checks): string
- {
- if (in_array('error', array_column($checks, 'status'))) {
- return 'error';
- }
- if (in_array('warning', array_column($checks, 'status'))) {
- return 'warning';
- }
- private function determineOverallStatus(array $checks): string
- {
- if (in_array('error', array_column($checks, 'status'))) {
- return 'error';
- }
- if (in_array('warning', array_column($checks, 'status'))) {
- return 'warning';
- }
- return 'healthy';
- }
- foreach ($Qips as $allowedIp) {
- $ip = $allowedIp['ip'];
- if ($ip === '127.0.0.1' || $ip === 'localhost') {
- if (in_array($clientIp, ['127.0.0.1', '::1'])) {
- self::logSecurityEvent('Localhost access granted', [
- 'mcp_id' => $mcp_id,
- 'client_ip' => $clientIp
- ]);
- */
- public static function isLocalEnvironment(): bool
- {
- $ip = HTTP::getIpAddress();
- if (in_array($ip, ['127.0.0.1', '::1'])) {
- return true;
- }
- $serverName = $_SERVER['SERVER_NAME'] ?? '';
- $host = $_SERVER['HTTP_HOST'] ?? '';
- }
- $method = strtoupper($_SERVER["REQUEST_METHOD"]);
- $allowedMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'];
- if (!in_array($method, $allowedMethods)) {
- throw new Exception("Invalid HTTP method: " . $method);
- }
- return $method;
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_MCP_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_MCP_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- /**
- * Valide une clé d'API pour un niveau d'accès donné
- */
- public function validateMcpKey(string $mcpKey, string $accessLevel): bool {
- if (!in_array($accessLevel, $this->accessLevels)) {
- return false;
- }
- if (!isset($this->validMcpKeys[$accessLevel])) {
- return false;
- if (!isset($this->validMcpKeys[$accessLevel])) {
- return false;
- }
- return in_array($mcpKey, $this->validMcpKeys[$accessLevel]);
- }
- /**
- * Valide les headers de sécurité requis
- */
- 'ssl_enabled' => $sslEnabled,
- 'origin' => $origin
- ];
- // Add to allowed origins list
- if (!in_array($origin, $this->allowedOrigins)) {
- $this->allowedOrigins[] = $origin;
- }
- }
- // Fallback to localhost if no configurations found
- /**
- * Check if an origin is allowed
- */
- public function isOriginAllowed(string $origin): bool {
- return in_array($origin, $this->allowedOrigins);
- }
- /**
- * Valide une clé d'API pour un niveau d'accès donné
- */
- /**
- * Valide une clé d'API pour un niveau d'accès donné
- */
- public function validateMcpKey(string $mcpKey, string $accessLevel): bool {
- if (!in_array($accessLevel, $this->accessLevels)) {
- return false;
- }
- if (!isset($this->validMcpKeys[$accessLevel])) {
- return false;
- if (!isset($this->validMcpKeys[$accessLevel])) {
- return false;
- }
- return in_array($mcpKey, $this->validMcpKeys[$accessLevel]);
- }
- /**
- * Valide les headers de sécurité requis
- */
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_MODULES_HOOKS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_MODULES_HOOKS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_SEC_DIR_PERMISSIONS_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_SEC_DIR_PERMISSIONS_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- if ($handle = opendir($path)) {
- while (false !== ($filename = readdir($handle))) {
- if (!\in_array($filename, $exclude_array)) {
- $file = ['name' => $path . $filename,
- 'is_dir' => is_dir($path . $filename),
- 'writable' => FileSystem::isWritable($path . $filename)
- ];
- <th
- scope="row"><?php echo substr($file['name'], \strlen(CLICSHOPPING::getConfig('dir_root', 'Shop'))); ?></th>
- <td
- class="text-center"><?php echo $file['writable'] === true ? '<i class="bi-check text-success"></i>' : '<i class="bi bi-x text-danger"></i>'; ?></td>
- <td
- class="text-center"><?php echo(\in_array(substr($file['name'], \strlen(CLICSHOPPING::getConfig('dir_root', 'Shop'))), $whitelist_array) ? '<i class="bi-check text-success"></i>' : '<i class="bi bi-x text-danger"></i>'); ?></td>
- </tr>
- <?php
- }
- }
- ?>
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_SECURITY_CHECK_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_SECURITY_CHECK_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- <?php
- foreach ($modules as $module) {
- $secCheck = $GLOBALS[$module['class']];
- if (!\in_array($secCheck->type, $types)) {
- $secCheck->type = 'info';
- }
- $output = '';
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_SERVICE_APP_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_SERVICE_APP_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_UPGRADE_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_UPGRADE_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- public function uninstall()
- {
- parent::uninstall();
- $installed = explode(';', MODULE_MODULES_WHOS_ONLINE_INSTALLED);
- $installed_pos = array_search($this->app->vendor . '\\' . $this->app->code . '\\' . $this->code, $installed);
- if ($installed_pos !== false) {
- unset($installed[$installed_pos]);
- $this->app->saveCfgParam('MODULE_MODULES_WHOS_ONLINE_INSTALLED', implode(';', $installed));
- $default_module = $m;
- break;
- }
- }
- $this->page->data['current_module'] = (isset($_GET['module']) && \in_array($_GET['module'], $modules)) ? $_GET['module'] : $default_module;
- }
- }
- continue;
- }
- $fullClass = self::NAMESPACE_PREFIX . $fileInfo->getBasename('.php');
- if (class_exists($fullClass) && in_array(ActionToolsInterface::class, class_implements($fullClass))) {
- try {
- /** @var ActionToolsInterface $toolInstance */
- $toolInstance = new $fullClass();
- $toolName = $toolInstance->getName();
- $this->tools[$toolName] = $fullClass;
- $details_string = preg_replace('/comment\(.+\)$/', '', $details_string);
- $details = array_filter(explode(' ', $details_string), fn($v) => $v !== null && $v !== '');
- $details = array_values($details);
- }
- $is_binary = array_search('binary', $details);
- if (is_int($is_binary)) {
- array_splice($details, $is_binary, 1);
- $schema['col'][$field_name]['binary'] = true;
- }
- if (is_int($is_binary)) {
- array_splice($details, $is_binary, 1);
- $schema['col'][$field_name]['binary'] = true;
- }
- $is_unsigned = array_search('unsigned', $details);
- if (is_int($is_unsigned)) {
- array_splice($details, $is_unsigned, 1);
- $schema['col'][$field_name]['unsigned'] = true;
- }
- if (is_int($is_unsigned)) {
- array_splice($details, $is_unsigned, 1);
- $schema['col'][$field_name]['unsigned'] = true;
- }
- $is_not_null = array_search('not_null', $details);
- if (is_int($is_not_null)) {
- array_splice($details, $is_not_null, 1);
- $schema['col'][$field_name]['not_null'] = true;
- }
- if (is_int($is_not_null)) {
- array_splice($details, $is_not_null, 1);
- $schema['col'][$field_name]['not_null'] = true;
- }
- $is_auto_increment = array_search('auto_increment', $details);
- if (preg_match('/on_update\(([^)]+)\)/', $details_string, $on_update_match)) {
- $schema['col'][$field_name]['on_update'] = $on_update_match[1];
- $details_string = preg_replace('/on_update\([^)]+\)/', '', $details_string);
- $details = array_values(array_filter(explode(' ', $details_string)));
- $this->result = $this->cache_data;
- } else {
- $fetch_argument = $args[0] ?? null;
- $ctor_args = $args[1] ?? [];
- if (in_array($fetch_style, [PDO::FETCH_COLUMN])) {
- $this->result = parent::fetchAll($fetch_style, $fetch_argument);
- } elseif (in_array($fetch_style, [PDO::FETCH_CLASS, PDO::FETCH_FUNC])) {
- $this->result = parent::fetchAll($fetch_style, $fetch_argument, $ctor_args);
- } else {
- $this->result = parent::fetchAll($fetch_style);
- $fetch_argument = $args[0] ?? null;
- $ctor_args = $args[1] ?? [];
- if (in_array($fetch_style, [PDO::FETCH_COLUMN])) {
- $this->result = parent::fetchAll($fetch_style, $fetch_argument);
- } elseif (in_array($fetch_style, [PDO::FETCH_CLASS, PDO::FETCH_FUNC])) {
- $this->result = parent::fetchAll($fetch_style, $fetch_argument, $ctor_args);
- } else {
- $this->result = parent::fetchAll($fetch_style);
- }
- */
- public function setExcludeEntries(?array $entries)
- {
- if (is_array($entries)) {
- foreach ($entries as $value) {
- if (!in_array($value, $this->exclude_entries)) {
- $this->exclude_entries[] = $value;
- }
- }
- } elseif (is_string($entries)) {
- if (!in_array($entries, $this->exclude_entries)) {
- if (!in_array($value, $this->exclude_entries)) {
- $this->exclude_entries[] = $value;
- }
- }
- } elseif (is_string($entries)) {
- if (!in_array($entries, $this->exclude_entries)) {
- $this->exclude_entries[] = $entries;
- }
- }
- }
- $this->listing = array();
- }
- if ($dir = @dir($directory)) {
- while (($entry = $dir->read()) !== false) {
- if (!in_array($entry, $this->exclude_entries)) {
- if (($this->include_files === true) && is_file($dir->path . DIRECTORY_SEPARATOR . $entry)) {
- if (empty($this->check_extension) || in_array(mb_strtolower(substr($entry, strrpos($entry, '.') + 1)), $this->check_extension)) {
- if ($this->adddirectory_to_filename === true) {
- if ($dir->path !== $this->directory) {
- $entry = substr($dir->path, strlen($this->directory) + 1) . DIRECTORY_SEPARATOR . $entry;
- if ($dir = @dir($directory)) {
- while (($entry = $dir->read()) !== false) {
- if (!in_array($entry, $this->exclude_entries)) {
- if (($this->include_files === true) && is_file($dir->path . DIRECTORY_SEPARATOR . $entry)) {
- if (empty($this->check_extension) || in_array(mb_strtolower(substr($entry, strrpos($entry, '.') + 1)), $this->check_extension)) {
- if ($this->adddirectory_to_filename === true) {
- if ($dir->path !== $this->directory) {
- $entry = substr($dir->path, strlen($this->directory) + 1) . DIRECTORY_SEPARATOR . $entry;
- }
- }
- * @param string $type The type of the module to check for.
- * @return bool Returns true if the module exists, false otherwise.
- */
- final public function hasModule(string $module, string $type): bool
- {
- return isset($this->modules[$type]) && in_array($module, $this->modules[$type]);
- }
- /**
- * Sets the app information by reflecting the current class and loading data
- * from a metafile. Assigns the app's code, vendor, title, version, and modules
- $field .= ' id="' . static::output(substr($parameters, $offset + 4, strpos($parameters, '"', $offset + 4) - ($offset + 4))) . '_' . $counter . '"';
- }
- $field .= ' value="' . static::output($selection_value) . '"';
- if (isset($default) && (($default === true) || (!is_array($default) && ((string)$default == (string)$selection_value)) || (is_array($default) && in_array($selection_value, $default)))) {
- $field .= ' checked="checked"';
- }
- if (!empty($parameters)) {
- $field .= ' ' . $parameters;
- if (!isset($params['type'])) {
- $params['type'] = 'submit';
- }
- if (!in_array($params['type'], $types)) {
- $params['type'] = 'submit';
- }
- if (($params['type'] == 'submit') && isset($link)) {
- $params['type'] = 'button';
- if (($params['type'] == 'submit') && isset($link)) {
- $params['type'] = 'button';
- }
- if (isset($style) && !in_array($style, $styles)) {
- unset($style);
- }
- if (isset($size) && !in_array($size, $size_button)) {
- unset($size);
- if (isset($style) && !in_array($style, $styles)) {
- unset($style);
- }
- if (isset($size) && !in_array($size, $size_button)) {
- unset($size);
- }
- $button = '';
- if (!isset($data['cafile'])) {
- $data['cafile'] = CLICSHOPPING::BASE_DIR . 'External/cacert.pem';
- }
- if (isset($data['format']) && !in_array($data['format'], ['json'])) {
- trigger_error('HttpRequest::getResponse(): Unknown "format": ' . $data['format']);
- unset($data['format']);
- }
- ];
- $domain = strtolower(substr(strrchr($email, "@"), 1));
- if (in_array($domain, $temp_domains)) {
- return true;
- }
- }
- return false;
- $stack = [
- 'text' => $message,
- 'type' => $type
- ];
- if (!$this->exists($group) || !in_array($stack, $this->data[$group])) {
- $this->data[$group][] = $stack;
- }
- }
- /**
- }
- }
- if (!empty($this->_upload)) {
- if (!empty($this->_extensions)) {
- if (!in_array(mb_strtolower(substr($this->_upload['name'], strrpos($this->_upload['name'], '.') + 1)), $this->_extensions)) {
- $CLICSHOPPING_MessageStack->add(CLICSHOPPING::getDef('error_filetype_not_allowed') . implode(', ', $this->_extensions), 'warning');
- return false;
- }
- }
- public function isInstalled()
- {
- $module = HTML::sanitize(str_replace(' ', '', $this->_module));
- if (defined('MODULE_ACTION_RECORDER_INSTALLED') && !is_null(MODULE_ACTION_RECORDER_INSTALLED)) {
- if (!is_null($module) && \in_array($module . '.' . substr(CLICSHOPPING::getIndex(), (strrpos(CLICSHOPPING::getIndex(), '.') + 1)), explode(';', MODULE_ACTION_RECORDER_INSTALLED))) {
- if (!class_exists($module)) {
- if (is_file(CLICSHOPPING::getConfig('dir_root', 'Shop') . 'Core/modules/action_recorder/' . $module . '.' . substr(CLICSHOPPING::getIndex(), (strrpos(CLICSHOPPING::getIndex(), '.') + 1)))) {
- $this->lang->loadDefinitions('Shop/Module/ActionRecorder/' . $module);
- $name = (($key) ? 'configuration[' . $key . ']' : 'configuration_value');
- foreach ($contents as $item) {
- $fileInfo = pathinfo($item);
- if (array_key_exists('extension', $fileInfo) && \in_array($fileInfo['extension'], $fileTypes)) {
- $found[] = $item;
- }
- }
- if ($found) { // Check the $found array is not empty
- sort($select_array);
- $values_array = explode(';', $values);
- $output = '';
- foreach ($select_array as $file) {
- $output .= HTML::checkboxField('ht_datepicker_jquery_file[]', $file, \in_array($file, $values_array)) . ' ' . HTML::outputProtected($file) . '<br />';
- }
- if (!empty($output)) {
- $output = '<br />' . substr($output, 0, -6);
- }
- $Qproducts->bindInt(':language_id', (int)$CLICSHOPPING_Language->getId());
- $Qproducts->execute();
- while ($Qproducts->fetch()) {
- if (MODE_B2B_B2C == 'True') {
- if (!in_array($Qproducts->valueInt('products_id'), $exclude)) {
- $Qprice = $CLICSHOPPING_Db->prepare('select customers_group_price,
- customers_group_id
- from :table_products_groups
- where products_id = :products_id
- $price_string = '';
- $sde = 0;
- //while(list($sdek,$sdev)=each($all_groups)){
- foreach ($all_groups as $sdek => $sdev) {
- if (!in_array($Qproducts->valueInt('products_id') . ":" . (int)$sdek, $exclude)) {
- if ($sde)
- $price_string .= ' - ';
- $price_string .= $sdev . ' : ' . $CLICSHOPPING_Currencies->format(isset($product_prices[$sdek]) ? $product_prices[$sdek] : $Qproducts->valueDecimal('products_price'));
- $sde = 1;
- }
- // Ajouter VISITOR_NAME . ': ' . $CLICSHOPPING_Currencies->format($Qproducts->valueDecimal('products_price')) pour permettre d'afficher le prix des clients qui ne font pas partie d'un groupe B2B(
- $select_string .= '<option value="' . $Qproducts->valueInt('products_id') . '">' . HTML::outputProtected($Qproducts->value('products_name')) . ' (' . CLICSHOPPING::getDef('visitor_name') . ': ' . $CLICSHOPPING_Currencies->format($Qproducts->valueDecimal('products_price')) . ' - ' . $price_string . ')</option>';
- }
- } else {
- if (!in_array($Qproducts->valueInt('products_id'), $exclude)) {
- $select_string .= '<option value="' . $Qproducts->valueInt('products_id') . '">' . HTML::outputProtected($Qproducts->value('products_name')) . ' (' . $CLICSHOPPING_Currencies->format($Qproducts->valueDecimal('products_price')) . ')</option>';
- }
- }
- // ####### END #######
- {
- if (is_dir($source) === true) {
- $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::CHILD_FIRST);
- foreach ($files as $file) {
- if (in_array($file->getBasename(), array('.', '..')) !== true) {
- if ($file->isDir() === true) {
- rmdir($file->getPathName());
- } elseif (($file->isFile() === true) || ($file->isLink() === true)) {
- unlink($file->getPathname());
- }
- $fileTypes = ['php']; // Create an array of file types
- $found = []; // Traverse the folder, and add filename to $found array if type matches
- foreach ($contents as $item) {
- $fileInfo = pathinfo($item);
- if (array_key_exists('extension', $fileInfo) && in_array($fileInfo['extension'], $fileTypes)) {
- $found[] = $item;
- }
- }
- if ($found) { // Check the $found array is not empty
- $QpaymentsNotAllowed->execute();
- $payments_not_allowed = $QpaymentsNotAllowed->fetch();
- $payments_unallowed = explode(",", $payments_not_allowed['group_payment_unallowed']);
- $clearance = (in_array($pay_check, $payments_unallowed)) ? true : false;
- } elseif ($CLICSHOPPING_Customer->isLoggedOn()) {
- $clearance = true;
- } else {
- $clearance = false;
- $Qpayments->execute();
- $payments_not_allowed = $Qpayments->fetch();
- $payments_unallowed = explode(",", $payments_not_allowed['group_payment_unallowed']);
- $clearance = (!in_array($pay_check, $payments_unallowed)) ? true : false;
- return $clearance;
- }
- }
- $QshippingNotAllowed->execute();
- $shipping_not_allowed = $QshippingNotAllowed->fetch();
- $shipping_unallowed = explode(",", $shipping_not_allowed['group_shipping_unallowed']);
- $shipping_clearance = (in_array($shipping_check, $shipping_unallowed)) ? true : false;
- } elseif ($CLICSHOPPING_Customer->isLoggedOn()) {
- $shipping_clearance = true;
- } else {
- $shipping_clearance = false;
- }
- $shipping_not_allowed = $Qshipping->fetch();
- if (!empty($shipping_not_allowed['group_payment_unallowed'])) {
- $shipping_unallowed = explode(',', $shipping_not_allowed['group_payment_unallowed']);
- $shipping_clearance = (!in_array($shipping_check, $shipping_unallowed)) ? true : false;
- } else {
- $shipping_clearance = false;
- }
- return $shipping_clearance;
- $string = '';
- if (is_array($array) && !empty($array)) {
- foreach ($array as $key => $value) {
- if (!in_array($key, $exclude)) {
- $string .= $key . '=' . $value . '&';
- }
- }
- $string = substr($string, 0, -1);
- $Qglobal->execute();
- $global = $Qglobal->fetch();
- if (isset($_POST['action']) && ($_POST['action'] == 'process') && isset($_POST['formid']) && ($_POST['formid'] === $_SESSION['sessiontoken'])) {
- if (isset($_POST['product_global']) && is_numeric($_POST['product_global']) && in_array($_POST['product_global'], ['0', '1'])) {
- $product_global = (int)$_POST['product_global'];
- } else {
- $product_global = 0;
- }
- } elseif (count($products) > 0) {
- $products_parsed = [];
- foreach ($products as $value) {
- if (is_numeric($value) && !in_array($value, $products_parsed)) {
- $products_parsed[] = $value;
- }
- }
- if (count($products_parsed) > 0) {
- if (defined('MODULE_PAYMENT_INSTALLED') && !is_null(MODULE_PAYMENT_INSTALLED)) {
- $this->modules = explode(';', MODULE_PAYMENT_INSTALLED);
- $include_modules = [];
- if ((!is_null($module)) && (in_array($module . '.' . substr(CLICSHOPPING::getIndex(), (strrpos(CLICSHOPPING::getIndex(), '.') + 1)), $this->modules, true) || in_array($module, $this->modules))) {
- $this->selected_module = $module;
- if (str_contains($module, '\\')) {
- $class = Apps::getModuleClass($module, 'Payment');
- if (($this->getCountPaymentModules() == 1) && (!isset($_SESSION['payment']) || ($_SESSION['payment'] != $include_modules[0]['class']))) {
- $_SESSION['payment'] = $include_modules[0]['class'];
- }
- if ((!is_null($module)) && (in_array($module . '.' . substr(CLICSHOPPING::getIndex(), (strrpos(CLICSHOPPING::getIndex(), '.') + 1)), $this->modules, true) || in_array($module, $this->modules))) {
- if (str_contains($module, '\\')) {
- $CLICSHOPPING_PM = Registry::get('Payment_' . str_replace('\\', '_', $module));
- if (isset($CLICSHOPPING_PM->form_action_url)) {
- /**
- $code = $vendor . '\\' . $app . '\\' . $module;
- }
- }
- if (isset($code) && (in_array($code . '.' . substr(CLICSHOPPING::getIndex(), (strrpos(CLICSHOPPING::getIndex(), '.') + 1)), $this->modules) || in_array($code, $this->modules))) {
- if (str_contains($code, '\\')) {
- $class = Apps::getModuleClass($code, 'Shipping');
- $include_modules[] = [
- 'class' => $code,
- include($this->_directoryIncludes . $this->_directoryModules . $group . DIRECTORY_SEPARATOR . $class . '.php');
- }
- }
- // exclude $modules_boxe and search if the modules exist
- if (is_numeric(array_search($group, $this->getReadModulesDefaultDirectories())) && $group != $modules_boxes) {
- $result = array_search($group, $this->getReadModulesDefaultDirectories());
- if (!is_null($result)) {
- if (is_file($this->getPathDirectoryTemplateThema() . $this->_directoryModules . $group . DIRECTORY_SEPARATOR . $class . '.php')) {
- include($this->getPathDirectoryTemplateThema() . $this->_directoryModules . $group . DIRECTORY_SEPARATOR . $class . '.php');
- }
- }
- // exclude $modules_boxe and search if the modules exist
- if (is_numeric(array_search($group, $this->getReadModulesDefaultDirectories())) && $group != $modules_boxes) {
- $result = array_search($group, $this->getReadModulesDefaultDirectories());
- if (!is_null($result)) {
- if (is_file($this->getPathDirectoryTemplateThema() . $this->_directoryModules . $group . DIRECTORY_SEPARATOR . $class . '.php')) {
- include($this->getPathDirectoryTemplateThema() . $this->_directoryModules . $group . DIRECTORY_SEPARATOR . $class . '.php');
- } elseif (is_file($this->getDefaultTemplateDirectory() . DIRECTORY_SEPARATOR . $this->_directoryModules . $group . DIRECTORY_SEPARATOR . $class . '.php')) {
- $currentParent = $newParentId;
- $visitedCategories = [];
- // Traverse up the parent chain to check for circular reference
- while ($currentParent !== 0) {
- if (in_array($currentParent, $visitedCategories)) {
- return true; // Already visited, indicates circular reference
- }
- if ($currentParent === $categoryId) {
- return true; // Found the original category in the parent chain
- // Validate numeric fields
- if (isset($data['suppliers_country_id']) && !is_numeric($data['suppliers_country_id'])) {
- $errors[] = 'Country ID must be numeric';
- }
- if (isset($data['suppliers_status']) && !in_array($data['suppliers_status'], [0, 1])) {
- $errors[] = 'Supplier status must be 0 or 1';
- }
- if (isset($data['languages_id']) && !is_numeric($data['languages_id'])) {
- $errors[] = 'Language ID must be numeric';
- while ($file = $dir->read()) {
- if (!is_dir($backup_directory . $file)) {
- $ext = substr($file, strrpos($file, '.') + 1);
- if (in_array($ext, array('zip', 'sql', 'gz')) && !isset($contents[$ext])) {
- $contents[$ext] = $file;
- if ($ext != 'sql') { // zip and gz (binaries) are prioritized over sql (plain text)
- break;
- }
- }
- } else {
- $products_attributes_image = '';
- }
- $checked = \is_array($selected_attributes) && \in_array($value['id'], $selected_attributes) ? ' checked' : '';
- $chk_id = 'chk_' . $QproductsOptionsName->valueInt('products_options_id') . '_' . $value['id'];
- $products_options_content_display .= '<div class="col-md-12">';
- $products_options_content_display .= '<span class="ModuleProductsInfoOptionsPullDownMenu">';
- $products_options_content_display .= '<div class="custom-control custom-checkbox">';
- foreach ($dir_content as $key => $content) {
- $path = $root_dir . DIRECTORY_SEPARATOR . $content;
- if (is_file($path) && is_readable($path)) {
- // skip ignored files
- if (!\in_array($content, $ignore_files)) {
- if (preg_match($ignore_regex, $content) == 0) {
- $content_chunks = explode(".", $content);
- $ext = $content_chunks[\count($content_chunks) - 1];
- // only include files with desired extensions
- if (\in_array($ext, $allow_extensions)) {
- if (!\in_array($content, $ignore_files)) {
- if (preg_match($ignore_regex, $content) == 0) {
- $content_chunks = explode(".", $content);
- $ext = $content_chunks[\count($content_chunks) - 1];
- // only include files with desired extensions
- if (\in_array($ext, $allow_extensions)) {
- // save file name with path
- $all_data[] = $path;
- }
- }
- }
- }
- }
- } // if content is a directory and readable, add path and name
- elseif (is_dir($path) && is_readable($path)) {
- // skip any ignored dirs
- if (!\in_array($content, $ignore_dirs)) {
- // recursive callback to open new directory
- $all_data = get_files($path, $all_data);
- }
- }
- } // end foreach
Your project should not use insecure random number functions 3
- Read doc
- Security
- Major
More information: https://insight.symfony.com/what-we-analyse/php.use_insecure_random_function
- // Boucle infinie pour l'envoi des événements
- while (true) {
- try {
- // Simulate random failure before computing data
- if ($sim_fail_rate > 0 && mt_rand(0, mt_getrandmax()) / mt_getrandmax() < $sim_fail_rate) {
- throw new \Exception('Simulated failure');
- }
- // Récupérer les données de performance
- $data = $monitor->getPerformanceData($range);
- $data['metrics']['error_frequency'] = max(0.0, (float)$sim_error_pct);
- }
- }
- // Optionally force a random connection drop to test auto-reconnect
- if ($sim_drop && (mt_rand(1, 100) <= 5)) { // ~5% chance per tick
- // Flush a final event then terminate the connection
- echo "event: error\n";
- echo "data: {\"error\":\"Simulated connection drop\"}\n\n";
- ob_flush();
- flush();
- } catch (Exception $e) {
- if ($secure === true) {
- throw $e;
- }
- $result = mt_rand($min, $max);
- }
- return $result;
- }
Your project should not contain PHP files defining multiple classes 2
- Read doc
- Productivity
- Info
More information: https://insight.symfony.com/what-we-analyse/php.file_contains_more_than_one_class
Your project should use dedicated PHP string functions 261
- Read doc
- Productivity
- Info
More information: https://insight.symfony.com/what-we-analyse/php.use_string_function
- // Check if column type is VECTOR (cannot have empty string default)
- $is_vector_type = preg_match('/^vector/i', $columnType);
- // Check if default value is already quoted (starts and ends with single quote)
- $is_already_quoted = (strlen($default_value) >= 2 &&
- substr($default_value, 0, 1) === "'" &&
- substr($default_value, -1) === "'");
- // Skip empty string defaults for numeric types (invalid SQL)
- if ($is_numeric_type && $default_value === '') {
- // Don't add default clause - let MySQL use its default behavior
- $is_vector_type = preg_match('/^vector/i', $columnType);
- // Check if default value is already quoted (starts and ends with single quote)
- $is_already_quoted = (strlen($default_value) >= 2 &&
- substr($default_value, 0, 1) === "'" &&
- substr($default_value, -1) === "'");
- // Skip empty string defaults for numeric types (invalid SQL)
- if ($is_numeric_type && $default_value === '') {
- // Don't add default clause - let MySQL use its default behavior
- } elseif ($is_datetime_type && $default_value === '') {
- $schema .= 'NULL, ';
- } elseif (!\is_null($Qrows->value($i))) {
- $row = $Qrows->value($i);
- // Check if this is a VECTOR column
- if (isset($columnTypes[$i]) && strpos(strtolower($columnTypes[$i]), 'vector') !== false) {
- // VECTOR data is already in the correct format from MariaDB
- // Just escape it properly
- $row = addslashes($row);
- } else {
- $row = addslashes($row);
- glob($oldCacheDir . 'Rag_Embedding_*.cache'),
- glob($oldCacheDir . 'embedding_*.cache')
- );
- // Exclude embedding_search files
- $oldFiles = array_filter($oldFiles, function($file) {
- return strpos(basename($file), 'embedding_search_') !== 0;
- });
- $filesBefore += count($oldFiles);
- // Delete old embedding cache files
- foreach ($oldFiles as $file) {
- $oldFiles = array_merge(
- glob($oldCacheDir . 'Rag_Embedding_*.cache'),
- glob($oldCacheDir . 'embedding_*.cache')
- );
- $oldFiles = array_filter($oldFiles, function($file) {
- return strpos(basename($file), 'embedding_search_') !== 0;
- });
- $filesAfter += count($oldFiles);
- }
- $results['embedding'] = $filesBefore - $filesAfter;
- $oldFiles = array_merge(
- glob($oldCacheDir . 'Rag_Embedding_*.cache'),
- glob($oldCacheDir . 'embedding_*.cache')
- );
- $oldFiles = array_filter($oldFiles, function($file) {
- return strpos(basename($file), 'embedding_search_') !== 0;
- });
- $filesBefore += count($oldFiles);
- foreach ($oldFiles as $file) {
- @unlink($file);
- }
- $oldFilesAfter = array_merge(
- glob($oldCacheDir . 'Rag_Embedding_*.cache'),
- glob($oldCacheDir . 'embedding_*.cache')
- );
- $oldFilesAfter = array_filter($oldFilesAfter, function($file) {
- return strpos(basename($file), 'embedding_search_') !== 0;
- });
- $filesAfter += count($oldFilesAfter);
- }
- $results['embeddings'] = $filesBefore - $filesAfter;
- ['grow', 'shrink']
- ];
- // Check if goals contain contradictory terms
- foreach ($contradictions as $pair) {
- $has1in1 = strpos($goal1, $pair[0]) !== false;
- $has2in1 = strpos($goal1, $pair[1]) !== false;
- $has1in2 = strpos($goal2, $pair[0]) !== false;
- $has2in2 = strpos($goal2, $pair[1]) !== false;
- // If obj1 has first term and obj2 has second term (or vice versa)
- ];
- // Check if goals contain contradictory terms
- foreach ($contradictions as $pair) {
- $has1in1 = strpos($goal1, $pair[0]) !== false;
- $has2in1 = strpos($goal1, $pair[1]) !== false;
- $has1in2 = strpos($goal2, $pair[0]) !== false;
- $has2in2 = strpos($goal2, $pair[1]) !== false;
- // If obj1 has first term and obj2 has second term (or vice versa)
- if (($has1in1 && $has2in2) || ($has2in1 && $has1in2)) {
- // Check if goals contain contradictory terms
- foreach ($contradictions as $pair) {
- $has1in1 = strpos($goal1, $pair[0]) !== false;
- $has2in1 = strpos($goal1, $pair[1]) !== false;
- $has1in2 = strpos($goal2, $pair[0]) !== false;
- $has2in2 = strpos($goal2, $pair[1]) !== false;
- // If obj1 has first term and obj2 has second term (or vice versa)
- if (($has1in1 && $has2in2) || ($has2in1 && $has1in2)) {
- // Check if they're operating on similar subjects
- // Check if goals contain contradictory terms
- foreach ($contradictions as $pair) {
- $has1in1 = strpos($goal1, $pair[0]) !== false;
- $has2in1 = strpos($goal1, $pair[1]) !== false;
- $has1in2 = strpos($goal2, $pair[0]) !== false;
- $has2in2 = strpos($goal2, $pair[1]) !== false;
- // If obj1 has first term and obj2 has second term (or vice versa)
- if (($has1in1 && $has2in2) || ($has2in1 && $has1in2)) {
- // Check if they're operating on similar subjects
- $similarity = $this->calculateSimilarity($obj1, $obj2);
- 'database', 'table', 'index', 'query', 'cache', 'memory',
- 'file', 'log', 'configuration', 'setting', 'registry'
- ];
- foreach ($resourceKeywords as $keyword) {
- if (strpos($text, $keyword) !== false) {
- $resources[] = $keyword;
- }
- }
- return array_unique($resources);
- 'optimize' => ['optimize', 'improve', 'enhance', 'tune']
- ];
- foreach ($operationPatterns as $operation => $keywords) {
- foreach ($keywords as $keyword) {
- if (strpos($text, $keyword) !== false) {
- $operations[] = $operation;
- break;
- }
- }
- }
- * @param string $ip The IP address to check
- * @param string $range The CIDR range (e.g., '
- */
- public static function ipInRange(string $ip, string $range): bool
- {
- if (strpos($range, '/') === false) {
- return $ip === $range;
- }
- list($subnet, $bits) = explode('/', $range);
- $ip = ip2long($ip);
- {
- $params = [];
- // Model-specific parameter mapping
- // GPT-4o-mini, GPT-4.1 series, GPT-5 series use max_completion_tokens
- if (strpos($model, 'gpt-4.1-mini') === 0 ||
- strpos($model, 'gpt-4.1') === 0 ||
- strpos($model, 'gpt-5') === 0) {
- $params['max_completion_tokens'] = $maxtoken;
- } else {
- // Default for GPT-4o, Anthropic, Mistral, LM Studio, and other models
- $params = [];
- // Model-specific parameter mapping
- // GPT-4o-mini, GPT-4.1 series, GPT-5 series use max_completion_tokens
- if (strpos($model, 'gpt-4.1-mini') === 0 ||
- strpos($model, 'gpt-4.1') === 0 ||
- strpos($model, 'gpt-5') === 0) {
- $params['max_completion_tokens'] = $maxtoken;
- } else {
- // Default for GPT-4o, Anthropic, Mistral, LM Studio, and other models
- $params['max_tokens'] = $maxtoken;
- // Model-specific parameter mapping
- // GPT-4o-mini, GPT-4.1 series, GPT-5 series use max_completion_tokens
- if (strpos($model, 'gpt-4.1-mini') === 0 ||
- strpos($model, 'gpt-4.1') === 0 ||
- strpos($model, 'gpt-5') === 0) {
- $params['max_completion_tokens'] = $maxtoken;
- } else {
- // Default for GPT-4o, Anthropic, Mistral, LM Studio, and other models
- $params['max_tokens'] = $maxtoken;
- }
- $models = self::getGptModel();
- foreach ($models as $modelInfo) {
- if ($modelInfo['id'] === $model) {
- // Check if this is a GPT-5 series model (uses reasoning API)
- if (strpos($modelInfo['id'], 'gpt-5') === 0) {
- return true;
- }
- return false;
- }
- return false;
- }
- }
- // Model not found in list - check by prefix as fallback
- return strpos($model, 'gpt-5') === 0;
- }
- /**
- * Get model context length limit
- *
- $module_key = $CLICSHOPPING_CfgModule->get($set, 'key');
- $appModuleType = $CLICSHOPPING_ModulesAdmin->getSwitchModules($module_type);
- if (strpos($_GET['module'], '\\') !== false) {
- $class = Apps::getModuleClass($_GET['module'], $appModuleType);
- if (class_exists($class)) {
- $file_extension = '';
- $module = new $class();
- $modules_payment = explode(';', $Qconfiguration_payment->value('configuration_value'));
- $include_modules = [];
- foreach ($modules_payment as $value) {
- if (strpos($value, '\\') !== false) {
- $class = Apps::getModuleClass($value, 'Payment');
- $include_modules[] = ['class' => $value,
- 'file' => $class
- ];
- ];
- }
- }
- for ($i = 0, $n = \count($include_modules); $i < $n; $i++) {
- if (strpos($include_modules[$i]['class'], '\\') !== false) {
- Registry::set('Payment_' . str_replace('\\', '_', $include_modules[$i]['class']), new $include_modules[$i]['file']);
- $module = Registry::get('Payment_' . str_replace('\\', '_', $include_modules[$i]['class']));
- ?>
- <div class="row">
- <div class="col-md-12">
- $modules_shipping = explode(';', $Qconfiguration_shipping->value('configuration_value'));
- $include_modules = [];
- foreach ($modules_shipping as $value) {
- if (strpos($value, '\\') !== false) {
- $class = Apps::getModuleClass($value, 'Shipping');
- $include_modules[] = ['class' => $value,
- 'file' => $class
- ];
- ];
- }
- }
- for ($i = 0, $n = \count($include_modules); $i < $n; $i++) {
- if (strpos($include_modules[$i]['class'], '\\') !== false) {
- Registry::set('Shipping_' . str_replace('\\', '_', $include_modules[$i]['class']), new $include_modules[$i]['file']);
- $module = Registry::get('Shipping_' . str_replace('\\', '_', $include_modules[$i]['class']));
- ?>
- <div class="row">
- <div class="col-md-12">
- while ($Qcols->fetch()) {
- if ($Qcols->hasValue('Collation') && !\is_null($Qcols->value('Collation'))) {
- // Skip VECTOR columns - they are binary data and cannot be converted to UTF8
- $columnType = strtolower($Qcols->value('Type'));
- if (strpos($columnType, 'vector') !== false) {
- continue;
- }
- if ($_POST['from_charset'] == 'auto') {
- $old_charset = substr($Qcols->value('Collation'), 0, strpos($Qcols->value('Collation'), '_'));
- * @param string $ip The IP address to check
- * @param string $range The CIDR range (e.g., '192.168.1.0/24')
- */
- public static function ipInRange(string $ip, string $range): bool
- {
- if (strpos($range, '/') === false) {
- return $ip === $range;
- }
- list($subnet, $bits) = explode('/', $range);
- $ip = ip2long($ip);
- // Process special vector fields
- $vector_fields = [];
- foreach ($data as $field => $value) {
- // Check if the field is meant to be a vector and starts with 'vec_'
- if (substr($field, 0, 4) === 'vec_') {
- $actual_field = substr($field, 4); // Get the actual field name without 'vec_' prefix
- $vector_fields[$actual_field] = $value; // Store the vector value
- unset($data[$field]); // Remove the special prefixed field
- }
- }
- if (!preg_match('/^[a-zA-Z0-9_]*$/', $prefix)) {
- throw new \InvalidArgumentException('Invalid table prefix');
- }
- // Ajout d'un underscore terminal si le préfixe est non vide et ne se termine pas déjà par un underscore
- if ($prefix !== '' && substr($prefix, -1) !== '_') {
- $prefix .= '_';
- }
- // Substitution sûre des tokens
- return preg_replace_callback('/:table_([a-zA-Z0-9_]+)/', function ($matches) use ($prefix) {
- if ($path === '' || $path === '.' . $separator) {
- return $systemroot;
- }
- if (substr($path, 0, 3) === '..' . $separator) {
- $path = $systemroot . $path;
- }
- // Normalize path
- $path = rtrim($path, $separator) . $separator;
- // Normalize path
- $path = rtrim($path, $separator) . $separator;
- // Absolute path
- if ($path[0] === $separator || strpos($path, $systemroot) === 0) {
- return $path;
- }
- // Relative path from 'Here'
- if (substr($path, 0, 2) === '.' . $separator || $path[0] !== '.') {
- if ($path[0] === $separator || strpos($path, $systemroot) === 0) {
- return $path;
- }
- // Relative path from 'Here'
- if (substr($path, 0, 2) === '.' . $separator || $path[0] !== '.') {
- $arrn = preg_split('/\\' . $separator . '/', $path, -1, PREG_SPLIT_NO_EMPTY);
- if ($arrn[0] !== '.') {
- array_unshift($arrn, '.');
- }
- $arrn[0] = rtrim($base, $separator);
- if ($output !== null) {
- // Envoi des Headers HTTP
- header('Content-Type: ' . $mimeType);
- // Détermine l'extension et encode si c'est du JSON
- if (strpos($mimeType, 'json') !== false) {
- // S'assurer que la sortie est un tableau/objet avant d'encoder
- if (is_array($output) || is_object($output)) {
- $output = json_encode($output, JSON_PRETTY_PRINT);
- }
- }
- // Simple contradiction check
- $s1Lower = strtolower($statement1);
- $s2Lower = strtolower($statement2);
- // Check for negation patterns
- if (strpos($s1Lower, 'not') !== false && strpos($s2Lower, 'not') === false) {
- return true;
- }
- return false;
- }
- private function evaluateSqlEfficiency(string $sql, array $tablesUsed, string $queryType): float
- {
- $score = 0.7; // Base score
- // Check for SELECT * (inefficient)
- if (strpos($sql, 'SELECT *') !== false) {
- $score -= 0.2;
- }
- // Check for proper indexing hints
- if ($this->hasProperIndexing($sql, $tablesUsed)) {
- $queryWords = explode(' ', strtolower($userQuery));
- $sqlLower = strtolower($sql);
- $matches = 0;
- foreach ($queryWords as $word) {
- if (strlen($word) > 3 && strpos($sqlLower, $word) !== false) {
- $matches++;
- }
- }
- return $matches > 0;
- }
- private function hasProperIndexing(string $sql, array $tables): bool
- {
- // Check for WHERE clauses that might benefit from indexes
- return strpos($sql, 'WHERE') !== false;
- }
- private function hasUnnecessaryJoins(string $sql): bool
- {
- // Count JOINs - more than 5 might be excessive
- }
- private function isWellFormatted(string $sql): bool
- {
- // Check for basic formatting (line breaks, indentation)
- return strpos($sql, "\n") !== false || strpos($sql, "\r") !== false;
- }
- private function hasMeaningfulAliases(string $sql): bool
- {
- // Check for table aliases that are more than single letters
- return false;
- }
- private function hasComments(string $sql): bool
- {
- return strpos($sql, '--') !== false || strpos($sql, '/*') !== false;
- }
- private function hasConsistentData(array $results): bool
- {
- if (empty($results)) return true;
- // Fallback to simple keyword detection if detector fails
- $ambiguousTerms = ['best', 'good', 'recent', 'popular', 'top', 'better', 'worse'];
- $queryLower = strtolower($query);
- foreach ($ambiguousTerms as $term) {
- if (strpos($queryLower, $term) !== false) {
- return true;
- }
- }
- return false;
- 'HAVING',
- 'DISTINCT'
- ];
- foreach ($slowPatterns as $pattern) {
- if (strpos($sqlUpper, $pattern) !== false) {
- return true;
- }
- }
- // Check for multiple JOINs
- * @return string Escaped value
- */
- private function escapeCsvValue(string $value): string
- {
- // Escape quotes and wrap in quotes if contains comma, quote, or newline
- if (strpos($value, ',') !== false || strpos($value, '"') !== false || strpos($value, "\n") !== false) {
- return '"' . str_replace('"', '""', $value) . '"';
- }
- return $value;
- }
- // Propose permission level always requires approval for write actions
- if ($permissionLevel === self::PERMISSION_PROPOSE) {
- $writeActions = ['create', 'update', 'delete', 'modify', 'propose'];
- foreach ($writeActions as $writeAction) {
- if (strpos($action, $writeAction) !== false) {
- return true;
- }
- }
- }
- $text = strtolower("$reason $comment");
- foreach ($keywords as $type => $words) {
- foreach ($words as $word) {
- if (strpos($text, $word) !== false) {
- return $type;
- }
- }
- }
- // 🔍 DEBUG: Log prompt loading verification
- if ($this->debug) {
- error_log("[INFO : ANALYSE] [UnifiedQueryAnalyzer] Prompt Loading Verification:");
- error_log(" Prompt length: " . strlen($prompt) . " characters");
- error_log(" Prompt preview (first 200 chars): " . substr($prompt, 0, 200) . "...");
- error_log(" Query in prompt: " . (strpos($prompt, $query) !== false ? 'YES' : 'NO'));
- }
- // Single GPT call for everything
- // Use Gpt::getGptResponse() instead of non-existent complete() method
- if ($this->debug) {
- error_log("UnifiedQueryAnalyzer: Built prompt from language file sections");
- error_log("UnifiedQueryAnalyzer: Query to analyze: {$query}");
- error_log("UnifiedQueryAnalyzer: Total prompt length: " . strlen($prompt) . " characters");
- error_log("UnifiedQueryAnalyzer: Prompt contains query: " . (strpos($prompt, $query) !== false ? 'YES' : 'NO'));
- }
- return $prompt;
- }
- */
- private function categorizeError(string $errorMessage): string
- {
- $message = strtolower($errorMessage);
- if (strpos($message, 'database') !== false || strpos($message, 'sql') !== false) {
- return 'database';
- }
- if (strpos($message, 'timeout') !== false || strpos($message, 'time out') !== false) {
- return 'timeout';
- }
- $message = strtolower($errorMessage);
- if (strpos($message, 'database') !== false || strpos($message, 'sql') !== false) {
- return 'database';
- }
- if (strpos($message, 'timeout') !== false || strpos($message, 'time out') !== false) {
- return 'timeout';
- }
- if (strpos($message, 'memory') !== false) {
- return 'memory';
- }
- return 'database';
- }
- if (strpos($message, 'timeout') !== false || strpos($message, 'time out') !== false) {
- return 'timeout';
- }
- if (strpos($message, 'memory') !== false) {
- return 'memory';
- }
- if (strpos($message, 'validation') !== false || strpos($message, 'invalid') !== false) {
- return 'validation';
- }
- return 'timeout';
- }
- if (strpos($message, 'memory') !== false) {
- return 'memory';
- }
- if (strpos($message, 'validation') !== false || strpos($message, 'invalid') !== false) {
- return 'validation';
- }
- if (strpos($message, 'classification') !== false || strpos($message, 'intent') !== false) {
- return 'classification';
- }
- return 'memory';
- }
- if (strpos($message, 'validation') !== false || strpos($message, 'invalid') !== false) {
- return 'validation';
- }
- if (strpos($message, 'classification') !== false || strpos($message, 'intent') !== false) {
- return 'classification';
- }
- if (strpos($message, 'api') !== false || strpos($message, 'gpt') !== false) {
- return 'api';
- }
- return 'validation';
- }
- if (strpos($message, 'classification') !== false || strpos($message, 'intent') !== false) {
- return 'classification';
- }
- if (strpos($message, 'api') !== false || strpos($message, 'gpt') !== false) {
- return 'api';
- }
- return 'unknown';
- }
- // If it's an array, search for the response
- if (is_array($executionResult)) {
- if (isset($executionResult['text_response']) && !empty($executionResult['text_response'])) {
- // Check if text_response is NOT the JSON fallback
- if (strpos($executionResult['text_response'], 'Résultat:') === false) {
- return $executionResult['text_response'];
- }
- }
- if (isset($executionResult['response']) && !empty($executionResult['response'])) {
- }
- }
- // Priority 4: Check if rawResult has 'text_response' field (but not if it's the JSON fallback)
- if (isset($rawResult['text_response']) && !empty($rawResult['text_response'])) {
- if (strpos($rawResult['text_response'], 'Résultat:') === false) {
- return $rawResult['text_response'];
- }
- }
- // Priority 5: Use finalResponse if available (but not if it's the JSON fallback)
- return $rawResult['text_response'];
- }
- }
- // Priority 5: Use finalResponse if available (but not if it's the JSON fallback)
- if (!empty($finalResponse) && strpos($finalResponse, 'Résultat:') === false) {
- return $finalResponse;
- }
- return '';
- }
- // Check if source type is valid (case-insensitive, partial match)
- $sourceType = strtolower($sourceAttr['source_type']);
- $isValidSource = false;
- foreach ($validSourceTypes as $validType) {
- if (strpos($sourceType, strtolower($validType)) !== false) {
- $isValidSource = true;
- break;
- }
- }
- 'as an ai',
- 'i\'m an ai'
- ];
- foreach ($genericPhrases as $phrase) {
- if (strpos($response, $phrase) !== false) {
- $validationErrors[] = "Response contains generic LLM phrase indicating lack of knowledge";
- return false;
- }
- }
- $table = $matches[1];
- }
- // Ajouter le préfixe si nécessaire
- $prefix = CLICSHOPPING::getConfig('db_prefix');
- if (!empty($prefix) && strpos($table, $prefix) !== 0) {
- $table = $prefix . $table;
- }
- return trim($table, '`"\'');
- }
- private function determineSuggestedActionForSqlError(string $errorMessage, string $temporalPeriod): string
- {
- $errorLower = strtolower($errorMessage);
- // Check for common error patterns
- if (strpos($errorLower, 'column') !== false || strpos($errorLower, 'field') !== false) {
- return "The database may not have the required columns for {$temporalPeriod} aggregation. Try a different time period or check your data schema.";
- }
- if (strpos($errorLower, 'table') !== false) {
- return "The required table for {$temporalPeriod} aggregation may not exist. Verify your database structure.";
- // Check for common error patterns
- if (strpos($errorLower, 'column') !== false || strpos($errorLower, 'field') !== false) {
- return "The database may not have the required columns for {$temporalPeriod} aggregation. Try a different time period or check your data schema.";
- }
- if (strpos($errorLower, 'table') !== false) {
- return "The required table for {$temporalPeriod} aggregation may not exist. Verify your database structure.";
- }
- if (strpos($errorLower, 'syntax') !== false) {
- return "There was a SQL syntax error. Try rephrasing your query or using a simpler time period.";
- if (strpos($errorLower, 'table') !== false) {
- return "The required table for {$temporalPeriod} aggregation may not exist. Verify your database structure.";
- }
- if (strpos($errorLower, 'syntax') !== false) {
- return "There was a SQL syntax error. Try rephrasing your query or using a simpler time period.";
- }
- if (strpos($errorLower, 'permission') !== false || strpos($errorLower, 'access') !== false) {
- return "You may not have permission to access the required data. Contact your administrator.";
- if (strpos($errorLower, 'syntax') !== false) {
- return "There was a SQL syntax error. Try rephrasing your query or using a simpler time period.";
- }
- if (strpos($errorLower, 'permission') !== false || strpos($errorLower, 'access') !== false) {
- return "You may not have permission to access the required data. Contact your administrator.";
- }
- if (strpos($errorLower, 'timeout') !== false) {
- return "The query took too long. Try a shorter time range or simpler aggregation.";
- if (strpos($errorLower, 'permission') !== false || strpos($errorLower, 'access') !== false) {
- return "You may not have permission to access the required data. Contact your administrator.";
- }
- if (strpos($errorLower, 'timeout') !== false) {
- return "The query took too long. Try a shorter time range or simpler aggregation.";
- }
- // Default suggestion
- return "Try rephrasing your query or using a different temporal period. If the problem persists, contact support.";
- // Semantic results MUST have sources OR data, unless it's a valid LLM/memory fallback
- if (!$hasSources) {
- $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
- $isLLMFallback = $hasTextResponse && (
- strpos($sourceType, 'llm') !== false ||
- strpos($sourceType, 'general knowledge') !== false ||
- strpos($sourceType, 'conversation') !== false ||
- strpos($sourceType, 'memory') !== false
- );
- // Semantic results MUST have sources OR data, unless it's a valid LLM/memory fallback
- if (!$hasSources) {
- $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
- $isLLMFallback = $hasTextResponse && (
- strpos($sourceType, 'llm') !== false ||
- strpos($sourceType, 'general knowledge') !== false ||
- strpos($sourceType, 'conversation') !== false ||
- strpos($sourceType, 'memory') !== false
- );
- if (!$isLLMFallback) {
- if (!$hasSources) {
- $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
- $isLLMFallback = $hasTextResponse && (
- strpos($sourceType, 'llm') !== false ||
- strpos($sourceType, 'general knowledge') !== false ||
- strpos($sourceType, 'conversation') !== false ||
- strpos($sourceType, 'memory') !== false
- );
- if (!$isLLMFallback) {
- $sourcesStatus = isset($finalResult['sources']) ? 'empty' : 'not set';
- $sourceType = strtolower($finalResult['source_attribution']['source_type'] ?? '');
- $isLLMFallback = $hasTextResponse && (
- strpos($sourceType, 'llm') !== false ||
- strpos($sourceType, 'general knowledge') !== false ||
- strpos($sourceType, 'conversation') !== false ||
- strpos($sourceType, 'memory') !== false
- );
- if (!$isLLMFallback) {
- $sourcesStatus = isset($finalResult['sources']) ? 'empty' : 'not set';
- $dataStatus = isset($finalResult['data']) ? 'empty' : 'not set';
- private function generateUserFriendlyErrorMessage(array $errors): string
- {
- // Check for common error patterns and generate appropriate messages
- foreach ($errors as $error) {
- // Pattern: "Semantic result missing sources and data"
- if (strpos($error, 'Semantic result missing sources and data') !== false) {
- 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.";
- }
- // Pattern: "Analytics result missing data"
- if (strpos($error, 'Analytics result missing data') !== false) {
- if (strpos($error, 'Semantic result missing sources and data') !== false) {
- 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.";
- }
- // Pattern: "Analytics result missing data"
- if (strpos($error, 'Analytics result missing data') !== false) {
- 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.";
- }
- // Pattern: "Hybrid result missing"
- if (strpos($error, 'Hybrid result missing') !== false) {
- if (strpos($error, 'Analytics result missing data') !== false) {
- 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.";
- }
- // Pattern: "Hybrid result missing"
- if (strpos($error, 'Hybrid result missing') !== false) {
- 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.";
- }
- // Pattern: "Empty response"
- if (strpos($error, 'empty') !== false || strpos($error, 'Empty') !== false) {
- if (strpos($error, 'Hybrid result missing') !== false) {
- 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.";
- }
- // Pattern: "Empty response"
- if (strpos($error, 'empty') !== false || strpos($error, 'Empty') !== false) {
- 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.";
- }
- }
- // Default fallback message
- // Fallback to source_table if no name found
- if ($docName === null && isset($metadata['source_table'])) {
- $tableName = $metadata['source_table'];
- // Remove prefix and _embedding suffix
- $prefix = defined('CLICSHOPPING_DB_TABLE_PREFIX') ? CLICSHOPPING_DB_TABLE_PREFIX : 'clic_';
- if (strpos($tableName, $prefix) === 0) {
- $tableName = substr($tableName, strlen($prefix));
- }
- $tableName = str_replace('_embedding', '', $tableName);
- $tableName = str_replace('_', ' ', $tableName);
- $docName = ucwords($tableName);
- return $entityType;
- }
- // Remove table prefix if present
- $prefix = CLICSHOPPING::getConfig('db_table_prefix');
- if (!empty($prefix) && strpos($tableName, $prefix) === 0) {
- $tableName = substr($tableName, strlen($prefix));
- }
- // Remove '_embedding' suffix if present
- $tableName = str_replace('_embedding', '', $tableName);
- }
- $keywords[] = $entityType;
- $keywords[] = str_replace('_', ' ', $entityType);
- if (substr($entityType, -3) === 'ies') {
- $keywords[] = substr($entityType, 0, -3) . 'y';
- } elseif (substr($entityType, -1) === 's') {
- $keywords[] = substr($entityType, 0, -1);
- } else {
- $keywords[] = $entityType . 's';
- $keywords[] = $entityType;
- $keywords[] = str_replace('_', ' ', $entityType);
- if (substr($entityType, -3) === 'ies') {
- $keywords[] = substr($entityType, 0, -3) . 'y';
- } elseif (substr($entityType, -1) === 's') {
- $keywords[] = substr($entityType, 0, -1);
- } else {
- $keywords[] = $entityType . 's';
- }
- }
- * @return bool
- */
- private function hasKeyword(string $text, array $keywords): bool
- {
- foreach ($keywords as $keyword) {
- if (strpos($text, $keyword) !== false) {
- return true;
- }
- }
- return false;
- }
- // Simple keyword matching (replaces deleted PatternAnalysisPattern)
- $patternKeywords = ['pattern', 'trend', 'style', 'dominant', 'recurring', 'common'];
- $queryLower = strtolower($queryToAnalyze);
- foreach ($patternKeywords as $keyword) {
- if (strpos($queryLower, $keyword) !== false) {
- if ($this->debug) {
- $this->logDebug("Pattern analysis keyword detected: $keyword");
- }
- return true;
- }
- // 🔧 FIX: If interpretations array is empty, use defaults based on ambiguity type
- if (empty($availableInterpretations)) {
- $ambiguityType = $ambiguityAnalysis['ambiguity_type'] ?? '';
- // For quantification queries, default to count and sum
- if (strpos($ambiguityType, 'quantification') !== false) {
- $availableInterpretations = ['count', 'sum'];
- if ($this->debug) {
- $this->logger->logSecurityEvent(
- "AmbiguityOptimizer: Empty interpretations array, using defaults for quantification: count, sum",
- // Extract type from column info (now returns array with 'type' and 'comment')
- $type = is_array($columnInfo) ? $columnInfo['type'] : $columnInfo;
- // Detect ID columns that could be foreign keys
- if (preg_match('/_id$/', $column) && strpos($type, 'int') !== false) {
- $relatedTable = str_replace('_id', '', $column);
- // Validate related table name
- $safeRelatedTable = InputValidator::sanitizeIdentifier($relatedTable);
- // Extract type from column info (now returns array with 'type' and 'comment')
- $type = is_array($columnInfo) ? $columnInfo['type'] : $columnInfo;
- // Detect ID columns that could be foreign keys
- if (preg_match('/_id$/', $column) && strpos($type, 'int') !== false) {
- $relatedTable = str_replace('_id', '', $column);
- // Validate related table name
- $safeRelatedTable = InputValidator::sanitizeIdentifier($relatedTable);
- // Load language definitions
- $CLICSHOPPING_Language = Registry::get('Language');
- DomainConfig::loadLanguageFile('rag_error_handler');
- // Suggestions based on the type of error
- if (strpos($errorMessage, 'Unknown column') !== false) {
- return CLICSHOPPING::getDef('text_column_reference_does_not_exist');
- }
- if (strpos($errorMessage, 'syntax error') !== false) {
- return CLICSHOPPING::getDef('text_sql_query_generated_error');
- // Suggestions based on the type of error
- if (strpos($errorMessage, 'Unknown column') !== false) {
- return CLICSHOPPING::getDef('text_column_reference_does_not_exist');
- }
- if (strpos($errorMessage, 'syntax error') !== false) {
- return CLICSHOPPING::getDef('text_sql_query_generated_error');
- }
- if (strpos($errorMessage, 'Table') !== false && strpos($errorMessage, 'doesn\'t exist') !== false) {
- return CLICSHOPPING::getDef('text_table_referenced_does_not_exist');
- if (strpos($errorMessage, 'syntax error') !== false) {
- return CLICSHOPPING::getDef('text_sql_query_generated_error');
- }
- if (strpos($errorMessage, 'Table') !== false && strpos($errorMessage, 'doesn\'t exist') !== false) {
- return CLICSHOPPING::getDef('text_table_referenced_does_not_exist');
- }
- // Generic suggestion
- return CLICSHOPPING::getDef('text_error_executing_query');
- if ($this->debug) {
- error_log("AmbiguousQueryDetector: LLM returned empty interpretations for ambiguous query, generating defaults");
- }
- // Generate default interpretations based on ambiguity type
- if (strpos($ambiguityType, 'quantification') !== false) {
- // For quantification queries: count vs sum
- $interpretations = [
- [
- 'type' => 'count',
- 'label' => 'Count of items',
- 'label' => 'Sum of quantities',
- 'description' => 'Sum the total quantity',
- 'sql_hint' => 'Use SUM(quantity_field)'
- ]
- ];
- } else if (strpos($ambiguityType, 'scope') !== false) {
- // For scope queries: all vs recent
- $interpretations = [
- [
- 'type' => 'all',
- 'label' => 'All items',
- $isHtmlContent = false;
- if (isset($results['text_response']) && !empty($results['text_response'])) {
- $interpretationText = $results['text_response'];
- // Check if text_response contains HTML
- $isHtmlContent = (strpos($interpretationText, '<div') !== false || strpos($interpretationText, '<p>') !== false);
- } elseif (isset($results['interpretation']) && $results['interpretation'] !== 'Array') {
- $interpretationText = $results['interpretation'];
- }
- if (!empty($interpretationText)) {
- public static function hasTemporalConnector(string $query): bool
- {
- $query = strtolower($query);
- foreach (self::$temporalConnectors as $connector) {
- if (strpos($query, $connector) !== false) {
- return true;
- }
- }
- return false;
- {
- $query = strtolower($query);
- $detected = [];
- foreach (self::$temporalConnectors as $connector) {
- if (strpos($query, $connector) !== false) {
- $detected[] = $connector;
- }
- }
- return $detected;
- public static function hasFinancialMetric(string $query): bool
- {
- $query = strtolower($query);
- foreach (self::$financialMetrics as $metric) {
- if (strpos($query, $metric) !== false) {
- return true;
- }
- }
- return false;
- public static function extractBaseMetric(string $query): ?string
- {
- $query = strtolower($query);
- foreach (self::FINANCIAL_METRICS as $pattern => $metric) {
- if (strpos($query, $pattern) !== false) {
- return $metric;
- }
- }
- return null;
- return "year {$matches[2]}";
- }
- // Check for relative time patterns
- foreach (self::RELATIVE_TIME_PATTERNS as $pattern => $range) {
- if (strpos($query, $pattern) !== false) {
- return $range;
- }
- }
- return null;
- public static function hasSuperlativePattern(string $query): bool
- {
- $query = strtolower($query);
- foreach (SuperlativePatterns::$superlativeKeywords as $pattern) {
- if (strpos($query, $pattern) !== false) {
- return true;
- }
- }
- return false;
- public static function hasEntityKeyword(string $query): bool
- {
- $query = strtolower($query);
- foreach (SuperlativePatterns::$entityKeywords as $entity) {
- if (strpos($query, $entity) !== false) {
- return true;
- }
- }
- return false;
- {
- $query = strtolower($query);
- $detected = [];
- foreach (SuperlativePatterns::$superlativeKeywords as $pattern) {
- if (strpos($query, $pattern) !== false) {
- $detected[] = $pattern;
- }
- }
- return $detected;
- {
- $query = strtolower($query);
- $detected = [];
- foreach (SuperlativePatterns::$entityKeywords as $entity) {
- if (strpos($query, $entity) !== false) {
- $detected[] = $entity;
- }
- }
- return $detected;
- }
- // Check for relative time patterns
- $relativePatterns = self::getRelativeTimePatterns();
- foreach ($relativePatterns as $pattern => $range) {
- if (strpos($query, $pattern) !== false) {
- return $range;
- }
- }
- // Check for date range patterns (e.g., "from January to March")
- */
- private static function getApiKey(): string
- {
- $api_key = CLICSHOPPING_APP_CHATGPT_CH_API_KEY;
- if (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'mistral') === 0) {
- $api_key = CLICSHOPPING_APP_CHATGPT_CH_API_KEY_MISTRAL;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage') === 0) {
- $api_key = CLICSHOPPING_APP_CHATGPT_RA_API_KEY_VOYAGE_AI;
- }
- {
- $api_key = CLICSHOPPING_APP_CHATGPT_CH_API_KEY;
- if (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'mistral') === 0) {
- $api_key = CLICSHOPPING_APP_CHATGPT_CH_API_KEY_MISTRAL;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage') === 0) {
- $api_key = CLICSHOPPING_APP_CHATGPT_RA_API_KEY_VOYAGE_AI;
- }
- return $api_key;
- }
- * @param string $model The embedding model to check
- * @return bool True if API keys are available, false otherwise
- */
- private static function checkApiKeys(string $model): bool
- {
- if (strpos($model, 'gpt') === 0) {
- return !empty(CLICSHOPPING_APP_CHATGPT_CH_API_KEY);
- } elseif (strpos($model, 'mistral') === 0) {
- return !empty(CLICSHOPPING_APP_CHATGPT_CH_API_KEY_MISTRAL);
- } elseif (strpos($model, 'voyage') === 0) {
- return !empty(CLICSHOPPING_APP_CHATGPT_RA_API_KEY_VOYAGE_AI);
- */
- private static function checkApiKeys(string $model): bool
- {
- if (strpos($model, 'gpt') === 0) {
- return !empty(CLICSHOPPING_APP_CHATGPT_CH_API_KEY);
- } elseif (strpos($model, 'mistral') === 0) {
- return !empty(CLICSHOPPING_APP_CHATGPT_CH_API_KEY_MISTRAL);
- } elseif (strpos($model, 'voyage') === 0) {
- return !empty(CLICSHOPPING_APP_CHATGPT_RA_API_KEY_VOYAGE_AI);
- } elseif (strpos($model, 'ollama') === 0) {
- return true;
- {
- if (strpos($model, 'gpt') === 0) {
- return !empty(CLICSHOPPING_APP_CHATGPT_CH_API_KEY);
- } elseif (strpos($model, 'mistral') === 0) {
- return !empty(CLICSHOPPING_APP_CHATGPT_CH_API_KEY_MISTRAL);
- } elseif (strpos($model, 'voyage') === 0) {
- return !empty(CLICSHOPPING_APP_CHATGPT_RA_API_KEY_VOYAGE_AI);
- } elseif (strpos($model, 'ollama') === 0) {
- return true;
- }
- return !empty(CLICSHOPPING_APP_CHATGPT_CH_API_KEY);
- } elseif (strpos($model, 'mistral') === 0) {
- return !empty(CLICSHOPPING_APP_CHATGPT_CH_API_KEY_MISTRAL);
- } elseif (strpos($model, 'voyage') === 0) {
- return !empty(CLICSHOPPING_APP_CHATGPT_RA_API_KEY_VOYAGE_AI);
- } elseif (strpos($model, 'ollama') === 0) {
- return true;
- }
- return false;
- }
- return null;
- }
- $api_key = self::getApiKey();
- if (strpos($model, 'gpt-large') === 0) {
- $config = new OpenAIConfig();
- $config->apiKey = $api_key;
- return new OpenAI3LargeEmbeddingGenerator($config);
- } elseif (strpos($model, 'gpt-medium') === 0) {
- $config = new OpenAIConfig();
- if (strpos($model, 'gpt-large') === 0) {
- $config = new OpenAIConfig();
- $config->apiKey = $api_key;
- return new OpenAI3LargeEmbeddingGenerator($config);
- } elseif (strpos($model, 'gpt-medium') === 0) {
- $config = new OpenAIConfig();
- $config->apiKey = $api_key;
- return new OpenAI3SmallEmbeddingGenerator($config);
- } elseif (strpos($model, 'mistral') === 0) {
- $config = new OpenAIConfig();
- return new OpenAI3LargeEmbeddingGenerator($config);
- } elseif (strpos($model, 'gpt-medium') === 0) {
- $config = new OpenAIConfig();
- $config->apiKey = $api_key;
- return new OpenAI3SmallEmbeddingGenerator($config);
- } elseif (strpos($model, 'mistral') === 0) {
- $config = new OpenAIConfig();
- $config->apiKey = $api_key;
- return new MistralEmbeddingGenerator($config);
- } elseif (strpos($model, 'voyage3-large') === 0) {
- $config = new VoyageAIConfig();
- return new OpenAI3SmallEmbeddingGenerator($config);
- } elseif (strpos($model, 'mistral') === 0) {
- $config = new OpenAIConfig();
- $config->apiKey = $api_key;
- return new MistralEmbeddingGenerator($config);
- } elseif (strpos($model, 'voyage3-large') === 0) {
- $config = new VoyageAIConfig();
- $config->apiKey = $api_key;
- return new Voyage3LargeEmbeddingGenerator($config);
- } elseif (strpos($model, 'voyage3-lite') === 0) {
- $config = new VoyageAIConfig();
- return new MistralEmbeddingGenerator($config);
- } elseif (strpos($model, 'voyage3-large') === 0) {
- $config = new VoyageAIConfig();
- $config->apiKey = $api_key;
- return new Voyage3LargeEmbeddingGenerator($config);
- } elseif (strpos($model, 'voyage3-lite') === 0) {
- $config = new VoyageAIConfig();
- $config->apiKey = $api_key;
- return new Voyage3LiteEmbeddingGenerator($config);
- } elseif (strpos($model, 'voyage3') === 0) {
- $config = new VoyageAIConfig();
- return new Voyage3LargeEmbeddingGenerator($config);
- } elseif (strpos($model, 'voyage3-lite') === 0) {
- $config = new VoyageAIConfig();
- $config->apiKey = $api_key;
- return new Voyage3LiteEmbeddingGenerator($config);
- } elseif (strpos($model, 'voyage3') === 0) {
- $config = new VoyageAIConfig();
- $config->apiKey = $api_key;
- return new Voyage3EmbeddingGenerator($config);
- } else {
- return new OllamaEmbeddingGenerator($model);
- $errorMessage .= " (estimated tokens: {$estimatedTokens}, chunk size: {$token_length})";
- }
- error_log($errorMessage);
- if (strpos($e->getMessage(), 'maximum context length') !== false && $token_length > 200) {
- error_log("Retrying with smaller chunk size...");
- return self::createEmbedding($path_file_upload, $text_description, (int)($token_length / 2));
- }
- return null;
- */
- private static function estimateTokenCount(string $text): int
- {
- $model = CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL;
- if (strpos($model, 'gpt') === 0 || strpos($model, 'voyage') === 0) {
- $avgCharsPerToken = 3.5;
- return (int)ceil(strlen($text) / $avgCharsPerToken);
- }
- return (int)ceil(strlen($text) / 4);
- *
- * @return int The embedding length in dimensions for the selected model
- */
- public static function getEmbeddingLength(): int
- {
- if (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'gpt-large') === 0) {
- return 3072;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'gpt-medium') === 0) {
- return 1536;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'mistral') === 0) {
- return 1024;
- */
- public static function getEmbeddingLength(): int
- {
- if (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'gpt-large') === 0) {
- return 3072;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'gpt-medium') === 0) {
- return 1536;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'mistral') === 0) {
- return 1024;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage3-large') === 0) {
- return 4096;
- {
- if (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'gpt-large') === 0) {
- return 3072;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'gpt-medium') === 0) {
- return 1536;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'mistral') === 0) {
- return 1024;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage3-large') === 0) {
- return 4096;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage3-lite') === 0) {
- return 384;
- return 3072;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'gpt-medium') === 0) {
- return 1536;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'mistral') === 0) {
- return 1024;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage3-large') === 0) {
- return 4096;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage3-lite') === 0) {
- return 384;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage3') === 0) {
- return 1024;
- return 1536;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'mistral') === 0) {
- return 1024;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage3-large') === 0) {
- return 4096;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage3-lite') === 0) {
- return 384;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage3') === 0) {
- return 1024;
- } else {
- return 1536;
- return 1024;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage3-large') === 0) {
- return 4096;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage3-lite') === 0) {
- return 384;
- } elseif (strpos(CLICSHOPPING_APP_CHATGPT_RA_EMBEDDING_MODEL, 'voyage3') === 0) {
- return 1024;
- } else {
- return 1536;
- }
- }
- 'voyage3-lite' => 4000,
- 'nomic-embed-text' => 8192,
- ];
- foreach ($contextLengths as $modelPrefix => $length) {
- if (strpos($model, $modelPrefix) === 0) {
- return $length;
- }
- }
- return 4096;
- 'voyage3-lite' => 300,
- 'nomic-embed-text' => 800,
- ];
- foreach ($chunkSizes as $modelPrefix => $size) {
- if (strpos($model, $modelPrefix) === 0) {
- return $size;
- }
- }
- return 500;
- * @param string $model
- * @return string
- */
- private static function getModelProvider(string $model): string
- {
- if (strpos($model, 'gpt') === 0) return 'openai';
- if (strpos($model, 'mistral') === 0) return 'mistral';
- if (strpos($model, 'voyage') === 0) return 'voyageai';
- if (strpos($model, 'nomic') === 0) return 'ollama';
- return 'unknown';
- * @return string
- */
- private static function getModelProvider(string $model): string
- {
- if (strpos($model, 'gpt') === 0) return 'openai';
- if (strpos($model, 'mistral') === 0) return 'mistral';
- if (strpos($model, 'voyage') === 0) return 'voyageai';
- if (strpos($model, 'nomic') === 0) return 'ollama';
- return 'unknown';
- }
- */
- private static function getModelProvider(string $model): string
- {
- if (strpos($model, 'gpt') === 0) return 'openai';
- if (strpos($model, 'mistral') === 0) return 'mistral';
- if (strpos($model, 'voyage') === 0) return 'voyageai';
- if (strpos($model, 'nomic') === 0) return 'ollama';
- return 'unknown';
- }
- private static function getModelProvider(string $model): string
- {
- if (strpos($model, 'gpt') === 0) return 'openai';
- if (strpos($model, 'mistral') === 0) return 'mistral';
- if (strpos($model, 'voyage') === 0) return 'voyageai';
- if (strpos($model, 'nomic') === 0) return 'ollama';
- return 'unknown';
- }
- //*********************
- if ($value === null) {
- return null;
- }
- // Si la valeur est déjà une chaîne formatée correctement, la retourner telle quelle
- if (is_string($value) && strpos($value, '[') === 0) {
- return $value;
- }
- // Convertir le tableau en chaîne formatée pour MariaDB
- if (is_array($value)) {
- if (isset($specialCases[$entityType])) {
- return $specialCases[$entityType];
- }
- // Handle compound words with underscores (e.g., "return_orders" -> "return_order")
- if (strpos($entityType, '_') !== false) {
- $parts = explode('_', $entityType);
- $lastPart = array_pop($parts);
- // Apply singularization to the last part only
- $singularLastPart = self::singularizeWord($lastPart);
- if (strlen($word) < 2) {
- return $word;
- }
- // Words ending in "ies" -> "y" (e.g., "categories" -> "category")
- if (substr($word, -3) === 'ies') {
- return substr($word, 0, -3) . 'y';
- }
- // Words ending in "es" -> remove "es" (e.g., "boxes" -> "box")
- if (substr($word, -2) === 'es') {
- if (substr($word, -3) === 'ies') {
- return substr($word, 0, -3) . 'y';
- }
- // Words ending in "es" -> remove "es" (e.g., "boxes" -> "box")
- if (substr($word, -2) === 'es') {
- return substr($word, 0, -2);
- }
- // Words ending in "s" -> remove "s" (e.g., "products" -> "product")
- if (substr($word, -1) === 's') {
- if (substr($word, -2) === 'es') {
- return substr($word, 0, -2);
- }
- // Words ending in "s" -> remove "s" (e.g., "products" -> "product")
- if (substr($word, -1) === 's') {
- return substr($word, 0, -1);
- }
- // No change needed
- return $word;
- if (isset($specialCases[$entityType])) {
- return $specialCases[$entityType];
- }
- // Handle compound words with underscores
- if (strpos($entityType, '_') !== false) {
- $parts = explode('_', $entityType);
- $lastPart = array_pop($parts);
- // Apply pluralization to the last part only
- $pluralLastPart = self::pluralizeWord($lastPart);
- if (strlen($word) < 2) {
- return $word;
- }
- // Words ending in "y" -> "ies" (e.g., "category" -> "categories")
- if (substr($word, -1) === 'y') {
- return substr($word, 0, -1) . 'ies';
- }
- // Words ending in "s", "x", "z", "ch", "sh" -> add "es"
- if (preg_match('/(s|x|z|ch|sh)$/i', $word)) {
- // Check for table names in FROM clause
- foreach ($entityColumnMap as $columnName => $entityType) {
- $tableName = str_replace('_id', '', $columnName);
- // Check if table name appears in query
- if (strpos($sqlLower, "from {$tableName}") !== false ||
- strpos($sqlLower, "from clic_{$tableName}") !== false ||
- strpos($sqlLower, "join {$tableName}") !== false ||
- strpos($sqlLower, "join clic_{$tableName}") !== false) {
- return [
- foreach ($entityColumnMap as $columnName => $entityType) {
- $tableName = str_replace('_id', '', $columnName);
- // Check if table name appears in query
- if (strpos($sqlLower, "from {$tableName}") !== false ||
- strpos($sqlLower, "from clic_{$tableName}") !== false ||
- strpos($sqlLower, "join {$tableName}") !== false ||
- strpos($sqlLower, "join clic_{$tableName}") !== false) {
- return [
- 'entity_id' => null, // Can't extract ID from query alone
- $tableName = str_replace('_id', '', $columnName);
- // Check if table name appears in query
- if (strpos($sqlLower, "from {$tableName}") !== false ||
- strpos($sqlLower, "from clic_{$tableName}") !== false ||
- strpos($sqlLower, "join {$tableName}") !== false ||
- strpos($sqlLower, "join clic_{$tableName}") !== false) {
- return [
- 'entity_id' => null, // Can't extract ID from query alone
- 'entity_type' => $entityType,
- // Check if table name appears in query
- if (strpos($sqlLower, "from {$tableName}") !== false ||
- strpos($sqlLower, "from clic_{$tableName}") !== false ||
- strpos($sqlLower, "join {$tableName}") !== false ||
- strpos($sqlLower, "join clic_{$tableName}") !== false) {
- return [
- 'entity_id' => null, // Can't extract ID from query alone
- 'entity_type' => $entityType,
- ];
- {
- $markers = self::getResetMarkers();
- $queryLower = mb_strtolower($query);
- foreach ($markers as $marker) {
- if (strpos($queryLower, $marker) !== false) {
- return true;
- }
- }
- return false;
- $markers = self::getResetMarkers();
- $queryLower = mb_strtolower($query);
- $foundMarkers = [];
- foreach ($markers as $marker) {
- if (strpos($queryLower, $marker) !== false) {
- $foundMarkers[] = $marker;
- }
- }
- $hasReset = !empty($foundMarkers);
- {
- $keywords = self::getModificationKeywords();
- $queryLower = mb_strtolower($query);
- foreach ($keywords as $keyword) {
- if (strpos($queryLower, $keyword) !== false) {
- return true;
- }
- }
- return false;
- {
- $keywords = self::getModificationKeywords();
- $queryLower = mb_strtolower($query);
- foreach ($keywords as $keyword) {
- if (strpos($queryLower, $keyword) !== false) {
- return $keyword;
- }
- }
- return null;
- $isHtmlContent = false;
- if (isset($results['text_response']) && !empty($results['text_response'])) {
- $interpretationText = $results['text_response'];
- // Check if text_response contains HTML
- $isHtmlContent = (strpos($interpretationText, '<div') !== false || strpos($interpretationText, '<p>') !== false);
- } elseif (isset($results['response']) && !empty($results['response'])) {
- $interpretationText = $results['response'];
- } elseif (isset($results['interpretation']) && $results['interpretation'] !== 'Array') {
- $interpretationText = $results['interpretation'];
- }
- $tableName = $metadata['source_table'];
- // Remove prefix and _embedding suffix
- $prefix = CLICSHOPPING::getConfig('db_table_prefix');
- if (strpos($tableName, $prefix) === 0) {
- $tableName = substr($tableName, strlen($prefix));
- }
- $tableName = str_replace('_embedding', '', $tableName);
- $tableName = str_replace('_', ' ', $tableName);
- $docName = ucwords($tableName);
- foreach ($termGroups as $groupType => $terms) {
- $weight = $this->termWeights[$groupType] ?? 0.5;
- foreach ($terms as $term) {
- if (strpos($query, $term) !== false) {
- $domainScore += $weight;
- $matchedTerms[] = [
- 'term' => $term,
- 'type' => $groupType,
- 'weight' => $weight,
- $supplierBonus = 0;
- $manufacturerBonus = 0;
- foreach ($supplierIndicators as $indicator) {
- if (strpos($query, $indicator) !== false) {
- $supplierBonus += 1.0;
- }
- }
- foreach ($manufacturerIndicators as $indicator) {
- $supplierBonus += 1.0;
- }
- }
- foreach ($manufacturerIndicators as $indicator) {
- if (strpos($query, $indicator) !== false) {
- $manufacturerBonus += 1.0;
- }
- }
- $scores['suppliers']['score'] += $supplierBonus;
- if (abs($reviewScore - $sentimentScore) < 0.5) {
- $sentimentIndicators = ['sentiment', 'feeling', 'positive', 'negative', 'emotion', 'analysis'];
- $sentimentBonus = 0;
- foreach ($sentimentIndicators as $indicator) {
- if (strpos($query, $indicator) !== false) {
- $sentimentBonus += 0.5;
- }
- }
- if ($sentimentBonus > 0) {
- 'wrong category',
- 'incorrect classification'
- ];
- foreach ($classificationKeywords as $keyword) {
- if (strpos($comment, $keyword) !== false) {
- return true;
- }
- }
- if ($reason === 'irrelevant') {
- $isClassificationError = false;
- $errorType = 'unknown';
- // Detect classification errors
- if (strpos($comment, 'wrong type') !== false ||
- strpos($comment, 'misclassified') !== false ||
- strpos($comment, 'should be analytics') !== false ||
- strpos($comment, 'should be semantic') !== false) {
- $isClassificationError = true;
- $errorType = 'misclassification';
- $isClassificationError = false;
- $errorType = 'unknown';
- // Detect classification errors
- if (strpos($comment, 'wrong type') !== false ||
- strpos($comment, 'misclassified') !== false ||
- strpos($comment, 'should be analytics') !== false ||
- strpos($comment, 'should be semantic') !== false) {
- $isClassificationError = true;
- $errorType = 'misclassification';
- } elseif ($reason === 'irrelevant' || strpos($comment, 'irrelevant') !== false) {
- $errorType = 'unknown';
- // Detect classification errors
- if (strpos($comment, 'wrong type') !== false ||
- strpos($comment, 'misclassified') !== false ||
- strpos($comment, 'should be analytics') !== false ||
- strpos($comment, 'should be semantic') !== false) {
- $isClassificationError = true;
- $errorType = 'misclassification';
- } elseif ($reason === 'irrelevant' || strpos($comment, 'irrelevant') !== false) {
- $isClassificationError = true;
- // Detect classification errors
- if (strpos($comment, 'wrong type') !== false ||
- strpos($comment, 'misclassified') !== false ||
- strpos($comment, 'should be analytics') !== false ||
- strpos($comment, 'should be semantic') !== false) {
- $isClassificationError = true;
- $errorType = 'misclassification';
- } elseif ($reason === 'irrelevant' || strpos($comment, 'irrelevant') !== false) {
- $isClassificationError = true;
- $errorType = 'irrelevant_result';
- strpos($comment, 'misclassified') !== false ||
- strpos($comment, 'should be analytics') !== false ||
- strpos($comment, 'should be semantic') !== false) {
- $isClassificationError = true;
- $errorType = 'misclassification';
- } elseif ($reason === 'irrelevant' || strpos($comment, 'irrelevant') !== false) {
- $isClassificationError = true;
- $errorType = 'irrelevant_result';
- } elseif ($reason === 'incomplete' && strpos($comment, 'wrong') !== false) {
- $isClassificationError = true;
- $errorType = 'partial_misclassification';
- $isClassificationError = true;
- $errorType = 'misclassification';
- } elseif ($reason === 'irrelevant' || strpos($comment, 'irrelevant') !== false) {
- $isClassificationError = true;
- $errorType = 'irrelevant_result';
- } elseif ($reason === 'incomplete' && strpos($comment, 'wrong') !== false) {
- $isClassificationError = true;
- $errorType = 'partial_misclassification';
- }
- if ($isClassificationError) {
- $isClassificationError = false;
- $errorType = 'unknown';
- // Detect classification errors
- if (strpos($comment, 'wrong type') !== false ||
- strpos($comment, 'misclassified') !== false ||
- strpos($comment, 'should be analytics') !== false ||
- strpos($comment, 'should be semantic') !== false) {
- $isClassificationError = true;
- $errorType = 'misclassification';
- $isClassificationError = false;
- $errorType = 'unknown';
- // Detect classification errors
- if (strpos($comment, 'wrong type') !== false ||
- strpos($comment, 'misclassified') !== false ||
- strpos($comment, 'should be analytics') !== false ||
- strpos($comment, 'should be semantic') !== false) {
- $isClassificationError = true;
- $errorType = 'misclassification';
- } elseif ($reason === 'irrelevant' || strpos($comment, 'irrelevant') !== false) {
- $errorType = 'unknown';
- // Detect classification errors
- if (strpos($comment, 'wrong type') !== false ||
- strpos($comment, 'misclassified') !== false ||
- strpos($comment, 'should be analytics') !== false ||
- strpos($comment, 'should be semantic') !== false) {
- $isClassificationError = true;
- $errorType = 'misclassification';
- } elseif ($reason === 'irrelevant' || strpos($comment, 'irrelevant') !== false) {
- $isClassificationError = true;
- // Detect classification errors
- if (strpos($comment, 'wrong type') !== false ||
- strpos($comment, 'misclassified') !== false ||
- strpos($comment, 'should be analytics') !== false ||
- strpos($comment, 'should be semantic') !== false) {
- $isClassificationError = true;
- $errorType = 'misclassification';
- } elseif ($reason === 'irrelevant' || strpos($comment, 'irrelevant') !== false) {
- $isClassificationError = true;
- $errorType = 'irrelevant_result';
- strpos($comment, 'misclassified') !== false ||
- strpos($comment, 'should be analytics') !== false ||
- strpos($comment, 'should be semantic') !== false) {
- $isClassificationError = true;
- $errorType = 'misclassification';
- } elseif ($reason === 'irrelevant' || strpos($comment, 'irrelevant') !== false) {
- $isClassificationError = true;
- $errorType = 'irrelevant_result';
- } elseif ($reason === 'incomplete' && strpos($comment, 'wrong') !== false) {
- $isClassificationError = true;
- $errorType = 'partial_misclassification';
- $isClassificationError = true;
- $errorType = 'misclassification';
- } elseif ($reason === 'irrelevant' || strpos($comment, 'irrelevant') !== false) {
- $isClassificationError = true;
- $errorType = 'irrelevant_result';
- } elseif ($reason === 'incomplete' && strpos($comment, 'wrong') !== false) {
- $isClassificationError = true;
- $errorType = 'partial_misclassification';
- }
- if ($isClassificationError) {
- if (preg_match('/is:\s*["\'](.+?)["\']$/i', $cleaned, $matches)) {
- $cleaned = $matches[1];
- }
- // STEP 4: Remove leading/trailing quotes if they wrap the entire string
- if ((substr($cleaned, 0, 1) === '"' && substr($cleaned, -1) === '"') ||
- (substr($cleaned, 0, 1) === "'" && substr($cleaned, -1) === "'")) {
- $cleaned = substr($cleaned, 1, -1);
- }
- return trim($cleaned);
- if (preg_match('/is:\s*["\'](.+?)["\']$/i', $cleaned, $matches)) {
- $cleaned = $matches[1];
- }
- // STEP 4: Remove leading/trailing quotes if they wrap the entire string
- if ((substr($cleaned, 0, 1) === '"' && substr($cleaned, -1) === '"') ||
- (substr($cleaned, 0, 1) === "'" && substr($cleaned, -1) === "'")) {
- $cleaned = substr($cleaned, 1, -1);
- }
- return trim($cleaned);
- $cleaned = $matches[1];
- }
- // STEP 4: Remove leading/trailing quotes if they wrap the entire string
- if ((substr($cleaned, 0, 1) === '"' && substr($cleaned, -1) === '"') ||
- (substr($cleaned, 0, 1) === "'" && substr($cleaned, -1) === "'")) {
- $cleaned = substr($cleaned, 1, -1);
- }
- return trim($cleaned);
- }
- $cleaned = $matches[1];
- }
- // STEP 4: Remove leading/trailing quotes if they wrap the entire string
- if ((substr($cleaned, 0, 1) === '"' && substr($cleaned, -1) === '"') ||
- (substr($cleaned, 0, 1) === "'" && substr($cleaned, -1) === "'")) {
- $cleaned = substr($cleaned, 1, -1);
- }
- return trim($cleaned);
- }
- if ($this->debug) {
- error_log('[WebSearchFormatter] Formatting web search results\n');
- error_log('[WebSearchFormatter] Result keys: ' . implode(', ', array_keys($results)) . "\n");
- error_log('[WebSearchFormatter] Has text_response: ' . (isset($results['text_response']) ? 'YES' : 'NO') . "\n");
- if (isset($results['text_response'])) {
- $isHtml = (strpos($results['text_response'], '<') !== false);
- error_log('[WebSearchFormatter] text_response is HTML: ' . ($isHtml ? 'YES' : 'NO') . "\n");
- error_log('[WebSearchFormatter] text_response length: ' . strlen($results['text_response']) . "\n");
- }
- }
- $isHtmlContent = false;
- if (isset($results['text_response']) && !empty($results['text_response'])) {
- $interpretationText = $results['text_response'];
- // Check if text_response contains HTML (from ResultSynthesizer)
- $isHtmlContent = (strpos($interpretationText, '<div') !== false || strpos($interpretationText, '<p>') !== false);
- } elseif (isset($results['interpretation']) && $results['interpretation'] !== 'Array') {
- $interpretationText = $results['interpretation'];
- } elseif (isset($results['response']) && !empty($results['response'])) {
- $interpretationText = $results['response'];
- }
- // Check if query has entity keywords (database query, not web search)
- // 🔧 MIGRATION: Use centralized EntityKeywordsPattern instead of WebSearchPatterns
- $hasEntityKeyword = false;
- foreach (WebSearchPatterns::getEntityKeywords() as $entity) {
- if (strpos($query, $entity) !== false) {
- $hasEntityKeyword = true;
- break;
- }
- }
- }
- // Check if query has financial metric keywords (analytics query, not web search)
- $hasFinancialKeyword = false;
- foreach ($financialMetricKeywords as $keyword) {
- if (strpos($query, $keyword) !== false) {
- $hasFinancialKeyword = true;
- break;
- }
- }
- }
- // Only apply trends/news override if NO entity keywords AND NO financial keywords present
- if (!$hasEntityKeyword && !$hasFinancialKeyword) {
- foreach (WebSearchPatterns::$trendsNewsKeywords as $keyword) {
- if (strpos($query, $keyword) !== false) {
- $analysis['intent_type'] = 'web_search';
- $analysis['confidence'] = 0.95;
- $analysis['override_reason'] = "Trends/news keyword detected: $keyword (no entity/financial keywords)";
- $analysis['detection_method'] = 'pattern_post_filter';
- return $analysis;
- // ========================================================================
- // STEP 2: Check for competitor keywords (ENGLISH ONLY)
- // ========================================================================
- foreach (WebSearchPatterns::$competitorKeywords as $keyword) {
- if (strpos($query, $keyword) !== false) {
- $analysis['intent_type'] = 'web_search';
- $analysis['confidence'] = 0.95;
- $analysis['override_reason'] = "Competitor keyword detected: $keyword";
- $analysis['detection_method'] = 'pattern_post_filter';
- return $analysis;
- $externalSites[] = strtolower($row['site_domain']);
- }
- // Check if query mentions any configured external site
- foreach ($externalSites as $site) {
- if (strpos($query, $site) !== false) {
- $analysis['intent_type'] = 'web_search';
- $analysis['confidence'] = 0.95;
- $analysis['override_reason'] = "External site detected: $site (from database)";
- $analysis['detection_method'] = 'pattern_post_filter';
- return $analysis;
- // Only check comparison if query is price-related
- $hasPriceKeyword = false;
- foreach (WebSearchPatterns::$priceKeywords as $priceWord) {
- if (strpos($query, $priceWord) !== false) {
- $hasPriceKeyword = true;
- break;
- }
- }
- }
- }
- if ($hasPriceKeyword) {
- foreach (WebSearchPatterns::$comparisonKeywords as $keyword) {
- if (strpos($query, $keyword) !== false) {
- // Additional check: ensure it's not just internal comparison
- // If query contains "database" or "internal", it's likely hybrid, not pure web_search
- if (strpos($query, 'database') === false && strpos($query, 'internal') === false) {
- $analysis['intent_type'] = 'web_search';
- $analysis['confidence'] = 0.90;
- if ($hasPriceKeyword) {
- foreach (WebSearchPatterns::$comparisonKeywords as $keyword) {
- if (strpos($query, $keyword) !== false) {
- // Additional check: ensure it's not just internal comparison
- // If query contains "database" or "internal", it's likely hybrid, not pure web_search
- if (strpos($query, 'database') === false && strpos($query, 'internal') === false) {
- $analysis['intent_type'] = 'web_search';
- $analysis['confidence'] = 0.90;
- $analysis['override_reason'] = "Price comparison detected: $keyword";
- $analysis['detection_method'] = 'pattern_post_filter';
- return $analysis;
- // Clear from Memcached (note: Memcached doesn't support key pattern matching easily)
- // We'll rely on TTL expiration for Memcached
- // Clear from file cache
- foreach ($this->promptCache as $key => $data) {
- if (strpos($key, $prefix) === 0) {
- unset($this->promptCache[$key]);
- $cleared++;
- }
- }
- // iterate through all keys. We'll rely on TTL expiration for Memcached.
- // For production use, consider using Redis for better invalidation support.
- // Invalidate from file cache
- foreach ($this->promptCache as $key => $data) {
- if (strpos($key, self::CACHE_TYPE_SQL) === 0) {
- if (isset($data['tables_used']) && in_array($cleanTableName, $data['tables_used'], true)) {
- unset($this->promptCache[$key]);
- $invalidated++;
- }
- }
- }
- }
- // Invalidate from file cache
- foreach ($this->promptCache as $key => $data) {
- if (strpos($key, self::CACHE_TYPE_SQL) === 0) {
- if (isset($data['tables_used'])) {
- $intersection = array_intersect($cleanTableNames, $data['tables_used']);
- if (!empty($intersection)) {
- unset($this->promptCache[$key]);
- $invalidated++;
- {
- // Remove backticks and quotes
- $tableName = str_replace(['`', '"', "'"], '', $tableName);
- // Remove database prefix (e.g., database.table -> table)
- if (strpos($tableName, '.') !== false) {
- $parts = explode('.', $tableName);
- $tableName = end($parts);
- }
- // Remove alias (take only the first word)
- return self::PRICING[$model];
- }
- // Match partiel (ex: "gpt-4-0613" match "gpt-4")
- foreach (self::PRICING as $knownModel => $pricing) {
- if (strpos($model, $knownModel) !== false) {
- return $pricing;
- }
- }
- // Détection par provider
- return $pricing;
- }
- }
- // Détection par provider
- if (strpos($model, 'gpt') !== false) {
- return self::PRICING['gpt-3.5-turbo']; // Défaut OpenAI
- }
- if (strpos($model, 'claude') !== false) {
- return self::PRICING['claude-3-haiku']; // Défaut Anthropic (le moins cher)
- }
- // Détection par provider
- if (strpos($model, 'gpt') !== false) {
- return self::PRICING['gpt-3.5-turbo']; // Défaut OpenAI
- }
- if (strpos($model, 'claude') !== false) {
- return self::PRICING['claude-3-haiku']; // Défaut Anthropic (le moins cher)
- }
- if (strpos($model, 'mistral') !== false) {
- return self::PRICING['mistral-small']; // Défaut Mistral
- }
- return self::PRICING['gpt-3.5-turbo']; // Défaut OpenAI
- }
- if (strpos($model, 'claude') !== false) {
- return self::PRICING['claude-3-haiku']; // Défaut Anthropic (le moins cher)
- }
- if (strpos($model, 'mistral') !== false) {
- return self::PRICING['mistral-small']; // Défaut Mistral
- }
- if (strpos($model, 'llama') !== false || strpos($model, 'ollama') !== false) {
- return [0.0, 0.0]; // Local, gratuit
- }
- return self::PRICING['claude-3-haiku']; // Défaut Anthropic (le moins cher)
- }
- if (strpos($model, 'mistral') !== false) {
- return self::PRICING['mistral-small']; // Défaut Mistral
- }
- if (strpos($model, 'llama') !== false || strpos($model, 'ollama') !== false) {
- return [0.0, 0.0]; // Local, gratuit
- }
- return null;
- }
- $metrics = array_merge($metrics, $componentStats);
- }
- // Méthodes spécifiques par type de composant
- switch (true) {
- case strpos($name, 'Planner') !== false:
- $metrics['type'] = 'planner';
- $metrics['total_plans'] = $componentStats['total_plans_created'] ?? 0;
- $metrics['avg_steps'] = $componentStats['avg_steps_per_plan'] ?? 0;
- break;
- $metrics['type'] = 'planner';
- $metrics['total_plans'] = $componentStats['total_plans_created'] ?? 0;
- $metrics['avg_steps'] = $componentStats['avg_steps_per_plan'] ?? 0;
- break;
- case strpos($name, 'Memory') !== false:
- $metrics['type'] = 'memory';
- if (method_exists($component, 'getStats')) {
- $memStats = $component->getStats();
- $metrics['total_interactions'] = $memStats['total_interactions'] ?? 0;
- $metrics['memory_size'] = $memStats['total_size'] ?? 0;
- $metrics['total_interactions'] = $memStats['total_interactions'] ?? 0;
- $metrics['memory_size'] = $memStats['total_size'] ?? 0;
- }
- break;
- case strpos($name, 'Correction') !== false:
- $metrics['type'] = 'correction';
- if (method_exists($component, 'getLearningStats')) {
- $learnStats = $component->getLearningStats();
- $metrics['correction_accuracy'] = $learnStats['correction_accuracy'] ?? 0;
- $metrics['learned_patterns'] = $learnStats['learned_patterns'] ?? 0;
- $metrics['correction_accuracy'] = $learnStats['correction_accuracy'] ?? 0;
- $metrics['learned_patterns'] = $learnStats['learned_patterns'] ?? 0;
- }
- break;
- case strpos($name, 'WebSearch') !== false:
- $metrics['type'] = 'web_search';
- $metrics['cache_hit_rate'] = $this->extractCacheHitRate($componentStats);
- break;
- }
- if ($serverVersion) {
- $serverVersionLower = strtolower($serverVersion);
- // Extraire et formater correctement la version
- if (strpos($serverVersionLower, 'mariadb') !== false) {
- // Format typique: "10.11.8-MariaDB" ou "11.7.0-mariadb"
- preg_match('/(\d+\.\d+\.\d+)/', $serverVersion, $matches);
- if (!empty($matches[1])) {
- $versionNumber = $matches[1];
- return true;
- }
- // Fuzzy match
- foreach ($allFields as $field) {
- if (strpos($field, $word) !== false || strpos($word, $field) !== false) {
- return true;
- }
- }
- // Check against non-database words
- if (in_array($fieldName, $skipFields, true)) {
- return null;
- }
- // Remove _id suffix for non-ID fields
- if ($fieldName !== 'id' && preg_match('/_id$/', $fieldName)) {
- return null;
- }
- return $fieldName;
- }
- if (self::$prefixDb === null) {
- self::$prefixDb = CLICSHOPPING::getConfig('db_table_prefix');
- }
- // Add prefix if not already present
- if (strpos($tableName, self::$prefixDb) !== 0) {
- $tableName = self::$prefixDb . $tableName;
- }
- $connection = self::getEntityManager()->getConnection();
- $affectedRows = $connection->insert($tableName, $data);
- if (self::$prefixDb === null) {
- self::$prefixDb = CLICSHOPPING::getConfig('db_table_prefix');
- }
- // Add prefix if not already present
- if (strpos($tableName, self::$prefixDb) !== 0) {
- $tableName = self::$prefixDb . $tableName;
- }
- $connection = self::getEntityManager()->getConnection();
- return $connection->update($tableName, $data, $criteria);
- if (self::$prefixDb === null) {
- self::$prefixDb = CLICSHOPPING::getConfig('db_table_prefix');
- }
- // Add prefix if not already present
- if (strpos($tableName, self::$prefixDb) !== 0) {
- $tableName = self::$prefixDb . $tableName;
- }
- $connection = self::getEntityManager()->getConnection();
- return $connection->delete($tableName, $criteria);
- error_log("text_order_calculation length: " . strlen($orderCalculation) . " chars");
- error_log("text_query_examples length: " . strlen($queryExamples) . " chars");
- error_log("sqlFormatInstructions length: " . strlen($sqlFormatInstructions) . " chars");
- error_log("text_response_format length: " . strlen($responseFormat) . " chars");
- error_log("text_multi_token_rules length: " . strlen($multiTokenRules) . " chars");
- error_log("Contains 'MULTI-TOKEN' in multiTokenRules: " . (strpos($multiTokenRules, 'MULTI-TOKEN') !== false ? 'YES' : 'NO'));
- error_log("Contains 'ABSOLUTE RULE' in aggregationRules: " . (strpos($aggregationRules, 'ABSOLUTE RULE') !== false ? 'YES' : 'NO'));
- error_log("First 200 chars of multiTokenRules: " . substr($multiTokenRules, 0, 200));
- error_log("================================================================================");
- }
- error_log("text_query_examples length: " . strlen($queryExamples) . " chars");
- error_log("sqlFormatInstructions length: " . strlen($sqlFormatInstructions) . " chars");
- error_log("text_response_format length: " . strlen($responseFormat) . " chars");
- error_log("text_multi_token_rules length: " . strlen($multiTokenRules) . " chars");
- error_log("Contains 'MULTI-TOKEN' in multiTokenRules: " . (strpos($multiTokenRules, 'MULTI-TOKEN') !== false ? 'YES' : 'NO'));
- error_log("Contains 'ABSOLUTE RULE' in aggregationRules: " . (strpos($aggregationRules, 'ABSOLUTE RULE') !== false ? 'YES' : 'NO'));
- error_log("First 200 chars of multiTokenRules: " . substr($multiTokenRules, 0, 200));
- error_log("================================================================================");
- }
- // Construct complete message in the correct order
- error_log("================================================================================");
- error_log("DEBUG PromptBuilder::buildSystemMessage() - FINAL");
- error_log("================================================================================");
- error_log("Language ID: " . $this->languageId);
- error_log("Final message length: " . strlen($finalMessage));
- error_log("Contains 'CRITICAL RULES': " . (strpos($finalMessage, 'CRITICAL RULES') !== false ? 'YES' : 'NO'));
- error_log("Contains 'products_quantity': " . (strpos($finalMessage, 'products_quantity') !== false ? 'YES' : 'NO'));
- error_log("First 500 chars: " . substr($finalMessage, 0, 500));
- error_log("================================================================================");
- }
- error_log("DEBUG PromptBuilder::buildSystemMessage() - FINAL");
- error_log("================================================================================");
- error_log("Language ID: " . $this->languageId);
- error_log("Final message length: " . strlen($finalMessage));
- error_log("Contains 'CRITICAL RULES': " . (strpos($finalMessage, 'CRITICAL RULES') !== false ? 'YES' : 'NO'));
- error_log("Contains 'products_quantity': " . (strpos($finalMessage, 'products_quantity') !== false ? 'YES' : 'NO'));
- error_log("First 500 chars: " . substr($finalMessage, 0, 500));
- error_log("================================================================================");
- }
- return $finalMessage;
- while ($tableRow = $tablesResult->fetch()) {
- $tableName = array_values($tableRow)[0];
- // Skip non-clic tables
- if (strpos($tableName, 'clic_') !== 0) {
- continue;
- }
- $schema .= "Table: {$tableName}\n";
- }
- }
- foreach ($tablesList as $tableName) {
- // Skip technical tables
- if (strpos($tableName, '_embedding') !== false || strpos($tableName, $prefix . 'rag_') === 0) {
- continue;
- }
- $this->totalTables++;
- }
- }
- foreach ($tablesList as $tableName) {
- // Skip technical tables
- if (strpos($tableName, '_embedding') !== false || strpos($tableName, $prefix . 'rag_') === 0) {
- continue;
- }
- $this->totalTables++;
- while ($Qembeddings->fetch()) {
- $tableName = $Qembeddings->value('table_name');
- // Skip technical tables (should not be in embeddings, but filter just in case)
- if (strpos($tableName, '_embedding') !== false || strpos($tableName, 'clic_rag_') === 0) {
- continue;
- }
- $embeddingText = $Qembeddings->value('embedding_text');
- while ($Qembeddings->fetch()) {
- $tableName = $Qembeddings->value('table_name');
- // Skip technical tables (should not be in embeddings, but filter just in case)
- if (strpos($tableName, '_embedding') !== false || strpos($tableName, 'clic_rag_') === 0) {
- continue;
- }
- $embeddingText = $Qembeddings->value('embedding_text');
- * @param string $tableName Table name
- * @return bool True if junction table
- */
- private function isJunctionTable(string $tableName): bool
- {
- return preg_match('/_to_/', $tableName) === 1;
- }
- /**
- * Calculate cosine similarity between two vectors
- *
- public function __construct(EmbeddingGeneratorInterface $embeddingGenerator, string $tableName = 'rag_embeddings')
- {
- $this->embeddingGenerator = $embeddingGenerator;
- $prefix = CLICSHOPPING::getConfig('db_table_prefix');
- if (!empty($prefix) && strpos($tableName, $prefix) === 0) {
- $this->tableName = $tableName;
- } else {
- $this->tableName = $prefix . $tableName;
- }
- if (isset($metadata['source_table']) && !empty($metadata['source_table'])) {
- $tableName = $metadata['source_table'];
- // Remove prefix and _embedding suffix
- $prefix = CLICSHOPPING::getConfig('db_table_prefix');
- if (!empty($prefix) && strpos($tableName, $prefix) === 0) {
- $tableName = substr($tableName, strlen($prefix));
- }
- $tableName = str_replace('_embedding', '', $tableName);
- // Convert to readable format (e.g., "pages_manager_description" -> "Pages Manager Description")
- // Check if the path is within allowed directories
- $isAllowed = false;
- foreach ($allowedDirs as $allowedDir) {
- $normalizedAllowedDir = str_replace('\\', '/', realpath($allowedDir));
- if ($normalizedAllowedDir && strpos($realPath, $normalizedAllowedDir) === 0) {
- $isAllowed = true;
- break;
- }
- }
- * @return bool True if the text contains valid JSON, false otherwise.
- */
- private static function validateJsonStructure(string $text): bool
- {
- // Si le texte contient du JSON, vérifier sa validité
- if (strpos($text, '{') !== false || strpos($text, '[') !== false) {
- return json_last_error() === JSON_ERROR_NONE;
- }
- return true; // Pas de JSON détecté
- }
- */
- private static function containsMaliciousPatterns(string $text): bool
- {
- $lowerText = strtolower($text);
- foreach (ObfuscationPatterns::$maliciousKeywords as $keyword) {
- if (strpos($lowerText, $keyword) !== false) {
- return true;
- }
- }
- return false;
- */
- private function detectQueryType(string $sql): string
- {
- $sql = trim(strtoupper($sql));
- if (strpos($sql, 'SELECT') === 0) return 'SELECT';
- if (strpos($sql, 'INSERT') === 0) return 'INSERT';
- if (strpos($sql, 'UPDATE') === 0) return 'UPDATE';
- if (strpos($sql, 'DELETE') === 0) return 'DELETE';
- return 'UNKNOWN';
- private function detectQueryType(string $sql): string
- {
- $sql = trim(strtoupper($sql));
- if (strpos($sql, 'SELECT') === 0) return 'SELECT';
- if (strpos($sql, 'INSERT') === 0) return 'INSERT';
- if (strpos($sql, 'UPDATE') === 0) return 'UPDATE';
- if (strpos($sql, 'DELETE') === 0) return 'DELETE';
- return 'UNKNOWN';
- }
- {
- $sql = trim(strtoupper($sql));
- if (strpos($sql, 'SELECT') === 0) return 'SELECT';
- if (strpos($sql, 'INSERT') === 0) return 'INSERT';
- if (strpos($sql, 'UPDATE') === 0) return 'UPDATE';
- if (strpos($sql, 'DELETE') === 0) return 'DELETE';
- return 'UNKNOWN';
- }
- $sql = trim(strtoupper($sql));
- if (strpos($sql, 'SELECT') === 0) return 'SELECT';
- if (strpos($sql, 'INSERT') === 0) return 'INSERT';
- if (strpos($sql, 'UPDATE') === 0) return 'UPDATE';
- if (strpos($sql, 'DELETE') === 0) return 'DELETE';
- return 'UNKNOWN';
- }
- /**
- {
- $query = strtolower($query);
- $metrics = self::getMetricsPatterns();
- foreach ($metrics as $pattern => $metric) {
- if (strpos($query, $pattern) !== false) {
- return $metric;
- }
- }
- return null;
- public static function hasTimePeriod(string $query): bool
- {
- $query = strtolower($query);
- foreach (self::$timePeriods as $period) {
- if (strpos($query, $period) !== false) {
- return true;
- }
- }
- return false;
- {
- $query = strtolower($query);
- $detected = [];
- foreach (self::$financialMetrics as $metric) {
- if (strpos($query, $metric) !== false) {
- $detected[] = $metric;
- }
- }
- return $detected;
- {
- $query = strtolower($query);
- $detected = [];
- foreach (self::$timePeriods as $period) {
- if (strpos($query, $period) !== false) {
- $detected[] = $period;
- }
- }
- return $detected;
- $hasConjunction = false;
- $conjunctionUsed = '';
- foreach ($conjunctions as $conj) {
- if (strpos($query, $conj) !== false) {
- $hasConjunction = true;
- $conjunctionUsed = trim($conj);
- break;
- }
- }
- $part = trim($part);
- $partIntent = null;
- // Check analytics
- foreach ($analyticsKeywords as $keyword) {
- if (strpos($part, $keyword) !== false) {
- $partIntent = 'analytics';
- break;
- }
- }
- }
- // Check semantic
- if ($partIntent === null) {
- foreach ($semanticKeywords as $keyword) {
- if (strpos($part, $keyword) !== false) {
- $partIntent = 'semantic';
- break;
- }
- }
- }
- }
- // Check web_search
- if ($partIntent === null) {
- foreach ($webSearchKeywords as $keyword) {
- if (strpos($part, $keyword) !== false) {
- $partIntent = 'web_search';
- break;
- }
- }
- }
- // Simple routing
- // --------------------------------------------------------------------------------
- // POST /agentic_commerce/delegate_payment - Handle delegated payment vaulting
- // --------------------------------------------------------------------------------
- if ($method === 'POST' && ($hasDelegatePaymentParam || strpos($path, '/agentic_commerce/delegate_payment') !== false)) {
- $headers = [
- 'idempotency_key' => $_SERVER['HTTP_IDEMPOTENCY_KEY'] ?? null,
- 'request_id' => $_SERVER['HTTP_REQUEST_ID'] ?? null
- ];
- $result = $CLICSHOPPING_getRetailers->handleDelegatePayment($input, $headers);
- // --------------------------------------------------------------------------------
- // GET /products - Returns product catalog
- // --------------------------------------------------------------------------------
- if ($method === 'GET' && ($hasProductsParam || strpos($path, '/products') !== false)) {
- // Return full product catalog
- $products = $CLICSHOPPING_getRetailers->getProducts();
- echo json_encode(['products' => $products], JSON_UNESCAPED_SLASHES);
- exit;
- } elseif (!empty($checkoutIdParam)) {
- // Fallback ou prise en compte du paramètre 'id' si l'ID n'est pas dans le chemin
- $sessionId = $checkoutIdParam;
- }
- if ($method === 'POST' && ($hasCheckoutParam || strpos($path, '/checkout_sessions') !== false)) {
- if ($sessionId) {
- if ($hasCompleteParam || strpos($path, '/complete') !== false) {
- $validation = $CLICSHOPPING_getRetailers->validateAcpInput($input, 'complete', $input['items'] ?? []);
- if (!empty($validation)) {
- http_response_code(400);
- $sessionId = $checkoutIdParam;
- }
- if ($method === 'POST' && ($hasCheckoutParam || strpos($path, '/checkout_sessions') !== false)) {
- if ($sessionId) {
- if ($hasCompleteParam || strpos($path, '/complete') !== false) {
- $validation = $CLICSHOPPING_getRetailers->validateAcpInput($input, 'complete', $input['items'] ?? []);
- if (!empty($validation)) {
- http_response_code(400);
- echo json_encode(['messages' => $validation], JSON_UNESCAPED_SLASHES);
- exit;
- echo json_encode($result['checkout_session'], JSON_UNESCAPED_SLASHES);
- } else {
- echo json_encode($result, JSON_UNESCAPED_SLASHES);
- }
- }
- } elseif ($hasCancelParam || strpos($path, '/cancel') !== false) {
- $result = $CLICSHOPPING_getRetailers->cancelSession($sessionId);
- if ($result === null) {
- http_response_code(404);
- echo json_encode(['error' => 'Session not found']);
- } else {
- exit;
- }
- // --------------------------------------------------------------------------------
- // POST /stripe_webhook - Handle Stripe webhooks
- // --------------------------------------------------------------------------------
- if ($method === 'POST' && ($hasStripeWebhookParam || strpos($path, '/stripe_webhook') !== false)) {
- $CLICSHOPPING_getRetailers->handleStripeWebhook();
- exit;
- }
- // --------------------------------------------------------------------------------
- // POST /create_order - Create ClicShopping order from session
- // --------------------------------------------------------------------------------
- $hasCreateOrderParam = isset($_GET['create_order']);
- $orderSessionIdParam = isset($_GET['session_id']) ? (string)$_GET['session_id'] : null;
- if ($method === 'POST' && ($hasCreateOrderParam || strpos($path, '/create_order') !== false)) {
- if (empty($orderSessionIdParam)) {
- http_response_code(400);
- echo json_encode(['error' => 'Session ID required']);
- exit;
- }
- // POST /complete_and_order - Complete session then create order
- // --------------------------------------------------------------------------------
- $hasCompleteAndOrderParam = isset($_GET['complete_and_order']);
- $completeSessionIdParam = isset($_GET['session_id']) ? (string)$_GET['session_id'] : null;
- if ($method === 'POST' && ($hasCompleteAndOrderParam || strpos($path, '/complete_and_order') !== false)) {
- if (empty($completeSessionIdParam)) {
- http_response_code(400);
- echo json_encode(['error' => 'Session ID required']);
- exit;
- }
- $hasCheckoutParam = isset($_GET['checkout_sessions']) || isset($_GET['retailers/checkout_sessions']);
- $checkoutIdParam = isset($_GET['id']) ? (string)$_GET['id'] : null;
- $hasCompleteParam = isset($_GET['complete']);
- $hasWebhookParam = isset($_GET['webhook']);
- if ($method === 'GET' && ($hasProductsParam || strpos($path, '/products') !== false)) {
- $filters = [
- 'page' => $_GET['page'] ?? 1,
- 'limit' => $_GET['limit'] ?? 100,
- 'category' => $_GET['category'] ?? null,
- 'min_price' => $_GET['min_price'] ?? null,
- 'action' => 'products'
- ]);
- exit;
- }
- if ($method === 'POST' && ($hasCheckoutParam || strpos($path, '/checkout_sessions') !== false)) {
- if (($hasCompleteParam || strpos($path, '/complete') !== false) && (($checkoutIdParam !== null) || preg_match('#/checkout_sessions/([^/]+)/complete#', $path, $matches))) {
- $sessionId = $checkoutIdParam ?? $matches[1] ?? null;
- if (!$sessionId) {
- $errorResponse('VALIDATION_ERROR', 'Missing session id');
- }
- ]);
- exit;
- }
- if ($method === 'POST' && ($hasCheckoutParam || strpos($path, '/checkout_sessions') !== false)) {
- if (($hasCompleteParam || strpos($path, '/complete') !== false) && (($checkoutIdParam !== null) || preg_match('#/checkout_sessions/([^/]+)/complete#', $path, $matches))) {
- $sessionId = $checkoutIdParam ?? $matches[1] ?? null;
- if (!$sessionId) {
- $errorResponse('VALIDATION_ERROR', 'Missing session id');
- }
- $result = $ucp->completeSession($sessionId, $input);
- 'action' => 'checkout_sessions.update'
- ]);
- exit;
- }
- if ($method === 'POST' && ($hasWebhookParam || strpos($path, '/webhook') !== false)) {
- $result = $ucp->handleWebhook($input);
- echo json_encode($result, JSON_UNESCAPED_SLASHES);
- $logger->info('UCP response', [
- 'request_id' => $requestId,
- 'status' => 200,
- * @return bool True if it contains a comparison operator, false otherwise.
- */
- private function isComparisonClause(string $clause): bool
- {
- foreach (self::ALLOWED_OPERATORS as $operator) {
- if (strpos($clause, $operator) !== false) {
- return true;
- }
- }
- return false;
- }
- while ($Qconfiguration->fetch()) {
- if ($Qconfiguration->hasValue('use_function') && !\is_null($Qconfiguration->value('use_function'))) {
- $use_function = $Qconfiguration->value('use_function');
- if (preg_match('/->/', $use_function)) {
- $class_method = explode('->', $use_function);
- if (!\is_object($class_method[0])) {
- include_once('Core/classes/' . $class_method[0] . '.php');
- ${$class_method[0]} = new $class_method[0]();
- // Register shutdown function to handle timeout gracefully
- register_shutdown_function(function() use ($seconds) {
- $error = error_get_last();
- if ($error && ($error['type'] === E_ERROR || $error['type'] === E_USER_ERROR)) {
- if (strpos($error['message'], 'Maximum execution time') !== false) {
- error_log('[INFO : TIME] TIMEOUT ERROR: Query exceeded ' . $seconds . ' seconds');
- if (ob_get_length()) ob_clean();
- header('Content-Type: application/json; charset=UTF-8');
- define('CLICSHOPPING_APP_CHATGPT_CH_MODEL', 'gpt-5-mini');
- }
- $model = $engine ?? CLICSHOPPING_APP_CHATGPT_CH_MODEL;
- if (strpos($model, 'gpt') === 0) {
- $maxtoken = self::getMaxTokens($maxtoken);
- $temperature = $temperature ?? (float)CLICSHOPPING_APP_CHATGPT_CH_TEMPERATURE;
- $tokenParams = ModelManager::getModelApiParameters($model, $maxtoken);
- if ($engine !== null) {
- $parameters['model'] = $engine;
- }
- $client = ProviderManager::getOpenAiGpt($parameters);
- } elseif (strpos($model, 'anth') === 0) {
- $client = ProviderManager::getAnthropicChat($model, $maxtoken);
- } elseif (strpos($model, 'mistral') === 0) {
- $client = ProviderManager::getMistralChat($model, $maxtoken);
- } elseif (strpos($model, 'ollama') === 0 || str_contains($model, ':latest')) {
- $client = ProviderManager::getOllamaChat($model);
- }
- $client = ProviderManager::getOpenAiGpt($parameters);
- } elseif (strpos($model, 'anth') === 0) {
- $client = ProviderManager::getAnthropicChat($model, $maxtoken);
- } elseif (strpos($model, 'mistral') === 0) {
- $client = ProviderManager::getMistralChat($model, $maxtoken);
- } elseif (strpos($model, 'ollama') === 0 || str_contains($model, ':latest')) {
- $client = ProviderManager::getOllamaChat($model);
- } elseif (strpos($model, 'openai/') === 0) {
- $client = ProviderManager::getLmStudioChat($model);
- $client = ProviderManager::getOpenAiGpt($parameters);
- } elseif (strpos($model, 'anth') === 0) {
- $client = ProviderManager::getAnthropicChat($model, $maxtoken);
- } elseif (strpos($model, 'mistral') === 0) {
- $client = ProviderManager::getMistralChat($model, $maxtoken);
- } elseif (strpos($model, 'ollama') === 0 || str_contains($model, ':latest')) {
- $client = ProviderManager::getOllamaChat($model);
- } elseif (strpos($model, 'openai/') === 0) {
- $client = ProviderManager::getLmStudioChat($model);
- } else {
- $client = ProviderManager::getLmStudioChat($model);
- $client = ProviderManager::getAnthropicChat($model, $maxtoken);
- } elseif (strpos($model, 'mistral') === 0) {
- $client = ProviderManager::getMistralChat($model, $maxtoken);
- } elseif (strpos($model, 'ollama') === 0 || str_contains($model, ':latest')) {
- $client = ProviderManager::getOllamaChat($model);
- } elseif (strpos($model, 'openai/') === 0) {
- $client = ProviderManager::getLmStudioChat($model);
- } else {
- $client = ProviderManager::getLmStudioChat($model);
- }
- if (is_null($temperature)) {
- $temperature = 0.5;
- }
- if (strpos(CLICSHOPPING_APP_CHATGPT_CH_MODEL, 'gpt') === 0) {
- $engine = CLICSHOPPING_APP_CHATGPT_CH_MODEL;
- $response = Gpt::getGptResponse($question, $maxtoken, $temperature, $engine);
- } else {
- //ollama
- $response = Gpt::getGptResponse($question, $maxtoken, $temperature);
- // Simple routing
- // --------------------------------------------------------------------------------
- // GET /products - Returns product catalog
- // --------------------------------------------------------------------------------
- if ($method === 'GET' && ($hasProductsParam || strpos($path, '/products') !== false)) {
- // Return full product catalog
- $products = $CLICSHOPPING_getRetailers->getProducts();
- echo json_encode(['products' => $products], JSON_UNESCAPED_SLASHES);
- exit;
- } elseif (!empty($checkoutIdParam)) {
- // Fallback ou prise en compte du paramètre 'id' si l'ID n'est pas dans le chemin
- $sessionId = $checkoutIdParam;
- }
- if ($method === 'POST' && ($hasCheckoutParam || strpos($path, '/checkout_sessions') !== false)) {
- if ($sessionId) {
- // Completion: POST /checkout_sessions/{id}
- // Choose Delegated Payment or Stripe based on payload
- if (!empty($input['delegated_payment'])) {
- $session = $CLICSHOPPING_getRetailers->completeSessionWithDelegatedPayment($sessionId, $input);
- exit;
- }
- // --------------------------------------------------------------------------------
- // POST /stripe_webhook - Handle Stripe webhooks
- // --------------------------------------------------------------------------------
- if ($method === 'POST' && ($hasStripeWebhookParam || strpos($path, '/stripe_webhook') !== false)) {
- $CLICSHOPPING_getRetailers->handleStripeWebhook();
- exit;
- }
- // --------------------------------------------------------------------------------
- // POST /create_order - Create ClicShopping order from session
- // --------------------------------------------------------------------------------
- $hasCreateOrderParam = isset($_GET['create_order']);
- $orderSessionIdParam = isset($_GET['session_id']) ? (string)$_GET['session_id'] : null;
- if ($method === 'POST' && ($hasCreateOrderParam || strpos($path, '/create_order') !== false)) {
- if (empty($orderSessionIdParam)) {
- http_response_code(400);
- echo json_encode(['error' => 'Session ID required']);
- exit;
- }
- // POST /complete_and_order - Complete session then create order
- // --------------------------------------------------------------------------------
- $hasCompleteAndOrderParam = isset($_GET['complete_and_order']);
- $completeSessionIdParam = isset($_GET['session_id']) ? (string)$_GET['session_id'] : null;
- if ($method === 'POST' && ($hasCompleteAndOrderParam || strpos($path, '/complete_and_order') !== false)) {
- if (empty($completeSessionIdParam)) {
- http_response_code(400);
- echo json_encode(['error' => 'Session ID required']);
- exit;
- }
- while ($Qconfiguration->fetch()) {
- if ($Qconfiguration->hasValue('use_function') && !\is_null($Qconfiguration->value('use_function'))) {
- $use_function = $Qconfiguration->value('use_function');
- if (preg_match('/->/', $use_function)) {
- $class_method = explode('->', $use_function);
- if (!\is_object($class_method[0])) {
- include_once('Core/classes/' . $class_method[0] . '.php');
- $class_method[0] = new $class_method[0]();
- $module_active = $modules_payment;
- $include_modules = [];
- foreach ($modules_payment as $value) {
- if (strpos($value, '\\') !== false) {
- $class = Apps::getModuleClass($value, 'Payment');
- $include_modules[] = ['class' => $value,
- 'file' => $class
- ];
- ];
- }
- }
- for ($i = 0, $n = \count($include_modules); $i < $n; $i++) {
- if (strpos($include_modules[$i]['class'], '\\') !== false) {
- Registry::set('Payment_' . str_replace('\\', '_', $include_modules[$i]['class']), new $include_modules[$i]['file']);
- $module = Registry::get('Payment_' . str_replace('\\', '_', $include_modules[$i]['class']));
- ?>
- <div class="row">
- <div class="col-md-12">
- $module_active = $modules_shipping;
- $include_modules = [];
- foreach ($modules_shipping as $value) {
- if (strpos($value, '\\') !== false) {
- $class = Apps::getModuleClass($value, 'Shipping');
- $include_modules[] = ['class' => $value,
- 'file' => $class
- ];
- ];
- }
- }
- for ($i = 0, $n = \count($include_modules); $i < $n; $i++) {
- if (strpos($include_modules[$i]['class'], '\\') !== false) {
- Registry::set('Shipping_' . str_replace('\\', '_', $include_modules[$i]['class']), new $include_modules[$i]['file']);
- $module = Registry::get('Shipping_' . str_replace('\\', '_', $include_modules[$i]['class']));
- ?>
- <div class="row">
- <div class="col-md-5">
- $basePath = CLICSHOPPING::getConfig('dir_root', 'Shop') . $CLICSHOPPING_Template->getDynamicTemplateDirectory() . '/modules/' . $directory_selected . '/content/';
- $filePath = realpath($basePath . $filename_selected);
- // Sécurité chemin
- if ($filePath === false || strpos($filePath, realpath($basePath)) !== 0 || !is_file($filePath)) {
- $CLICSHOPPING_MessageStack->add($CLICSHOPPING_EditDesign->getDef('error_file_does_not_exist'), 'error');
- $CLICSHOPPING_EditDesign->redirect('EditModuleContent&action=directory&directory_html=' . $directory_selected);
- return false;
- }
- $lang_dir = $CLICSHOPPING_Language->get('directory');
- $basePathLang = CLICSHOPPING::getConfig('dir_root', 'Shop') . $CLICSHOPPING_Template->getDynamicTemplateDirectory() . "/css/{$lang_dir}/{$directory_selected}/";
- $basePathFallback = CLICSHOPPING::getConfig('dir_root', 'Shop') . $CLICSHOPPING_Template->getDynamicTemplateDirectory() . "/css/english/{$directory_selected}/";
- $filePath = realpath($basePathLang . $filename_selected);
- if ($filePath === false || strpos($filePath, realpath($basePathLang)) !== 0 || !is_file($filePath)) {
- $filePath = realpath($basePathFallback . $filename_selected);
- if ($filePath === false || strpos($filePath, realpath($basePathFallback)) !== 0 || !is_file($filePath)) {
- $CLICSHOPPING_MessageStack->add($CLICSHOPPING_EditDesign->getDef('error_file_does_not_exist'), 'error');
- $CLICSHOPPING_EditDesign->redirect('EditCss&action=directory&directory_css=' . $directory_selected);
- return false;
- $basePathFallback = CLICSHOPPING::getConfig('dir_root', 'Shop') . $CLICSHOPPING_Template->getDynamicTemplateDirectory() . "/css/english/{$directory_selected}/";
- $filePath = realpath($basePathLang . $filename_selected);
- if ($filePath === false || strpos($filePath, realpath($basePathLang)) !== 0 || !is_file($filePath)) {
- $filePath = realpath($basePathFallback . $filename_selected);
- if ($filePath === false || strpos($filePath, realpath($basePathFallback)) !== 0 || !is_file($filePath)) {
- $CLICSHOPPING_MessageStack->add($CLICSHOPPING_EditDesign->getDef('error_file_does_not_exist'), 'error');
- $CLICSHOPPING_EditDesign->redirect('EditCss&action=directory&directory_css=' . $directory_selected);
- return false;
- }
- }
- $baseDir = CLICSHOPPING::getConfig('dir_root', 'Shop') . $CLICSHOPPING_Template->getDynamicTemplateDirectory() . '/files/';
- $filePath = realpath($baseDir . $filename_selected);
- // Sécuriser le chemin pour éviter directory traversal
- if ($filePath === false || strpos($filePath, realpath($baseDir)) !== 0) {
- $CLICSHOPPING_MessageStack->add($CLICSHOPPING_EditDesign->getDef('error_file_does_not_exist'), 'error');
- $CLICSHOPPING_EditDesign->redirect('EditModuleContent&action=directory&directory_html=' . $directory_selected);
- return false;
- }
- . $CLICSHOPPING_Template->getDynamicTemplateDirectory()
- . '/modules/' . $directory_selected . '/template_html/';
- $filePath = realpath($basePath . $filename_selected);
- if ($filePath === false || strpos($filePath, realpath($basePath)) !== 0 || !is_file($filePath)) {
- $CLICSHOPPING_MessageStack->add($CLICSHOPPING_EditDesign->getDef('error_file_does_not_exist'), 'error');
- $CLICSHOPPING_EditDesign->redirect('EditListing&action=directory&directory_html=' . $directory_selected);
- return false;
- }
- $Qcategories->execute();
- $categories_array = $Qcategories->fetchAll();
- foreach ($categories_array as $cat) {
- $catLower = strtolower($cat['categories_name'] ?? '');
- if (strpos($translated, $catLower) !== false) {
- $intent['entities']['category'] = $catLower;
- $matchWeight += 0.8;
- $totalWeight += 1;
- break;
- }
- 'text' => $Qproducts->valueInt('customers_basket_quantity') . ' x ' . $Qproducts->value('products_name')
- ];
- $attributes = [];
- if (strpos($Qproducts->valueInt('products_id'), '{') !== false) {
- $combos = [];
- preg_match_all('/(\{[0-9]+\}[0-9]+){1}/', $Qproducts->valueInt('products_id'), $combos);
- foreach ($combos[0] as $combo) {
- $att = [];
- 'Connection' => 'close'
- ];
- if (!empty($parameters['header'])) {
- foreach ($parameters['header'] as $header) {
- if (strpos($header, ':') !== false) {
- [$name, $value] = explode(':', $header, 2);
- $headers[trim($name)] = trim($value);
- }
- }
- }
- $headers = ['status_code' => $statusCode];
- while (($line = fgets($socket)) !== false) {
- $line = trim($line);
- if ($line === '') break;
- if (strpos($line, ':') !== false) {
- [$name, $value] = explode(':', $line, 2);
- $headers[strtolower(trim($name))] = trim($value);
- }
- }
- foreach ($files as $sm) {
- $result['file'][] = ['files_name' => $sm];
- }
- foreach ($result['file'] as &$module) {
- if (strpos($module['files_name'], '.') !== false) {
- $class = substr($module['files_name'], 0, strrpos($module['files_name'], '.'));
- $this->startService($class);
- }
- }
- }
- $content = file($spiders_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
- foreach ($content as $line) {
- $line = trim($line);
- // Ignore empty lines and comments starting with '#'
- if (!empty($line) && strpos($line, '#') !== 0) {
- $spiders_array[] = strtolower($line);
- }
- }
- // Save processed list to cache for future requests
- $this->logSecurityError("Invalid path detected", $path);
- continue;
- }
- // Ensure the resolved path is still within the root directory
- if (strpos($real_path, $root_dir) !== 0) {
- $this->logSecurityError("Path traversal attempt detected", $real_path);
- continue;
- }
- if (is_file($real_path) && is_readable($real_path)) {
- if ((substr($spider, strlen($spider) - 1, 1) == ' ') || (substr($spider, strlen($spider) - 1, 1) == "\n")) {
- $spider = substr($spider, 0, strlen($spider) - 1);
- }
- if (!empty($spider)) {
- if (strpos($user_agent, $spider) !== false) {
- $parameters['can_start'] = false;
- break;
- }
- }
- }
- // Also clear old embedding cache files from root cache directory (excluding embedding_search)
- $oldEmbeddingFiles = glob($generalCacheDir . 'embedding_*.cache');
- if ($oldEmbeddingFiles) {
- // Filter out embedding_search files
- $oldEmbeddingFiles = array_filter($oldEmbeddingFiles, function($file) {
- return strpos(basename($file), 'embedding_search_') !== 0;
- });
- $cleared = 0;
- foreach ($oldEmbeddingFiles as $file) {
- if (unlink($file)) {
- $CLICSHOPPING_templateCss->logSecurityError("CSS file not accessible", $cssFile);
- continue;
- }
- // Directory Traversal protection: ensure the file is within the allowed root directory
- if (strpos($real_path, $root_dir . DIRECTORY_SEPARATOR) !== 0) {
- $CLICSHOPPING_templateCss->logSecurityError("CSS file outside allowed directory", $cssFile);
- continue;
- }
- // Check individual file size
Your project uses legacy callable syntax instead of first-class callable syntax 5
- Read doc
- Productivity
- Info
More information: https://insight.symfony.com/what-we-analyse/php.use_first_class_callable_syntax
- $config = [];
- foreach ($embeddingTables as $embeddingTable) {
- // Extract entity type: clic_products_embedding -> products
- $entityType = str_replace([$prefix, '_embedding'], '', $embeddingTable);
- $table = $prefix . $entityType;
- // Get ID column from EntityRegistry (reuse existing logic)
- $idColumn = $entityRegistry->getIdColumnForEntityType($entityType);
- $config = [];
- foreach ($embeddingTables as $embeddingTable) {
- // Extract entity type: clic_products_embedding -> products
- $entityType = str_replace([$prefix, '_embedding'], '', $embeddingTable);
- $table = $prefix . $entityType;
- // Get ID column from EntityRegistry (reuse existing logic)
- $idColumn = $entityRegistry->getIdColumnForEntityType($entityType);
- // Build a mapping of table names (without prefix) to entity types
- $tableToEntityType = [];
- foreach ($allTables as $fullTableName) {
- $entityType = $registry->getEntityTypeForTable($fullTableName);
- // Remove prefix and _embedding suffix to get base table name
- $tableName = str_replace([$prefix, '_embedding'], '', $fullTableName);
- $tableToEntityType[$tableName] = $entityType;
- }
- // Pattern 1: FROM {table_name}
- if (preg_match('/FROM\s+(?:\w+\.)?(\w+)/i', $query, $matches)) {
- }
- $prefix = CLICSHOPPING::getConfig('db_table_prefix');
- // Remove prefix and '_embedding' suffix to get entity type
- $entityType = str_replace([$prefix, '_embedding'], '', $tableName);
- // Get ID column for this entity type
- $idColumn = $this->getIdColumnForEntityType($entityType);
- // Cache the result
- public function getEntityTypeForTable(string $tableName): string
- {
- $prefix = CLICSHOPPING::getConfig('db_table_prefix');
- // Remove prefix and '_embedding' suffix
- $entityType = str_replace([$prefix, '_embedding'], '', $tableName);
- return $entityType;
- }
- /**
gyakutsuki