Web file manager in less than 100 lines of code


Uploading and download files in web browser is a common task in virtually any web application or service. This article shows how to do this with very little coding - in less than 100 lines of code. The database used is PostgreSQL, and the web server is Nginx.

You will use Golf as an application server and the programming language. It will run behind the web server. This way end-user cannot talk to your application server directly because all such requests go through the web server, while your back-end application can talk directly to your application server for better performance.

Assuming your currently logged-on Linux user will own the application, create a source code directory and also create Golf application named "file-manager":
mkdir filemgr
cd filemgr
gg -k file-manager

Next, create PostgreSQL database named "db_file_manager", owned by currently logged-on user (i.e. passwordless setup):
echo "create user $(whoami);
create database db_file_manager with owner=$(whoami);
grant all on database db_file_manager to $(whoami);
\q"  | sudo -u postgres psql

Create database configuration file used by Golf that describes the database (it's a file "db"):
echo "user=$(whoami) dbname=db_file_manager" > db

Create SQL table that will hold files currently stored on the server:
echo "create table if not exists files (fileName varchar(100), localPath varchar(300), extension varchar(10), description varchar(200), fileSize int, fileID bigserial primary key);" | psql -d db_file_manager

Finally, create source Golf files. First create "start.golf" file and copy and paste:
 begin-handler /start public
    @<h2>File Manager</h2>
    @To manage the uploaded files, <a href="<<print-path "/list">>">click here.</a><br/>
    @<br/>
    @<form action="<<print-path "/upload">>" method="POST" enctype="multipart/form-data">
    @    <label for="file_description">File description:</label><br>
    @    <textarea name="filedesc" rows="3" columns="50"></textarea><br/>
    @    <br/>
    @    <label for="filename">File:</label>
    @    <input type="file" name="file" value=""><br><br>
    @    <input type="submit" value="Submit">
    @</form>
 end-handler

Create "list.golf" file and copy and paste:
 begin-handler /list public
     @<h2>List of files</h2>
     @To add a file, <a href="<<print-path "/start">>">click here</a><br/><br/>
     @<table border="1">
     @<tr>
     @    <td>File</td><td>Description</td><td>Size</td><td>Show</td><td>Delete</td>
     @</tr>
     run-query @db= \
         "select fileName, description, fileSize, fileID from files order by fileSize desc" \
         output file_name, description noencode, file_size, file_ID
         @<tr>
         @    <td><<print-out file_name web-encode>></td><td><<print-out description web-encode>><td><<print-out file_size web-encode>></td>
         @    <td><a href="<<print-path "/download">>/file_id=<<print-out file_ID url-encode>>">Show</a></td>
         @    <td><a href="<<print-path "/delete">>/action=confirm/file_id=<<print-out file_ID url-encode>>">Delete</a></td>
         @</tr>
     end-query
     @</table>
 end-handler

Create "upload.golf" file and copy and paste:
 begin-handler /upload public
    get-param filedesc      // file description from the upload form
    get-upload file local-file file_location size file_size \
        extension file_ext client-file file_filename
    @<h2>Uploading file</h2>
    run-query @db= \
         "insert into files (fileName, localPath, extension, description, fileSize) \
             values ('%s', '%s', '%s', '%s', '%s')" \
         input file_filename, file_location, file_ext, filedesc, $file_size
    end-query
    @File <<print-out file_filename web-encode>> of size <<print-out file_size >> \
         is stored on server at <<print-out file_location web-encode>>. \
         File description is <<print-out filedesc web-encode>>.<hr/>
 end-handler

Create "download.golf" file and copy and paste:
 begin-handler /download public
     get-param file_id
     run-query @db= \
         "select localPath,extension from files where fileID='%s'" \
         input file_id \
         output local_path, ext \
         row-count num_files
             if-true ext equal ".jpg"
                 send-file local_path headers content-type "image/jpg"
             else-if ext equal ".png"
                 send-file local_path headers content-type "image/png"
             else-if ext equal ".pdf"
                 send-file local_path headers content-type "application/pdf"
             else-if
                 send-file local_path headers content-type "application/octet-stream" download
             end-if
     end-query
     if-true num_files not-equal 1
         @Cannot find this file!<hr/>
         exit-handler
     end-if
 end-handler

Create "delete.golf" file and copy and paste:
 begin-handler /delete public
    @<h2>Delete a file</h2>
    get-param action
    get-param file_id
    run-query @db="select fileName, localPath, description  from files where fileID='%s'" output file_name, local_path, desc input file_id
         if-true action equal "confirm" // get file information to confirm what will be deleted
            @Are you sure you want to delete file <<print-out file_name web-encode>> (<<print-out desc web-encode>>)? Click <a href="<<print-path "/delete">>?action=delete&amp;file_id=<<print-out file_id url-encode>>">Delete</a> or click the browser's Back button to go back.<br/>
         else-if action equal "delete"  // actual delete file, once confirmed
            begin-transaction @db
            run-query @db= "delete from files where fileID='%s'" input file_id error err no-loop
            if-true err not-equal "0"
                @Could not delete the file (error <<print-out err web-encode>>)
                rollback-transaction @db
            else-if
                delete-file local_path status st
                if-true st equal GG_OKAY
                    commit-transaction @db
                    @File deleted. Go back to <a href="<<print-path "/start">>">start page</a>
                else-if
                    rollback-transaction @db
                    @File could not be deleted, error <<print-out st>>
                end-if
            end-if
         else-if
            @Unrecognized action <<print-out action web-encode>>
         end-if
    end-query
 end-handler

Make the application:
gg -q --db=postgres:db

Run your application server:
mgrg file-manager

A web server sits in front of Golf application server, so it needs to be setup. This example is for Ubuntu, so edit Nginx config file there:
sudo vi /etc/nginx/sites-enabled/default

Add this in "server {}" section ("client_max_body_size" allows for images of typical sizes to be uploaded), replace "your-user" with the name of your OS user:
location /file-manager/ { include /etc/nginx/fastcgi_params; fastcgi_pass  unix:///home/your-user/.golf/apps/file-manager/sock/.sock; }
client_max_body_size 100M;

Restart Nginx:
sudo systemctl restart nginx

Go to your web browser, and enter:
http://127.0.0.1/file-manager/start

This is what the end result looks like. Obviously, we used just bare-bone HTML, but that's not the point here at all. You can use any kind of front-end technology, the point is to demonstrate Golf as a back-end server for web applications/services.

Here's the home screen, with the form to upload a file and a link to list of files:

Golf

Listing files:

Golf

Asking to delete a file:

Golf

Confirmation of deletion:

Golf

See also
Articles
article-capi  
article-cookies  
article-debug  
article-distributed  
article-encryption  
article-fetch-web-page  
article-fifo  
article-file-manager  
article-hello-server  
article-hello-world  
article-hello-world-service  
article-hello-world-service-web  
article-how-to-create-golf-application  
article-json  
article-language  
article-mariadb  
article-memory-safety  
article-memory-safety-web  
article-notes-postgres  
article-random  
article-regex  
article-remote-call  
article-request-function  
article-security  
article-sendmail  
article-server  
article-shopping  
article-sqlite  
article-statements  
article-status-check  
article-tree  
article-tree-web  
article-vim-coloring  
article-web-framework-for-c-programming-language  
article-what-is-golf  
article-what-is-web-service  
See all
documentation


Copyright (c) 2019-2025 Gliim LLC. All contents on this web site is "AS IS" without warranties or guarantees of any kind.