A minimal, production-usable invoice management system. PHP 8.2+, JSON file storage, no SQL database, no Node.js build step.
- Admin login (session-based,
password_hash) - Clients CRUD (+ quick-add from the invoice form)
- Invoices with multiple line items, auto-incrementing numbers (
INV-00001) - Multiple payments per invoice; total / paid / balance / status always recalculated server-side
- Statuses: Draft, Unpaid, Partially Paid, Paid, Cancelled (auto-calculated unless Draft/Cancelled)
- Professional A4 invoice document (browser view identical to PDF)
- PDF download via dompdf, print-friendly CSS
- Company branding: logo, stamp, authorized signature (enable/disable each)
- Global default Terms & Conditions, overridable per invoice without touching the default
- Backup download (ZIP) and safe restore under Settings
- CSRF protection on all forms, uploads validated + randomized filenames,
storage/denied via.htaccess
-
Upload the project folder to your hosting (
public_htmlor a subfolder). -
Make sure
storage/is writable by PHP (755 or 775 usually works; on cPanel the owner is already correct). -
Install Composer dependencies once:
composer installIf Composer is not available on shared hosting, run
composer installlocally and upload the generatedvendor/folder. -
Open the site in a browser. You will be redirected to Initial Setup — create the admin account and company name.
-
Done. Configure logo/stamp/signature under Settings.
- PHP 8.2+ with extensions:
dom,json,mbstring,session,zip,fileinfo(all standard on cPanel/DirectAdmin) - Apache with
mod_authz_core(or mod_access_compat) for the.htaccessprotection of/storage - Composer only for
dompdf/dompdf(PDF generation)
All data lives in storage/ as JSON files — back up that folder and you have everything:
storage/
├── admin.json admin account (password_hash, never plain text)
├── clients.json all clients
├── invoices.json invoices incl. nested payments
├── settings.json company profile + defaults
└── uploads/ logo / stamp / signature (random 32-hex filenames)
Writes are locked (flock), atomic (temp file + rename), and keep a .bak of the previous state. Corrupted files are preserved as .corrupt-* instead of being overwritten.
- Invoice numbers are generated from Settings → "Invoice Number Prefix" + highest existing number + 1, so deleted invoices never cause number reuse.
- Payment status is derived, never stored blindly: paid = 0 → Unpaid, 0 < paid < total → Partially Paid, paid ≥ total → Paid. Draft/Cancelled invoices keep their status.
- Amounts are stored as numbers; formatting happens only at display time.