英文:
PHP can't decompress gzip data by Golang
问题
为什么我的 PHP 示例中无法使用 Go 解压缩 gzip 数据,但是 PHP 将 gzip 数据发送到 Go 是成功的?我需要将 gzip JSON 数据从 Go 发送到 PHP API 服务。
测试结果
-> | php | go
---------------------
php | 成功 | 成功
go | 失败 | 成功
PHP 代码
class GzipDemo
{
public function gzen($data, $file){
$json_data = json_encode($data);
$gz_data = gzencode($json_data,9);
file_put_contents($file,$gz_data);
}
public function gzdn($file){
$data = file_get_contents($file);
$unpacked = gzdecode($data);
if ($unpacked === FALSE)
{
print("失败:".$file."\n");
}else{
print($file. " 结果数据 :".$unpacked ."\n");
}
}
}
$demo = new GzipDemo();
$file="phpgzip.txt";
$demo->gzen("data",$file);
$demo->gzdn($file);
$demo->gzdn("gogzip.txt");
这个结果:
PHP 到 PHP 正常。
Go 到 PHP 失败。
Go 代码
package main
import (
"bytes"
"compress/gzip"
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
func main() {
gzen("data", "gogzip.txt")
gden("gogzip.txt")
gden("phpgzip.txt")
}
func gzen(data string, file string) {
b, _ := json.Marshal(data)
buffer := new(bytes.Buffer)
w, _ := gzip.NewWriterLevel(buffer, gzip.BestCompression)
defer w.Close()
w.Write(b)
w.Flush()
ioutil.WriteFile(file, buffer.Bytes(), os.ModePerm)
}
func gden(file string) {
b, _ := ioutil.ReadFile(file)
buffer := new(bytes.Buffer)
buffer.Write(b)
r, _ := gzip.NewReader(buffer)
defer r.close()
data, _ := ioutil.ReadAll(r)
fmt.Println(file, " 结果数据:", string(data))
}
这个结果:
Go 到 Go 正常。
PHP 到 Go 正常。
英文:
Why can't decompress gzip data by Go in my PHP demo, but PHP gzip data to Go is successful? I need post gzip JSON data from Go to PHP API service.
Test result
-> | php | go
---------------------
php | ok | ok
go | fail | ok
PHP code
class GzipDemo
{
public function gzen($data, $file){
$json_data = json_encode($data);
$gz_data = gzencode($json_data,9);
file_put_contents($file,$gz_data);
}
public function gzdn($file){
$data = file_get_contents($file);
$unpacked = gzdecode($data);
if ($unpacked === FALSE)
{
print("failed:".$file."\n");
}else{
print($file. " result Data :".$unpacked ."\n");
}
}
}
$demo = new GzipDemo();
$file="phpgzip.txt";
$demo->gzen("data",$file);
$demo->gzdn($file);
$demo->gzdn("gogzip.txt");
This result:
PHP to PHP okay.
Go to PHP fail.
Go code
package main
import (
"bytes"
"compress/gzip"
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
func main() {
gzen("data", "gogzip.txt")
gden("gogzip.txt")
gden("phpgzip.txt")
}
func gzen(data string, file string) {
b, _ := json.Marshal(data)
buffer := new(bytes.Buffer)
w, _ := gzip.NewWriterLevel(buffer, gzip.BestCompression)
defer w.Close()
w.Write(b)
w.Flush()
ioutil.WriteFile(file, buffer.Bytes(), os.ModePerm)
}
func gden(file string) {
b, _ := ioutil.ReadFile(file)
buffer := new(bytes.Buffer)
buffer.Write(b)
r, _ := gzip.NewReader(buffer)
defer r.close()
data, _ := ioutil.ReadAll(r)
fmt.Println(file, " result Data:", string(data))
}
This result:
Go to Go okay.
PHP to Go okay.
答案1
得分: 5
以下是翻译好的内容:
使用以下更改可以使其正常工作:
- 在你的 PHP 代码中,你想要使用
gzdecode
而不是gzinflate
。如果使用gzdecode
,你就不需要使用substr($data, 10)
这样的代码了。我没有详细了解 deflate 和 gzip 的关系,但简单来说,gzencode
/gzdecode
与 golang 的gzip
包以及 GNU 命令行工具中的gz*
家族所做的工作是相匹配的。 - 在你的 Go 代码中,将
gzip.Writer.Close()
的调用放在从buffer
读取之前。你可以在这里看到:http://golang.org/src/compress/gzip/gzip.go?s=6230:6260#L240,在关闭时会向底层流写入一些额外的内容,所以在你上面的示例中,你写入的内容是不完整的。(defer
语句会导致Close()
在包含它的函数退出后运行。)很可能 Go 的 gzip 解码可以成功解码,而 PHP 的实现则不行 - 无论如何,你应该正确关闭对内存缓冲区的流,以确保在将其写入文件之前它是完整的。
必要的注意事项:你在 Go 代码中忽略了所有的错误。这段代码看起来只是一个测试,所以我不会过多强调,但你肯定应该进行适当的错误处理(要么向用户报告问题,要么向调用你的函数的代码报告问题)。
英文:
It works with the following changes:
- In your PHP code you want to use
gzdecode
instead ofgzinflate
. And you don't need thissubstr($data, 10)
stuff if you use that. I didn't read up on how deflate relates to gzip but the simplicity is thatgzencode
/gzdecode
match what the golanggzip
package does and what thegz*
family of GNU command line tools do. - In your Go code move your gzip.Writer.Close() call to be done before you read from
buffer
. As you can see here: http://golang.org/src/compress/gzip/gzip.go?s=6230:6260#L240 there is some additional stuff that is written to the underlying stream upon close, so in your example above what you are writing is incomplete. (Thedefer
statement causesClose()
to be run after the containing function exits.) Most likely the Go gzip decoding is managing to decode anyway whereas the PHP implementation is not - in any case you should properly close the stream to your in memory buffer to ensure it is complete before writing it out to a file.
OBLIGATORY NOTE: You are ignoring all of your errors in your Go code. This code looks like just a test so I won't belabor the point but you definitely want to be doing proper error handling (either reporting the problem to the user or to the caller of your function).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论