diff --git a/classes/RequestSql.php b/classes/RequestSql.php index 638a173ec..02da7dfb7 100644 --- a/classes/RequestSql.php +++ b/classes/RequestSql.php @@ -38,50 +38,92 @@ class RequestSqlCore extends ObjectModel 'primary' => 'id_request_sql', 'fields' => array( 'name' => array('type' => self::TYPE_STRING, 'validate' => 'isString', 'required' => true, 'size' => 200), - 'sql' => array('type' => self::TYPE_STRING, 'validate' => 'isString', 'required' => true, 'size' => 400), + 'sql' => array('type' => self::TYPE_STRING, 'validate' => 'isString', 'required' => true, 'size' => 1000), ), ); - public $tested = array('required' => array ('SELECT', 'FROM'), - 'option' => array('WHERE', 'ORDER', 'LIMIT', 'HAVING', 'GROUP', 'UNION'), - 'operator' => array('AND', '&&', 'BETWEEN', 'AND', 'BINARY', '&', '~', '|', '^', 'CASE', 'WHEN', 'END', 'DIV', '/', '<=>', '=', '>=', - '>', 'IS', 'NOT', 'NULL', '<<', '<=', '<', 'LIKE', '-', '%', '!=', '<>', 'REGEXP', '!', '||', 'OR', '+', '>>', 'RLIKE', 'SOUNDS', '*', - '-', 'XOR', 'IN'), - 'function' => array('AVG', 'SUM', 'COUNT', 'MIN', 'MAX', 'STDDEV', 'STDDEV_SAMP', 'STDDEV_POP', 'VARIANCE', 'VAR_SAMP', 'VAR_POP', - 'GROUP_CONCAT', 'BIT_AND', 'BIT_OR', 'BIT_XOR'), - 'unauthorized' => array('DELETE', 'ALTER', 'INSERT', 'REPLACE', 'CREATE', 'TRUNCATE', 'OPTIMIZE', 'GRANT', 'REVOKE', 'SHOW', 'HANDLER', - 'LOAD', 'ROLLBACK', 'SAVEPOINT', 'UNLOCK', 'INSTALL', 'UNINSTALL', 'ANALZYE', 'BACKUP', 'CHECK', 'CHECKSUM', 'REPAIR', 'RESTORE', 'CACHE', - 'DESCRIBE', 'EXPLAIN', 'USE', 'HELP', 'SET', 'DUPLICATE', 'VALUES', 'INTO', 'RENAME', 'CALL', 'PROCEDURE', 'FUNCTION', 'DATABASE', 'SERVER', - 'LOGFILE', 'DEFINER', 'RETURNS', 'EVENT', 'TABLESPACE', 'VIEW', 'TRIGGER', 'DATA', 'DO', 'PASSWORD', 'USER', 'PLUGIN', 'FLUSH', 'KILL', - 'RESET', 'START', 'STOP', 'PURGE', 'EXECUTE', 'PREPARE', 'DEALLOCATE', 'LOCK', 'USING', 'DROP', 'FOR', 'UPDATE', 'BEGIN', 'BY', 'ALL', 'SHARE', - 'MODE', 'TO','KEY', 'DISTINCTROW', 'DISTINCT', 'HIGH_PRIORITY', 'LOW_PRIORITY', 'DELAYED', 'IGNORE', 'FORCE', 'STRAIGHT_JOIN', - 'SQL_SMALL_RESULT', 'SQL_BIG_RESULT', 'QUICK', 'SQL_BUFFER_RESULT', 'SQL_CACHE', 'SQL_NO_CACHE', 'SQL_CALC_FOUND_ROWS', 'WITH')); + /** @var array : List of params to tested */ + public $tested = array( + 'required' => array('SELECT', 'FROM'), + 'option' => array('WHERE', 'ORDER', 'LIMIT', 'HAVING', 'GROUP', 'UNION'), + 'operator' => array( + 'AND', '&&', 'BETWEEN', 'AND', 'BINARY', '&', '~', '|', '^', 'CASE', 'WHEN', 'END', 'DIV', '/', '<=>', '=', '>=', + '>', 'IS', 'NOT', 'NULL', '<<', '<=', '<', 'LIKE', '-', '%', '!=', '<>', 'REGEXP', '!', '||', 'OR', '+', '>>', 'RLIKE', 'SOUNDS', '*', + '-', 'XOR', 'IN' + ), + 'function' => array( + 'AVG', 'SUM', 'COUNT', 'MIN', 'MAX', 'STDDEV', 'STDDEV_SAMP', 'STDDEV_POP', 'VARIANCE', 'VAR_SAMP', 'VAR_POP', + 'GROUP_CONCAT', 'BIT_AND', 'BIT_OR', 'BIT_XOR' + ), + 'unauthorized' => array( + 'DELETE', 'ALTER', 'INSERT', 'REPLACE', 'CREATE', 'TRUNCATE', 'OPTIMIZE', 'GRANT', 'REVOKE', 'SHOW', 'HANDLER', + 'LOAD', 'ROLLBACK', 'SAVEPOINT', 'UNLOCK', 'INSTALL', 'UNINSTALL', 'ANALZYE', 'BACKUP', 'CHECK', 'CHECKSUM', 'REPAIR', 'RESTORE', 'CACHE', + 'DESCRIBE', 'EXPLAIN', 'USE', 'HELP', 'SET', 'DUPLICATE', 'VALUES', 'INTO', 'RENAME', 'CALL', 'PROCEDURE', 'FUNCTION', 'DATABASE', 'SERVER', + 'LOGFILE', 'DEFINER', 'RETURNS', 'EVENT', 'TABLESPACE', 'VIEW', 'TRIGGER', 'DATA', 'DO', 'PASSWORD', 'USER', 'PLUGIN', 'FLUSH', 'KILL', + 'RESET', 'START', 'STOP', 'PURGE', 'EXECUTE', 'PREPARE', 'DEALLOCATE', 'LOCK', 'USING', 'DROP', 'FOR', 'UPDATE', 'BEGIN', 'BY', 'ALL', 'SHARE', + 'MODE', 'TO','KEY', 'DISTINCTROW', 'DISTINCT', 'HIGH_PRIORITY', 'LOW_PRIORITY', 'DELAYED', 'IGNORE', 'FORCE', 'STRAIGHT_JOIN', + 'SQL_SMALL_RESULT', 'SQL_BIG_RESULT', 'QUICK', 'SQL_BUFFER_RESULT', 'SQL_CACHE', 'SQL_NO_CACHE', 'SQL_CALC_FOUND_ROWS', 'WITH' + ) + ); - public $attributes = array('passwd' => '*******************', - 'secure_key' => '*******************'); + public $attributes = array( + 'passwd' => '*******************', + 'secure_key' => '*******************' + ); + /** @var array : list of errors */ public $error_sql = array(); + /** + * Get list of request SQL + * + * @static + * @return array|bool + */ public static function getRequestSql() { if (!$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT * FROM `'._DB_PREFIX_.'request_sql` ORDER BY `id_request_sql`')) return false; + $request_sql = array(); foreach ($result as $row) $request_sql[] = $row['sql']; + return $request_sql; } + /** + * Get list of request SQL by id request + * + * @static + * @param $id + * @return array + */ public static function getRequestSqlById($id) { return Db::getInstance()->executeS(sprintf('SELECT `sql` FROM `'._DB_PREFIX_.'request_sql` WHERE `id_request_sql` = %d', $id)); } + /** + * Call the parserSQL() method in Tools class + * Cut the request in table for check it + * + * @param $sql + * @return bool + */ public function parsingSql($sql) { return Tools::parserSQL($sql); } + /** + * Check if the parsing of the SQL request is good or not + * + * @param $tab + * @param bool $in + * @param $sql + * @return bool + */ public function validateParser($tab, $in = false, $sql) { if (!$tab) @@ -100,6 +142,14 @@ class RequestSqlCore extends ObjectModel return $this->validateSql($tab, $in, $sql); } + /** + * Cut the request for check each cutting + * + * @param $tab + * @param $in + * @param $sql + * @return bool + */ public function validateSql($tab, $in, $sql) { if (!$this->testedRequired($tab)) @@ -138,9 +188,15 @@ class RequestSqlCore extends ObjectModel if (empty($this->_errors)) if (!Db::getInstance()->executeS($sql)) return false; + return true; } + /** + * Get list of all tables + * + * @return array + */ public function getTables() { $results = Db::getInstance()->executeS('SHOW TABLES'); @@ -152,17 +208,30 @@ class RequestSqlCore extends ObjectModel return $tables; } + /** + * Get list of all attributes by an table + * + * @param $table + * @return array + */ public function getAttributesByTable($table) { return Db::getInstance()->executeS(sprintf('DESCRIBE %s', $table)); } + /** + * Cut an join sentence + * + * @param $attrs + * @param $from + * @return array|bool + */ public function cutJoin($attrs, $from) { $attrs = explode('=', str_replace(' ', '', $attrs)); foreach ($attrs as $attr) { - if ($attribut = $this->cutAttribute($attr, $from)) + if ($attribut = $this->cutAttribute(trim($attr), $from)) $tab[] = $attribut; else return false; @@ -170,6 +239,13 @@ class RequestSqlCore extends ObjectModel return $tab; } + /** + * Cut an attribute with or without the alias + * + * @param $attr + * @param $from + * @return array|bool + */ public function cutAttribute($attr, $from) { if (preg_match('#^((`(\()?([a-z_])+`(\))?)|((\()?([a-z_])+(\))?))\.((`(\()?([a-z_])+`(\))?)|((\()?([a-z_])+(\))?))$#i', $attr)) @@ -197,6 +273,13 @@ class RequestSqlCore extends ObjectModel return false; } + /** + * Get name of table by alias + * + * @param bool $alias + * @param $tables + * @return array|bool + */ public function returnNameTable($alias = false, $tables) { if ($alias) @@ -220,6 +303,13 @@ class RequestSqlCore extends ObjectModel } } + /** + * Check if an attributes existe in an table + * + * @param $attr + * @param $table + * @return bool + */ public function attributExistInTable($attr, $table) { if (is_array($table) && (count($table) == 1)) @@ -231,6 +321,12 @@ class RequestSqlCore extends ObjectModel return false; } + /** + * Check if all required sentence existing + * + * @param $tab + * @return bool + */ public function testedRequired($tab) { foreach ($this->tested['required'] as $key) @@ -242,6 +338,12 @@ class RequestSqlCore extends ObjectModel return true; } + /** + * Check if an unauthorized existing in an array + * + * @param $tab + * @return bool + */ public function testedUnauthorized($tab) { foreach ($this->tested['unauthorized'] as $key) @@ -253,6 +355,12 @@ class RequestSqlCore extends ObjectModel return true; } + /** + * Check a "FROM" sentence + * + * @param $from + * @return bool + */ public function checkedFrom($from) { $nb = count($from); @@ -295,6 +403,14 @@ class RequestSqlCore extends ObjectModel return true; } + /** + * Check a "SELECT" sentence + * + * @param $select + * @param $from + * @param bool $in + * @return bool + */ public function checkedSelect($select, $from, $in = false) { $nb = count($select); @@ -305,7 +421,7 @@ class RequestSqlCore extends ObjectModel { if ($attribut['expr_type'] == 'colref' || $attribut['expr_type'] == 'reserved') { - if ($attr = $this->cutAttribute($attribut['base_expr'], $from)) + if ($attr = $this->cutAttribute(trim($attribut['base_expr']), $from)) { if (!$this->attributExistInTable($attr['attribut'], $attr['table'])) { @@ -340,6 +456,14 @@ class RequestSqlCore extends ObjectModel return true; } + /** + * Check a "WHERE" sentence + * + * @param $where + * @param $from + * @param $sql + * @return bool + */ public function checkedWhere($where, $from, $sql) { $nb = count($where); @@ -348,7 +472,7 @@ class RequestSqlCore extends ObjectModel $attribut = $where[$i]; if ($attribut['expr_type'] == 'colref' || $attribut['expr_type'] == 'reserved') { - if ($attr = $this->cutAttribute($attribut['base_expr'], $from)) + if ($attr = $this->cutAttribute(trim($attribut['base_expr']), $from)) { if (!$this->attributExistInTable($attr['attribut'], $attr['table'])) { @@ -387,6 +511,13 @@ class RequestSqlCore extends ObjectModel return true; } + /** + * Check a "HAVING" sentence + * + * @param $having + * @param $from + * @return bool + */ public function checkedHaving($having, $from) { $nb = count($having); @@ -395,7 +526,7 @@ class RequestSqlCore extends ObjectModel $attribut = $having[$i]; if ($attribut['expr_type'] == 'colref') { - if ($attr = $this->cutAttribute($attribut['base_expr'], $from)) + if ($attr = $this->cutAttribute(trim($attribut['base_expr']), $from)) { if (!$this->attributExistInTable($attr['attribut'], $attr['table'])) { @@ -430,12 +561,19 @@ class RequestSqlCore extends ObjectModel return true; } + /** + * Check a "ORDER" sentence + * + * @param $order + * @param $from + * @return bool + */ public function checkedOrder($order, $from) { $order = $order[0]; if ($order['type'] == 'expression') { - if ($attr = $this->cutAttribute($order['base_expr'], $from)) + if ($attr = $this->cutAttribute(trim($order['base_expr']), $from)) { if (!$this->attributExistInTable($attr['attribut'], $attr['table'])) { @@ -460,12 +598,19 @@ class RequestSqlCore extends ObjectModel return true; } + /** + * Check a "GROUP BY" sentence + * + * @param $group + * @param $from + * @return bool + */ public function checkedGroupBy($group, $from) { $group = $group[0]; if ($group['type'] == 'expression') { - if ($attr = $this->cutAttribute($group['base_expr'], $from)) + if ($attr = $this->cutAttribute(trim($group['base_expr']), $from)) { if (!$this->attributExistInTable($attr['attribut'], $attr['table'])) { @@ -490,6 +635,12 @@ class RequestSqlCore extends ObjectModel return true; } + /** + * Check a "LIMIT" sentence + * + * @param $limit + * @return bool + */ public function checkedLimit($limit) { if (!preg_match('#^[0-9]+$#', trim($limit['start'])) || !preg_match('#^[0-9]+$#', trim($limit['end']))) diff --git a/controllers/admin/AdminRequestSqlController.php b/controllers/admin/AdminRequestSqlController.php index 2334ac18f..1533d3793 100644 --- a/controllers/admin/AdminRequestSqlController.php +++ b/controllers/admin/AdminRequestSqlController.php @@ -27,6 +27,14 @@ class AdminRequestSqlControllerCore extends AdminController { + /** + * @var array : List of encoding type for a file + */ + public static $encoding_file = array( + array('value' => 1, 'name' => 'utf-8'), + array('value' => 2, 'name' => 'iso-8859-1') + ); + public function __construct() { $this->table = 'request_sql'; @@ -42,13 +50,62 @@ class AdminRequestSqlControllerCore extends AdminController 'name' => array('title' => $this->l('Name'), 'width' => 300), 'sql' => array('title' => $this->l('Request'), 'width' => 500) ); + + $this->options = array( + 'general' => array( + 'title' => $this->l('Settings'), + 'fields' => array( + 'PS_ENCODING_FILE_MANAGER_SQL' => array( + 'title' => $this->l('Select your encoding file by default:'), + 'cast' => 'intval', + 'type' => 'select', + 'identifier' => 'value', + 'list' => self::$encoding_file, + 'visibility' => Shop::CONTEXT_ALL + ) + ), + 'submit' => array() + ) + ); + $this->bulk_actions = array('delete' => array('text' => $this->l('Delete selected'),'confirm' => $this->l('Delete selected items?'))); parent::__construct(); } + public function renderOptions() + { + // Set toolbar options + $this->display = 'options'; + $this->show_toolbar = true; + $this->toolbar_scroll = true; + $this->initToolbar(); + + return parent::renderOptions(); + } + + public function initToolbar() + { + if ($this->display == 'view' && $id_request = Tools::getValue('id_request_sql')) + $this->toolbar_btn['edit'] = array( + 'href' => self::$currentIndex.'&updaterequest_sql&token='.$this->token.'&id_request_sql='.(int)$id_request, + 'desc' => $this->l('Edit this request') + ); + + parent::initToolbar(); + + if ($this->display == 'options') + unset($this->toolbar_btn['new']); + else + unset($this->toolbar_btn['save']); + } + public function renderList() { + // Set toolbar options + $this->display = null; + $this->initToolbar(); + $this->displayWarning($this->l('When saving the query, only the request type "SELECT" are allowed.')); $this->displayInformation(' '.$this->l('How to create a new sql query?').' @@ -223,6 +280,9 @@ class AdminRequestSqlControllerCore extends AdminController )); } + /** + * Genrating a export file + */ public function generateExport() { $id = Tools::getValue($this->identifier); @@ -244,7 +304,7 @@ class AdminRequestSqlControllerCore extends AdminController { fputs($csv, "\n"); foreach ($tab_key as $name) - fputs($csv, '"'.Tools::safeOutput($result[$name]).'";'); + fputs($csv, '"'.strip_tags($result[$name]).'";'); } if (file_exists(_PS_ADMIN_DIR_.'/export/'.$file)) { @@ -252,7 +312,12 @@ class AdminRequestSqlControllerCore extends AdminController $upload_max_filesize = $this->returnBytes(ini_get('upload_max_filesize')); if ($filesize < $upload_max_filesize) { - header('Content-type: text/csv'); + if (Configuration::get('PS_ENCODING_FILE_MANAGER_SQL')) + $charset = Configuration::get('PS_ENCODING_FILE_MANAGER_SQL'); + else + $charset = self::$encoding_file[0]['name']; + + header('Content-Type: text/csv; charset='.$charset); header('Cache-Control: no-store, no-cache'); header('Content-Disposition: attachment; filename="'.$file.'"'); header('Content-Length: '.$filesize); @@ -266,6 +331,12 @@ class AdminRequestSqlControllerCore extends AdminController } } + /** + * Get number of bytes + * + * @param $val + * @return int|string + */ public function returnBytes($val) { $val = trim($val); @@ -282,6 +353,11 @@ class AdminRequestSqlControllerCore extends AdminController return $val; } + /** + * Display all errors + * + * @param $e : array of errors + */ public function displayError($e) { foreach (array_keys($e) as $key) diff --git a/translations/fr/admin.php b/translations/fr/admin.php index e44e8ee1b..51dfc9e3b 100644 --- a/translations/fr/admin.php +++ b/translations/fr/admin.php @@ -3043,6 +3043,7 @@ $_LANGADM['AdminRequestSql4e140ba723a03baa6948340bf90e2ef6'] = 'Nom : '; $_LANGADM['AdminRequestSql500ed780c28b031ff17cf9415f170bd0'] = 'La table'; $_LANGADM['AdminRequestSql503d56551bb8c49dc062e28df2d5c347'] = 'Ajouter une table'; $_LANGADM['AdminRequestSql5e4d646cb0cba34ec216552319c41fa6'] = 'Liste des tables MySQL:'; +$_LANGADM['AdminRequestSql5ee1c8222479e0b3fa99c9079e4e1f41'] = 'Sélectionner votre encodage de fichier par défaut'; $_LANGADM['AdminRequestSql62a66bd7e2f1feae6d2eb45ec251c141'] = 'Cette requête n\'a pas de résultat.'; $_LANGADM['AdminRequestSql888cb3575217d185929dee26268c285b'] = 'n\'existe pas dans la table : '; $_LANGADM['AdminRequestSql8b1c81b3ab3def7adeab2092dde06c01'] = 'n\'existe pas dans : '; @@ -3056,6 +3057,7 @@ $_LANGADM['AdminRequestSqlab1d92ebad371934228c8b85f65fa449'] = 'Requête : '; $_LANGADM['AdminRequestSqlb718adec73e04ce3ec720dd11a06a308'] = 'ID'; $_LANGADM['AdminRequestSqlb7ccdf6ab58f5514acc520721ddc9f08'] = 'Remplissez les champs et cliquez sur \"Enregistrer\".'; $_LANGADM['AdminRequestSqlb8bf3ffcbb8025ef76f8d67fff0cdf2b'] = 'Cliquez sur \"Créer\".'; +$_LANGADM['AdminRequestSqlc0c5ed95f9249b70bb6e70763e55a4e5'] = 'Modifier cette requête'; $_LANGADM['AdminRequestSqlc9cc8cce247e49bae79f15173ce97354'] = 'Enregistrer'; $_LANGADM['AdminRequestSqld3b206d196cd6be3a2764c1fb90b200f'] = 'Supprimer la sélection'; $_LANGADM['AdminRequestSqle25f0ecd41211b01c83e5fec41df4fe7'] = 'Supprimer les éléments sélectionnés ?'; @@ -3064,6 +3066,7 @@ $_LANGADM['AdminRequestSqlf102493313886fbc48767cac746083ec'] = 'Ajouter un attri $_LANGADM['AdminRequestSqlf262813987f17120ffae515b59e74905'] = 'Lors de l\'enregistrement de la requête, seul les requêtes de type \"SELECT\" sont autorisées.'; $_LANGADM['AdminRequestSqlf2bbdf9f72c085adc4d0404e370f0f4c'] = 'Attribut'; $_LANGADM['AdminRequestSqlf4d1b953eb8ff1f32c0c23a27fddc2e5'] = 'L\'opérande \"*\" ne peut être utilisée dans une requête imbriquée.'; +$_LANGADM['AdminRequestSqlf4f70727dc34561dfde1a3c529b6205c'] = 'Paramètres'; $_LANGADM['AdminReturn004bf6c9a40003140292e97330236c53'] = 'Outils'; $_LANGADM['AdminReturn24a23d787190f2c4812ff9ab11847a72'] = 'État :'; $_LANGADM['AdminReturn2ca3deb5cd68fa9119b285804fab572f'] = 'Commande :';