File upload

Fileupload uses the storageApiUrl which can be retrieved from any FileserverInfo.
An optional parameter is the Url parameter.
Normally the XML with the Status and Message will be returned, however when the Url parameter is appended, we will use that to redirect to after uploading finishes.

'Chunking' can, and should be used when uploading large files. The file is then split up in chunks, and uploaded with various calls.

Note that the name of the uploaded file must be one that is supported on all platforms

Authentication Methods


  • With a username and password
Input Parameter Type Description
Token* String Security token
FileserverName* String FileServer name
Path* String Path of the folder where the file will be stored
Url String Optional url that, if added, will be used to redirect to after the upload finishes (both for a successful upload and error cases)
Response Type Description
Success Boolean True on success, False on failure

EXAMPLES

The files must be posted with the name ‘file[]’ to the storageApiUrl.

When using chunking, the Content-Range header must be used in the following format:
"Content-Range: bytes STARTBYTE/ENDBYTE-TOTALBYTES"

Example:
Uploading a file with a size of 150000 bytes and chunk size 100000 bytes requires 2 uploads.

Upload 1:
    "Content-Range: bytes 0/99999-150000"
Upload 2:
    "Content-Range: bytes 100000/149999-150000"

Without the Optional Url parameter:

curl 'https://storage.example.com/storage/api.php?Token=rc1d3ntb53tt6b2vhail6rdtrsxov3v&Task=FileUpload&FileserverName=nmsa000010&Path=/dir/'

With the Url parameter:

curl 'https://storage.example.com/storage/api.php?Token=rc1d3ntb53tt6b2vhail6rdtrsxov3v&Task=FileUpload&FileserverName=nmsa000010&Path=/dir%2F/yes%2F&Url=https://mynomadesk.com/file/finishedupload'

RESPONSE

Without the optional Url parameter:

<Response>
    <Status>999</Status>
    <Message></Message>
    <Files>
        <File>
            <Path>/testfile/file.txt</Path>
            <Status>1</Status>
            <Message</Message>
        </File>
        <File>
            <Path>/testfile/.hiddenfile</Path>
            <Status>4029</Status>
            <Message></Message>
        </File>
    </Files>
</Response>

When all files are uploaded successfully the normal XML is returned:

<Response>
    <Status>1</Status>
    <Message></Message>
</Response>

With the Url parameter a redirect occurs with the Status Code and Message appended, and the FilePath, FileStatus and FileMessage of each file.

curl -g 'https://storage.example.com/mynomadesk/file/finishedupload&Status=999&Message=&FilePath[]=%2Ftestfile%2Ffile.txt&FileStatus[]=4029&FileMessage[]='

Example PHP code that demonstrates a chunked upload

/**
 * Fill in your settings here
 */
$ctrller = "https://storage.example.com/ctrller/api.php";
$email = "email@example.com";
$pw = "password";
$vault_name = 'vaultname'; // -- nmsa name
$chunksize = 100000; // 100kb - Chunk size is in bytes
$filepath = "/path/to/file";

/**
 * First log on so we have an authentication token
 */
$token = Logon($ctrller, $email, $pw);

/**
 * Now we need to know the url for the storage node our vault is located on
 */
$storageapiurl = GetStorageApiUrl($ctrller, $token, $vault_name);

/**
 * Start uploading the file
 */
$result = UploadFile($storageapiurl, $token, $vault_name, $filepath, $chunksize);
$xml = new SimpleXMLElement($result);
echo "Uploaded File -> ".$xml->Message->__toString()."<br /><br /><br />\n\n\n";

/**
 * Log off (invalidates our authentication token)
 */
LogOut($ctrller, $token);


function UploadFile($pUrl, $pToken, $pVaultName, $pFile, $pChunkSize) {
    $upload = function($pFile, $pUrl, $pToken, $pVaultName, $pChunk, $pChunkSize) {
        //Create the temp file for this chunk
        $start = $pChunk * $pChunkSize; // start byte
        $tmp = '/tmp/'.uniqid();
        file_put_contents($tmp, file_get_contents($pFile, false, null, $start, $pChunkSize));
        $end = $start + (filesize($tmp) - 1); // index starts on 0, so end is filesize - 1


        $curl = curl_init();
        $optionsSuccess = true;
        $optionsSuccess &= curl_setopt($curl, CURLOPT_URL, $pUrl);
        $optionsSuccess &= curl_setopt($curl, CURLOPT_SAFE_UPLOAD, false);
        $optionsSuccess &= curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
        $optionsSuccess &= curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        $optionsSuccess &= curl_setopt($curl, CURLOPT_POST, 1);
        $optionsSuccess &= curl_setopt($curl, CURLOPT_HTTPHEADER, [ 'Content-Range: bytes '.$start.'-'.$end.'/'.filesize($pFile) ]);
        $optionsSuccess &= curl_setopt($curl, CURLOPT_POSTFIELDS, [
            'Token' => $pToken,
            'FileserverName' => $pVaultName,
            'Path' => '/',
            'Task' => 'FileUpload',
            'Name' => basename($pFile),
            'file[0]' => new CURLFile($tmp, null, basename($pFile))
        ]);

        $result = curl_exec($curl);
        curl_close($curl);
        unlink($tmp);
        return $result;
    };

    //Start the upload for x chunks
    $size = filesize($pFile);
    $chunks = ($size > $pChunkSize) ? ceil($size / $pChunkSize) : 1;

    echo "Uploading $chunks Chunks <br />\n";
    for($i = 0; $i < $chunks; $i++) {
        echo "Uploading Chunk $i<br />\n";
        $result = $upload($pFile, $pUrl, $pToken, $pVaultName, $i, $pChunkSize);
    }
     return $result;
}

