FileAPI — a set of javascript tools for working with files. Multiupload, drag'n'drop and chunked file upload. Images: crop, resize and auto orientation by EXIF.

Overview

FileAPI

A set of JavaScript tools for working with files.

Get started

Download the files from the dist directory, and then:

	<div>
		<!-- "js-fileapi-wrapper" -- required class -->
		<div class="js-fileapi-wrapper upload-btn">
			<div class="upload-btn__txt">Choose files</div>
			<input id="choose" name="files" type="file" multiple />
		</div>
		<div id="images"><!-- previews --></div>
	</div>

	<script>window.FileAPI = { staticPath: '/js/FileAPI/dist/' };</script>
	<script src="/js/FileAPI/dist/FileAPI.min.js"></script>
	<script>
		var choose = document.getElementById('choose');
		FileAPI.event.on(choose, 'change', function (evt){
			var files = FileAPI.getFiles(evt); // Retrieve file list

			FileAPI.filterFiles(files, function (file, info/**Object*/){
				if( /^image/.test(file.type) ){
					return	info.width >= 320 && info.height >= 240;
				}
				return	false;
			}, function (files/**Array*/, rejected/**Array*/){
				if( files.length ){
					// Make preview 100x100
					FileAPI.each(files, function (file){
						FileAPI.Image(file).preview(100).get(function (err, img){
							images.appendChild(img);
						});
					});

					// Uploading Files
					FileAPI.upload({
						url: './ctrl.php',
						files: { images: files },
						progress: function (evt){ /* ... */ },
						complete: function (err, xhr){ /* ... */ }
					});
				}
			});
		});
	</script>

Setup options

Edit the file crossdomain.xml and place it to the root of the domain to which files will be uploaded.

	<script>
		window.FileAPI = {
			  debug: false   // debug mode, see Console
			, cors: false    // if used CORS, set `true`
			, media: false   // if used WebCam, set `true`
			, staticPath: '/js/FileAPI/dist/' // path to '*.swf'
			, postNameConcat: function (name, idx){
				// Default: object[foo]=1&object[bar][baz]=2
				// .NET: https://github.com/mailru/FileAPI/issues/121#issuecomment-24590395
				return	name + (idx != null ? '['+ idx +']' : '');
			}
		};
	</script>
	<script src="/js/FileAPI/dist/FileAPI.min.js"></script>

	<!-- OR -->

	<script>
		window.FileAPI = { /* options */ };
		require(['FileAPI'], function (FileAPI){
			// ...
		});
	</script>

getFiles(input:HTMLInputElement|Event|$.Event):Array

Retrieve file list from input element or event object, also support jQuery.

  • input — HTMLInputElement, change and drop event, jQuery collection or jQuery.Event
var el = document.getElement('my-input');
FileAPI.event.on(el, 'change', function (evt/**Event*/){
	// Retrieve file list
	var files = FileAPI.getFiles(el);

	// or event
	var files = FileAPI.getFiles(evt);
});

getInfo(file:Object, callback:Function):void

Get info of file (see also: FileAPI.addInfoReader).

// Get info of image file (FileAPI.exif.js included)
FileAPI.getInfo(file, function (err/**String*/, info/**Object*/){
	if( !err ){
		console.log(info); // { width: 800, height: 600, exif: {..} }
	}
});

// Get info of mp3 file (FileAPI.id3.js included)
FileAPI.getInfo(file, function (err/**String*/, info/**Object*/){
	if( !err ){
		console.log(info); // { title: "...", album: "...", artists: "...", ... }
	}
});

filterFiles(files:Array, filter:Function, callback:Function):void

Filtering the list of files, with additional information about files. See also: FileAPI.getInfo and FileAPI.addInfoReader.

  • files — original list of files
  • filter — function, takes two arguments: file — the file itself, info — additional information.
  • callback — function: list — files that match the condition, other — all the rest.
// Get list of file
var files = FileAPI.getFiles(input);

// Filter the List
FileAPI.filterFiles(files, function (file/**Object*/, info/**Object*/){
	if( /^image/.test(file.type) && info ){
		return	info.width > 320 && info.height > 240;
	} else {
		return	file.size < 20 * FileAPI.MB;
	}
}, function (list/**Array*/, other/**Array*/){
	if( list.length ){
		// ..
	}
});

getDropFiles(evt:Event|$.Event, callback:Function):void

Get a list of files, including directories.

  • evt — drop event
  • callback — function, takes one argument, a list of files
FileAPI.event.on(document, 'drop', function (evt/**Event*/){
	evt.preventDefault();

	// Get a list of files
	FileAPI.getDropFiles(evt, function (files/**Array*/){
		// ...
	});
});

upload(opts:Object):XmlHttpRequest

Uploading files to the server (successively). Returns XHR-like object. It is important to remember to correctly worked flash-transport server response body must not be empty, for example, you can pass, just text "ok".

