screenshotSFBrowser is a file browser and uploader for jQuery. It returns a list of objects with containing the names and additional information of the selected files.
You can use it, like any open-file-dialog, to select one or more files. Most inherent functionalities are also there like: file upload, file preview, creating folders and renaming or deleting files and folders.
You can download as zip or do a repository checkout. If you stumble upon anything out of the ordinary you can file them here.

SFBrowser is also available as a Wordpress plugin.

features

caution

The initial intentions for this filebrowser were for use in a CMS, and those are normally password protected. SFBrowser does try do do things as secure as possible: incoming data is always checked on validity and paths are always compared to the base path set in the server side config file. However: if you intend to use this plugin in an unprotected part of your site you'd do good to doublecheck and test (hack) the server side scripts yourself. You are using this plugin at your own risk.
Should you find holes, leaks or anything else that can be improved report them here.

installation

SFBrowser can (theoretically) be connected to different server side languages. For sake of clarity this document will asume you're running PHP, so when PHP is mentioned further on you can interpret it as every other server side scripting connector. Check the connectors paragraph if you want to use another server side scripting language.

configuration file

The 'sfbrowser/connectors/php/config.php' file contains a few basic constants.

propertytypedescriptiondefault
SFB_PATH String path of sfbrowser (relative to the page it is run from)"sfbrowser/"
SFB_BASE String upload folder (relative to SFB_PATH)"../data/"
SFB_LANG String language ISO code"en"
PREVIEW_BYTES Integer ASCII files can be previewed up to a certain amout of bytes.600
SFB_DENY String forbidden file extensions"php,php3,phtml"
FILETIME String datetime format"j-n-Y H:i"
SFB_ERROR_RETURN String return value in case of error"<html><head><meta http-equiv="Refresh" content="0;URL=http:/" /></head></html>"
SFB_PLUGINS String case sensitive, comma separated string with plugin names""imageresize,filetree""
SFB_DEBUG Boolean debug boolean, enables log file and console tracefalse

localisation

You can easily make SFBrowser into another language. Simply copy one of the existing language po files (sfbrowser/lang/[iso].po and sfbrowser/plugins/[name]/lang/[iso].po) and name them the ISO_3166 code of the new language. Then edit the SFB_LANG constant in 'sfbrowser/connectors/php/config.php' to that ISO code.
Should you make any language file other than the ones already present, I'd be happy to include them in a later release. Please send them to: sfbrowser@sjeiti.com.

debug

Setting the SFB_DEBUG value will do three things. Setting the value to true will cause inclusion of the uncompressed scripts rather than the minified ones. It will enable tracing in the console window. It will log all server side actions into 'sfbrowser/connectors/php/log.txt'.

javascript

You can call up SFBrowser by '$.fn.sfbrowser();' or the shorter '$.sfb();'

SFBrowser has a number of properties you can parse:

propertytypedescriptiondefault
title String title of the SFBrowser window"SFBrowser"
select Function calback function on choosefunction(a,params){trace(a,params)}
selectparamsObjectoptional value to be parsed as the second parameter of the select functionnull
selectnumIntegernumber of selectable files (0==any)0
file String selected file""
folder String a subfolder (relative to base, to which all returned files are relative)""
dirs Boolean allow visibility and creation/deletion of subdirectories.true
upload Boolean allow upload of filestrue
swfuploadBoolean use swf uploader instead of form hackfalse
allow Array<String> allowed file extensions[]
resize Array<Integer> maximum image constraint: array(width,height) or nullnull
inline String a JQuery selector for inline browser"body"
fixed Boolean keep the browser open after selection (only works when inline is not "body")false
cookie Boolean use a cookie to remember path, x, y, w, hfalse
copyRelativeBooleanCTRL-c the relative or absolute path (false for absolute)false
bgcolor String a hex string for the background color"#000"
bgalpha Float a floating point from 0 to 1 for background alpha.5
x Integer x position, centered if left nullnull
y Integer y position, centered if left nullnull
w Integer width460
h Integer height480
the following properties normally need no change
img Array<String> image file extensions for preview["gif", "jpg", "jpeg", "png"]
ascii Array<String> text file extensions for preview["txt", "xml", "html", "htm", "eml", "ffcmd", "js", "as", "php", "css", "java", "cpp", "pl", "log"]
movie Array<String> movie file extensions for preview["mp3","mp4","m4v","m4a","3gp","mov","flv","f4v"]
The following properties are set automaticly from the init file, explicitly setting these from js can lead to unexpected results.
sfbpathString the path of sfbrowser"sfbrowser/"
base String the upload folder"data/"
deny Array<String> denied file extensions["php", "php3", "phtml"]
icons Array<String> list of existing file icons["jpg", "html", "ico"...(etc)]
previewInteger amount of bytes for ascii preview600
connectorString server side script type"php"
langObject language objectsee lang/en.js
pluginsArray plugins[]
maxsizeInteger upload_max_filesize in bytes2097152
debugBoolean allows trace to consolefalse

