# upload_file

A small, general purpose PHP receiver for file uploads. A client POSTs a file (multipart/form-data) along with any number of other parameters; the script saves the file under a configurable storage directory and, optionally, writes a companion `.info` file listing the parameters. It is the generalized form of `upload_sysinfo_report.php` and is the receiving end of the `upload_http` transport of the sysinfo client.

This is part of the **sysadmin_scripts** project. Subversion path: `http://svn.dailydata.net/svn/sysadmin_scripts/trunk/upload_file`

## Files

| File | Purpose |
|---|---|
| `upload_file.php` | The receiver |
| `upload_file.ini.sample` | Documented sample configuration; copy to `upload_file.ini` |
| `test.html` | Manual test form |
| `.htaccess` | Denies `.svn` and `upload_file.ini` when the script is served by Apache |
| `VERSION.md`, `CHANGELOG.md` | Version and history |

## Request

| Parameter | Meaning |
|---|---|
| any file field | The file to save (the field name does not matter) |
| `upload_type` | Selects the subdirectory (see Configuration). Optional |
| `filename` | Name to store the file under. Optional; otherwise the client's own file name is used, falling back to a random name |
| anything else | Recorded in the `.info` file |

Names are sanitized: path components are removed, everything except letters, digits, `_`, `.` and `-` becomes `-`, and leading dots are removed. If the name (or its `.info` companion) already exists, `.1`, `.2`, ... is appended.

Example:

```
curl -F upload_type=sysinfo -F "filename=joe.info" -F "client=My Client" -F "report=@/tmp/report.yaml" http://server/upload_file/upload_file.php
```

On success the response is HTTP 200 with the size in bytes of each saved file, one per line. On failure it is HTTP 400 (bad request, unknown type, upload error), 413 (too large) or 500 (server problem) with a text message.

## The `.info` file

The saved file `joe.info` gets a companion `joe.info.info` (when enabled for the type) with one `key:value` line for every parameter sent, line breaks in values replaced by spaces:

```
upload_type:sysinfo
filename:joe.info
client:My Client
```

## Configuration

Settings come from the first `upload_file.ini` found in the current directory, `DOCUMENT_ROOT/..`, then `DOCUMENT_ROOT/../private`. Without one the built-in defaults apply (storage in `/srv/camp/reports`, unknown types stored in a sanitized subdirectory, `.info` files written). Keep the file out of the web root if you can; the supplied `.htaccess` blocks it if not.

| Setting | Default | Meaning |
|---|---|---|
| `storage_path` | `/srv/camp/reports` | Base directory for all uploads |
| `dir_mode` | `0775` | Mode for directories the script creates |
| `unknown_type` | `sanitize` | For an `upload_type` not listed: `sanitize` (use it as the subdirectory), `reject` (HTTP 400), `root` (store in `storage_path`) |
| `write_info` | `true` | Write the `.info` file |
| `info_suffix` | `.info` | Suffix of the info file |
| `max_file_size` | `0` | Maximum bytes per file, 0 for PHP's own limit only |

Each known upload type is a section `[type.NAME]` with `dir` (subdirectory of `storage_path`, may be nested, no `..`, default NAME) and optionally `write_info`, which overrides the global setting. A section named `[type.unknown]` is special: it catches a missing `upload_type` and any type not listed, and takes precedence over `unknown_type`. Example for the sysinfo importer:

```ini
storage_path = /srv/sysinfo_reports
unknown_type = reject

[type.sysinfo]
dir = unprocessed
write_info = false

[type.unknown]
dir = unknowns
```

## Storage directory

The web server user must be able to write to it. If the script creates it, it is owned by the web server user. To create it manually (as root), for example:

```
mkdir -p /srv/sysinfo_reports/unprocessed
chown camp:www-data /srv/sysinfo_reports/unprocessed
chmod 2775 /srv/sysinfo_reports/unprocessed
```

## Not done

Authentication is deliberately not part of this script; restrict access in the web server configuration if the URL is reachable by untrusted clients.
