How to Convert CSV to PDF with PHP
This PHP tutorial converts CSV data into a polished, tagged PDF table with the pdfRest Convert to PDF API Tool. It combines the upload with settings for column proportions, alignment, header colors, alternating rows, borders, padding, and overflow.
Why Convert CSV to PDF with PHP?
Commerce and portal applications often generate CSV for orders, commissions, and account activity. That format is convenient for importing data, but customers and internal reviewers may need a ready-to-read document rather than a dataset they must style themselves.
An affiliate platform, for example, can export campaign names, transaction descriptions, and commission amounts as CSV at month end. PHP can convert the data to PDF with readable descriptions, aligned currency values, and repeated column labels. The partner receives a statement-like report while the platform retains CSV for downstream analysis.
A server-generated table also avoids differences between spreadsheet applications and print settings. The PHP workflow controls page dimensions and table appearance consistently for every account and reporting period.
PHP Code Example for Converting CSV to PDF
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Utils;
// By default, we use the US-based API service. This is the primary endpoint for global use.
$apiUrl = "https://api.pdfrest.com";
/* For GDPR compliance and enhanced performance for European users, you can switch to the EU-based service by uncommenting the URL below.
* For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work
*/
//$apiUrl = "https://eu-api.pdfrest.com";
$inputPath = '/path/to/sample.csv';
$options = json_decode('{"title":"Structured Content Sample","language":"en-US","enable_tagging":true,"page_setup":{"size":"Letter","orientation":"portrait","margin":{"top":36,"right":42,"bottom":36,"left":42}},"style":{"font":"Arial","heading_font":"Arial","code_font":"Courier","text_size":11,"text_color_rgb":[34,34,34],"heading_scale":1.35,"table":{"column_width_weights":[2,3,2],"keep_header_with_first_row":true,"repeat_headers_on_overflow":true,"show_borders":true,"border_width":0.75,"border_color_rgb":[180,188,200],"header_fill_color_rgb":[33,64,98],"header_text_color_rgb":[255,255,255],"row_fill_color_rgb":[250,250,252],"alternate_row_fill_color_rgb":[235,240,246],"cell_padding":{"top":6,"right":8,"bottom":6,"left":8}}},"csv":{"first_row_is_header":true,"delimiter":",","columns":[{"index":0,"width_weight":2,"text_align":"left"},{"index":1,"width_weight":3,"text_align":"left"},{"index":2,"width_weight":1,"text_align":"right"}]}}', true);
// This sample converts CSV input to a tagged PDF through multipart /pdf.
// It demonstrates structured_text_options and the format-specific conversion options.
$multipart = [
['name' => 'file', 'contents' => Utils::tryFopen($inputPath, 'r'), 'filename' => basename($inputPath)],
['name' => 'structured_text_options', 'contents' => json_encode($options)],
['name' => 'output', 'contents' => 'pdf_from_csv'],
];
$response = (new Client())->post($apiUrl . '/pdf', ['headers' => ['Api-Key' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 'Accept' => 'application/json'], 'multipart' => $multipart]);
echo $response->getBody();
Source: View the sample on GitHub
Breaking Down the Code
This PHP CSV example relies on Guzzle for HTTP and PSR-7 stream utilities for the upload. When using the code outside this repository, add the client with composer require guzzlehttp/guzzle.
require 'vendor/autoload.php'; use GuzzleHttp\Client; use GuzzleHttp\Psr7\Request; use GuzzleHttp\Psr7\Utils;
The PHP endpoint excerpt keeps regional routing explicit for this CSV operation:
// By default, we use the US-based API service. This is the primary endpoint for global use. $apiUrl = "https://api.pdfrest.com"; /* For GDPR compliance and enhanced performance for European users, you can switch to the EU-based service by uncommenting the URL below. * For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work */ //$apiUrl = "https://eu-api.pdfrest.com";
PHP opens the .csv source as a PSR-7 stream and includes its filename in the multipart part. The extension selects CSV processing without duplicating the format in the options JSON.
$inputPath = '/path/to/sample.csv';
$options = json_decode('{"title":"Structured Content Sample","language":"en-US","enable_tagging":true,"page_setup":{"size":"Letter","orientation":"portrait","margin":{"top":36,"right":42,"bottom":36,"left":42}},"style":{"font":"Arial","heading_font":"Arial","code_font":"Courier","text_size":11,"text_color_rgb":[34,34,34],"heading_scale":1.35,"table":{"column_width_weights":[2,3,2],"keep_header_with_first_row":true,"repeat_headers_on_overflow":true,"show_borders":true,"border_width":0.75,"border_color_rgb":[180,188,200],"header_fill_color_rgb":[33,64,98],"header_text_color_rgb":[255,255,255],"row_fill_color_rgb":[250,250,252],"alternate_row_fill_color_rgb":[235,240,246],"cell_padding":{"top":6,"right":8,"bottom":6,"left":8}}},"csv":{"first_row_is_header":true,"delimiter":",","columns":[{"index":0,"width_weight":2,"text_align":"left"},{"index":1,"width_weight":3,"text_align":"left"},{"index":2,"width_weight":1,"text_align":"right"}]}}', true);
The array decoded into $options is serialized as pdfRest’s structured_text_options. It describes the PDF title and language, explicitly turns on tagging, chooses Letter portrait pages with 36-point margins, and provides typography plus CSV-specific styling.
{
"csv": {
"first_row_is_header": true,
"delimiter": ",",
"columns": [
{
"index": 0,
"width_weight": 2,
"text_align": "left"
},
{
"index": 1,
"width_weight": 3,
"text_align": "left"
},
{
"index": 2,
"width_weight": 1,
"text_align": "right"
}
]
}
}
first_row_is_header defaults to true; setting it to false renders every record as a body row. delimiter defaults to a comma and must contain exactly one character, so a tab or semicolon can be selected but a multi-character separator cannot.
Column indexes are zero-based. Unspecified columns default to weight 1 and left alignment. Width weights are positive relative proportions, not points or pixels, and text_align accepts only left, center, or right. An index outside the parsed CSV, a nonpositive weight, or another alignment value produces a validation error.
The per-column CSV weights take precedence over style.table.column_width_weights; the broader table list is only a fallback when CSV-specific widths are absent. The remaining table style controls borders, colors, row striping, and padding. keep_header_with_first_row prevents a header from appearing alone, and repeat_headers_on_overflow repeats it as rows continue onto later pages.
The PHP multipart array assigns name and contents values to the CSV stream, serialized structured_text_options, and requested output name.
// It demonstrates structured_text_options and the format-specific conversion options. $multipart = [ ['name' => 'file', 'contents' => Utils::tryFopen($inputPath, 'r'), 'filename' => basename($inputPath)], ['name' => 'structured_text_options', 'contents' => json_encode($options)], ['name' => 'output', 'contents' => 'pdf_from_csv'], ]; $response = (new Client())->post($apiUrl . '/pdf', ['headers' => ['Api-Key' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 'Accept' => 'application/json'], 'multipart' => $multipart]); echo $response->getBody();
Guzzle prepares and submits the CSV multipart body with the API key. The response body contains generated-resource information on success and service error details when the conversion cannot be completed.
['name' => 'file', 'contents' => Utils::tryFopen($inputPath, 'r'), 'filename' => basename($inputPath)], ['name' => 'structured_text_options', 'contents' => json_encode($options)], ['name' => 'output', 'contents' => 'pdf_from_csv'], ]; $response = (new Client())->post($apiUrl . '/pdf', ['headers' => ['Api-Key' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 'Accept' => 'application/json'], 'multipart' => $multipart]); echo $response->getBody();
Beyond the Tutorial
This approach can produce payout statements, order summaries, subscription exports, and downloadable account reports without building an HTML table for each document. Per-column options preserve clarity even when one field contains much longer text than another.
Logical table tags support navigation and document processing but are not a promise of full accessibility conformance. Exercise the request with sample data in API Lab and use the Convert to PDF API documentation as the authoritative field reference.