Repository: codeigniter4/CodeIgniter4 (PHP)

Issue:
Bug: [Validation] JSON data causes Array to string conversion Error
### PHP Version

8.1

### CodeIgniter4 Version

4.2.5

### CodeIgniter4 Installation Method

Manual (zip or tar.gz)

### Which operating systems have you tested for this bug?

Linux

### Which server did you use?

apache

### Database

Mariadb

### What happened?

Validation error occurs when try to validate an array 

Looks like validation doesn't accept multi array with key (using implode function)
```php
if (is_array($value)) {
    $value = '[' . implode(', ', $value) . ']'; // error when array with keys needs to be validated
} elseif (is_object($value)) {
    $value = json_encode($value);
}
```

Error message as below
```json
{
    "title": "ErrorException",
    "type": "ErrorException",
    "code": 500,
    "message": "Array to string conversion",
    "file": "/var/www/src/system/Validation/Validation.php",
    "line": 331,
    "trace": [
        {
            "function": "errorHandler",
            "class": "CodeIgniter\\Debug\\Exceptions",
            "type": "->",
            "args": [
                2,
                "Array to string conversion",
                "/var/www/src/system/Validation/Validation.php",
                331
            ]
        },
        {
            "file": "/var/www/src/system/Validation/Validation.php",
            "line": 331,
            "function": "implode",
            "args": [
...
```

### Steps to Reproduce

Data is send in `application/json` format
```json
{
    "p": [
        {
            "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
        }
    ]
}
```

My validation Rule
```php
public function array_length($value, $length): bool
{
    return (is_array($value) && count($value) === (int) $length);
}
```

### Expected Output

Validation run correctly

### Anything else?

_No response_


Discussion:
What's the exact validation rules?

I think u can using alternative validation with

```
        /**
        * Sample Data
        * 
        * $data = [
        *    'p' => [
        *        ['id' => null],
        *        ['id' => null],
        *    ],
        * ];
        * /
        $sourceData = json_decode($data, TRUE);

        $this->validation->setRules(
            ['p.*.id' => ['label' => 'ID', 'rules' => 'max_length[3]']]
        );

        $this->validation->run($sourceData);
```
@kenjis 
@ddevsr 
here are my validation rules
```
[
    'p' => 'required|array_length[1]'
]
```
i need to validate than `p` is an array with the exact length of `1`
@shishamo Thank you. I confirmed this bug.
I sent a PR #6467

Thanks a lot @kenjis !



Patch:
diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php
index ed370a2f5c08..68557eed4083 100644
--- a/system/Validation/Validation.php
+++ b/system/Validation/Validation.php
@@ -328,7 +328,9 @@ protected function processRules(
             if ($passed === false) {
                 // if the $value is an array, convert it to as string representation
                 if (is_array($value)) {
-                    $value = '[' . implode(', ', $value) . ']';
+                    $value = $this->isStringList($value)
+                        ? '[' . implode(', ', $value) . ']'
+                        : json_encode($value);
                 } elseif (is_object($value)) {
                     $value = json_encode($value);
                 }
@@ -351,6 +353,32 @@ protected function processRules(
         return true;
     }
 
+    /**
+     * Is the array a string list `list<string>`?
+     */
+    private function isStringList(array $array): bool
+    {
+        $expectedKey = 0;
+
+        foreach ($array as $key => $val) {
+            // Note: also covers PHP array key conversion, e.g. '5' and 5.1 both become 5
+            if (! is_int($key)) {
+                return false;
+            }
+
+            if ($key !== $expectedKey) {
+                return false;
+            }
+            $expectedKey++;
+
+            if (! is_string($val)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     /**
      * Takes a Request object and grabs the input data to use from its
      * array values.


Test patch:
diff --git a/tests/_support/Validation/TestRules.php b/tests/_support/Validation/TestRules.php
index 507d17ef89bf..e44b9d459fc7 100644
--- a/tests/_support/Validation/TestRules.php
+++ b/tests/_support/Validation/TestRules.php
@@ -32,4 +32,9 @@ public function check_object_rule(object $value, ?string $fields, array $data =
 
         return $find;
     }
+
+    public function array_count($value, $count): bool
+    {
+        return is_array($value) && count($value) === (int) $count;
+    }
 }
diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php
index 5a48615b6c05..e5443eba1938 100644
--- a/tests/system/Validation/ValidationTest.php
+++ b/tests/system/Validation/ValidationTest.php
@@ -641,6 +641,42 @@ public function testJsonInput(): void
         unset($_SERVER['CONTENT_TYPE']);
     }
 
+    /**
+     * @see https://github.com/codeigniter4/CodeIgniter4/issues/6466
+     */
+    public function testJsonInputObjectArray(): void
+    {
+        $json = <<<'EOL'
+            {
+                "p": [
+                    {
+                        "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+                    }
+                ]
+            }
+            EOL;
+
+        $_SERVER['CONTENT_TYPE'] = 'application/json';
+
+        $config          = new App();
+        $config->baseURL = 'http://example.com/';
+
+        $request = new IncomingRequest($config, new URI(), $json, new UserAgent());
+
+        $rules = [
+            'p' => 'required|array_count[2]',
+        ];
+        $validated = $this->validation
+            ->withRequest($request->withMethod('patch'))
+            ->setRules($rules)
+            ->run();
+
+        $this->assertFalse($validated);
+        $this->assertSame(['p' => 'Validation.array_count'], $this->validation->getErrors());
+
+        unset($_SERVER['CONTENT_TYPE']);
+    }
+
     public function testHasRule(): void
     {
         $this->validation->setRuleGroup('groupA');