function Logon($pApiUrl, $pEmail, $pPassword) {
    $loginurl = $pApiUrl."?Task=Logon&Email=".$pEmail."&Password=".$pPassword;
    echo "URL -> ".$loginurl."<br />\n";
    $xml = new SimpleXMLElement($loginurl, null, true);
    echo "Logon -> ".$xml->Message->__toString()."<br />\n";

    $securitytoken = $xml->Token->__toString();
    echo "Token -> ".$securitytoken."<br /><br />\n\n";
    return $securitytoken;
}

function LogOut($pApiUrl, $pToken) {
    $logouturl = $pApiUrl."?Task=Logout&Token=".$pToken;
    $xml = new SimpleXMLElement($logouturl, null, true);
    echo "Logout -> ".$xml->Message->__toString()."<br />\n";
}

function GetStorageApiUrl($pApiUrl, $pToken, $pVaultName) {
    $getinfourl = $pApiUrl."?Token=".$pToken."&Task=GetFileserverInfo&FileserverName=".$pVaultName."&ExtendedInfo=false";
    echo "URL -> ".$getinfourl."<br />\n";
    $xml = new SimpleXMLElement($getinfourl, null, true);
    echo "Get FileServerInfo -> ".$xml->Message->__toString()."<br />\n";
    $fileserverName  = $xml->Fileservers->Fileserver->Name->__toString();
    $StorageApiUrl  = $xml->Fileservers->Fileserver->StorageApiUrl->__toString();
    echo "Fileserver Name ->".$fileserverName."<br /><br />\n\n";
    echo "StorageApiUrl ->".$StorageApiUrl."<br /><br />\n\n";
    return $StorageApiUrl;
}

Example C# code to upload a file

using System.Collections.Specialized;
using System.Net;

//Use the Logon request to get a Token
const string token = "[TOKEN]";
//Use the GetFileservers or GetFileserverInfo request to get the storage node and vault name
const string vaultName = "[VAULTNAME]";
const string storageNode = "[STORAGENODE]";
//Source file path
const string filePath = "[FILE PATH]";
//Target path on the vault
const string targetPath = "[TARGET PATH]";

//Now upload the file
await new UploadSample().Upload(token, storageNode, vaultName, targetPath, filePath);

class UploadSample
{
    public async Task Upload(string token, string storageNode, string vaultName, string targetPath, string filePath)
    {
        //Add the parameters that are required in querystring
        var parameters = new NameValueCollection()
        {
            { "Token", token },
            { "Task", "FileUpload" },
            { "FileserverName", vaultName },
            { "FileName", Path.GetFileName(targetPath) },
            { "Path", Path.GetDirectoryName(targetPath) }
        };
        var storageNodeUri = GetUri(storageNode, parameters);

        //Upload the file
        //UploadUsingWebClient(storageNodeUri, filePath);
        await UploadUsingHttpClient(storageNodeUri, filePath);
    }

    private static Uri GetUri(string storageNode, NameValueCollection queryParams)
    {
        var uriBuilder = new UriBuilder(storageNode)
        {
            Query = string.Join("&", queryParams.AllKeys.ToDictionary(x => x, x => queryParams[x])
                .Select(kvp => $"{kvp.Key}={kvp.Value}"))
        };
        return uriBuilder.Uri;
    }

    private static void UploadUsingWebClient(Uri storageNodeUri, string filePath)
    {
        using var client = new WebClient();
        client.UploadFile(storageNodeUri, filePath);
    }

    private static async Task UploadUsingHttpClient(Uri storageNodeUri, string filePath)
    {
        var content = new MultipartFormDataContent();
        var file = new FileInfo(filePath);
        var fileContent = new StreamContent(file.OpenRead());
        content.Add(fileContent, "file", file.Name);

        using var client = new HttpClient();
        await client.PostAsync(storageNodeUri, content);
    }
}