在Goland中反序列化PHP对象。

huangapple go评论82阅读模式
英文:

unserialize php in goland

问题

我有一个包含序列化数组的PHP文件。
文件的内容如下:

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";}}

反序列化后的数组如下:

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

)

现在,我想在GO中获取文件的内容,将其反序列化并转换为数组。
在GO中,我可以使用以下代码获取文件的内容:

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)
    }
}

然后,使用github.com/techoner/gophp库对其进行反序列化:

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,""
}

但是,我无法访问数组,例如,当我尝试使用out["abcd.jp"]访问数组键时,我会收到以下错误消息:

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

out的结果是:

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

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]]

答案1

得分: 2

> 看起来是在反序列化

在你的代码中,不要对代码的成功与否做任何假设。错误响应是唯一可靠的方式来判断函数是否成功。在这种情况下,这个假设可能成立,但忽略错误总是一个错误。花时间来捕获错误并至少使用panic来处理它们,而不是浪费时间忽略错误,然后尝试调试不可靠的代码。

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

你正在使用的包很不幸地没有提供任何文档,所以你必须阅读源代码才能理解gophp.Unserialize返回的是(interface{}, error)。这是有道理的;php可以序列化任何值,所以Unserialize必须能够返回任何值。

因此,out是一个interface{},其底层值取决于数据。要将interface{}转换为特定的值,需要进行类型断言。在这种情况下,我们认为底层数据应该是map[string]interface{}。所以我们需要进行类型断言:

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

在我们进入可工作的代码之前,还有一点我希望你考虑一下。看一下下面的代码:我从你的代码开始,但相似之处非常小。我删除了几乎所有的代码,因为它与你的问题完全无关。我添加了输入数据到代码中,以便最小化重现你的代码(正如我要求你做的,但你拒绝了)。这是一个非常好的做法,有两个原因:首先,它使得获取答案变得更容易(因为它显示了你付出了足够的努力,并且简化了问题的描述),其次,因为它是优秀的调试实践。我经常制作最小化的代码流来更好地理解如何做事情。

你会注意到,现在你可以运行这段代码而不需要额外的努力。这是提供一个最小可重现示例的正确方式 - 不是用一大块大部分与问题无关的代码,仍然无法被任何人执行。

Go Playground是展示其他人可以执行和调查的特定于Go的代码的好方法。你也可以在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"])
	}
}
英文:

> 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"])
	}
}

huangapple
  • 本文由 发表于 2022年2月18日 08:23:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/71167024.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定