var el = document.getElementById('my-input');
FileAPI.event.on(el, 'change', function (evt/**Event*/){
	var files = FileAPI.getFiles(evt);
	var xhr = FileAPI.upload({
		url: 'http://rubaxa.org/FileAPI/server/ctrl.php',
		files: { file: files[0] },
		complete: function (err, xhr){
			if( !err ){
				var result = xhr.responseText;
				// ...
			}
		}
	});
});

addInfoReader(mime:RegExp, handler:Function):void

Adds a handler for the collection of information about a file. See also: FileAPI.getInfo and FileAPI.filterFiles.

  • mime — pattern of mime-type
  • handler — takes two arguments: file object and complete function callback
FileAPI.addInfoReader(/^image/, function (file/**File*/, callback/**Function*/){
	// http://www.nihilogic.dk/labs/exif/exif.js
	// http://www.nihilogic.dk/labs/binaryajax/binaryajax.js
	FileAPI.readAsBinaryString(file, function (evt/**Object*/){
		if( evt.type == 'load' ){
			var binaryString = evt.result;
			var oFile = new BinaryFile(binaryString, 0, file.size);
			var exif  = EXIF.readFromBinaryFile(oFile);
			callback(false, { 'exif': exif || {} });
		}
		else if( evt.type == 'error' ){
			callback('read_as_binary_string');
		}
		else if( evt.type == 'progress' ){
			// ...
		}
	});
});

readAsDataURL(file:Object, callback:Function):void

Reading the contents of the specified File as dataURL.

  • file — file object
  • callback — function, receives a result
FileAPI.readAsDataURL(file, function (evt/**Object*/){
	if( evt.type == 'load' ){
		// Success
	 	var dataURL = evt.result;
	} else if( evt.type =='progress' ){
		var pr = evt.loaded/evt.total * 100;
	} else {
		// Error
	}
})

readAsBinaryString(file:Object, callback:Function):void

Reading the contents of the specified File as BinaryString.

  • file — file object
  • callback — function, receives a result
FileAPI.readAsBinaryString(file, function (evt/**Object*/){
	if( evt.type == 'load' ){
		// Success
	 	var binaryString = evt.result;
	} else if( evt.type =='progress' ){
		var pr = evt.loaded/evt.total * 100;
	} else {
		// Error
	}
})

readAsArrayBuffer(file:Object, callback:Function):void

Reading the contents of the specified File as ArrayBuffer.

  • file — file object
  • callback — function, receives a result
FileAPI.readAsArrayBuffer(file, function (evt/**Object*/){
	if( evt.type == 'load' ){
		// Success
	 	var arrayBuffer = evt.result;
	} else if( evt.type =='progress' ){
		var pr = evt.loaded/evt.total * 100;
	} else {
		// Error
	}
})

readAsText(file:Object, callback:Function):void

Reading the contents of the specified File as text.

  • file — file object
  • callback — function, receives a result
FileAPI.readAsText(file, function (evt/**Object*/){
	if( evt.type == 'load' ){
		// Success
	 	var text = evt.result;
	} else if( evt.type =='progress' ){
		var pr = evt.loaded/evt.total * 100;
	} else {
		// Error
	}
})

readAsText(file:Object, encoding:String, callback:Function):void

Reading the contents of the specified File as text.

  • encoding — a string indicating the encoding to use for the returned data. By default, UTF-8.
FileAPI.readAsText(file, "utf-8", function (evt/**Object*/){
	if( evt.type == 'load' ){
		// Success
	 	var text = evt.result;
	} else if( evt.type =='progress' ){
		var pr = evt.loaded/evt.total * 100;
	} else {
		// Error
	}
})

Upload options

url:String

A string containing the URL to which the request is sent.


data:Object

Additional post data to be sent along with the file uploads.

var xhr = FileAPI.upload({
	url: '...',
	data: { 'session-id': 123 },
	files: { ... },
});

uploadMethod:String

Request method, HTML5 only.

var xhr = FileAPI.upload({
	url: '...',
	uploadMethod: 'PUT',
	files: { .. },
});

uploadCredentials:Boolean

Pass credentials to upload request, HTML5 only.

var xhr = FileAPI.upload({
	url: '...',
	uploadCredentials: false,
	files: { .. },
});

headers:Object

Additional request headers, HTML5 only.

var xhr = FileAPI.upload({
	url: '...',
	headers: { 'x-upload': 'fileapi' },
	files: { .. },
});

cache:Boolean

Setting to true removes the default timestamp URL parameter.


files:Object

Key-value object, key — post name, value — File or FileAPI.Image object.

var xhr = FileAPI.upload({
	url: '...',
	files: {
		audio: files
	}
});

chunkSize:Number

Chunk size in bytes, HTML5 only.

var xhr = FileAPI.upload({
	url: '...',
	files: { images: fileList },
	chunkSize: 0.5 * FileAPI.MB
});

chunkUploadRetry:Number

Number of retries during upload chunks, HTML5 only.