select

The select property is something you will want to set if you want SFBrowser to be usefull. It's value has to be a function with one parameter: an array containing objects for the selected files (for instance: function(a){alert(a)};). Each object in that array has the following properties (where applicable):

propertytypedescription
file String the file including its path (relative to base)
mime String the filetype
rsize Integer the size in bytes
size String the size formatted to B, kB, MB, GB etc...
time Integer the time in seconds from Unix Epoch
date String the time formatted in 'j-n-Y H:i'
width Integer if image, the width
height Integer if image, the height

Keep in mind that all returned filepaths are relative to base (or rather SFB_BASE). If you run SFBrowser from within a CMS you'll have to alter the returned paths to the correct frontend path.

allow and deny

These properties are arrays containing file extensions that are, or are not shown in SFBrowser. This also applies to the file types that you upload.
For security reasons the main deny list is located at 'sfbrowser/connectors/php/config.php' by the name of SFB_DENY (a comma separated list of extensions). Additional file types can be denied through javascript with the deny property.
If allow is left empty (which is the default) all file types are allowed except those listed in deny.
Denying is stronger than allowing so an extension in both arrays will always be denied. The SFB_DENY constant in 'sfbrowser/connectors/php/config.php' always has priority over the deny property parsed through javascript.

usage

SFBrowser is designed to work like a normal OS's filebrowser, however, some interactions are not possible from within most web-browsers.

file selection

There are three ways to select a file: either press the 'Choose' button, double click the file, or select 'Choose' from the (right-click) context menu.

To select multiple files you can hold CTRL while clicking files, or press CTRL-A to select all files.

context menu

contextmenuRight clicking a file will popup a context menu with additional (or obvious) file operations. The two functions in here that are not found anywhere else in the interface are 'Duplicate' and 'Resize'.

'Duplicate' creates a copy of the selected file and appends it with a number (multiple file duplication does not work yet).

keyboard shortcuts

SFBrowser also comes with a number of keyboard shortcuts to make your life easier:

shortcutaction
Escape or CTRL-q closes SFBrowser
CTRL-f opens SFBrowser (only after one run)
F2 rename selected file
Return choose file and close SFBrowser
CTRL-a select all files
CTRL-click select multiple files

examples

For security reasons all manipulations in the examples are disabled. You can look at it, but it will not work.

a simple one

The selected files are added to a list and their sizes are shown. Select multiple files by pressing CTRL and selecting. Start adding files.

$.sfb({select:addFiles,plugins:[]});

swf uploader

The swf uploader allows multiple simultanious uploads but does require the Adobe Shockwave plugin.

$.sfb({
	 select:addFiles
	,plugins:['createascii']
	,swfupload:true
	,preview:false
	,bgcolor:'#CEE9F4'
	,bgalpha:.8
});

allowing only images

The allow property is set to accept only images. The selected images are added to a div. Note also the title of the SFBrowser is now changed to: Add some images.

$.sfb({
	 folder:	'ImageFolder/'
	,title:		'Add some images'
	,allow:		['jpeg','png','gif','jpg']
	,resize:	[640,480]
	,select:	addImages
	,plugins:	['filetree']
});

inline

When you set the inline property to something other than "body" SFBrowser will no appear as an overlay but inside the new value. The value has to be a regular JQuery selector with a single result. A selector with possible multiple results will really screw things up. If you're unsure about your selector simply add ':eq(0)' to it to ensure a single result
Contrary to an overlay, an inline SFBrowser will keep the rest of your page clickable.
Setting the fixed property to 'true' will also disable closing the filebrowser (this will only work on inline SFBrowsers). However, calling up a new instance of SFBrowser will close any previous instance.
Open inline fixed

$.sfb({ inline:'#inhere', fixed:true, select:function(a){alert(a.length+" files selected")} });

plugins

Plugins can be used to extend or alter the basic functionality of SFBrowser. These have to be set in 'sfbrowser/connectors/php/config.php'.
Once set, the init will automaticly fill the $.sfbrowser.defaults.plugins variable. You can override this by parsing the plugins variable in your SFBrowser call (as shown in example 1).

Right now SFBrowser comes with a couple plugins:

filetree

filetreeThis plugin adds an additional filetree to the left of the filetable.

createascii

A simple plugin that lets you create and edit ascii files. Don't expect anything fancy, it's just a plain text editor. Naturally you can only create and edit files that are set in allow or not set in deny.

imageresize

imageresizeThis plugin lets you resize and crop jpeg images. Indexed color images (gif and png) require different code that isn't implemented yet.
Selecting 'Resize' from a files context menu will bring up a window as shown here. Larger images are always scaled down to fit the window, this scale is shown as a percentage above the image. You can resize the window if you want to bring the scaling up to one hundred percent.
Dragging the red squares resizes the image. Dragging the blue squares will crop the image. You can also manually enter the desired with or height.
Since upscaling mostly results in ugly images, upscaling is turned off. The images aspect ratio will always be maintained (meaning you can't just resize the width, the height will always follow accordingly).

plugin creation

A plugin can be one Javascript file (filetree plugin) but it can also make use of PHP (imageresize plugin).
If a plugin contains either or both a config.php and/or and init.php file the initialisation will include them. It is then assumed that all javascript and/or css inclusion will be handled by that init.php file.
If no init.php file is found, the SFBrowser initialisation will then try to find and add both the plugin.js and/or the plugin.css.
Right now that is all the documentation there is for plugin development. If you want to develop one simply have to look at the existing two and follow their structure.

connectors

A connector folder should at least have the following files.

config file

The config file should at least have the following settings:

The config file is used in both the init file (to parse to sfbrowser js) and in the actual sfbrowser file (which does the actual server side thinking).

init file

The init file must be called in the html documents header in order to write these lines:

<link rel="stylesheet" type="text/css" media="screen" href="sfbrowser/css/sfbrowser.css" />
<script type="text/javascript" src="sfbrowser/array.js"></script>
<script type="text/javascript" src="sfbrowser/jquery.tinysort.min.js"></script>
<script type="text/javascript" src="sfbrowser/jquery.sfbrowser.min.js"></script>
<script type="text/javascript" src="sfbrowser/lang/en.js"></script>
<script type="text/javascript">
	<!--
	$.sfbrowser.defaults.connector = "php";
	$.sfbrowser.defaults.sfbpath = "sfbrowser/";
	$.sfbrowser.defaults.base = "../data/";
	$.sfbrowser.defaults.preview = 600;
	$.sfbrowser.defaults.deny = ["php","php3","phtml"];
	$.sfbrowser.defaults.icons = ['ai','as','avi','bmp','cs','default',(...)];
	-->
</script>

As you might have noticed, most of these lines are formed to what is set in the config file. The icons variable is a folder readout from the sfbrowser/icons/ folder.

sfbrowser file

The sfbrowser file is the actual connector to the SFBrowser plugin. Mostly it will require some POST variables and a JSON output object.
A POST will always contain a variable "a" that will determine the action to be taken.

For all actions counts: make absolutely sure that the incoming data corresponds with that set in the config file!

Mostly, a POST (or GET in case of force download) will contain the variable "folder" and the variable "file". Check both of these against the base upload folder set in the config. If it's outside, somebody is probably screwing around.
Just to be sure, check the number of _GET, _POST and _FILES variables. A _POST["a"] can only get a certain ammount of each, if these differ, something fishy might be going on.
If suspicious action occurs you can redirect them to the return error code set in the config file in order to block acces or whatever you'd like to do(??haven't really figured out how to go from there, consider it a loose stub??).

A number of the JSON outputs contain file descriptions. In the description of the types of actions the file object is referred to as <FileObject>. It looks like this:

