OpenXE/classes/Components/Http/docs/uploads.md
2021-05-21 08:49:41 +02:00

183 lines
5.9 KiB
Markdown

# Http Dateiuploads
In den Folgenden Beispielen wird gezeigt, wie man Http Datei Uploads realisieren und verarbeiten kann.
## Einfacher Dateiupload
### Frontend (HTML)
Der Dateiupload nutzt im Frontend ein HTML-Formular.
Wichtig: Parameter `enctype="multipart/form-data` muss gesetzt sein.
```html
<form action="?module=upload&action=upload" method="post" enctype="multipart/form-data">
<input name="file" type="file">
<input name="anotherfile" type="file">
<button type="submit">UPLOAD</button>
</form>
```
### Verarbeitung in PHP
Bei einem Dateiupload werden die Dateien von PHP vor der Programmausführung entgegengenommen und in `/tmp` gespeichert.
Zusätzlich werden die Informationen über den Upload in der `$_FILES` Variable gespeichert.
`var_dump($_FILES)` erzeugt diesen Output:
```php
array (size=2)
'file' =>
array (size=5)
'name' => string 'my_uploaded_file.md' (length=19)
'type' => string 'text/markdown' (length=13)
'tmp_name' => string '/tmp/phphoXkRU' (length=14)
'error' => int 0
'size' => int 8972
'anotherfile' =>
array (size=5)
'name' => string 'my_other_file.txt.xml' (length=28)
'type' => string 'text/xml' (length=8)
'tmp_name' => string '/tmp/php2NqM0Z' (length=14)
'error' => int 0
'size' => int 9499
```
### Verarbeitung im Controller
Auf die Uploadinfo kann man pro datei über die Request Klasse zugreifen:
```php
$request = $this->app->Container->get('Request');
$fileUpload = $request->getFile('file');
```
`getFile` liefert eine Instanz von `FileUpload` zurück.
#### Validierung
Bevor der FileUpload weiterverwertet wird, sollte aus Sicherheitsgründen die Integrität des Uploads überprüft werden.
Dafür stehen mehrere Methoden zur Verfügung:
* `$fileUpload->isValid()` prüft, ob die Datei zu einem gültigen `POST` Upload gehört und sollte **immer** ausgeführt werden.
* `$fileUpload->isFile()` prüft, ob die Datei im `/tmp` existiert.
* `$fileUpload->isReadable()` prüft, ob die Datei gelesen werden kann.
* `$fileUpload->hasError()` prüft, ob ein Http Error vorliegt.
**Hinweis:** Wenn ein Http Fehler vorliegt, kann man den Grund dafür per `$fileUpload->getErrorMessage()` ermitteln
und ggf. an den Client weitergeben. Liegt allerdings kein Fehler vor, führt diese Methode zu einer Exception!
#### Speicherung
Wenn ein Upload dauerhaft gespeichert werden soll, muss die Datei aus dem `/temp` an einen dauerhaften Speicherort
verschoben werden:
```php
$fileUpload->move('/var/storage', 'upload.txt');
```
**Hinweis:** Wenn sich bereits eine Datei mit diesem Namen am Zielort befindet, wird eine Exception geworfen und die
Datei wird **nicht** überschrieben oder anderweitig gespeichert.
#### Zugriff
Man kann auf zwei Arten auf den Inhalt des Uploads zugreifen:
* `$fileUpload->getContent()` liefert den Inhalt als `string` zurück. (empfohlen für kleinere Dateien)
* `$fileUpload->createContentStream()` liefert eine `resource`, aus der der Inhalt gestreamed werden kann.
**Tipp:** Mit `$fileUpload->getMimeType()` kann man vor dem Einlesen nocht prüfen, ob der User die Datei im
richtigen Format (json, csv, xml usw.) hochgeladen hat.
## Dateiupload in Array
### Frontend (HTML)
Für den Dateiupload können Dateien auch in zusammengehörigen Arrays hochgeladen werden.
Beispiel: Upload einer eigenen Schriftart. Hier werden vier dateien hochgeladen, die aber semantisch zusammengehören.
```html
<form action="?module=upload&action=upload" method="post" enctype="multipart/form-data">
<input name="font[default]" type="file">
<input name="font[bold]" type="file">
<input name="font[italic]" type="file">
<input name="font[bolditalic]" type="file">
<button type="submit">UPLOAD</button>
</form>
```
### Verarbeitung in PHP
In diesem Fall wird die `$_FILES` Variable in einer anderen hierarchie aufgebaut:
```php
array (size=1)
'font' =>
array (size=5)
'name' =>
array (size=4)
'regular' => string 'LiberationMono-Regular.ttf' (length=26)
'bold' => string 'LiberationMono-Bold.ttf' (length=23)
'italic' => string 'LiberationMono-Italic.ttf' (length=25)
'bolditalic' => string 'LiberationMono-BoldItalic.ttf' (length=29)
'type' =>
array (size=4)
'regular' => string 'font/ttf' (length=8)
'bold' => string 'font/ttf' (length=8)
'italic' => string 'font/ttf' (length=8)
'bolditalic' => string 'font/ttf' (length=8)
'tmp_name' =>
array (size=4)
'regular' => string '/tmp/phpN3NU7D' (length=14)
'bold' => string '/tmp/phpKzBu8u' (length=14)
'italic' => string '/tmp/php9wVd9l' (length=14)
'bolditalic' => string '/tmp/phpRYicad' (length=14)
'error' =>
array (size=4)
'regular' => int 0
'bold' => int 0
'italic' => int 0
'bolditalic' => int 0
'size' =>
array (size=4)
'regular' => int 108172
'bold' => int 105460
'italic' => int 124012
'bolditalic' => int 118296
```
### Verarbeitung im Controller
Auf die Uploadinfo muss jetzt anders zugegriffen werden, da `getFile` nur die oberste Ebene des Arrays ausgibt.
```php
$request = $this->app->Container->get('Request');
$fileArray = $request->getFile('font');
$fontRegular = $fileArray['regular'];
$fontBold = $fileArray['bold'];
```
Alternativ ist auch möglich:
```php
$request = $this->app->Container->get('Request');
$fileArray = $request->files->all();
$fontRegular = $fileArray['font']['regular'];
$fontBold = $fileArray['font']['bold'];
```
Beispiel: über alle Uploads iterieren:
```php
$request = $this->app->Container->get('Request');
foreach($request->files as $fontType => $file) {
doSomething($fontType, $file);
}
```
Mit den einzelnen `FileUpload` Objekten verfährt man nun genau wie im oberen Beispiel.
**Hinweis:** Die Hierarchie der Dateiuploads kann beliebig tief geschachtelt sein. Getestet wird aber nur bis zur
dritten Ebene.