var xhr = FileAPI.upload({
	url: '...',
	files: { images: fileList },
	chunkSize: 0.5 * FileAPI.MB,
	chunkUploadRetry: 3
});

--

imageTransform:Object

Rules of changes the original image on the client.

var xhr = FileAPI.upload({
	url: '...',
	files: { image: imageFiles },
	// Changes the original image
	imageTransform: {
		// resize by max side
		maxWidth: 800,
		maxHeight: 600,
		// Add watermark
		overlay: [{ x: 10, y: 10, src: '/i/watemark.png', rel: FileAPI.Image.RIGHT_BOTTOM }]
	}
});

--

imageTransform:Object

Rules of image transformation on the client, for more images.

var xhr = FileAPI.upload({
	url: '...',
	files: { image: imageFiles },
	imageTransform: {
		// resize by max side
		'huge': { maxWidth: 800, maxHeight: 600 },
		// crop & resize
		'medium': { width: 320, height: 240, preview: true },
		// crop & resize + watemark
		'small': {
			width: 100, height: 100,
			// Add watermark
			overlay: [{ x: 5, y: 5, src: '/i/watemark.png', rel: FileAPI.Image.RIGHT_BOTTOM }]
		}
	}
});

--

imageTransform:Object

Convert all images to jpeg or png.

var xhr = FileAPI.upload({
	url: '...',
	files: { image: imageFiles },
	imageTransform: {
		type: 'image/jpeg',
		quality: 0.86 // jpeg quality
	}
});

imageOriginal:Boolean

Sent to the server the original image or not, if defined imageTransform option.

--

imageAutoOrientation:Boolean

Auto-rotate images on the basis of EXIF.

--

prepare:Function

Prepare options upload for a particular file.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	prepare: function (file/**Object*/, options/**Object*/){
		options.data.secret = utils.getSecretKey(file.name);
	}
});

--

upload:Function

Start uploading.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	upload: function (xhr/**Object*/, options/**Object*/){
		// ...
	}
});

--

fileupload:Function

Start file uploading.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	fileupload: function (file/**Object*/, xhr/**Object*/, options/**Object*/){
		// ...
	}
});

--

progress:Function

Callback for upload progress events.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	progress: function (evt/**Object*/, file/**Object*/, xhr/**Object*/, options/**Object*/){
		var pr = evt.loaded/evt.total * 100;
	}
});

--

fileprogress:Function

Callback for upload file progress events.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	fileprogress: function (evt/**Object*/, file/**Object*/, xhr/**Object*/, options/**Object*/){
		var pr = evt.loaded/evt.total * 100;
	}
});

--

complete:Function

Callback for end upload requests.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	complete: function (err/**String*/, xhr/**Object*/, file/**Object/, options/**Object*/){
		if( !err ){
			// All files successfully uploaded.
		}
	}
});

--

filecomplete:Function

Callback for end upload requests.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	filecomplete: function (err/**String*/, xhr/**Object*/, file/**Object/, options/**Object*/){
		if( !err ){
			// File successfully uploaded
			var result = xhr.responseText;
		}
	}
});

File object

name

The name of the file referenced by the File object.

type

The type (MIME type) of the file referenced by the File object.

size

The size (in bytes) of the file referenced by the File object.


FileAPI.event

on(el:HTMLElement, events:String, handler:Function):void

Attach an event handler function.

  • el — DOM element
  • events — one or more space-separated event types.
  • handler — A function to execute when the event is triggered.

off(el:HTMLElement, events:String, handler:Function):void

Remove an event handler.

  • el — DOM element
  • events — one or more space-separated event types.
  • handler — a handler function previously attached for the event(s).

one(el:HTMLElement, events:String, handler:Function):void

Attach an event handler function. The handler is executed at most once.

  • el — DOM element
  • events — one or more space-separated event types.
  • handler — a function to execute when the event is triggered.

dnd(el:HTMLElement, hover:Function, handler:Function):void

Attach an drag and drop event handler function.

  • el — drop zone
  • hover — dragenter and dragleave listener
  • handler — drop event handler.
var el = document.getElementById('dropzone');
FileAPI.event.dnd(el, function (over){
	el.style.backgroundColor = over ? '#f60': '';
}, function (files){
	if( files.length ){
		// Upload their.
	}
});

// or jQuery
$('#dropzone').dnd(hoverFn, dropFn);

dnd.off(el:HTMLElement, hover:Function, handler:Function):void

Remove an drag and drop event handler function.

  • el — drop zone
  • hover — dragenter and dragleave listener
  • handler — drop event handler.
// Native
FileAPI.event.dnd.off(el, hoverFn, dropFn);

// jQuery
$('#dropzone').dndoff(hoverFn, dropFn);

--

FileAPI.Image

Class for working with images

constructor(file:Object):void

The constructor takes a single argument, the File object.

  • file — the File object
FileAPI.Image(imageFile).get(function (err/**String*/, img/**HTMLElement*/){
	if( !err ){
		document.body.appendChild( img );
	}
});