JSON FileObject: {
	 file:		<String>	file name
	,mime:		<String>	file extention
	,rsize:		<uint>		file size in bytes
	,size:		<String>	file size in kB, MB or whatever
	,time:		<uint>		time in Unix Epoch
	,date:		<String>	time in "j-n-Y H:i"
	,width:		<uint>		image width in pixels
	,height:	<uint>		image height in pixels
}

The following are the possible values for _POST["a"]: the possible actions that can be taken and the required return values.

_POST["a"]=="fileList" :: retreive file list

input:
	_POST["folder"] <String>	path to folder
action:
	Read the contents of a folder
	Filter out the forbidden file types
	If applicable, filter for allowed file types
output: JSON {
	 error:		<String>	error message (see lang.js)
	,msg:		<String>	succes message (see lang.js)
	,data:		<Object>	object containing <FileObject>'s
}
example: {
	error:	"",
	msg:	"fileListing",
	data: {
		a: <FileObject>,
		b: <FileObject>,
		c: <FileObject>,
		...
	}
}

_POST["a"]=="upload" :: file upload

input:
	_FILES["fileToUpload"]	<Object>	file object
	_POST["file"]		<String>	path to folder
	_POST["deny"]		<String>	pipe separated string of denied file extensions ("php|tpl|log")
	_POST["allow"]		<String>	pipe separated string of allowed file extensions ("gif|jpg|jpeg|png")
	_POST["resize"]		<Array>		resize image to [width,heigth]
	
action:
	Check for _FILES["fileToUpload"]["error"]
	Check _FILES["fileToUpload"]["tmp_name"] for actual upload
	Check forbidden filetypes
	Check allowed filetypes
	Check upload folder for similarly named file
	Move file to upload folder
	If applicable, resize image
output: JSON {
	 error:		<String>	error message (see lang.js)
	,msg:		<String>	succes message (see lang.js)
	,data:		<FileObject>	uploaded file
}

_POST["a"]=="duplicate" :: duplicate file

input:
	_POST["file"]	<String>	file name
	_POST["folder"]	<String>	file folder
action:
	Create new non-existing file name
	Duplicate file to that name
output: JSON {
	 error:		<String>	error message (see lang.js)
	,msg:		<String>	succes message (see lang.js)
	,data:		<FileObject>	duplicated file
}

_POST["a"]=="delete" :: file delete

input:
	_POST["file"]	<String>	file name
	_POST["folder"]	<String>	file folder
action:
	delete file
output: JSON {
	 error:		<String>	error message (see lang.js)
	,msg:		<String>	succes message (see lang.js)
}

_POST["a"]=="download" :: file force download

input:
	_POST["file"]	<String>	file name
	_POST["folder"]	<String>	file folder
action:
	Force file download
output: nothing

_POST["a"]=="read" :: read txt file contents

input:
	_POST["file"]	<String>	file name
	_POST["folder"]	<String>	file folder
action:
	Read and return file contents
output: JSON {
	 error:		<String>	error message (see lang.js)
	,msg:		<String>	succes message (see lang.js)
	,data: {
		text:	<String>	first x amount of bytes from ascii file
	}
}

_POST["a"]=="rename" :: rename file

input:
	_POST["file"]	<String>	original file name
	_POST["folder"]	<String>	file folder
	_POST["nfile"]	<String>	new file name
action:
	Check if new file name is valid
	Rename file
output: JSON {
	 error:		<String>	error message (see lang.js)
	,msg:		<String>	succes message (see lang.js)
}

_POST["a"]=="addFolder" :: add folder

input:
	_POST["folder"]		<String>	folder to create new folder into
	_POST["foldername"]	<String>	new folder name
action:
	Create new folder
output: JSON {
	 error:		<String>	error message (see lang.js)
	,msg:		<String>	succes message (see lang.js)
	,data:		<FileObject>	newly created folder
}

_POST["a"]=="bar" :: image resize (in imageresize plugin)

input:
	_POST["file"]	<String>	file name
	_POST["folder"]	<String>	file folder
	_POST["w"]	<uint>		new width
	_POST["h"]	<uint>		new height
action:
	Resize image
output: JSON {
	 error:		<String>	error message (see lang.js)
	,msg:		<String>	succes message (see lang.js)
}