Repository: erikdubbelboer/phpRedisAdmin (language: php)

Issue:
Unable to delete keys with comma(s)
My keys list:

![изображение](https://user-images.githubusercontent.com/2164874/196998078-33c9b5f2-9b6e-4561-9305-92f43a25483b.png)

I select `Articles.All(rid=11,did=14,page=12)` and press "Delete selected"

Nothing changed, but I recieved:

![изображение](https://user-images.githubusercontent.com/2164874/196998450-a5fc4771-40f8-40c0-863c-a9fe2f74a816.png)

`Select All -> Delete selected` broken too with same situation on screen above

Click on key 

![изображение](https://user-images.githubusercontent.com/2164874/196998760-50c7bad7-6307-441d-8863-906417e02f08.png)

and click on red cross works, with answer:

![изображение](https://user-images.githubusercontent.com/2164874/196998935-e6e29cb9-483e-4294-9f90-cd967a397b24.png)
(just as planned)

P.S. Keys with `(`, `)` and `,` allowed by redis:

![изображение](https://user-images.githubusercontent.com/2164874/196999403-a22012ef-1f9b-42b7-8d9e-e8aa527772cd.png)




Discussion / hints:
Update: 

Problem with `,` symbol. 

![изображение](https://user-images.githubusercontent.com/2164874/197002487-590321c7-b2c0-4d68-8f74-000a8adcc353.png)

I can't seem to reproduce this. But I see in some of your screenshots that the last `)` seems to be missing. Do you have any idea what might be causing this?

Can you give me some steps to reproduce this on an empty database? Like which keys to create and which buttons to press?
![изображение](https://user-images.githubusercontent.com/2164874/197336755-e85b0f13-f77b-4ffb-950f-fee8e9077fde.png)

Press "+ Add another key"

![изображение](https://user-images.githubusercontent.com/2164874/197336788-e9b09dac-2021-4556-912b-52a195de6f33.png)

Press "Add"

![изображение](https://user-images.githubusercontent.com/2164874/197336801-abab79f7-29ea-4ac1-b9e8-d4ff9febcfda.png)

All okey... may be...

Press "Select all"

![изображение](https://user-images.githubusercontent.com/2164874/197336814-3fcb0c1d-76ad-425c-a78d-e5db95ce231e.png)

Press "Delete selected"

Requested:

```
POST http://redisadmin.local/delete.php?s=0&d=0&batch_del=1&csrf=7849468d849021992208f318eff7a30c
```

Answer:
```
?view&s=0&d=0&key=Articles%28x%3D1
```
![изображение](https://user-images.githubusercontent.com/2164874/197336824-4e3d76f3-89fc-473f-ba08-7e8ee609d715.png)

Click on key again: 

![изображение](https://user-images.githubusercontent.com/2164874/197336834-b39f3d49-c735-4e36-88e9-2043c4104352.png)

Already present. 

Looks like problem in on frontend, because POST request have broken data:

![изображение](https://user-images.githubusercontent.com/2164874/197337045-d2d41d5f-a544-4f06-863e-53e6390de68e.png)

so, https://github.com/erikdubbelboer/phpRedisAdmin/blob/master/delete.php#L63 will recieve only
```
"Articles(x"
```

I think, problem is here: 

A bit later (average at ~ evening of sunday) I can make pull request :)

I think, problem is here: 
https://github.com/erikdubbelboer/phpRedisAdmin/blob/master/js/index.js#L31
'post=1&selected_keys=' + selected_keys + '&csrf=' + phpRedisAdmin_csrfToken
```
data: {
post: 1,
selected_keys: JSON.stringify(selected_keys),
csrf: phpRedisAdmin_csrfToken
}
```
+ json_decode of given data on backside (or not, testing required)
Good find, that definitely needs to be turned into a JSON body. If you can make a pull request that would be great!

Fix patch:
diff --git a/composer.json b/composer.json
index 50c18ee..3136710 100644
--- a/composer.json
+++ b/composer.json
@@ -13,6 +13,8 @@
         }
     ],
     "require": {
+        "ext-mbstring": "*",
+        "ext-json": "*",
         "predis/predis": "v1.1.9",
         "paragonie/random_compat": ">=2"
     },
diff --git a/delete.php b/delete.php
index cde8539..c329919 100644
--- a/delete.php
+++ b/delete.php
@@ -1,13 +1,13 @@
 <?php
 
-
 if (!isset($_POST['post'])) {
   die('Javascript needs to be enabled for you to delete keys.');
 }
 
-
 require_once 'includes/common.inc.php';
 
+global $redis;
+global $server;
 
 if (isset($_GET['key'])) {
   // String
@@ -61,11 +61,11 @@
 }
 
 if (isset($_GET['batch_del'])) {
-  $keys = $_POST['selected_keys'];
-  $keys = trim($keys, ',');
-  if (empty($keys)) die('No keys to delete');
+  if (empty($_POST['selected_keys'])) {
+    die('No keys to delete');
+  }
+  $keys = json_decode($_POST['selected_keys']);
 
-  $keys = explode(',', $keys);
   foreach ($keys as $key) {
     $redis->del($key);
   }
@@ -73,4 +73,3 @@
   die('?view&s=' . $server['id'] . '&d=' . $server['db'] . '&key=' . urlencode($keys[0]));
 }
 
-?>
diff --git a/edit.php b/edit.php
index 0e0b360..6f3fd20 100644
--- a/edit.php
+++ b/edit.php
@@ -2,8 +2,7 @@
 
 require_once 'includes/common.inc.php';
 
-
-
+global $redis, $config, $csrfToken, $server;
 
 // Are we editing or creating a new key?
 $edit = false;
@@ -192,4 +191,4 @@
 
 require 'includes/footer.inc.php';
 
-?>
+?>
\ No newline at end of file
diff --git a/export.php b/export.php
index 2812705..d17839e 100644
--- a/export.php
+++ b/export.php
@@ -2,6 +2,7 @@
 
 require_once 'includes/common.inc.php';
 
+global $redis, $config, $csrfToken, $server;
 
 // Export to redis-cli commands
 function export_redis($key, $filter = false, $transform = false) {
diff --git a/flush.php b/flush.php
index 4e74489..c8fc1f5 100644
--- a/flush.php
+++ b/flush.php
@@ -1,13 +1,11 @@
 <?php
 
-
 if (!isset($_POST['post'])) {
   die('Javascript needs to be enabled for you to flush a database.');
 }
 
-
 require_once 'includes/common.inc.php';
-
+global $redis, $config, $csrfToken, $server;
 
 $redis->flushdb();
 
diff --git a/import.php b/import.php
index e9176dc..5e5a89e 100644
--- a/import.php
+++ b/import.php
@@ -1,9 +1,7 @@
 <?php
 
 require_once 'includes/common.inc.php';
-
-
-
+global $redis, $config, $csrfToken, $server;
 
 // This mess could need some cleanup!
 if (isset($_POST['commands'])) {
diff --git a/includes/common.inc.php b/includes/common.inc.php
index cfa5059..ae0bd52 100644
--- a/includes/common.inc.php
+++ b/includes/common.inc.php
@@ -1,9 +1,8 @@
 <?php
-require dirname(__FILE__) . '/../vendor/autoload.php';
+require __DIR__ . '/../vendor/autoload.php';
 
 define('PHPREDIS_ADMIN_PATH', dirname(__DIR__));
 
-
 if (session_status() !== PHP_SESSION_DISABLED) {
   session_start();
 
@@ -44,7 +43,6 @@
   $i = 0;
 }
 
-
 if (isset($_GET['s']) && is_numeric($_GET['s']) && ($_GET['s'] < count($config['servers']))) {
   $i = $_GET['s'];
 }
@@ -53,10 +51,8 @@
 $server['id']      = $i;
 $server['charset'] = isset($server['charset']) && $server['charset'] ? $server['charset'] : false;
 
-
 mb_internal_encoding('utf-8');
 
-
 if (isset($login, $login['servers'])) {
   if (array_search($i, $login['servers']) === false) {
     die('You are not allowed to access this database.');
@@ -142,5 +138,3 @@
     die('ERROR: Selecting database failed ('.$server['host'].':'.$server['port'].','.$server['db'].')');
   }
 }
-
-?>
diff --git a/includes/page.inc.php b/includes/page.inc.php
index 2f1a0e9..2941e68 100644
--- a/includes/page.inc.php
+++ b/includes/page.inc.php
@@ -1,6 +1,5 @@
 <?php
 
-
 // Returns true when the user is using IE
 function is_ie() {
   if (isset($_SERVER['HTTP_USER_AGENT']) &&
@@ -11,9 +10,6 @@ function is_ie() {
   }
 }
 
-
-
-
 $page = array(
   'css' => array('common'),
   'js'  => array('jquery')
diff --git a/index.php b/index.php
index be7c9d8..94dd90a 100644
--- a/index.php
+++ b/index.php
@@ -1,6 +1,7 @@
 <?php
 
 require_once 'includes/common.inc.php';
+global $redis, $config, $csrfToken, $server;
 
 if($redis) {
 
@@ -33,7 +34,7 @@
         continue;
       }
 
-      $key = explode($server['seperator'], $key);
+      $key = explode($server['seperator'], $key); //@todo: may be separator ?
       if ($config['showEmptyNamespaceAsKey'] && $key[count($key) - 1] == '') {
         array_pop($key);
         $key[count($key) - 1] .= ':';
diff --git a/info.php b/info.php
index d657533..77c6a3d 100644
--- a/info.php
+++ b/info.php
@@ -1,9 +1,7 @@
 <?php
 
 require_once 'includes/common.inc.php';
-
-
-
+global $redis, $config, $csrfToken, $server;
 
 if (isset($_GET['reset'])) {
   $redis->config('resetstat');
@@ -12,15 +10,10 @@
   die;
 }
 
-
-
 // Fetch the info
 $info = $redis->info();
 $alt  = false;
 
-
-
-
 $page['css'][] = 'frame';
 $page['js'][]  = 'frame';
 
diff --git a/js/frame.js b/js/frame.js
index 1a77e34..0196452 100644
--- a/js/frame.js
+++ b/js/frame.js
@@ -3,14 +3,12 @@ $(function() {
     window.parent.history.replaceState({}, '', document.location.href.replace('?', '&').replace(/\/([a-z]*)\.php/, '/?$1'));
   }
 
-
   $('#type').change(function(e) {
     $('#hkeyp' ).css('display', e.target.value == 'hash' ? 'block' : 'none');
     $('#indexp').css('display', e.target.value == 'list' ? 'block' : 'none');
     $('#scorep').css('display', e.target.value == 'zset' ? 'block' : 'none');
   }).change();
 
-
   $('.delkey, .delval').click(function(e) {
     e.preventDefault();
 
diff --git a/js/index.js b/js/index.js
index a3ba627..a3f3414 100644
--- a/js/index.js
+++ b/js/index.js
@@ -14,13 +14,13 @@ $(function() {
   })
 
   $('#sidebar').on('click', 'a', function(e) {
-    if (e.currentTarget.className.indexOf('batch_del') !== -1){
+    if (e.currentTarget.className.indexOf('batch_del') !== -1) {
       e.preventDefault();
-      var selected_keys = '';
+      var selected_keys = [];
       $('input[name=checked_keys]:checked').each(function () {
-        selected_keys += $(this).val() + ',';
+        selected_keys.push($(this).val());
       });
-      if (!selected_keys) {
+      if (selected_keys.length == 0) {
         alert('Please select the keys you want to delete.');
         return;
       }
@@ -28,20 +28,27 @@ $(function() {
         $.ajax({
           type: "POST",
           url: this.href,
-          data: 'post=1&selected_keys=' + selected_keys + '&csrf=' + phpRedisAdmin_csrfToken,
+          data: {
+            post: 1,
+            selected_keys: JSON.stringify(selected_keys),
+            csrf: phpRedisAdmin_csrfToken
+          },
           success: function(url) {
             top.location.href = top.location.pathname+url;
           }
         });
       }
-    }else if (e.currentTarget.className.indexOf('deltree') !== -1) {
+    } else if (e.currentTarget.className.indexOf('deltree') !== -1) {
       e.preventDefault();
 
       if (confirm('Are you sure you want to delete this whole tree and all it\'s keys?')) {
         $.ajax({
           type: "POST",
           url: this.href,
-          data: 'post=1&csrf=' + phpRedisAdmin_csrfToken,
+          data: {
+            post: 1,
+            csrf: phpRedisAdmin_csrfToken
+          },
           success: function(url) {
             top.location.href = top.location.pathname+url;
           }
@@ -74,7 +81,10 @@ $(function() {
           $.ajax({
             type: "POST",
             url: href,
-            data: 'post=1&csrf=' + phpRedisAdmin_csrfToken,
+            data: {
+              post: 1,
+              csrf: phpRedisAdmin_csrfToken
+            },
             success: function() {
               window.location.reload();
             }
diff --git a/login.php b/login.php
index 298b32f..a80a24c 100644
--- a/login.php
+++ b/login.php
@@ -2,6 +2,7 @@
 define('LOGIN_PAGE', true);
 
 require_once 'includes/common.inc.php';
+global $redis, $config, $csrfToken, $server;
 
 $page['css'][] = 'login';
 
diff --git a/logout.php b/logout.php
index 44b1785..12cc80b 100644
--- a/logout.php
+++ b/logout.php
@@ -1,6 +1,7 @@
 <?php
 
 require_once 'includes/common.inc.php';
+global $redis, $config, $csrfToken, $server;
 
 if (!empty($config['cookie_auth'])) {
     // Cookie-based auth
diff --git a/overview.php b/overview.php
index 007e2d6..3e426db 100644
--- a/overview.php
+++ b/overview.php
@@ -1,9 +1,7 @@
 <?php
 
 require_once 'includes/common.inc.php';
-
-
-
+global $redis, $config, $csrfToken, $server;
 
 $info = array();
 
@@ -109,7 +107,7 @@
 </p>
 
 <p>
-<a href="http://redis.io/documentation" target="_blank">Redis Documentation</a>
+<a href="https://redis.io/documentation" target="_blank">Redis Documentation</a>
 </p>
 <?php
 
diff --git a/rename.php b/rename.php
index 5a878ba..f744c48 100644
--- a/rename.php
+++ b/rename.php
@@ -1,9 +1,7 @@
 <?php
 
 require_once 'includes/common.inc.php';
-
-
-
+global $redis, $config, $csrfToken, $server;
 
 if (isset($_POST['old'], $_POST['key'])) {
   if (strlen($_POST['key']) > $config['maxkeylen']) {
diff --git a/save.php b/save.php
index 3154e8c..ef8b1d8 100644
--- a/save.php
+++ b/save.php
@@ -1,9 +1,7 @@
 <?php
 
 require_once 'includes/common.inc.php';
-
-
-
+global $redis, $config, $csrfToken, $server;
 
 $page['css'][] = 'frame';
 $page['js'][]  = 'frame';
diff --git a/ttl.php b/ttl.php
index 1a50008..92e6cca 100644
--- a/ttl.php
+++ b/ttl.php
@@ -1,9 +1,7 @@
 <?php
 
 require_once 'includes/common.inc.php';
-
-
-
+global $redis, $config, $csrfToken, $server;
 
 if (isset($_POST['key'], $_POST['ttl'])) {
   if ($_POST['ttl'] == -1) {
@@ -16,9 +14,6 @@
   die;
 }
 
-
-
-
 $page['css'][] = 'frame';
 $page['js'][]  = 'frame';
 
diff --git a/view.php b/view.php
index e33bcae..1836979 100644
--- a/view.php
+++ b/view.php
@@ -1,14 +1,13 @@
 <?php
 
 require_once 'includes/common.inc.php';
+global $redis, $config, $csrfToken, $server;
 
 $page['css'][] = 'frame';
 $page['js'][]  = 'frame';
 
 require 'includes/header.inc.php';
 
-
-
 if (!isset($_GET['key'])) {
   ?>
   Invalid key
@@ -18,8 +17,6 @@
   die;
 }
 
-
-
 $type   = $redis->type($_GET['key']);
 $exists = $redis->exists($_GET['key']);
 
@@ -27,8 +24,6 @@
 $page_num_request    = isset($_GET['page']) ? (int)$_GET['page'] : 1;
 $page_num_request    = $page_num_request === 0 ? 1 : $page_num_request;
 
-
-
 ?>
 <h2><?php echo format_html($_GET['key'])?>
 <?php if ($exists) { ?>
@@ -48,8 +43,6 @@
   die;
 }
 
-
-
 $alt      = false;
 $ttl      = $redis->ttl($_GET['key']);
 
@@ -59,7 +52,6 @@
   $encoding = null;
 }
 
-
 switch ($type) {
   case 'string':
     $value = $redis->get($_GET['key']);


Test patch: