| @@ -148,9 +148,26 @@ | ||
| 148 | 148 | } |
| 149 | 149 | |
| 150 | 150 | return [ |
| 151 | 151 | 'name' => $name, |
| 152 | - 'value' => mb_strcut($value, 0, self::MAX_VALUE_BYTES), | |
| 152 | + 'value' => self::cut($value, self::MAX_VALUE_BYTES), | |
| 153 | 153 | 'truncated' => 'Cut after ' . self::MAX_VALUE_BYTES . ' bytes, of ' . $size . ' the option holds.', |
| 154 | 154 | ]; |
| 155 | + } | |
| 156 | + | |
| 157 | + /** | |
| 158 | + * Cut at a byte cap without splitting a multibyte character. | |
| 159 | + * | |
| 160 | + * @param string $value The string to cut. | |
| 161 | + * @param integer $bytes The cap. | |
| 162 | + * @return string | |
| 163 | + */ | |
| 164 | + private static function cut($value, $bytes) | |
| 165 | + { | |
| 166 | + // A UTF-8 lead byte the cap separated from its continuation bytes. | |
| 167 | + return (string) preg_replace( | |
| 168 | + '/(?:[\xC2-\xDF]|[\xE0-\xEF][\x80-\xBF]?|[\xF0-\xF4][\x80-\xBF]{0,2})$/D', | |
| 169 | + '', | |
| 170 | + substr($value, 0, $bytes) | |
| 171 | + ); | |
| 155 | 172 | } |
| 156 | 173 | } |