crop(width:Number, height:Number):FileAPI.Image

Crop image by width and height.

  • width — new image width
  • height — new image height
FileAPI.Image(imageFile)
	.crop(640, 480)
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

crop(x:Number, y:Number, width:Number, height:Number):FileAPI.Image

Crop image by x, y, width and height.

  • x — offset from the top corner
  • y — offset from the left corner
FileAPI.Image(imageFile)
	.crop(100, 50, 320, 240)
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

resize(width:Number, height:Number[, strategy:String]):FileAPI.Image

Resize image.

  • width — new image width
  • height — new image height
  • strategy — enum: min, max, preview, width, height. By default undefined.
FileAPI.Image(imageFile)
	.resize(320, 240)
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

// Resize image on by max side.
FileAPI.Image(imageFile)
	.resize(320, 240, 'max')
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

// Resize image on by fixed height.
FileAPI.Image(imageFile)
	.resize(240, 'height')
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

preview(width:Number[, height:Number]):FileAPI.Image

Crop and resize image.

  • width — new image width
  • height — new image height
FileAPI.Image(imageFile)
	.preview(100, 100)
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

rotate(deg:Number):FileAPI.Image

Rotate image.

  • deg — rotation angle in degrees
FileAPI.Image(imageFile)
	.rotate(90)
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

filter(callback:Function):FileAPI.Image

Apply filter function. Only HTML5.

  • callback — takes two arguments, canvas element and done method.
FileAPI.Image(imageFile)
	.filter(function (canvas/**HTMLCanvasElement*/, doneFn/**Function*/){
		// bla-bla-lba
		doneFn();
	})
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

filter(name:String):FileAPI.Image

Uses CamanJS, include it before FileAPI library.

  • name — CamanJS filter name (custom or preset)
Caman.Filter.register("my-funky-filter", function () {
	// http://camanjs.com/guides/#Extending
});

FileAPI.Image(imageFile)
	.filter("my-funky-filter") // or .filter("vintage")
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

overlay(images:Array):FileAPI.Image

Add overlay images, eg: watermark.

  • images — array of overlays
FileAPI.Image(imageFile)
	.overlay([
		// Left corner.
		{ x: 10, y: 10, w: 100, h: 10, src: '/i/watermark.png' },

		// Right bottom corner.
		{ x: 10, y: 10, src: '/i/watermark.png', rel: FileAPI.Image.RIGHT_BOTTOM }
	])
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

get(fn:Function):FileAPI.Image

Get the final image.

  • fn — complete callback

FileAPI.Camera

To work with a webcam, be sure to set FileAPI.media: true.

publish(el:HTMLElement, options:Object, callback:Function):void

Publication of the camera.

  • el — target
  • options — { width: 100%, height: 100%, start: true }
  • callback — the first parameter is a possible error, the second instance of FileAPI.Camera
var el = document.getElementById('cam');
FileAPI.Camera.publish(el, { width: 320, height: 240 }, function (err, cam/**FileAPI.Camera*/){
	if( !err ){
		// The webcam is ready, you can use it.
	}
});

start(callback:Function):void

Turn on the camera.

  • callback — will be called when the camera ready
var el = document.getElementById('cam');
FileAPI.Camera.publish(el, { start: false }, function (err, cam/**FileAPI.Camera*/){
	if( !err ){
		// Turn on
		cam.start(function (err){
			if( !err ){
				// The camera is ready for use.
			}
		});
	}
});

stop():void

Turn off the camera.


shot():FileAPI.Image

Take a picture with the camera.

