A robust Go package that provides PHP-compatible serialize (Marshal) and unserialize (Unmarshal) functions. This
library is designed for reliable data exchange between Go and PHP applications, particularly when dealing with
persistent data formats like session data or database-stored serialized values.
✅ Full PHP Compatibility: Supports PHP 4, 5, 7, and 8 serialization formats.
✅ All PHP Types: Handles null, bool, int, float, string, array, and object.
✅ Security Options: Includes nesting depth limits and allowed class filtering for robust handling of untrusted
data.
✅ Unified API: A single Option interface is used to customize both Marshal and Unmarshal behavior.
✅ Special Type Handling: Correctly manages NaN, Inf, -Inf, and PHP's private/protected property naming
conventions.
✅ Binary Safe: Properly handles strings containing null bytes and non-UTF-8 data.
✅ Zero Dependencies and Go 1.24+ support.
go get github.com/stlong5/phpserializeThis example shows how to serialize a Go map and then unserialize it back.
package main
import (
"fmt"
"log"
"github.com/stlong5/phpserialize"
)
func main() {
// Go data structure
data := map[string]interface{}{
"name": "John Doe",
"age": 30,
"roles": []interface{}{"admin", "user"},
}
// 1. Marshal (Serialize) Go to PHP format
serialized, err := phpserialize.Marshal(data)
if err != nil {
log.Fatal(err)
}
fmt.Println("Serialized:", serialized)
// Output: a:3:{s:4:"name";s:8:"John Doe";s:3:"age";i:30;s:5:"roles";a:2:{i:0;s:5:"admin";i:1;s:4:"user";}}
// 2. Unmarshal (Unserialize) PHP format back to Go
unserialized, err := phpserialize.Unmarshal(serialized)
if err != nil {
log.Fatal(err)
}
// The result is a map[string]interface{}
fmt.Printf("Unserialized: %+v\n", unserialized)
// Output: Unserialized: map[age:30 name:John Doe roles:[admin user]]
}PHP objects are represented in Go using the phpserialize.PHPObject struct.
// PHPObject definition
type PHPObject struct {
ClassName string
Properties map[string]interface{}
}
// Serialization
phpObject := phpserialize.PHPObject{
ClassName: "User",
Properties: map[string]interface{}{
"id": 123,
"username": "john_doe",
},
}
serialized, _ := phpserialize.MarshalObject(phpObject)
// Output: O:4:"User":2:{s:2:"id";i:123;s:8:"username";s:8:"john_doe";}
// Unserialization
result, _ := phpserialize.Unmarshal(serialized)
phpObj := result.(phpserialize.PHPObject)
fmt.Printf("Class: %s, ID: %d\n", phpObj.ClassName, phpObj.Properties["id"])
// Output: Class: User, ID: 123The core functions are Marshal and Unmarshal. Both accept an optional list of Option interfaces for customization.
| Function | Description |
|---|---|
Marshal(value interface{}, options ...Option) (string, error)- |
Serializes a Go value to PHP format. |
Unmarshal(data string, options ...Option) (interface{}, error) |
Unserializes PHP data to Go values. |
MarshalObject(obj PHPObject, options ...Option) (string, error) |
Dedicated function for serializing a PHPObject. |
| Function | Description |
|---|---|
IsValidMarshaled(data string) bool |
Checks if a string is valid PHP serialized data. |
MustMarshal(value interface{}, options ...Option) string |
Serializes and panics on error. |
MustUnmarshal(data string, options ...Option) interface{} |
Unserializes and panics on error. |
Options are created using factory functions and implement the unified Option interface.
Limits the nesting depth to prevent stack overflow or DoS attacks from deeply nested, malicious data.
| Context | depth=0 Behavior |
Default |
|---|---|---|
| Marshal | Unlimited (matches PHP's behavior) | 0 |
| Unmarshal | Uses PHP's default maximum depth of 4096 | 4096 |
// Limit serialization/unserialization to 10 levels
data, err := phpserialize.Marshal(nestedData, phpserialize.WithMaxDepth(10))
result, err := phpserialize.Unmarshal(data, phpserialize.WithMaxDepth(10))Enforces strict PHP compatibility rules (default: true). When set to false, it may allow Go-specific features
like uint64 serialization (u:<number>;), which is not standard in PHP but can be useful for internal Go-to-Go data
transfer.
// Allow Go-native uint64 serialization
data, _ := phpserialize.Marshal(uint64(math.MaxUint64), phpserialize.WithStrictPHP(false))
// Output: u:18446744073709551615; (Non-strict PHP format)Security Feature: Restricts which PHP classes can be un-serialized to prevent POP chains or other remote code execution vulnerabilities from untrusted data.
- Pass a slice of allowed class names (e.g.,
[]string{"User", "Order"}). - Pass
nilor an empty slice ([]string{}) to disable all object unserialization entirely ( likePHP's allowed_classes = false).
// Only allow "User" and "Admin" classes
result, err := phpserialize.Unmarshal(data,
phpserialize.WithAllowedClasses([]string{"User", "Admin"}))
// Disable all object unserialization
result, err := phpserialize.Unmarshal(data,
phpserialize.WithAllowedClasses(nil))| PHP Type | Go Type | Notes |
|---|---|---|
null |
nil |
|
boolean |
bool |
|
integer |
int64 |
All integers become 64-bit to prevent overflow. |
float/double |
float64 |
Includes NaN, Inf, -Inf. |
string |
string |
Binary safe. |
array (sequential) |
[]interface{} |
Only if keys are sequential integers starting from 0. |
array (associative) |
map[string]interface{} |
Any other array key structure. |
object |
phpserialize.PHPObject |
Contains ClassName and Properties. |
| Go Type | PHP Type | PHP Serialized Format |
|---|---|---|
nil |
null |
N; |
bool |
boolean |
b:0; or b:1; |
int, int64 |
integer |
i:<number>; |
float64 |
double |
d:<number>; |
string |
string |
s:<length>:"<string>"; |
[]interface{} |
array |
a:<count>:{...} (indexed keys) |
map[string]interface{} |
associative array |
a:<count>:{...} (string/int keys) |
phpserialize.PHPObject |
object |
O:<len>:"<class>":<count>:{...} |