Home

Awesome

Cool File Transfer

Directly transfer files between two devices using nothing more than a web browser and a standard PHP enabled web server. Choose from a MIT or LGPL license.

Instead of using third-party services such as Dropbox or Google Drive to transfer files, Cool File Transfer directly transfers files through a host that both devices have access to. It's great for moving large files without requiring intermediate storage!

Your PC, tablet, smartphone, refridgerator, and IT department thank you for choosing Cool File Transfer.

Awesome demo of Cool File Transfer

Donate Discord

Features

Getting Started

Put the contents of this repository on a web server running PHP. Then run the install.php file using your web browser. SQLite is a great starting database that sets up quickly but MySQL and Postgres are supported too. Assuming you have a decent setup, the installer takes only a couple of minutes.

Once Cool File Transfer is installed, secure the installation path and then start using it. A nifty class that is creatively called CoolFileTransfer is inside cft.php. It's designed to be an intermediate, isolated layer between the configuration (config.php), the database, and an application (or API). Also included with Cool File Transfer is jQuery Fancy File Uploader. Let's use the CoolFileTransfer class to display a file transfer dropzone:

<?php
	require_once "/var/www/cool-file-transfer/cft.php";

	$cft = new CoolFileTransfer();

	$srcuser = "The Webmaster (webmaster@cubiclesoft.com)";

	if (isset($_REQUEST["action"]) && $_REQUEST["action"] === "starttransfer")
	{
		if (!isset($_REQUEST["destuser"]) || !isset($_REQUEST["filename"]) || !isset($_REQUEST["filesize"]))
		{
			$result = array(
				"success" => false,
				"error" => "Missing 'destuser', 'filename', or 'filesize'.",
				"errorcode" => "missing_required_fields"
			);
		}
		else
		{
			$result = $cft->StartSendFile($srcuser, $_REQUEST["destuser"], $_REQUEST["filename"], $_REQUEST["filesize"]);
		}

		header("Content-Type: application/json");

		echo json_encode($result, JSON_UNESCAPED_SLASHES);
	}
	else
	{
		// Obviously, you'll use something more dynamic for production use.
		$destuser = "Bob (bob@forapples.com)";

		require_once "/var/www/cool-file-transfer/support/flex_forms.php";
		require_once "/var/www/cool-file-transfer/support/flex_forms_fileuploader.php";
?>
<div class="fileuploadwrap"><input class="text" type="file" id="uploader" name="file" /></div>

<script type="text/javascript" src="/cool-file-transfer/support/jquery-3.5.0.min.js"></script>

<link rel="stylesheet" href="/cool-file-transfer/support/fancy-file-uploader/fancy_fileupload.css" type="text/css" media="all" />
<script type="text/javascript" src="/cool-file-transfer/support/fancy-file-uploader/jquery.ui.widget.js"></script>
<script type="text/javascript" src="/cool-file-transfer/support/fancy-file-uploader/jquery.fileupload.js"></script>
<script type="text/javascript" src="/cool-file-transfer/support/fancy-file-uploader/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="/cool-file-transfer/support/fancy-file-uploader/jquery.fancy-fileupload.js"></script>

<script type="text/javascript" src="<?php echo $cft->GetDefaultJS(); ?>"></script>

<script type="text/javascript">
jQuery(function() {
	var options = {
		'fileupload' : {
			'maxChunkSize' : <?php echo FlexForms_FileUploader::GetMaxUploadFileSize(); ?>
		},
		'preinit' : CoolFileTransfer.PreInit,
		'startupload' : CoolFileTransfer.StartUpload,
		'uploadcancelled' : CoolFileTransfer.UploadCancelled
	};

	jQuery('#uploader').FancyFileUpload(options);
});
</script>

<script type="text/javascript">
CoolFileTransfer.targeturl = '/yourapp/';

CoolFileTransfer.initrequest = {
	'action' : 'starttransfer',
	'destuser' : '<?php echo FlexForms::JSSafe($destuser); ?>',
	'xsrf_token' : 'your_xsrf_token_here'
};
</script>
<?php
	}
?>

Okay, that's half of the equation. That puts the uploader widget onto a page. Target users have to be aware that there is a file waiting for them, so the CoolFileTransfer class makes it easy to display notifications to users:

	require_once "/var/www/cool-file-transfer/cft.php";

	$cft = new CoolFileTransfer();

	$srcuser = "Bob (bob@forapples.com)";

	// Retrieve the notification list.
	$result = $cft->GetRecvList($srcuser);
	if ($result["success"] && count($result["users"]))
	{
?>
<link rel="stylesheet" href="<?=$cft->GetDefaultCSS()?>" type="text/css" media="all" />
<?php
		$cft->OutputHTMLNotifications($result["users"]);
	}

Just put that code somewhere before the closing body tag in your HTML and your users will see nice notification boxes whenever a file is ready to transfer.

Options

The default Javascript implementation of Cool File Transfer accepts the following options:

