47 | ... (elements for the edit UI)
48 |
49 |
50 |
51 |
52 |
59 | ```
60 |
--------------------------------------------------------------------------------
/samples/java/web/style.css:
--------------------------------------------------------------------------------
1 | /* Reset */
2 | body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,th,var{font-style:normal;font-weight:normal;}ol,ul {list-style:none;}caption,th {text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;}
3 |
4 | /* Baseline */
5 | body, p, h1, h2, h3, h4, h5, h6 {font:normal 12px/1.3em Helvetica, Arial, sans-serif; color:#333; }
6 | h1 {font-size:22px; font-weight:bold;}
7 | h2 {font-size:19px; font-weight:bold;}
8 | h3 {font-size:16px; font-weight:bold;}
9 | h4 {font-size:14px; font-weight:bold;}
10 | h5 {font-size:12px; font-weight:bold;}
11 | p {margin:10px 0;}
12 |
13 |
14 | body {text-align:center; margin:40px;}
15 | #frame {margin:0 auto; width:800px; text-align:left;}
16 |
17 |
18 |
19 | /* Uploader: Drag & Drop */
20 | .resumable-error {display:none; font-size:14px; font-style:italic;}
21 | .resumable-drop {padding:15px; font-size:13px; text-align:center; color:#666; font-weight:bold;background-color:#eee; border:2px dashed #aaa; border-radius:10px; margin-top:40px; z-index:9999; display:none;}
22 | .resumable-dragover {padding:30px; color:#555; background-color:#ddd; border:1px solid #999;}
23 |
24 | /* Uploader: Progress bar */
25 | .resumable-progress {margin:30px 0 30px 0; width:100%; display:none;}
26 | .progress-container {height:7px; background:#9CBD94; position:relative; }
27 | .progress-bar {position:absolute; top:0; left:0; bottom:0; background:#45913A; width:0;}
28 | .progress-text {font-size:11px; line-height:9px; padding-left:10px;}
29 | .progress-pause {padding:0 0 0 7px;}
30 | .progress-resume-link {display:none;}
31 | .is-paused .progress-resume-link {display:inline;}
32 | .is-paused .progress-pause-link {display:none;}
33 | .is-complete .progress-pause {display:none;}
34 |
35 | /* Uploader: List of items being uploaded */
36 | .resumable-list {overflow:auto; margin-right:-20px; display:none;}
37 | .uploader-item {width:148px; height:90px; background-color:#666; position:relative; border:2px solid black; float:left; margin:0 6px 6px 0;}
38 | .uploader-item-thumbnail {width:100%; height:100%; position:absolute; top:0; left:0;}
39 | .uploader-item img.uploader-item-thumbnail {opacity:0;}
40 | .uploader-item-creating-thumbnail {padding:0 5px; font-size:9px; color:white;}
41 | .uploader-item-title {position:absolute; font-size:9px; line-height:11px; padding:3px 50px 3px 5px; bottom:0; left:0; right:0; color:white; background-color:rgba(0,0,0,0.6); min-height:27px;}
42 | .uploader-item-status {position:absolute; bottom:3px; right:3px;}
43 |
44 | /* Uploader: Hover & Active status */
45 | .uploader-item:hover, .is-active .uploader-item {border-color:#4a873c; cursor:pointer; }
46 | .uploader-item:hover .uploader-item-title, .is-active .uploader-item .uploader-item-title {background-color:rgba(74,135,60,0.8);}
47 |
48 | /* Uploader: Error status */
49 | .is-error .uploader-item:hover, .is-active.is-error .uploader-item {border-color:#900;}
50 | .is-error .uploader-item:hover .uploader-item-title, .is-active.is-error .uploader-item .uploader-item-title {background-color:rgba(153,0,0,0.6);}
51 | .is-error .uploader-item-creating-thumbnail {display:none;}
--------------------------------------------------------------------------------
/samples/Node.js/public/style.css:
--------------------------------------------------------------------------------
1 | /* Reset */
2 | body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,th,var{font-style:normal;font-weight:normal;}ol,ul {list-style:none;}caption,th {text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;}
3 |
4 | /* Baseline */
5 | body, p, h1, h2, h3, h4, h5, h6 {font:normal 12px/1.3em Helvetica, Arial, sans-serif; color:#333; }
6 | h1 {font-size:22px; font-weight:bold;}
7 | h2 {font-size:19px; font-weight:bold;}
8 | h3 {font-size:16px; font-weight:bold;}
9 | h4 {font-size:14px; font-weight:bold;}
10 | h5 {font-size:12px; font-weight:bold;}
11 | p {margin:10px 0;}
12 |
13 |
14 | body {text-align:center; margin:40px;}
15 | #frame {margin:0 auto; width:800px; text-align:left;}
16 |
17 |
18 |
19 | /* Uploader: Drag & Drop */
20 | .resumable-error {display:none; font-size:14px; font-style:italic;}
21 | .resumable-drop {padding:15px; font-size:13px; text-align:center; color:#666; font-weight:bold;background-color:#eee; border:2px dashed #aaa; border-radius:10px; margin-top:40px; z-index:9999; display:none;}
22 | .resumable-dragover {padding:30px; color:#555; background-color:#ddd; border:1px solid #999;}
23 |
24 | /* Uploader: Progress bar */
25 | .resumable-progress {margin:30px 0 30px 0; width:100%; display:none;}
26 | .progress-container {height:7px; background:#9CBD94; position:relative; }
27 | .progress-bar {position:absolute; top:0; left:0; bottom:0; background:#45913A; width:0;}
28 | .progress-text {font-size:11px; line-height:9px; padding-left:10px;}
29 | .progress-pause {padding:0 0 0 7px;}
30 | .progress-resume-link {display:none;}
31 | .is-paused .progress-resume-link {display:inline;}
32 | .is-paused .progress-pause-link {display:none;}
33 | .is-complete .progress-pause {display:none;}
34 |
35 | /* Uploader: List of items being uploaded */
36 | .resumable-list {overflow:auto; margin-right:-20px; display:none;}
37 | .uploader-item {width:148px; height:90px; background-color:#666; position:relative; border:2px solid black; float:left; margin:0 6px 6px 0;}
38 | .uploader-item-thumbnail {width:100%; height:100%; position:absolute; top:0; left:0;}
39 | .uploader-item img.uploader-item-thumbnail {opacity:0;}
40 | .uploader-item-creating-thumbnail {padding:0 5px; font-size:9px; color:white;}
41 | .uploader-item-title {position:absolute; font-size:9px; line-height:11px; padding:3px 50px 3px 5px; bottom:0; left:0; right:0; color:white; background-color:rgba(0,0,0,0.6); min-height:27px;}
42 | .uploader-item-status {position:absolute; bottom:3px; right:3px;}
43 |
44 | /* Uploader: Hover & Active status */
45 | .uploader-item:hover, .is-active .uploader-item {border-color:#4a873c; cursor:pointer; }
46 | .uploader-item:hover .uploader-item-title, .is-active .uploader-item .uploader-item-title {background-color:rgba(74,135,60,0.8);}
47 |
48 | /* Uploader: Error status */
49 | .is-error .uploader-item:hover, .is-active.is-error .uploader-item {border-color:#900;}
50 | .is-error .uploader-item:hover .uploader-item-title, .is-active.is-error .uploader-item .uploader-item-title {background-color:rgba(153,0,0,0.6);}
51 | .is-error .uploader-item-creating-thumbnail {display:none;}
--------------------------------------------------------------------------------
/samples/java/src/resumable/js/upload/UploadServlet.java:
--------------------------------------------------------------------------------
1 | package resumable.js.upload;
2 |
3 | import javax.servlet.ServletException;
4 | import javax.servlet.http.HttpServlet;
5 | import javax.servlet.http.HttpServletRequest;
6 | import javax.servlet.http.HttpServletResponse;
7 | import java.io.File;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.io.RandomAccessFile;
11 |
12 | /**
13 | *
14 | * This is a servlet demo, for using Resumable.js to upload files.
15 | *
16 | * by fanxu123
17 | */
18 | public class UploadServlet extends HttpServlet {
19 |
20 | public static final String UPLOAD_DIR = "e:\\";
21 |
22 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
23 | int resumableChunkNumber = getResumableChunkNumber(request);
24 |
25 | ResumableInfo info = getResumableInfo(request);
26 |
27 | RandomAccessFile raf = new RandomAccessFile(info.resumableFilePath, "rw");
28 |
29 | //Seek to position
30 | raf.seek((resumableChunkNumber - 1) * info.resumableChunkSize);
31 |
32 | //Save to file
33 | InputStream is = request.getInputStream();
34 | long readed = 0;
35 | long content_length = request.getContentLength();
36 | byte[] bytes = new byte[1024 * 100];
37 | while(readed < content_length) {
38 | int r = is.read(bytes);
39 | if (r < 0) {
40 | break;
41 | }
42 | raf.write(bytes, 0, r);
43 | readed += r;
44 | }
45 | raf.close();
46 |
47 |
48 | //Mark as uploaded.
49 | info.uploadedChunks.add(new ResumableInfo.ResumableChunkNumber(resumableChunkNumber));
50 | if (info.checkIfUploadFinished()) { //Check if all chunks uploaded, and change filename
51 | ResumableInfoStorage.getInstance().remove(info);
52 | response.getWriter().print("All finished.");
53 | } else {
54 | response.getWriter().print("Upload");
55 | }
56 | }
57 |
58 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
59 | int resumableChunkNumber = getResumableChunkNumber(request);
60 |
61 | ResumableInfo info = getResumableInfo(request);
62 |
63 | if (info.uploadedChunks.contains(new ResumableInfo.ResumableChunkNumber(resumableChunkNumber))) {
64 | response.getWriter().print("Uploaded."); //This Chunk has been Uploaded.
65 | } else {
66 | response.setStatus(HttpServletResponse.SC_NOT_FOUND);
67 | }
68 | }
69 |
70 | private int getResumableChunkNumber(HttpServletRequest request) {
71 | return HttpUtils.toInt(request.getParameter("resumableChunkNumber"), -1);
72 | }
73 |
74 | private ResumableInfo getResumableInfo(HttpServletRequest request) throws ServletException {
75 | String base_dir = UPLOAD_DIR;
76 |
77 | int resumableChunkSize = HttpUtils.toInt(request.getParameter("resumableChunkSize"), -1);
78 | long resumableTotalSize = HttpUtils.toLong(request.getParameter("resumableTotalSize"), -1);
79 | String resumableIdentifier = request.getParameter("resumableIdentifier");
80 | String resumableFilename = request.getParameter("resumableFilename");
81 | String resumableRelativePath = request.getParameter("resumableRelativePath");
82 | //Here we add a ".temp" to every upload file to indicate NON-FINISHED
83 | String resumableFilePath = new File(base_dir, resumableFilename).getAbsolutePath() + ".temp";
84 |
85 | ResumableInfoStorage storage = ResumableInfoStorage.getInstance();
86 |
87 | ResumableInfo info = storage.get(resumableChunkSize, resumableTotalSize,
88 | resumableIdentifier, resumableFilename, resumableRelativePath, resumableFilePath);
89 | if (!info.vaild()) {
90 | storage.remove(info);
91 | throw new ServletException("Invalid request params.");
92 | }
93 | return info;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/samples/java/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
Resumable.js
12 |
It's a JavaScript library providing multiple simultaneous, stable and resumable uploads via the HTML5 File API.
13 |
14 |
The library is designed to introduce fault-tolerance into the upload of large files through HTTP. This is done by splitting each files into small chunks; whenever the upload of a chunk fails, uploading is retried until the procedure completes. This allows uploads to automatically resume uploading after a network connection is lost either locally or to the server. Additionally, it allows for users to pause and resume uploads without loosing state.
15 |
16 |
Resumable.js relies on the HTML5 File API and the ability to chunks files into smaller pieces. Currently, this means that support is limited to Firefox 4+ and Chrome 11+.
17 |
18 |
19 |
20 |
Demo
21 |
22 |
23 |
24 |
27 |
28 |
31 |
32 |
33 |
34 |
35 | |
36 | |
37 |
38 |
39 |
40 | |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/samples/Backend on AOLserver and OpenACS.md:
--------------------------------------------------------------------------------
1 | # AOLserver and OpenACS
2 | [@steffentchr](http://twitter.com/steffentchr)
3 |
4 | Our upload managers are using [AOLserver](http://www.aolserver.com/) and [OpenACS](http://www.openacs.com/).
5 | Generally, all Resumable.js request are handled through a single method:
6 |
7 | ad_proc handle_resumable_file {
8 | {-file_parameter_name "file"}
9 | {-folder "/tmp"}
10 | -check_video:boolean
11 | {-max_file_size ""}
12 | } {} {
13 | # Check parameter to see if this is indeed a resumable
14 | ad_page_contract {} {
15 | {resumableChunkNumber:integer "0"}
16 | {resumableChunkSize:integer "0"}
17 | {resumableTotalSize:integer "0"}
18 | {resumableIdentifier ""}
19 | {resumableFilename ""}
20 | }
21 |
22 | # Clean up the identifier
23 | regsub -all {[^0-9A-Za-z_-]} $resumableIdentifier "" resumableIdentifier
24 |
25 | # Check if the request is sane
26 | if { $resumableChunkNumber==0 || $resumableChunkSize==0 || $resumableTotalSize==0 || $resumableIdentifier eq "" } {
27 | return "non_resumable_request"
28 | }
29 | set number_of_chunks [expr int(floor($resumableTotalSize/($resumableChunkSize*1.0)))]
30 | if { $number_of_chunks==0 } {set number_of_chunks 1}
31 | if { $resumableChunkNumber>$number_of_chunks } {
32 | return "invalid_resumable_request"
33 | }
34 |
35 | # What would the file name be?
36 | set filename [file join $folder "resumable-${resumableIdentifier}.${resumableChunkNumber}"]
37 |
38 | # If this is a GET request, we should tell the uploader if the file is already in place or not
39 | if { [ns_conn method] eq "GET" } {
40 | if { [file exists $filename] && [file size $filename]==$resumableChunkSize } {
41 | doc_return 200 text/plain "ok"
42 | } else {
43 | doc_return 404 text/plain "not found"
44 | }
45 | ad_script_abort
46 | }
47 |
48 | # Assign a tmp file
49 | ad_page_contract {} [list "${file_parameter_name}:trim" "${file_parameter_name}.tmpfile:tmpfile"]
50 | set tmp_filename [set "${file_parameter_name}.tmpfile"]
51 | if { $resumableFilename ne "" } {
52 | set original_filename $resumableFilename
53 | } else {
54 | set original_filename [set $file_parameter_name]
55 | }
56 |
57 | # Check data size
58 | if { $max_file_size ne "" && $resumableTotalSize>$max_file_size } {
59 | return [list "invalid_resumable_request" "The file is too large" $original_filename]
60 | } elseif { $resumableChunkNumber<$number_of_chunks && [file size $tmp_filename]!=$resumableChunkSize } {
61 | return [list "invalid_resumable_request" "Wrong data size" $original_filename]
62 | } elseif { $number_of_chunks>1 && $resumableChunkNumber==$number_of_chunks && [file size $tmp_filename] != [expr ($resumableTotalSize % $resumableChunkSize) + $resumableChunkSize] } {
63 | return [list "invalid_resumable_request" "Wrong data size" $original_filename]
64 | } elseif { $number_of_chunks==1 && [file size $tmp_filename] != $resumableTotalSize } {
65 | return [list "invalid_resumable_request" "Wrong data size" $original_filename]
66 | }
67 |
68 | # Save the chunk
69 | file mkdir $folder
70 | file copy -force $tmp_filename $filename
71 |
72 | # Try collating the first and last chunk -- and identify
73 | if { $check_video_p && ($resumableChunkNumber==1 || $resumableChunkNumber==$number_of_chunks) } {
74 | ## (Here you can do check on first and last chunk if needed
75 | ## For example, we will check if this is a support video file.)
76 | }
77 |
78 | # Check if all chunks have come in
79 | set chunk_num 1
80 | set chunk_files [list]
81 | while { $chunk_num<=$number_of_chunks } {
82 | set chunk_filename [file join $folder "resumable-${resumableIdentifier}.${chunk_num}"]
83 | if { ![file exists $chunk_filename] } {
84 | return [list "partly_done" $filename $original_filename]
85 | }
86 | lappend chunk_files $chunk_filename
87 | incr chunk_num
88 | }
89 |
90 | # We've come this far, meaning that all the pieces are in place
91 | set output_filename [file join $folder "resumable-${resumableIdentifier}.final"]
92 | foreach file $chunk_files {
93 | exec cat $file >> $output_filename
94 | catch {
95 | file delete $file
96 | }
97 | }
98 |
99 | return [list "done" $output_filename $original_filename $resumableIdentifier]
100 | }
101 |
102 |
103 | After this, all Resumable.js cases can be handled easily, including
104 | fallback to non-resumable requests.
105 |
106 | # Is this a file from Resumable.js?
107 | lassign [handle_resumable_file] resumable_status resumable_context resumable_original_filename resumable_identifier
108 | if { $resumable_status ne "non_resumable_request" } {
109 | # Yes, it is
110 | switch -exact $resumable_status {
111 | partly_done {
112 | doc_return 200 text/plain ok
113 | ad_script_abort
114 | }
115 | done {
116 | # All the pieces are in place
117 | ad_page_contract {} {
118 | {file:trim "unknown"}
119 | }
120 | set "file.tmpfile" $resumable_context
121 | set file $resumable_identifier
122 | }
123 | invalid_resumable_request -
124 | default {
125 | doc_return 500 text/plain $resumable_context
126 | ad_script_abort
127 | }
128 | }
129 | } else {
130 | # Nope, it's just a straight-forward HTTP request
131 | ad_page_contract {} {
132 | file:trim
133 | file.tmpfile:tmpfile
134 | }
135 | }
136 |
137 |
--------------------------------------------------------------------------------
/samples/Node.js/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
Resumable.js
12 |
It's a JavaScript library providing multiple simultaneous, stable and resumable uploads via the HTML5 File API.
13 |
14 |
The library is designed to introduce fault-tolerance into the upload of large files through HTTP. This is done by splitting each files into small chunks; whenever the upload of a chunk fails, uploading is retried until the procedure completes. This allows uploads to automatically resume uploading after a network connection is lost either locally or to the server. Additionally, it allows for users to pause and resume uploads without loosing state.
15 |
16 |
Resumable.js relies on the HTML5 File API and the ability to chunks files into smaller pieces. Currently, this means that support is limited to Firefox 4+ and Chrome 11+.
17 |
18 |
19 |
20 |
Demo
21 |
22 |
23 |
24 |
27 |
28 |
31 |
32 |
33 |
34 |
35 | |
36 | |
37 |
38 |
39 |
40 |
41 | |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/samples/Backend on PHP.md:
--------------------------------------------------------------------------------
1 | # Sample server implementation in PHP
2 |
3 | [Chris Gregory](http://online-php.com) has provided this sample implementation for PHP.
4 |
5 | It's a sample implementation to illustrate chunking. It should probably not be used as-is (for example, be sure to clean file names for dot and dashes to make sure you don't allow files to escape the tempory upload directory). The script is unsupported.
6 |
7 | ```php
8 | `. Once all
19 | * the parts have been uploaded, a final destination file is
20 | * being created from all the stored parts (appending one by one).
21 | *
22 | * @author Gregory Chris (http://online-php.com)
23 | * @email www.online.php@gmail.com
24 | */
25 |
26 |
27 | ////////////////////////////////////////////////////////////////////
28 | // THE FUNCTIONS
29 | ////////////////////////////////////////////////////////////////////
30 |
31 | /**
32 | *
33 | * Logging operation - to a file (upload_log.txt) and to the stdout
34 | * @param string $str - the logging string
35 | */
36 | function _log($str) {
37 |
38 | // log to the output
39 | $log_str = date('d.m.Y').": {$str}\r\n";
40 | echo $log_str;
41 |
42 | // log to file
43 | if (($fp = fopen('upload_log.txt', 'a+')) !== false) {
44 | fputs($fp, $log_str);
45 | fclose($fp);
46 | }
47 | }
48 |
49 | /**
50 | *
51 | * Delete a directory RECURSIVELY
52 | * @param string $dir - directory path
53 | * @link http://php.net/manual/en/function.rmdir.php
54 | */
55 | function rrmdir($dir) {
56 | if (is_dir($dir)) {
57 | $objects = scandir($dir);
58 | foreach ($objects as $object) {
59 | if ($object != "." && $object != "..") {
60 | if (filetype($dir . "/" . $object) == "dir") {
61 | rrmdir($dir . "/" . $object);
62 | } else {
63 | unlink($dir . "/" . $object);
64 | }
65 | }
66 | }
67 | reset($objects);
68 | rmdir($dir);
69 | }
70 | }
71 |
72 | /**
73 | *
74 | * Check if all the parts exist, and
75 | * gather all the parts of the file together
76 | * @param string $dir - the temporary directory holding all the parts of the file
77 | * @param string $fileName - the original file name
78 | * @param string $chunkSize - each chunk size (in bytes)
79 | * @param string $totalSize - original file size (in bytes)
80 | */
81 | function createFileFromChunks($temp_dir, $fileName, $chunkSize, $totalSize) {
82 |
83 | // count all the parts of this file
84 | $total_files = 0;
85 | foreach(scandir($temp_dir) as $file) {
86 | if (stripos($file, $fileName) !== false) {
87 | $total_files++;
88 | }
89 | }
90 |
91 | // check that all the parts are present
92 | // the size of the last part is between chunkSize and 2*$chunkSize
93 | if ($total_files * $chunkSize >= ($totalSize - $chunkSize + 1)) {
94 |
95 | // create the final destination file
96 | if (($fp = fopen('temp/'.$fileName, 'w')) !== false) {
97 | for ($i=1; $i<=$total_files; $i++) {
98 | fwrite($fp, file_get_contents($temp_dir.'/'.$fileName.'.part'.$i));
99 | _log('writing chunk '.$i);
100 | }
101 | fclose($fp);
102 | } else {
103 | _log('cannot create the destination file');
104 | return false;
105 | }
106 |
107 | // rename the temporary directory (to avoid access from other
108 | // concurrent chunks uploads) and than delete it
109 | if (rename($temp_dir, $temp_dir.'_UNUSED')) {
110 | rrmdir($temp_dir.'_UNUSED');
111 | } else {
112 | rrmdir($temp_dir);
113 | }
114 | }
115 |
116 | }
117 |
118 |
119 | ////////////////////////////////////////////////////////////////////
120 | // THE SCRIPT
121 | ////////////////////////////////////////////////////////////////////
122 |
123 | //check if request is GET and the requested chunk exists or not. this makes testChunks work
124 | if ($_SERVER['REQUEST_METHOD'] === 'GET') {
125 |
126 | $temp_dir = 'temp/'.$_GET['resumableIdentifier'];
127 | $chunk_file = $temp_dir.'/'.$_GET['resumableFilename'].'.part'.$_GET['resumableChunkNumber'];
128 | if (file_exists($chunk_file)) {
129 | header("HTTP/1.0 200 Ok");
130 | } else
131 | {
132 | header("HTTP/1.0 404 Not Found");
133 | }
134 | }
135 |
136 |
137 |
138 | // loop through files and move the chunks to a temporarily created directory
139 | if (!empty($_FILES)) foreach ($_FILES as $file) {
140 |
141 | // check the error status
142 | if ($file['error'] != 0) {
143 | _log('error '.$file['error'].' in file '.$_POST['resumableFilename']);
144 | continue;
145 | }
146 |
147 | // init the destination file (format