# Uploading Files

Uploading files is the next step in form processing, in case of files, we send the entire file data in the HTTP header, so we have to set the form encoding to `enctype="multipart/form-data"`. This will inform our server that we are going to get a file from the form along with the rest of the fields, if any.

This means we can get either either file(s) and data or just file(s) or just data and no file(s).

At the first line of our HTTP handler, we have to write this line, if this line is not present in the first line then it gives unexpected results

```go
file, handler, err := r.FormFile("uploadfile")

if handler != nil {
        r.ParseMultipartForm(32 << 20) //defined maximum size of file
        defer file.Close()
        f, err := os.OpenFile("./files/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
        if err != nil {
            log.Println(err)
            return
        }
        defer f.Close()
        io.Copy(f, file)
        filelink := "<br> <a href=./files/"+handler.Filename+">"+ handler.Filename+"</a>"
        content =  content + filelink
}
```

We first provide the maximum size of the file which is 32 ^ 20, which is gigantic for our webapp, not everyone has the Internet infrastructure to upload that big a file, but we want to be flexible.

We basically get a file from the form request, in the form handler we open another file with the same/different name and then read the file form the request and write it on the server. We need to handle the scene where we name the file differently so we'd need to store the old file name -> new file name relation somewhere, it can be a database table.

The file name should be scrubbed, since the user can give any malicious name to damage our application.

We now want to randomize the file name of the files which the users upload. In your `AddTaskFunc` add the following lines

```go
if handler != nil {
        r.ParseMultipartForm(32 << 20) //defined maximum size of file
        defer file.Close()
        randomFileName := md5.New()
        io.WriteString(randomFileName, strconv.FormatInt(time.Now().Unix(), 10))
        io.WriteString(randomFileName, handler.Filename)
        token := fmt.Sprintf("%x", randomFileName.Sum(nil))
        f, err := os.OpenFile("./files/"+token, os.O_WRONLY|os.O_CREATE, 0666)
        if err != nil {
            log.Println(err)
            return
        }
        defer f.Close()
        io.Copy(f, file)

        filelink := "<br> <a href=/files/" + token + ">" + handler.Filename + "</a>"
        content = content + filelink

        fileTruth := db.AddFile(handler.Filename, token)
        if fileTruth != nil {
            message = "Error adding filename in db"
            log.Println("error adding task to db")
        }
    }
```

file `~/Tasks/db/db.go`

```go
// AddFile is used to add the md5 of a file name which is uploaded to our application
// this will enable us to randomize the URL without worrying about the file names
func AddFile(fileName, token string) error {
    SQL, err := database.Prepare("insert into files values(?,?)")
    if err != nil {
        log.Println(err)
    }
    tx, err := database.Begin()

    if err != nil {
        log.Println(err)
    }
    _, err = tx.Stmt(SQL).Exec(fileName, token)
    if err != nil {
        log.Println(err)
        tx.Rollback()
    } else {
        log.Println(tx.Commit())
    }
    return err
}
```

table structure

```sql
    CREATE TABLE files(name varchar(1000) not null, autoName varchar(255) not null);
```

These block of code do the following things:

1. Create a version of name for each uploaded file&#x20;
2. Insert it in database
3. Reference the file as `/files/<randomName>`&#x20;
4. File is now referenced by our name rather than the user supplied name

The next part to do is registering the `/files/` handler.

file: `~/Tasks/views/views.go`

```go
// UploadedFileHandler is used to handle the uploaded file related requests
func UploadedFileHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method == "GET" {
        log.Println("into the handler")
        token := r.URL.Path[len("/files/"):]

        //file, err := db.GetFileName(token)
        //if err != nil {
        log.Println("serving file ./files/" + token)
        http.ServeFile(w, r, "./files/"+token)
        //}
    }
}
```

## Links

-[Previous section](/bo/2.4workingwithforms.md) -[Next section](/bo/3.0templating.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://thewhitetulip.gitbook.io/bo/2.4workingwithforms/2.5uploadingfiles.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
