0

I wanted to write data from the form to the database(different tables), but for some reason the images are not recorded.

func save_obj(w http.ResponseWriter, r *http.Request) {
    title := r.FormValue("title")
    type_obj := r.FormValue("type_obj")
    location := r.FormValue("location")
    long := r.FormValue("long")
    fond := r.FormValue("fond")
    //video := r.FormValue("video")
    inf := r.FormValue("inf")
    pros := r.FormValue("pros")
    about := r.FormValue("about")
    //docs := r.FormValue("docs")
    //подключение
    db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:8889)/service")
    if err != nil {
        panic(err)
    }

    defer db.Close()

    //установка
    insert, err := db.Query(fmt.Sprintf("INSERT INTO `objects` (`title`, `type_obj`, `location`, `long`, `fond`, `inf`, `pros`, `about`)"+
        " VALUES('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')", title, type_obj, location, long, fond, inf, pros, about))
    if err != nil {
        panic(err)
    }
    defer insert.Close()
    imgOne := b64.URLEncoding.DecodeString(r.FormValue("img-1"))
    imgTwo := b64.URLEncoding.DecodeString(r.FormValue("img-2"))
    imgThree := b64.URLEncoding.DecodeString(r.FormValue("img-3"))
    imgFour := b64.URLEncoding.DecodeString(r.FormValue("img-4"))
    ins, er := db.Query(fmt.Sprintf("INSERT INTO `img-1` (`title`, `img`) VALUES('%s', '%s')", title, imgOne))
    if er != nil {
        panic(er)
    }
    defer ins.Close()
    insr, error := db.Query(fmt.Sprintf("INSERT INTO `img-2` (`title`, `img`) VALUES('%s', '%s')", title, imgTwo))
    if error != nil {
        panic(error)
    }
    defer insr.Close()
    in, Error := db.Query(fmt.Sprintf("INSERT INTO `img-3` (`title`, `img`) VALUES('%s', '%s')", title, imgThree))
    if Error != nil {
        panic(Error)
    }
    defer in.Close()
    //последнее изображение
    in, Error := db.Query(fmt.Sprintf("INSERT INTO `img-4` (`title`, `img`) VALUES('%s', '%s')", title, imgFour))
    if Error != nil {
        panic(Error)
    }
    defer in.Close()
    http.Redirect(w, r, "/create_obj", http.StatusSeeOther)
}

Everything except the image recording works fine, but when I try to record, an error is displayed:

cannot use r.FormValue("img-1") (type string) as type []byte in argument to base64.URLEncoding.EncodeToString html:

<input type="file" class="img" name="img-1"><br>
      <input type="file" class="img" name="img-1"><br>
      <input type="file" class="img" name="img-3"><br>
      <input type="file" class="img" name="img-4"><br>

Why don't the types match and how can I encrypt an image in a blob?

Hamza Anis
  • 2,475
  • 1
  • 26
  • 36
righty_dev
  • 27
  • 5
  • 3
    FWIW, including mathematical operators within table/column identifiers is a cataclysmically bad idea. – Strawberry Jan 16 '21 at 08:16
  • Why not use the simpler way ?. Store pictures as files in any folder. And store the image path in the database. Benefits include: ease of development, elimination of image conversion processing, and a 30% reduction in storage space for each image. – Ahmed Jan 16 '21 at 13:35

2 Answers2

1

As per error the type of r.FormValue("img-1") (and possibly also img-2 and img-3) is already string but base64.URLEncoding.EncodeToString() takes []byte argument.

Since your form uses form type file you need to handle it as multipart and get images with r.FormFile("img-1") like this to get the bytes:

file, header, err := r.FormFile("img-1")    
defer file.Close()
if err != nil {
    // handle error
}
b := bytes.NewBuffer(nil)
if _, err := io.Copy(b, file); err != nil {
    // handle error
}
// convert bytes to base64
img := base64.URLEncoding.EncodeToString(b.Bytes())

You can make a convenience function out of this that takes file and header. In header you can find metadata such as filename, size and mime/type which can be useful thing to store to DB alongside with image for further use.

blami
  • 6,588
  • 2
  • 23
  • 31
  • Updated my answer accordingly – blami Jan 16 '21 at 06:36
  • "cannot use b (type *bytes.Buffer) as type []byte in argument to base64.URLEncoding.EncodeToString" – righty_dev Jan 16 '21 at 06:59
  • Sorry my bad it is `b.Bytes()`, I was typing on my phone of top of my head. Try `b.Bytes()` that should return `[]byte`. – blami Jan 16 '21 at 07:03
  • I wrote as an error panic(err), and now the error is run time error – righty_dev Jan 16 '21 at 10:02
  • error "invalid memory address or nil pointer dereference" – righty_dev Jan 16 '21 at 10:02
  • That must be error somewhere else in your code. I put together minimal example that works as expected. It listens on localhost:8080/ and allows you to upload an image, then prints base64 encoded payload on console (not in browser). You can find it [here](https://play.golang.org/p/SNetU9GqtCW) . NOTE: you won't be able to run it in Playground, I just put it there as it is convenient place to share Go code. – blami Jan 16 '21 at 11:40
0

There are quite a few issues with your code, but concentrating on the inserting of your image in your table.

  1. You should use Exec(), and not Query()
  2. Never use fmt.Printf and %s format: use SQL placeholders ? (especially when your data is coming from HTML forms) (has been mentioned in comments); the MySQL drivers knows how to deal with bytes
  3. Storing images in an RDBMS is working, but it is usually the wrong approach

Here is how you should save your decoded base64:

    ins, er := db.Exec("INSERT INTO `img-1` (`title`, `img`) VALUES(?, ?)",
        title, imgOne))
    if er != nil {
        panic(er)
    }

Also, consider returning the error, name it err (not er).

geertjanvdk
  • 3,440
  • 24
  • 26