unserialize php in goland

Issue

I have a file with serialized array in PHP.
The content of the file locks like this

a:2:{i:250;s:7:"my_catz";s:7:"abcd.jp";a:2:{s:11:"category_id";i:250;s:13:"category_name";s:7:"my_catz";}}

The array unserialized is this

(
    [250] => my_catz
    [abcd.jp] => Array
        (
            [category_id] => 250
            [category_name] => my_catz
        )

)

Now, i want to get the content of the file in GO, unserialize it convert it to an array.
In GO i can get the content of the file using

dat, err := os.ReadFile("/etc/squid3/compiled-categories.db")
    if err != nil {
        if e.Debug {
            log.Printf("error reading /etc/squid3/compiled-categories.db: ", err)
        }
    }

And unserialized it using github.com/techoner/gophp library

package categorization

import (  
    "fmt"
    "os"
    "github.com/techoner/gophp"
    "log"
    "errors"
)

type Data struct {  
    Website   string
    Debug   bool
}

func (e Data) CheckPersonalCategories() (int,string) {  
    if e.Debug {
        log.Printf("Checking Personal Categories")
    }
    if _, err := os.Stat("/etc/squid3/compiled-categories.db"); errors.Is(err, os.ErrNotExist) {
        if e.Debug {
            log.Printf("/etc/squid3/compiled-categories.db not exit: ", err)
        }
        return  0,""
    }
    dat, err := os.ReadFile("/etc/squid3/compiled-categories.db")
    if err != nil {
        if e.Debug {
            log.Printf("error reading /etc/squid3/compiled-categories.db: ", err)
        }
    }
    
    out, _ := gophp.Unserialize(dat)
    
    fmt.Println(out["abcd.jp"])
return  0,""
}

But I can’t access to the array, for example, when I try access to array key using out["abcd.jp"] i get this error message

invalid operation: out["abcd.jp"] (type interface {} does not support indexing)

The result of out is

map[250:my_catz abcd.jp:map[category_id:250 category_name:my_catz]]

Solution

Seams that is unserializing

Don’t make assumptions about what is and isn’t succeeding in your code. Error responses are the only reliable way to know whether a function succeeded. In this case the assumption may hold, but ignoring errors is always a mistake. Invest time in catching errors and at least panic them – don’t instead waste your time ignoring errors and then trying to debug unreliable code.

invalid operation: out["abcd.jp"] (type interface {} does not support indexing)

The package you’re using unfortunately doesn’t provide any documentation so you have to read the source to understand that gophp.Unserialize returns (interface{}, error). This makes sense; php can serialize any value, so Unserialize must be able to return any value.

out is therefore an interface{} whose underlying value depends on the data. To turn an interface{} into a particular value requires a type assertion. In this case, we think the underlying data should be map[string]interface{}. So we need to do a type assertion:

mout, ok := out.(map[string]interface{})

Before we get to the working code, one more point I’d like you to think about. Look at the code below: I started it from your code, but the resemblance is very slight. I took out almost all the code because it was completely irrelevant to your question. I added the input data to the code to make a minimal reproduction of your code (as I asked you to do and you declined to do). This is a very good use of your time for 2 reasons: first, it makes it a lot easier to get answers (both because it shows sufficient effort on your part and because it simplifies the description of the problem), and second, because it’s excellent practice for debugging. I make minimal reproductions of code flows all the time to better understand how to do things.

You’ll notice you can run this code now without any additional effort. That’s the right way to provide a minimal reproducible example – not with a chunk of mostly irrelevant code which still can’t be executed by anybody.

The Go Plaground is a great way to demonstrate go-specific code that others can execute and investigate. You can also see the code below at https://go.dev/play/p/QfCl08Gx53e

package main

import (
    "fmt"

    "github.com/techoner/gophp"
)

type Data struct {
    Website string
    Debug   bool
}

func main() {
    var dat = []byte(`a:2:{i:250;s:7:"my_catz";s:7:"abcd.jp";a:2:{s:11:"category_id";i:250;s:13:"category_name";s:7:"my_catz";}}`)
    out, err := gophp.Unserialize(dat)
    if err != nil {
        panic(err)
    }
    if mout, ok := out.(map[string]interface{}); ok {
        fmt.Println(mout["abcd.jp"])
    }
}

Answered By – Daniel Farrell

Answer Checked By – Clifford M. (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.