BinaryTextCast.php 4.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. <?php
  2. namespace App\Casts;
  3. use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
  4. use Illuminate\Support\Facades\DB;
  5. /**
  6. * Class BinaryTextCast
  7. *
  8. * Пользовательский класс для приведения типов, который обеспечивает преобразование
  9. * текстовых данных, хранящихся в бинарном формате (VARBINARY) в базе данных,
  10. * в строку UTF-8 для использования в приложении, и обратно.
  11. *
  12. * Это необходимо для корректной работы с данными, которые хранятся в кодировке (Windows-1251),
  13. * отличной от используемой в приложении.
  14. *
  15. * @package App\Casts
  16. */
  17. class BinaryTextCast implements CastsAttributes
  18. {
  19. /**
  20. * Преобразует значение из базы данных для использования в приложении.
  21. *
  22. * Этот метод вызывается, когда мы получаем значение атрибута из модели Eloquent.
  23. * Он обрабатывает бинарные данные, конвертируя их из Windows-1251 в UTF-8.
  24. *
  25. * @param \\Illuminate\\Database\\Eloquent\\Model $model
  26. * @param string $key
  27. * @param mixed $value
  28. * @param array $attributes
  29. * @return string|null
  30. */
  31. public function get($model, string $key, $value, array $attributes)
  32. {
  33. // Если значение из БД равно null, возвращаем null
  34. if (is_null($value)) {
  35. return null;
  36. }
  37. // Проверяем, является ли значение шестнадцатеричной строкой (например, '0x...').
  38. // Некоторые драйверы баз данных могут возвращать бинарные данные в таком формате.
  39. if (ctype_xdigit($value) && str_starts_with(strtolower($value), '0x')) {
  40. // Если да, убираем префикс '0x' и конвертируем из hex в бинарные данные.
  41. $binary_data = hex2bin(substr($value, 2));
  42. } else {
  43. // В противном случае, считаем, что значение уже является бинарными данными.
  44. $binary_data = $value;
  45. }
  46. // Конвертируем бинарные данные из кодировки Windows-1251 в UTF-8
  47. // и удаляем пробельные символы в конце строки.
  48. return rtrim(mb_convert_encoding($binary_data, 'UTF-8', 'Windows-1251'));
  49. }
  50. /**
  51. * Преобразует значение из приложения для сохранения в базу данных.
  52. *
  53. * Этот метод вызывается, когда мы устанавливаем значение атрибута в модели Eloquent.
  54. * Он конвертирует строку из UTF-8 в Windows-1251 и подготавливает ее
  55. * для сохранения в поле типа VARBINARY.
  56. *
  57. * @param \\Illuminate\\Database\\Eloquent\\Model $model
  58. * @param string $key
  59. * @param mixed $value
  60. * @param array $attributes
  61. * @return array
  62. */
  63. public function set($model, string $key, $value, array $attributes)
  64. {
  65. // Если устанавливаемое значение равно null, сохраняем null в БД.
  66. if (is_null($value)) {
  67. return [$key => null];
  68. }
  69. // Конвертируем строку из UTF-8 в Windows-1251.
  70. $win1251_string = mb_convert_encoding($value, 'Windows-1251', 'UTF-8');
  71. // Преобразуем строку в ее шестнадцатеричное представление.
  72. $hex_string = bin2hex($win1251_string);
  73. // Формируем бинарный литерал для SQL-запроса (например, 0x...).
  74. $binary_literal = '0x' . $hex_string;
  75. // Возвращаем массив, где ключ - это имя атрибута, а значение -
  76. // сырое SQL-выражение для преобразования hex-строки в VARBINARY(MAX).
  77. // Это специфично для MS SQL Server.
  78. return [
  79. $key => DB::raw("CONVERT(VARBINARY(MAX), " . $binary_literal . ")")
  80. ];
  81. }
  82. }