onnov/detect-encoding
Fast Cyrillic text encoding detector for PHP to replace unreliable mb_detect_encoding. Identifies Windows-1251, KOI8-R, ISO-8859-5 (optionally IBM866/MacCyrillic) using code page ranges, with high accuracy even on short strings and very large texts.
Install via Composer:
composer require onnov/detect-encoding
First use case: Replace unreliable mb_detect_encoding for Cyrillic/legacy text in a Laravel controller:
use Onnov\DetectEncoding\EncodingDetector;
class TextController extends Controller
{
public function processLegacyText(string $rawText)
{
$detector = new EncodingDetector();
$encoding = $detector->getEncoding($rawText);
// Convert to UTF-8 for storage
$utf8Text = $detector->iconvXtoEncoding($rawText);
// Store or process...
}
}
Key starting points:
EncodingDetector::class constants (e.g., IBM866, WINDOWS_1251) for configuration.Wrap in a Laravel service with dependency injection:
// app/Services/EncodingService.php
class EncodingService
{
protected $detector;
public function __construct(EncodingDetector $detector)
{
$this->detector = $detector;
$this->configureDetector();
}
protected function configureDetector(): void
{
$this->detector->enableEncoding([
EncodingDetector::WINDOWS_1251,
EncodingDetector::KOI8_R,
]);
}
public function detectAndConvert(string $text): string
{
return $this->detector->iconvXtoEncoding($text);
}
}
Register in AppServiceProvider:
public function register()
{
$this->app->singleton(EncodingService::class, function ($app) {
return new EncodingService(new EncodingDetector());
});
}
Detect encoding in API requests or file uploads:
// app/Http/Middleware/DetectEncoding.php
public function handle($request, Closure $next)
{
if ($request->has('legacy_text')) {
$detector = app(EncodingDetector::class);
$encoding = $detector->getEncoding($request->legacy_text);
$request->merge(['detected_encoding' => $encoding]);
}
return $next($request);
}
php artisan encoding:convert database/legacy_texts.csv
Command implementation:
protected $signature = 'encoding:convert {file}';
protected $detector;
public function __construct(EncodingDetector $detector)
{
$this->detector = $detector;
}
public function handle()
{
$contents = file_get_contents($this->argument('file'));
$utf8Text = $this->detector->iconvXtoEncoding($contents);
file_put_contents("converted_{$this->argument('file')}", $utf8Text);
}
Trigger on file uploads or imports:
// app/Listeners/DetectUploadEncoding.php
public function handle(FileUploaded $event)
{
$detector = app(EncodingDetector::class);
$encoding = $detector->getEncoding($event->file->getContent());
// Log or process encoding metadata
}
Use Laravel config to manage enabled/disabled encodings:
// config/encoding.php
return [
'enabled_encodings' => [
EncodingDetector::WINDOWS_1251,
EncodingDetector::KOI8_R,
EncodingDetector::ISO_8859_5,
],
'default_target_encoding' => 'utf-8',
'iconv_options' => ['//TRANSLIT'],
];
Service initialization:
public function __construct(EncodingDetector $detector)
{
$this->detector = $detector;
$this->detector->enableEncoding(config('encoding.enabled_encodings'));
}
Short Text Accuracy:
$text = str_pad($shortText, 30, ' ');
$encoding = $detector->getEncoding($text);
Windows-1251 vs. KOI8-R Confusion:
WINDOWS_1251).MacCyrillic/IBM866 Disabled by Default:
$detector->enableEncoding([EncodingDetector::IBM866]);
Iconv Limitations:
iconvXtoEncoding() relies on PHP’s iconv, which may fail for unsupported encodings. Tip: Validate target encoding support first:
if (!in_array($targetEncoding, iconv_encodings())) {
throw new \RuntimeException("Unsupported target encoding: {$targetEncoding}");
}
Mixed Encoding Text:
Performance with Large Texts:
iconvXtoEncoding() can be slow for multi-MB files. Tip: Process in chunks or use streaming:
$handle = fopen($largeFile, 'r');
while (!feof($handle)) {
$chunk = fread($handle, 8192);
$utf8Chunk = $detector->iconvXtoEncoding($chunk);
// Process chunk...
}
Verify Encodings:
$encoding = $detector->getEncoding($text);
\Log::debug("Detected encoding for sample text: {$encoding}");
Test Edge Cases:
Fallback Strategy:
mb_detect_encoding for broader coverage:
$detector = new EncodingDetector();
$encodings = [$detector->getEncoding($text)];
if (empty($encodings)) {
$encodings = ['UTF-8', 'WINDOWS-1251', 'KOI8-R'];
}
$encoding = mb_detect_encoding($text, implode(',', $encodings));
Custom Encoding Validation:
$codePage = new \Onnov\DetectEncoding\CodePage();
$range = $codePage->getRange($uppercase, $lowercase, 'custom_name');
Add Custom Encodings:
Big5, Shift_JIS):
$detector->addEncoding([
'big5' => [
'upper' => '0xA1-0xFE', // Example range (research required)
'lower' => '0x40-0x7E',
],
]);
Create a Facade:
// app/Facades/Encoding.php
public static function detect(string $text): string
{
return app(EncodingDetector::class)->getEncoding($text);
}
Integrate with Laravel Filesystem:
$file = $request->file('legacy_file');
$contents = $file->get();
$encoding = Encoding::detect($contents);
$utf8Contents = Encoding::convert($contents, 'utf-8');
Cache Results:
$cacheKey = 'encoding_'.md5($text);
$encoding = Cache::remember($cacheKey, now()->addHours(1), function() use ($text) {
return $detector->getEncoding($text);
});
iconvXtoEncoding() defaults to utf-8 with //TRANSLIT. OverHow can I help you explore Laravel packages today?