Laravelでtextareaのmaxlengthと、ValidationRuleのmaxが改行によって判定ずれする

# 何が起こったか
例えば maxlength=10のtextareaがあったとして、このような入力をする。

```
1[改行]
2[改行]
3[改行]
4[改行]
5[改行]
```

```html:form.html
<html>
(省略)
  <textarea name="body_text" maxlength="10"></textarea>
(省略)
</html>
```
FormRequestを継承したRequestFileでこういうRuleを指定したとすると、弾かれてしまう。

```php:XxxRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
class InformationRegistrationRequest extends FormRequest
{
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'body_text' => ['max:10'],
        ];
    }
}
```

# なぜ弾かれるか
原因は、この問題が再現した環境の改行コード差異。

|役割|OS|改行コード|
|:--:|:--:|:--:|
|Client側| Windows|\r\n|
|Server側|Linux|\n|

Client側では、`\r\n`は1文字として扱われるが、Server側では、maxルールで使われている`mb_strlen()`により2文字にカウントされてしまう。
`vendor\laravel\framework\src\Illuminate\Validation\Concerns\ValidatesAttributes.php`

```php:ValidatesAttributes.php
namespace Illuminate\Validation\Concerns;
trait ValidatesAttributes
{
(省略)
    /**
     * Validate the size of an attribute is less than a maximum value.
     *
     * @param  string  $attribute
     * @param  mixed   $value
     * @param  array   $parameters
     * @return bool
     */
    public function validateMax($attribute, $value, $parameters)
    {
        $this->requireParameterCount(1, $parameters, 'max');

        if ($value instanceof UploadedFile && ! $value->isValid()) {
            return false;
        }

        return $this->getSize($attribute, $value) <= $parameters[0];
    }
(省略)
    /**
     * Get the size of an attribute.
     *
     * @param  string  $attribute
     * @param  mixed   $value
     * @return mixed
     */
    protected function getSize($attribute, $value)
    {
        $hasNumeric = $this->hasRule($attribute, $this->numericRules);

        // This method will determine if the attribute is a number, string, or file and
        // return the proper size accordingly. If it is a number, then number itself
        // is the size. If it is a file, we take kilobytes, and for a string the
        // entire length of the string will be considered the attribute size.
        if (is_numeric($value) && $hasNumeric) {
            return $value;
        } elseif (is_array($value)) {
            return count($value);
        } elseif ($value instanceof File) {
            return $value->getSize() / 1024;
        }

        return mb_strlen($value); // <----------------------- ここ
    }
(省略)
}
```

## やったこと
てっとりばやく、かつ見逃しにくい方法として、バリデーション実行前に改行コードを上書きすることにした。
（ミドルウェアで変換するなども検討したものの、変換処理を見逃しそうだなと考えて保留、もっといい方法がある気がする。）
FormRequestの`validationData`をOverRideし、`\r\n`を`\n`へ変換する。

```php:XxxRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
class InformationRegistrationRequest extends FormRequest
{
    /**
     * @overRide
     * Get data to be validated from the request.
     *
     * @return array
     */
    protected function validationData()
    {
        $all =  $this->all();
        if (isset($all['body_text'])) {
            $all['body_text'] = preg_replace("/\r\n/", "\n", $all['body_text']);
        }
        return $all;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'body_text' => ['max:10'],
        ];
    }
}
```

# 注意点
Controllerで入力値を受け取る時は、バリデートされた値を取得する`validated()`を利用しないと、変換後のデータを取ってこれない。

```php:XxxController.ophp
<?php

namespace App\Http\Controllers;

use App\Http\Requests\XxxRequest;
class XxxController extends Controller
{
    public function register(XxxRequest $request)
    {
        $input = $request->validated();        // "1\n1\n2\n1\n3\n4\n5" ←OK
        $input = $request->body_text;          // "1\r\n1\r\n2\r\n1\r\n3\r\n4\r\n5" ←NG
        $input = $request->input('body_text'); // "1\r\n1\r\n2\r\n1\r\n3\r\n4\r\n5" ←NG
    }
}

```