From aae5bd82750b4f1742e971cf5961fe9e0d49df39 Mon Sep 17 00:00:00 2001 From: Aden Date: Fri, 29 Aug 2025 14:45:19 +1000 Subject: [PATCH] Respect multibyte UTF8 when splitting task logs Fixes an error where task logs would be split on multibyte UTF8 characters, resulting in _tasks/actions.php returning a response with an empty body and a parsererror being triggered in the ruTorrent GUI. This was causing issues when creating torrents with many files containing multibyte UTF8 characters (e.g. those with non-English characters), where ruTorrent would lose track of the torrent creation task and hang, despite the .torrent file being successfully created. --- plugins/_task/task.php | 43 +++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/plugins/_task/task.php b/plugins/_task/task.php index d91b21b79..121e9ceba 100644 --- a/plugins/_task/task.php +++ b/plugins/_task/task.php @@ -153,25 +153,50 @@ static protected function tail($filename, $lines = 128, $buffer = 16384) return( file($filename) ); else { - $f = fopen($filename, "rb"); + $f = fopen($filename, "rb"); fseek($f, -1, SEEK_END); if(fread($f, 1) != "\n") $lines -= 1; $output = ''; $chunk = ''; + + $currentLines = 0; - while(ftell($f) > 0 && ($lines >= 0)) - { + while($currentLines < $lines && ftell($f) > 0) + { $seek = min(ftell($f), $buffer); fseek($f, -$seek, SEEK_CUR); - $output = ($chunk = fread($f, $seek)).$output; - fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR); - $lines -= substr_count($chunk, "\n"); - } + + $startPosition = ftell($f); + $checkPosition = $startPosition; + $offset = 0; + while ($checkPosition > 0) { + fseek($f, $checkPosition, SEEK_SET); + $byte = fread($f, 1); + $byteValue = ord($byte); + if (($byteValue & 0xC0) === 0x80) { + $checkPosition++; + } else { + $offset = $checkPosition - $startPosition; + $startPosition = $checkPosition; + break; + } + } + fseek($f, $startPosition, SEEK_SET); + $chunk = fread($f, $seek - $offset); + $currentLines += substr_count($chunk, "\n"); + $output = $chunk . $output; + fseek($f, $startPosition, SEEK_SET); + + } fclose($f); - return( explode("\n", $output) ); - } + $linesArray = explode("\n", $output); + if(count($linesArray) > $lines) { + $linesArray = array_slice($linesArray, -$lines); + } + return $linesArray; + } } static protected function processLog( $dir, $logName, &$ret, $stripConsole, $removeASCII, $doNotTrim )