var el = document.getElementById('cam');
FileAPI.Camera.publish(el, function (err, cam/**FileAPI.Camera*/){
	if( !err ){
		var shot = cam.shot(); // take a picture

		// create thumbnail 100x100
		shot.preview(100).get(function (err, img){
			previews.appendChild(img);
		});

		// and/or
		FileAPI.upload({
			url: '...',
			files: { cam: shot
		});
	}
});

Constants

FileAPI.KB:Number

1024 bytes

FileAPI.MB:Number

1048576 bytes

FileAPI.GB:Number

1073741824 bytes

FileAPI.TB:Number

1.0995116e+12 bytes


Utils

FileAPI.each(obj:Object|Array, callback:Function[, thisObject:Mixed]):void

Iterate over an object or array, executing a function for each matched element.

  • obj — array or object
  • callback — a function to execute for each element.
  • thisObject — object to use as this when executing callback.

--

FileAPI.extend(dst:Object, src:Object):Object

Merge the contents of two objects together into the first object.

  • dst — an object that will receive the new properties
  • src — an object containing additional properties to merge in.

--

FileAPI.filter(array:Array, callback:Function[, thisObject:Mixed):Object

Creates a new array with all elements that pass the test implemented by the provided function.

  • array — original Array
  • callback — Function to test each element of the array.
  • thisObject — object to use as this when executing callback.

Support

  • Multiupload: all browsers that support HTML5 or Flash
  • Drag'n'Drop upload: files (HTML5) & directories (Chrome 21+)
  • Chunked file upload (HTML5)
  • Upload one file: all browsers
  • Working with Images: IE6+, FF 3.6+, Chrome 10+, Opera 11.1+, Safari 6+
    • crop, resize, preview & rotate (HTML5 or Flash)
    • auto orientation by exif (HTML5, if include FileAPI.exif.js or Flash)

FileAPI.support.html5:Boolean

HTML5 browser support

FileAPI.support.cors:Boolean

This cross-origin resource sharing is used to enable cross-site HTTP requests.

FileAPI.support.dnd:Boolean

Drag'n'drop events support.

FileAPI.support.flash:Boolean

Availability Flash plugin.

FileAPI.support.canvas:Boolean

Canvas support.

FileAPI.support.dataURI:Boolean

Support dataURI as src for image.

FileAPI.support.chunked:Boolean

Support chunked upload.


Flash

Flash is very "buggy" thing :] The server response can not be empty. Therefore, in the event of a successful uploading http status should be only 200 OK.

Settings

Flash settings. It is advisable to place flash on the same server where the files will be uploaded.

<script>
	var FileAPI = {
	 	// @default: "./dist/"
		staticPath: '/js/',

		 // @default: FileAPI.staticPath + "FileAPI.flash.swf"
		flashUrl: '/statics/FileAPI.flash.swf',

		// @default: FileAPI.staticPath + "FileAPI.flash.image.swf"
		flashImageUrl: '/statics/FileAPI.flash.image.swf'
	};
</script>
<script src="/js/FileAPI.min.js"></script>

crossdomain.xml

Necessarily make this file on the server. Do not forget to replace youdomain.com on the name of your domain.

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
	<site-control permitted-cross-domain-policies="all"/>
	<allow-access-from domain="youdomain.com" secure="false"/>
	<allow-access-from domain="*.youdomain.com" secure="false"/>
	<allow-http-request-headers-from domain="*" headers="*" secure="false"/>
</cross-domain-policy>

request

The following sample HTTP POST request is sent from Flash Player to a server-side script if no parameters are specified:

POST /server/ctrl.php HTTP/1.1
Accept: text/*
Content-Type: multipart/form-data;
boundary=----------Ij5ae0ae0KM7GI3KM7
User-Agent: Shockwave Flash
Host: www.youdomain.com
Content-Length: 421
Connection: Keep-Alive
Cache-Control: no-cache

------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Filename"

MyFile.jpg
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Filedata"; filename="MyFile.jpg"
Content-Type: application/octet-stream

[[..FILE_DATA_HERE..]]
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Upload"

Submit Query
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7--

Security

By default FileAPI.flash.swf allows access from any domain via Security.allowDomain("*"). This can lead to same origin bypass vulnerability if swf is loaded from the same domain as your critical data. To prevent this, allow only your domains here and rebuild flash.


Server settings

IFrame/JSONP

<script>
(function (ctx, jsonp){
	'use strict';
	var status = {{httpStatus}}, statusText = "{{httpStatusText}}", response = "{{responseBody}}";
	try {
		ctx[jsonp](status, statusText, response);
	} catch (e){
		var data = "{\"id\":\""+jsonp+"\",\"status\":"+status+",\"statusText\":\""+statusText+"\",\"response\":\""+response.replace(/\"/g, '\\\\\"')+"\"}";
		try {
			ctx.postMessage(data, document.referrer);
		} catch (e){}
	}
})(window.parent, '{{request_param_callback}}');
</script>

<!-- or -->

<?php
	include './FileAPI.class.php';

	if( strtoupper($_SERVER['REQUEST_METHOD']) == 'POST' ){
		// Retrieve File List
		$files	= FileAPI::getFiles();

		// ... your logic

		// JSONP callback name
		$jsonp	= isset($_REQUEST['callback']) ? trim($_REQUEST['callback']) : null;

		// Server response: "HTTP/1.1 200 OK"
		FileAPI::makeResponse(array(
			  'status' => FileAPI::OK
			, 'statusText' => 'OK'
			, 'body' => array('count' => sizeof($files))
		), $jsonp);
		exit;
	}
?>

CORS

Enable CORS.

<?php
	// Permitted types of request
    header('Access-Control-Allow-Methods: POST, OPTIONS');

    // Describe custom headers
    header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Range, Content-Disposition, Content-Type');

    // A comma-separated list of domains
    header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);

	// Allow cookie
	header('Access-Control-Allow-Credentials: true');

    if( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ){
        exit;
    }

    if( $_SERVER['REQUEST_METHOD'] == 'POST' ){
        // ...
    }
?>

Chunked file upload

Client and server communicate to each other using the following HTTP headers and status codes.
Client explicitly sets the following headers:

  • Content-Range: bytes <start-offset>-<end-offset>/<total>
  • Content-Disposition: attachment; filename=<file-name>
Any other headers are set by a target browser and are not used by client. Library does not provide any facilities to track a file uniqueness across requests, it's left on developer's consideration.
Response codes:
  • 200 - last chunk is uploaded
  • 201 - chunk is successfully saved
  • 416 - range is not acceptable error, recoverable
  • 500 - server error, recoverable
For recoverable errors server tries to resend chunk `chunkUploadRetry` times then fails.
  • X-Last-Known-Byte: int, library tries to resend chunk from the given offset. Applicable to response codes 200 and 416
  • All the other codes - fatal error, user's involvement is recommended.

    Buttons examples

    Base

    Simple input[type="file"]

    <span class="js-fileapi-wrapper" style="position: relative; display: inline-block;">
        <input name="files" type="file" multiple/>
    </span>

    Button

    Stylized button.

    <style>
    .upload-btn {
        width: 130px;
        height: 25px;
        overflow: hidden;
        position: relative;
        border: 3px solid #06c;
        border-radius: 5px;
        background: #0cf;
    
    }
        .upload-btn:hover {
            background: #09f;
        }
        .upload-btn__txt {
            z-index: 1;
            position: relative;
            color: #fff;
            font-size: 18px;
            font-family: "Helvetica Neue";
            line-height: 24px;
            text-align: center;
            text-shadow: 0 1px 1px #000;
        }
        .upload-btn input {
            top: -10px;
            right: -40px;
            z-index: 2;
            position: absolute;
            cursor: pointer;
            opacity: 0;
            filter: alpha(opacity=0);
            font-size: 50px;
        }
    </style>
    <div class="js-fileapi-wrapper upload-btn">
        <div class="upload-btn__txt">Upload files</div>
        <input name="files" type="file" multiple />
    </div>

    Link

    Button like link.

    <style>
    .upload-link {
        color: #36c;
        display: inline-block;
        *zoom: 1;
        *display: inline;
        overflow: hidden;
        position: relative;
        padding-bottom: 2px;
        text-decoration: none;
    }
        .upload-link__txt {
            z-index: 1;
            position: relative;
            border-bottom: 1px dotted #36c;
        }
            .upload-link:hover .upload-link__txt {
                color: #f00;
                border-bottom-color: #f00;
            }
    
        .upload-link input {
            top: -10px;
            right: -40px;
            z-index: 2;
            position: absolute;
            cursor: pointer;
            opacity: 0;
            filter: alpha(opacity=0);
            font-size: 50px;
        }
    </style>
    <a class="js-fileapi-wrapper upload-link">
        <span class="upload-link__txt">Upload photo</span>
        <input name="photo" type="file" accept="image/*" />
    </a>

    Installation, testing, assembling

    npm install fileapi
    cd fileapi
    npm install
    grunt


    Changelog

    2.0.20

    • #369: * IEMobile

    2.0.19

    • #367: * [flash] allow gif and bmp to resize

    2.0.18

    • #364: * Camera#stop
    • #363: * support `Blob` in `FileAPI.getInfo`
    • #361: + upload zero-files

    2.0.16-2.0.17

    • #353: debug mode vs. IE
    • #352: correct filename via flash-uploading

    2.0.12-2.0.15 (!)

    • #346, #342, #344: fixes for XSS into Flash-transport

    2.0.11

    • #322, #308: dnd & safari + $.fn.dnd (store all dropped items)
    • #319: NodeJS tesing
    • #317, #313: fixed "malformed entry.name (OSX Unicode NFD)"
    • #311: fixed "Arithmetic result exceeded 32 bits"

    2.0.10

    • #289: * WebCam & html5 == false
    • #199, #265: flash fix 2015 error with BitmapData
    • #177: IE9, IE11 flash.camera remembered settigns
    • #254: check 'onLoadFnName' before call
    • #272: fixed `entry.createReader().readEntries`

    2.0.9

    • #253: fixed `proxyXHR.loaded`
    • #250: + check `disabled`-attr

    2.0.8

    • Two new resize strategies `width` and `height`

    2.0.7

    • #214: iframe transport under IE8
    • Fixed iframe-transport (remove `disabled`-attr for input)

    2.0.6

    • #240: Fixed `FileAPI.event.dnd.off`

    2.0.5

    • + #228: check callbacks with regexp
    • * Updated devDepending
    • + #207: support EXIF.Orientation == 4, 5 & 7

    2.0.4

    • + #176: Add params to the beginning of form
    • + #190: Add 204 as a successful response
    • + #192: many bugfixes; + `retry` & `multipass` options; + QUnit-tests for BigSizeImage

    2.0.3

    • + QUnit-tests for iframe-transport
    • + `postMessage` for iframe-transport
    • + `jsonp: "callback"` option
    • * resize: `imageTransform.type` rename to `imageTransform.strategy` (!!!)
    • + https://github.com/mailru/FileAPI/pull/165 (#140: fix)

    2.0.2

    • + test: upload headers
    • + test: upload + camanjs
    • + test: upload + autoOrientation
    • FileAPI.class.php: + HTTP header Content-Type: application/json
    • #143: + `FileAPI.flashWebcamUrl` option
    • * merge v1.2.7
    • + `FileAPI.formData: true` option

    2.0.1

    • + support 'filter' prop in imageTransform

    2.0.0

    1.2.6

    1.2.5

    1.2.4

    1.2.3

    1.2.2

    1.2.1

    1.2.0

    1.1.0

    1.0.1

    1.0.0

    • first release
    Comments
    • Remove '_'+file.name

      Remove '_'+file.name

      Why Form.prototype.toFormData appends '_'+file.name?

      When upload request body looks like:

      ------WebKitFormBoundary13nJwlOAdYFVK3qi Content-Disposition: form-data; name="file"; filename="949A0453.JPG" Content-Type: image/jpeg

      ------WebKitFormBoundary13nJwlOAdYFVK3qi Content-Disposition: form-data; name="_file"

      949A0453.JPG ------WebKitFormBoundary13nJwlOAdYFVK3qi--

      opened by lenarakhmadeev 7
    • Consider phantomjs and casperjs headless browser as html5 compatible

      Consider phantomjs and casperjs headless browser as html5 compatible

      phantomjs is webkit based and should be considered as html5 compliant.

      Not sure if exception in user agent html5 control should be added like that, specially as you can choose agent in those headless browser but i tought maybe someone would like that fix

      opened by fadomire 5
    • Added experimental webgl resizing

      Added experimental webgl resizing

      Hey! After fronttalks I decided to play with webgl resizing of images.

      Few of drawbacks:

      • Textures is limited by width and height
      • It's slower than canvas
      opened by floatdrop 4
    • Node.js test server

      Node.js test server

      Начало тестового сервака. Использует express 4. Работает на node.js 0.10 (ну и выше).

      1. запускается на 8000 порту
      2. умеет раздавать статику
      3. отвечает json и jsonp (jsonp встроенный, а не как в php)
      4. работают все примеры, кроме watermark.html
      5. умеет выставлять заголовки, но их не тестил

      Для начала вот так. Жду обратной связи, готов доделывать)

      opened by arusakov 3
    • Fix transform with serial: false

      Fix transform with serial: false

      I am trying to use serial: false from dev branch and it only transform properly the first image. Here is the code I am using.

      FileAPI.upload('./upload', files, {
        serial: false,
        imageTransform: {
          type: 'image/jpeg',
          quality: 0.86, // jpeg quality
          maxWidth: 100
        },
        progress: function (evt){ /* ... */ },
        complete: function (err, xhr){ /* ... */ }
      });
      

      After take a look to the code I found this block:

      if( isOrignTrans ){
          // Convert to array for transform function
          trans = [trans];
      }
      

      It is inside of an each so we modify trans every iteration and finally we get something similar to [[[trans]]], it causes transformation errors. I hope I fix it properly.

      opened by jrdi 3
    • Add params to the beginning of form.

      Add params to the beginning of form.

      https://github.com/mailru/FileAPI/pull/175

      Добавлять параметры загрузки (params) на начало формы.

      https://github.com/mailru/FileAPI/blob/dev/lib/FileAPI.core.js#L1619-L1629

      Зачем это нужно!? Например на стороне сервера у нас есть stream обработчик формы, допустим для загрузки файла нужно указать ключ/токен (в params) или что то еще.

      Потом когда начало формы прилетит на сервер мы сможем получить параметры и продолжить загрузку файла в противном случае нам нужно будет закачать файл (а это ресурсы и время работы скриптов) и только потом сделать проверку.

      Да, есть QueryString и Headers, но думаю еще один способ не помешает.

      opened by korzhyk 3
    • Link to final files

      Link to final files

      Hello,

      This seems like a great lib and the docs seems comprehensive and easy to follow.

      However, it doesn't look like they answer the crucial question: where do I download the final library files from? :)

      opened by scribu 2
    • Fallback to flash camera capture in case of insecure origin in Chromium

      Fallback to flash camera capture in case of insecure origin in Chromium

      In Chromium version 47 a group of features were disabled on insecure origins, including getUserMedia. This fix checks for that case and falls back to flash capture if the origin is insecure.

      opened by anton-evseev 1
    • Add error handling to image parsing & filename fix for multipart data

      Add error handling to image parsing & filename fix for multipart data

      I found that there was no good handling for corrupt or unreadable image files, (like a text file mislabled as a .jpg), so this handling seems to work well, assuming the client can catch the errors gracefully. (my project worked with no changes, since I already had error handling in the complete() function)

      In my testing, I also found that the filename would sometimes come through as undefined, the cause appeared to be due to uploading preview images that had been scaled and cropped. (Lost metadata?) This patch fixed my uploads to Amazon S3.

      opened by mix3d 1
    • fix mailru/FileAPI#314 malformed entry.name (OSX Unicode NFD)

      fix mailru/FileAPI#314 malformed entry.name (OSX Unicode NFD)

      Загрузку папок с Unicode NFD именами победить не удалось, но это не работает ни в Dropbox, ни в Google Drive.

      Принцип фикса в следующем: вместо того чтобы итерировать конкретные массивы dataTransfer.items или dataTransfer.files, пытаем составить новый массив из этих двух. Если entry является файлом и его имя в формате Unicode NFC или entry – папка, значит кладем в новый массив dataTransfer.items[i], иначе dataTransfer.files[i].

      opened by Octane 1
    Owner
    Free and open source software developed at Mail.Ru
    Free and open source software developed at Mail.Ru
    Moxiecode 5.6k Jan 1, 2023
    🌊 A flexible and fun JavaScript file upload library

    A JavaScript library that can upload anything you throw at it, optimizes images for faster uploads, and offers a great, accessible, silky smooth user

    pqina 13.2k Jan 3, 2023
    Multiple file upload plugin with image previews, drag and drop, progress bars. S3 and Azure support, image scaling, form support, chunking, resume, pause, and tons of other features.

    Fine Uploader is no longer maintained and the project has been effectively shut down. For more info, see https://github.com/FineUploader/fine-uploader

    Fine Uploader 8.2k Jan 2, 2023
    A JavaScript library providing multiple simultaneous, stable, fault-tolerant and resumable/restartable file uploads via the HTML5 File API.

    Flow.js Flow.js is a JavaScript library providing multiple simultaneous, stable and resumable uploads via the HTML5 File API. (Demo) The library is de

    HTML5 File upload 2.9k Dec 18, 2022
    Multi Upload with Progress Bar in Vanilla JS

    js-progress-bar-multi-upload Multi Upload with Progress Bar in Vanilla JS Youtube dersinde birlikte hazırladığımız çoklu progress barlı javascript upl

    Tayfun Erbilen 11 Jun 10, 2022
    runk is a simple file and folder sharer.

    runk It is a simple file and folder sharer. It uses hyperswarm for sharing over network. Installation: Prerequisite: Node.js To mount, configured fuse

    Amansinh Parmar 8 Mar 11, 2022
    Dropzone is an easy to use drag'n'drop library. It supports image previews and shows nice progress bars.

    Dropzone is a JavaScript library that turns any HTML element into a dropzone. This means that a user can drag and drop a file onto it, and Dropzone wi

    Dropzone 17k Dec 30, 2022
    A simple React App that plays Public Domain TV shows and integrates with Twitch Chat for the controls.

    Public Domain Television for Twitch This application plays movies from Public Domain Movies The current version is only used to play Cartoons, but can

    Ravavyr 8 Mar 29, 2022
    Moxiecode 5.6k Jan 1, 2023
    jQuery plugin for 'responsive cropping'. Dynamically crop images to fill available space without cutting out the image's subject. Great for full-screen images.

    jQuery plugin for 'responsive cropping'. Dynamically crop images to fill available space without cutting out the image's subject. Great for full-screen images.

    Jono Menz 3.2k Dec 30, 2022
    Adds links to Discogs pages from various sites. Auto search for music on torrent and other sites. Does multi auto-search on Artist/Discography pages. Auto search local HDDs/filelists using Voidtools Everything search engine.

    Discogs Scout: Adds links to Discogs pages from various sites. Auto search for music on torrent and other sites. Does multi auto-search on Artist/Disc

    null 27 Dec 27, 2022
    Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

    JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

    Svante Jonsson IT-Högskolan 3 May 18, 2022
    Dynamically resize, format and optimize images based on url modifiers.

    Local Image Sharp Dynamically resize, format and optimize images based on url modifiers. Table of Contents ✨ Features ?? Installation ?? Usage Contrib

    Strapi Community 30 Nov 29, 2022
    jQuery Tabs Plugin. CSS Tabs with Accessible and Responsive Design. Lot of Tab Themes with Vertical and Horizontal Orientation.

    Macaw Tabs Macaw Tabs is jQuery tabs plugin. It helps you to create accessible and responsive jQuery tabs by implementing the W3 design patterns for t

    HTMLCSSFreebies 6 Dec 8, 2022
    📷 The fastest and most versatile JS EXIF reading library.

    Usage • Installation • Quick start • Demos • API • Perf • Changelog • FAQ • Contributing ?? The fastest and most versatile JavaScript EXIF reading lib

    Mike 786 Jan 2, 2023
    Parallax Engine that reacts to the orientation of a smart device

    Parallax Engine that reacts to the orientation of a smart device. Where no gyroscope or motion detection hardware is available, the position of the cu

    Matthew Wagerfield 16k Jan 8, 2023
    Browsertool zum Anzeigen/Verändern/Setzen des Fotostandorts (JPEG / EXIF-Daten)

    Fotostandort Browsertool zum Anzeigen/Verändern/Setzen des Fotostandorts (JPEG / EXIF-Daten) https://kreis-viersen.github.io/fotostandort/ Fragen, Anm

    Kreis Viersen 2 Apr 12, 2022