# Changelog

All notable changes to this project will be documented in this file.

## [1.1.0] - 2026-10-18

### Security

- **`sanitize_filename` actually sanitizes.** It used `str_replace` with the literal string `a-zA-Z0-9-_` as the search text, so it never changed anything and `upload_type` and `filename` could contain `../`, allowing files to be written (and directories created) anywhere the web server user could write. It now strips path components, replaces everything except letters, digits, underscore, dot and hyphen with a hyphen, and removes leading dots. The same rules apply to the file name sent by the client.
- **Removed the debug write to `/tmp/uploadFile`.** A fixed, predictable, world-readable path that leaked request data and was open to symlink attacks and races.
- **`.info` file injection closed.** Line breaks in keys and values are replaced with spaces so a value cannot forge additional `key:value` lines, non-scalar (array) values are skipped, and the content is built from `$_POST` and `$_GET` only, so cookies are no longer written.
- **Added `.htaccess`:** `.svn` directories return 404 and `upload_file.ini` is never served.

### Fixed

- Undefined constant `$filesHash[error]`, a fatal error on PHP 8; array-valued file fields are now rejected cleanly.
- Name collisions: the data file name is reserved atomically, and a name is only used if neither the data file nor its `.info` file already exists (otherwise `.1`, `.2`, ... is appended). Previously uploading `joe` then `joe.info` silently overwrote the first upload's info file.
- The value returned on success is now the size of the uploaded file, not of the `.info` file.
- Failures return an HTTP 4xx/5xx status with a text message instead of HTTP 200, and an unwritable or uncreatable storage directory is reported instead of ignored.
- Directories are created with mode 0775 (was 0777), configurable.

### Added

- **Configuration file** `upload_file.ini`, read from the first of the current directory, `DOCUMENT_ROOT/..`, `DOCUMENT_ROOT/../private`. Settings: `storage_path` (was the constant `/srv/camp/reports`, still the default), `dir_mode`, `unknown_type`, `write_info`, `info_suffix`, `max_file_size`. See `upload_file.ini.sample`.
- **Known upload types** (`[type.NAME]` sections) mapping an `upload_type` to a subdirectory, with a per-type `write_info` flag; when false the `.info` file is never created for that type. `unknown_type` decides what happens to types that are not listed (`sanitize`, `reject` or `root`).
- A `[type.unknown]` section is the catch-all for a missing or unlisted `upload_type` and takes precedence over `unknown_type`.
- `is_uploaded_file` and optional `max_file_size` checks.
- README.md, CHANGELOG.md and VERSION.md.

### Changed

- File names are now sanitized, so a client name such as `2026-10-11 00:00:00_Client Name_host_serial.sysinfo.yaml` is stored as `2026-10-11-00-00-00_Client-Name_host_serial.sysinfo.yaml` (spaces and colons become hyphens). Previously the name was stored unchanged.
- When several files are uploaded in one request, the requested `filename` applies to the first file only.

## [1.0] - 2022-06-04

- Initial version: general purpose upload script, generalized from `upload_sysinfo_report.php` of the sysinfo project.
