The export screen

TL;DR

A three-step query builder over the real schema: pick a table, pick what to join to it, add conditions, download the CSV. It accepts read statements and streams their result.

/system/export is how a CSV comes out of CCC without anyone writing SQL. It builds the query for you, step by step, from the database's own structure.

The three steps

Table. The screen lists every table in the database with its row count and size, so you can see what you are about to pull before pulling it. Picking one moves to the next step.

Joins. It reads the chosen table's SHOW CREATE TABLE text, finds the columns that look like foreign keys, and offers the tables those point at as checkboxes. Tick the ones whose columns you want beside your rows.

Where. It lists the fields available across the table and its joins. Pick a field, pick an operator, type a value, submit. Conditions accumulate, so this step is repeated until the filter is what you want. Dates are entered as YYYY-MM-DD.

Then Download posts the built query to public/export.php, which streams the CSV in a new tab.

What guards it

Three gates, all required: a session, the system/export page permission, and the export module flag on the user. Holding one or two is not enough.

Then a fourth, on the statement itself: export.php refuses anything that database->isreadquery() does not read as a single read. Write statements are rejected by that check; this is an application guard, not a separate read-only database credential.

export.php receives the query base64-encoded in the POST body rather than as a form of parameters. That it accepts a statement at all is deliberately recorded posture in AGENTS.md, not an oversight: replacing it with a server-rebuilt query is a separate piece of work. In normal use the statement is the one this screen built.

What comes out

A CSV of the rows the query returned, streamed rather than assembled in memory, so a large export does not have to fit in memory_limit.

A join can multiply rows. An order joined to its lines returns one row per line, and summing the order total across that counts it once per line. See data model before exporting anything you intend to total.

Where to look instead

For a per-order figure, cm_impact_salesorders is already one row per order. For field meanings, /dictionary. For a repeatable pull that another system consumes, see consumption contracts rather than exporting by hand.

Evidence

The three steps, the foreign-key discovery from SHOW CREATE TABLE and the field list from app/http/system/export.php and templates/main/system/export.tpl. The three gates, the base64 POST and the read-only statement check from AGENTS.md, Entry points and Known posture, and database->isreadquery(). Basis: code-checked against the current implementation.

About this document
  • Type
    page
  • Status
    active
  • Updated
    2026-09-14
  • Created
    2026-09-13
  • Covers
    system/export