Json Lines Writer
Writes records as JSON Lines for large data export or logs.
Function signature
ogWriteJsonLinesFile(base_path, relative_file, records = array(), options = array())
Categories
- File and Upload Safety
Parameters
base_pathApproved root directory used to keep path operations contained.relative_fileCaller-supplied value used for relative file processing.recordsRecord rows supplied for mapping, validation, export, or reporting.optionsOptional policy, formatting, or behavior controls for this helper. Recognized keys: `append`.Return value
Public-safe status string returned by the function.
- success
- message
- data
Compatibility
Existing function name, slug, path, and call order preserved; advertised metadata corrected to the actual source behavior.
Minimum PHP version: 7.4
Security notes
Use caller-owned allowlists and procedural mysqli prepared execution where SQL plans are returned; validate file paths, MIME policies, and permissions before file or download workflows.
Code
<?php
/*
* Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
* Free for personal and internal use. Paid project use requires visible credit
* to Jeffery L. Paris. Corporate use requires a paid license fee unless a
* separate written license states otherwise.
*/
/**
* Writes records as JSON Lines for large data export or logs.
*
* Primary use case: Data exchange and audit logs.
* Typical inputs: records, output path.
* Typical output: file write report.
*
* Implementation note: Validate path and encode each row safely.
*
* @return array Structured result data with success, message, and data keys.
*/
function ogWriteJsonLinesFile($base_path, $relative_file, $records = array(), $options = array()) {
$result = array(
'success' => false,
'message' => '',
'data' => array()
);
$base_path = (string)$base_path;
$relative_file = ltrim((string)$relative_file, DIRECTORY_SEPARATOR);
if (!is_array($records)) {
$result['message'] = 'Records must be an array.';
return $result;
}
if (!is_array($options)) {
$options = array();
}
$base_real = realpath($base_path);
if ($base_real === false || !is_dir($base_real)) {
$result['message'] = 'Approved base path is invalid.';
return $result;
}
if (empty($relative_file) || strpos($relative_file, '..') !== false) {
$result['message'] = 'Relative output path is invalid.';
return $result;
}
$extension = strtolower(pathinfo($relative_file, PATHINFO_EXTENSION));
if ($extension != 'jsonl' && $extension != 'ndjson' && $extension != 'log') {
$result['message'] = 'Output file extension is not allowed.';
return $result;
}
$target_path = $base_real . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relative_file);
$target_directory = dirname($target_path);
$target_directory_real = realpath($target_directory);
if ($target_directory_real === false || strpos($target_directory_real, $base_real) !== 0) {
$result['message'] = 'Output directory is outside the approved base path.';
return $result;
}
$append = false;
if (!empty($options['append']) && $options['append'] === true) {
$append = true;
}
$mode = 'wb';
if ($append) {
$mode = 'ab';
}
$handle = fopen($target_path, $mode);
if ($handle === false) {
$result['message'] = 'Output file could not be opened.';
return $result;
}
$written = 0;
$errors = array();
foreach ($records as $index => $record) {
$json = json_encode($record, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if ($json === false) {
$errors[] = 'Record ' . $index . ' could not be encoded.';
continue;
}
$bytes = fwrite($handle, $json . "\n");
if ($bytes === false) {
$errors[] = 'Record ' . $index . ' could not be written.';
} else {
$written++;
}
}
fclose($handle);
$result['success'] = empty($errors);
if (empty($errors)) {
$result['message'] = 'JSON Lines file written.';
} else {
$result['message'] = 'JSON Lines file written with errors.';
}
$result['data'] = array(
'path' => $target_path,
'written' => $written,
'errors' => $errors
);
return $result;
}