1 | # uppie
|
2 | [![](https://img.shields.io/npm/v/uppie.svg?style=flat)](https://www.npmjs.org/package/uppie) [![](https://img.shields.io/npm/dm/uppie.svg)](https://www.npmjs.org/package/uppie) [![](https://img.shields.io/bundlephobia/minzip/uppie.svg)](https://bundlephobia.com/package/uppie)
|
3 |
|
4 | > Cross-browser file and directory and upload library
|
5 |
|
6 | `uppie` is a tiny JavaScript library which helps you with file and directory uploads in browsers. It supports all current and past implementations of multi-file and directory uploads and provides you with a `FormData` object you can submit directly to a server through either `XMLHttpRequest` or `fetch`. Both the `<input type="file">` element and drag-and-drop are supported.
|
7 |
|
8 | ## Usage
|
9 | ```bash
|
10 | npm install uppie
|
11 | ```
|
12 | ```js
|
13 | import Uppie from 'uppie';
|
14 |
|
15 | const uppie = new Uppie();
|
16 | uppie(document.querySelector('#file'), async (event, formData, files) => {
|
17 | await fetch('/upload', {method: 'POST', body: formData});
|
18 | });
|
19 | ```
|
20 |
|
21 | ## Browser support
|
22 |
|
23 | || files via input[file] | files via DnD | directories via input[file] | directories via DnD |
|
24 | |---------|---------------------- |---------------|----------------------|--------------|
|
25 | | Firefox | yes | yes | yes (50+) | yes (50+) |
|
26 | | Chrome | yes | yes | yes (29+) | yes (29+) |
|
27 | | Edge | yes | yes | yes (13+) | yes (14+) |
|
28 | | Safari | yes | yes | yes (11.1+) | yes (11.1+) |
|
29 |
|
30 | ## Notes
|
31 |
|
32 | - Empty directories are excluded from the results by all browsers as dictated by the spec.
|
33 | - Firefox and Safari exclude files and directories starting with a `.`.
|
34 |
|
35 | ## API
|
36 | ### uppie(node, [opts], callback)
|
37 | - `node` *Node* or *NodeList*: One or more DOM nodes. If a `<input type="file">` is given, uppie will monitor it for `change` events. Any other element type will be enabled as a dropzone and watched for `drop` events. If you want to use both on the same element, use a hidden `<input>` and forward the click event.
|
38 | - `opts` *Object*: A options object which can contain:
|
39 | - `name`: The `name` attribute for creating the FormData entries. Default: `"files[]"`.
|
40 | - `callback` *Function*: callback which is called every time the selected files change or when files are dropped in the dropzone.
|
41 |
|
42 | The callback receives
|
43 |
|
44 | - `event` *Event*: the original event. Useful for calling `event.stopPropagation()`.
|
45 | - `formData` *FormData*: FormData object to be used for XHR2 uploading.
|
46 | - `files` *Array*: Array of paths for preview purposes.
|
47 |
|
48 | #### FormData format
|
49 |
|
50 | `name` defaults to `"files[]"`, `filename` will be the full path to the file, with `/` used as path separator. Does not include a leading slash. Make sure to sanitize `filename` on the server before writing it to the disk to prevent exploits involving `..` in the path. Example FormData:
|
51 |
|
52 | ```
|
53 | ------Boundary
|
54 | Content-Disposition: form-data; name="files[]"; filename="docs/1.txt"
|
55 | Content-Type: text/plain
|
56 |
|
57 | [DATA]
|
58 | ------Boundary
|
59 | Content-Disposition: form-data; name="files[]"; filename="docs/path/2.txt"
|
60 | Content-Type: text/plain
|
61 |
|
62 | [DATA]
|
63 | ------Boundary
|
64 | Content-Disposition: form-data; name="files[]"; filename="docs/path/to/3.txt"
|
65 | Content-Type: text/plain
|
66 | ```
|
67 |
|
68 | ## Recommended `input` element attributes
|
69 |
|
70 | - `multiple`: allow multiple files to be selected.
|
71 | - `webkitdirectory`: enable directory uploads in Chrome and Firefox.
|
72 | - `allowdirs`: enable experimental directory upload API in Firefox and Edge.
|
73 |
|
74 | ## PHP example
|
75 |
|
76 | Below is example for PHP 7.0 and possibly earlier versions. PHP does not parse the path from the `filename` field, so it is necessary to submit the path through other means, like as separate FormData fields as done in the example.
|
77 |
|
78 | ````js
|
79 | const uppie = new Uppie();
|
80 | uppie(document.documentElement, (event, formData, files) => {
|
81 | files.forEach(path => {
|
82 | formData.append("paths[]", path);
|
83 | });
|
84 |
|
85 | const xhr = new XMLHttpRequest();
|
86 | xhr.open('POST', 'upload.php');
|
87 | xhr.send(formData);
|
88 | });
|
89 | ````
|
90 | And in `upload.php`:
|
91 | ````php
|
92 | foreach ($_FILES['files']['name'] as $i => $name) {
|
93 | if (strlen($_FILES['files']['name'][$i]) > 1) {
|
94 | $fullpath = strip_tags($_POST['paths'][$i]);
|
95 | $path = dirname($fullpath);
|
96 |
|
97 | if (!is_dir('uploads/'.$path)){
|
98 | mkdir('uploads/'.$path);
|
99 | }
|
100 | if (move_uploaded_file($_FILES['files']['tmp_name'][$i], 'uploads/'.$fullpath)) {
|
101 | echo '<li>'.$name.'</li>';
|
102 | }
|
103 | }
|
104 | }
|
105 | ````
|
106 |
|
107 | Note that PHP's [upload limits](http://php.net/manual/en/ini.core.php#ini.sect.file-uploads) might need to be raised depending on use case.
|
108 |
|
109 | © [silverwind](https://github.com/silverwind), distributed under BSD licence
|
110 |
|
\ | No newline at end of file |