|
|
@@ -74,13 +74,22 @@ class CharMail extends Model
|
|
|
|
|
|
private function decodeBinaryValue(?string $value): ?string
|
|
|
{
|
|
|
+ // Удаляем завершающие нули – они часто встречаются в char( n ) столбцах
|
|
|
$value = $this->stripNulls($value);
|
|
|
if ($value === null || $value === '') {
|
|
|
return $value;
|
|
|
}
|
|
|
|
|
|
- $decoded = $this->decodeBase64($this->decodeBase64($value));
|
|
|
- $decoded = $this->stripNulls($decoded);
|
|
|
+ // Пробуем декодировать максимум два раза (схема хранения – двойной base64)
|
|
|
+ $decoded = $value;
|
|
|
+ for ($i = 0; $i < 2; $i++) {
|
|
|
+ $tmp = base64_decode($decoded, true);
|
|
|
+ if ($tmp === false) {
|
|
|
+ // Строка не похожа на base64 – прекращаем попытки
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ $decoded = $this->stripNulls($tmp);
|
|
|
+ }
|
|
|
|
|
|
return $decoded === null ? null : $this->ensureUtf8($decoded);
|
|
|
}
|
|
|
@@ -92,11 +101,23 @@ class CharMail extends Model
|
|
|
return $value;
|
|
|
}
|
|
|
|
|
|
+ // Если строка уже дважды закодирована – ничего не делаем
|
|
|
+ if ($this->isBase64($value)) {
|
|
|
+ $inner = base64_decode($value, true);
|
|
|
+ if ($inner !== false && $this->isBase64($inner)) {
|
|
|
+ return $value; // уже двойной base64
|
|
|
+ }
|
|
|
+ // Если только один слой – добавляем ещё один
|
|
|
+ return base64_encode($value);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Конвертируем в CP1251 (игровой клиент ожидает именно эту кодировку)
|
|
|
$prepared = @iconv('UTF-8', 'CP1251//IGNORE', $value);
|
|
|
if ($prepared === false) {
|
|
|
- $prepared = $value;
|
|
|
+ $prepared = $value; // если iconv не смог – используем как есть
|
|
|
}
|
|
|
|
|
|
+ // Двойное кодирование base64
|
|
|
return base64_encode(base64_encode($prepared));
|
|
|
}
|
|
|
|
|
|
@@ -105,10 +126,17 @@ class CharMail extends Model
|
|
|
return $value === null ? null : rtrim($value, "\0");
|
|
|
}
|
|
|
|
|
|
- private function decodeBase64(string $value): string
|
|
|
+ // Более лояльная проверка base64 (без строгого ===, учитываем отсутствие отступов и символы \r\n)
|
|
|
+ private function isBase64(string $value): bool
|
|
|
{
|
|
|
- $decoded = base64_decode($value, true);
|
|
|
- return $decoded === false ? $value : $decoded;
|
|
|
+ if ($value === '') {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // Проверяем набор допустимых символов и кратность 4
|
|
|
+ if (preg_match('/^[A-Za-z0-9+\/\r\n]+=*$/', $value) !== 1) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return (strlen($value) % 4 === 0);
|
|
|
}
|
|
|
|
|
|
private function ensureUtf8(string $value): string
|
|
|
@@ -160,6 +188,20 @@ class CharMail extends Model
|
|
|
public function toArray()
|
|
|
{
|
|
|
$array = parent::toArray();
|
|
|
+
|
|
|
+ // Явно декодируем бинарные поля, на случай если accessor не сработал при сериализации
|
|
|
+ if (array_key_exists('binTitle', $this->attributes)) {
|
|
|
+ $array['binTitle'] = $this->decodeBinaryValue($this->attributes['binTitle']);
|
|
|
+ } elseif (array_key_exists('binTitle', $array)) {
|
|
|
+ $array['binTitle'] = $this->decodeBinaryValue($array['binTitle']);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (array_key_exists('binLetter', $this->attributes)) {
|
|
|
+ $array['binLetter'] = $this->decodeBinaryValue($this->attributes['binLetter']);
|
|
|
+ } elseif (array_key_exists('binLetter', $array)) {
|
|
|
+ $array['binLetter'] = $this->decodeBinaryValue($array['binLetter']);
|
|
|
+ }
|
|
|
+
|
|
|
array_walk_recursive($array, function (&$v) {
|
|
|
if (is_string($v)) {
|
|
|
$v = $this->ensureUtf8($v);
|