Skip to content
← Back to Functions
Code

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;
}