How it Works

Other than PHP's default behavior for file handling, Cool File Transfer doesn't store file data to disk. Instead, the sending and receiving endpoints set up and connect to TCP/IP servers at various times to perform the necessary communication between two separate PHP processes. Most third-party services store a file upload until the recipient comes along and retrieves it. However, doing that requires storage space, which may or may not be feasible. Regardless, Cool File Transfer is a very different tool.

The sending side attempts to self-regulate its speed to a bitrate of 1.25 seconds of transferred data per request. This allows both sides to send and receive data at roughly the same rate during a lengthy transfer process. Since most web browsers will use keep-alive connections, a little extra overhead is fine. This approach prevents stalling either side for any significant amount of time.

Fun Facts

This product uses a LOT of existing CubicleSoft software (FlexForms, FlexForms Modules, CSDB, jQuery Fancy File Uploader, and some previously unpublished code). Completing the entire project in one weekend would not have been feasible without the existing technology stack.

You read that right: This entire project was produced in just one weekend. Fully releasing everything to the Interwebs took another day though, but only because making a video to showcase a project takes time.

Admin Pack/FlexForms Integration

If you use Admin Pack, then you can integrate the first half like this:

<?php
	require_once "/var/www/cool-file-transfer/cft.php";

	$cft = new CoolFileTransfer();

	$srcuser = "The Webmaster (webmaster@cubiclesoft.com)";

	if (isset($_REQUEST["action"]) && $_REQUEST["action"] === "starttransfer")
	{
		if (!isset($_REQUEST["destuser"]) || !isset($_REQUEST["filename"]) || !isset($_REQUEST["filesize"]))
		{
			$result = array(
				"success" => false,
				"error" => "Missing 'destuser', 'filename', or 'filesize'.",
				"errorcode" => "missing_required_fields"
			);
		}
		else
		{
			$result = $cft->StartSendFile($srcuser, $_REQUEST["destuser"], $_REQUEST["filename"], $_REQUEST["filesize"]);
		}

		header("Content-Type: application/json");

		echo json_encode($result, JSON_UNESCAPED_SLASHES);
	}
	else
	{
		// Obviously, you'll use something more dynamic for production use.
		$destuser = "Bob (bob@forapples.com)";

		require_once "support/flex_forms_fileuploader.php";

		$desc = "<br>";

		ob_start();
?>
<script type="text/javascript" src="<?php echo $cft->GetDefaultJS(); ?>"></script>
<script type="text/javascript">
CoolFileTransfer.targeturl = '<?php echo BB_JSSafe(BB_GetRequestURLBase()); ?>';

CoolFileTransfer.initrequest = {
	'action' : 'starttransfer',
	'destuser' : '<?php echo BB_JSSafe($destuser); ?>',
	'sec_t' : '<?php echo BB_CreateSecurityToken("starttransfer"); ?>'
};
</script>
<?php
		$desc .= ob_get_contents();
		ob_end_clean();

		$contentopts = array(
			"desc" => "You are signed in as '" . $srcuser . "'.  Send files to '" . $destuser . "'.",
			"htmldesc" => $desc,
			"fields" => array(
				array(
					"type" => "file",
					"name" => "file",
					"uploader" => true,
					"maxchunk" => FlexForms_FileUploader::GetMaxUploadFileSize(),
					"uploader_callbacks" => array(
						"preinit" => "CoolFileTransfer.PreInit",
						"startupload" => "CoolFileTransfer.StartUpload",
						"uploadcancelled" => "CoolFileTransfer.UploadCancelled"
					)
				)
			)
		);

		BB_GeneratePage("Transfer Files", $menuopts, $contentopts);
	}

For FlexForms Extras, the above will be similar but use the usual $ff->Generate($contentopts) method.

To implement the second half in Admin Pack, abusing FlexForms CSS dependency injection via BB_InjectLayoutHead() is the easiest way to get Cool File Transfer notifications to appear regardless of where the user is located in the application:

<?php
	function BB_InjectLayoutHead()
	{
		global $cft, $srcuser, $bb_flexforms;

		// Menu title underline:  Colors with 60% saturation and 75% brightness generally look good.
?>
<style type="text/css">
#menuwrap .menu .title { border-bottom: 2px solid #C48851; }

#contentwrap.showmenu .cft_notifications_wrap { display: none; }
</style>
<?php

		// Retrieve the notification list.
		$result = $cft->GetRecvList($srcuser);
		if ($result["success"] && count($result["users"]))
		{
			// Add everything to the FlexForms instance by (ab)using CSS options.
			$bb_flexforms->AddCSS("cft-default", array("mode" => "link", "dependency" => false, "src" => $cft->GetDefaultCSS()));

			ob_start();
			$cft->OutputHTMLNotifications($result["users"]);

			$bb_flexforms->AddCSS("cft-notifications", array("mode" => "inline", "dependency" => "cft-default", "src" => ob_get_contents()));
			ob_end_clean();
		}
	}