Coding standards
Security in ResourceSpace
Developer reference
Database
Action functions
Admin functions
Ajax functions
Annotation functions
API functions
Collections functions
Comment functions
Config functions
CSV export functions
Dash functions
Debug functions
Encryption functions
Facial recognition functions
File functions
General functions
Language functions
Log functions
Login functions
Message functions
Migration functions
Node functions
PDF functions
Plugin functions
Render functions
Reporting functions
Request functions
Research functions
Slideshow functions
Theme permission functions
User functions
Video functions
Database functions
Metadata functions
Resource functions
Search functions
Map functions
Job functions
Tab functions
Test functions

get_job_progress_from_log_file()

Description

Scan a log file from the end and return the most recent line matching a pattern.

The file is read in fixed-size blocks starting from EOF and scanned backwards
line-by-line for the first line that matches the supplied regular expression
(by default, lines containing "[PROGRESS]").

On the first read pass, the function also captures the last non-empty line in
the file (closest to EOF), regardless of whether it matches the pattern.


or if the file could not be read
last_line: string|null The last non-empty line in the file, or null if unavailable

Parameters

ColumnTypeDefaultDescription
$path string "" Path to the log file to scan
$pattern string "/\[PROGRESS\]/i" Regular expression used to match progress lines
$block_size int Number of bytes to read per backward scan iteration
'rb';

Return

array found: string|null The most recent line matching $pattern, or null if none found

Location

include/job_functions.php lines 522 to 593

Definition

 
function get_job_progress_from_log_file(string $path ""string $pattern "/\[PROGRESS\]/i"int $block_size 65536): array
{
    
$fp = @fopen($path'rb');

    if (!
$fp) {
        return [
'found' => null'last_line' => null];
    }

    if (
fseek($fp0SEEK_END) === -1) {
        
fclose($fp);
        return [
'found' => null'last_line' => null];
    }

    
$position  ftell($fp);
    
$carry     '';
    
$last_line  null;
    
$first_pass true;

    while (
$position 0) {
        
$read_size = ($position >= $block_size) ? $block_size $position;
        
$position -= $read_size;
        
        
fseek($fp$position);
        
        
$chunk fread($fp$read_size);

        
// Combine with carried partial line
        
$buffer $chunk $carry;

        
// Split into lines
        
$lines preg_split("/\r\n|\n|\r/"$buffer);

        
// The first element may be incomplete (its beginning lies in an earlier block)
        
$carry array_shift($lines);

        if (
$first_pass) {
            
// Capture the last non-empty line (closest to EOF)
            
for ($i count($lines) - 1$i >= 0$i--) {
                if (
$lines[$i] !== '') {
                    
$last_line $lines[$i];
                    break;
                }
            }
            
$first_pass false;
        }

        
// Scan lines backward (from newest to oldest)
        
for ($i count($lines) - 1$i >= 0$i--) {
            
$line $lines[$i];
            if (
$line === '') continue;
            if (@
preg_match($pattern$line)) {
                
fclose($fp);
                return [
'found' => $line'last_line' => $last_line];
            }
        }
    }

    
// Handle the very first (oldest) line if any partial remains
    
if ($carry !== '') {
        if (
$last_line === null && $carry !== '') {
            
$last_line $carry;
        }
        if (@
preg_match($pattern$carry)) {
            
fclose($fp);
            return [
'found' => $carry'last_line' => $last_line];
        }
    }

    
fclose($fp);
    return [
'found' => null'last_line' => $last_line];

}

This article was last updated 16th January 2026 17:35 Europe/London time based on the source file dated 16th January 2026 14:45 Europe/London time.