Skip to content
← Back to Functions
Code

Csv Stream Writer

Streams CSV rows with proper escaping, headers, and memory-safe iteration.

Function signature

ogStreamCsvRows(rows, headers = array(), options = array())

Categories

  • Security

Parameters

rowsRow data supplied for streaming, mapping, or reporting.headersStructured headers data supplied by the caller.optionsOptional policy, formatting, or behavior controls for this helper. Recognized keys: `delimiter`.

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.
 */

/**
 * Streams CSV rows with proper escaping, headers, and memory-safe iteration.
 *
 * Primary use case: Large exports.
 * Typical inputs: row iterator, column headers, filename.
 * Typical output: streamed response.
 *
 * Implementation note: Use fputcsv-style escaping in implementation.
 *
 * @return array Structured result data with success, message, and data keys.
 */
function ogStreamCsvRows($rows, $headers = array(), $options = array()) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

	if (!is_array($rows)) {
		$result['message'] = 'Rows must be supplied as an array.';
		return $result;
	}
	if (!is_array($headers)) {
		$headers = array();
	}
	if (!is_array($options)) {
		$options = array();
	}

	$delimiter = ',';
	if (!empty($options['delimiter'])) {
		$delimiter = (string)$options['delimiter'];
		if (strlen($delimiter) != 1) {
			$delimiter = ',';
		}
	}

	$handle = fopen('php://temp', 'r+');
	if ($handle === false) {
		$result['message'] = 'Temporary CSV stream could not be opened.';
		return $result;
	}

	$row_count = 0;
	if (!empty($headers)) {
		fputcsv($handle, $headers, $delimiter);
	}
	foreach ($rows as $row) {
		if (is_array($row)) {
			if (!empty($headers)) {
				$ordered_row = array();
				foreach ($headers as $header) {
					if (array_key_exists($header, $row)) {
						$ordered_row[] = $row[$header];
					} else {
						$ordered_row[] = '';
					}
				}
				fputcsv($handle, $ordered_row, $delimiter);
			} else {
				fputcsv($handle, $row, $delimiter);
			}
			$row_count++;
		}
	}

	rewind($handle);
	$csv = stream_get_contents($handle);
	fclose($handle);
	if ($csv === false) {
		$csv = '';
	}

	$result['success'] = true;
	$result['message'] = 'CSV stream prepared.';
	$result['data'] = array(
		'row_count' => $row_count,
		'csv' => $csv,
		'bytes' => strlen($csv)
	);

	return $result;
}