You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python解析PHP序列化对象时遇unexpected opcode错误

PHP序列化对象转Python字典时出现unexpected opcode错误的解决方法

问题背景

我用以下Python代码尝试将PHP序列化对象转换为字典:

def object_hook(name, d):
    return d

def php_serialized_to_dict(serialized):
    dict_bytes = unserialize(bytes(serialized, 'utf-8'), object_hook=object_hook)
    dict_regular = {
        key.decode(): val.decode() if isinstance(val, bytes) else val
        for key, val in dict_bytes.items()
    }
    return dict_regular

for i in df['serialized_object']:
    try:
         print(php_serialized_to_dict(i))
    except Exception as e:
         print(e)

运行后报错:unexpected opcode,换用phpserialize.dumps和phpserialize.loads方法后,错误依旧。

待转换的PHP序列化对象示例:

"O:38:"tesco_PartExchange_Model_PartExchange":15:{s:15:"*_eventPrefix";s:19:"tesco_partexchange";s:15:"*_eventObject";s:6:"object";s:16:"*_resourceName";s:32:"tesco_partexchange/partExchange";s:12:"*_resource";N;s:26:"*_resourceCollectionName";s:43:"tesco_partexchange/partExchange_collection";s:12:"*_cacheTag";b:0;s:19:"*_dataSaveAllowed";b:1;s:15:"*_isObjectNew";N;s:8:"*_data";a:22:{s:4:"step";i:1;s:3:"vrm";s:7:"KFGHP7";s:7:"mileage";i:112100;s:7:"success";s:4:"true";s:9:"timestamp";s:19:"21/05/1990 13:10:18";s:10:"lookup_vrm";s:7:"KFGHP7";s:4:"dvla";a:2:{s:17:"registration_date";i:20070904;s:6:"colour";s:4:"GREY";}s:3:"cap";a:12:{s:5:"capid";s:5:"34517";s:12:"manufacturer";s:5:"CAR";s:17:"manufacturer_code";s:5:"12345";s:10:"derivative";s:24:"CAR";s:5:"range";s:4:"XC90";s:5:"model";s:18:"XC90 DIESEL ESTATE";s:11:"model_dates";s:13:"(2006 - 2014)";s:8:"fueltype";s:6:"FUEL";s:5:"plate";s:7:"10005";s:10:"plate_year";i:2007;s:11:"plate_month";i:9;s:15:"derivative_spec";s:42:"Volvo Xc90 2.4 d5 se 5dr geartronic Diesel";}s:12:"alternatives";a:0:{}s:10:"derivative";a:3:{s:16:"expected_mileage";i:140000;s:26:"default_mileage_multiplier";i:10000;s:12:"current_year";s:4:"2021";}s:12:"cap_extended";a:66:{s:8:"emission";s:3:"224";s:12:"transmission";s:9:"Trans";s:15:"ec_combined_mpg";s:4:"33.2";s:18:"ec_extra_urban_mpg";s:4:"40.4";s:12:"ec_urban_mpg";s:4:"25.4";s:16:"engine_power_bhp";s:3:"185";s:15:"insurance_group";i:41;s:25:"st_manufacturers_warranty";s:1:"3";s:29:"manufacturers_warranty_mil";s:5:"60000";s:19:"ncap_adult_occupant";s:13:"Not Available";s:19:"ncap_child_occupant";s:13:"Not Available";s:19:"ncap_overall_rating";s:13:"Not Available";s:15:"ncap_pedestrian";s:13:"Not Available";s:18:"N_0_to_62_mph_secs";s:4:"11.5";s:18:"N_0_to_60_mph_secs";b:0;s:9:"top_speed";s:3:"118";s:11:"space_saver";s:2:"No";s:15:"tyre_size_spare";s:0:"";s:6:"height";s:4:"1743";s:6:"length";s:4:"4807";s:9:"wheelbase";s:4:"2857";s:5:"width";s:4:"1898";s:23:"width_including_mirrors";s:4:"2112";s:28:"fuel_tank_capacity_in_litres";s:2:"68";s:27:"luggage_capacity_seats_down";s:4:"1837";s:25:"luggage_capacity_seats_up";s:3:"249";s:24:"max_towing_weight_braked";s:4:"2250";s:26:"max_towing_weight_unbraked";s:3:"750";s:18:"minimum_kerbweight";s:4:"2121";s:5:"seats";s:1:"7";s:28:"corrosion_perf_guarantee_yrs";s:1:"8";s:27:"man_paintwork_guarantee_yrs";s:1:"3";s:15:"badge_engine_cc";s:3:"2.4";s:11:"coin_series";s:2:"SE";s:24:"service_interval_mileage";b:0;s:26:"service_interval_frequency";b:0;s:12:"manufacturer";s:5:"VOLVO";s:5:"range";s:4:"XC90";s:5:"model";s:18:"XC90 DIESEL ESTATE";s:10:"derivative";s:24:"2.4 D5 SE 5dr Geartronic";s:9:"bodystyle";s:3:"4x4";s:5:"doors";s:1:"5";s:15:"introduced_year";s:4:"2006";s:16:"introduced_month";s:1:"5";s:17:"discontinued_year";s:4:"2010";s:18:"discontinued_month";s:1:"9";s:8:"fueltype";s:6:"Diesel";s:8:"warranty";s:1:"3";s:18:"ncap_safety_assist";s:0:"";s:9:"bluetooth";b:0;s:14:"cruise_control";b:1;s:15:"parking_sensors";b:0;s:17:"dab_digital_radio";b:0;s:14:"usb_connection";b:0;s:17:"leather_upholstry";b:1;s:15:"climate_control";b:1;s:12:"heated_seats";b:0;s:20:"satellite_navigation";b:0;s:7:"iso_fix";b:1;s:28:"quickclear_heated_windscreen";b:0;s:5:"xenon";b:0;s:16:"miles_per_gallon";s:4:"33.2";s:16:"luggage_capacity";d:9;s:12:"product_name";s:42:"VOLVO XC90 2.4 SE 5 Doors Diesel Automatic";s:17:"road_fund_licence";s:1:"K";s:22:"road_fund_licence_cost";i:295;}s:10:"is_expired";b:0;s:13:"car_condition";s:1:"3";s:15:"additional_info";a:6:{i:0;a:7:{s:2:"id";s:1:"1";s:5:"title";s:27:"Do you have 2 sets of keys?";s:7:"checked";s:4:"false";s:7:"default";s:5:"true";s:10:"isRequired";s:5:"true";s:5:"error";s:118:"great";s:4:"hint";s:164:"great";}i:1;a:7:{s:2:"id";s:1:"6";s:5:"title";s:67:"Will your car have more than 2 months MOT at the point of delivery?";s:7:"checked";s:4:"false";s:7:"default";s:5:"false";s:10:"isRequired";s:4:"true";s:5:"error";s:51:"MOT required";s:4:"hint";s:104:"At the point of delivery- your trade in vehicle will have a minimum of 2 months remaining on it’s MOT.";}i:2;a:7:{s:2:"id";s:1:"2";s:5:"title";s:32:"Is there a full service history?";s:7:"checked";s:5:"True";s:7:"default";s:5:"false";s:10:"isRequired";s:5:"false";s:5:"error";s:0:"";s:4:"hint";s:135:"If your vehicle has a full service history then it may attract a higher Part Exchange valuation than an equivalent vehicle without one.";}i:3;a:7:{s:2:"id";s:1:"3";s:5:"title";s:35:"I want to keep my own number plate.";s:7:"checked";s:5:"false";s:7:"default";s:5:"false";s:10:"isRequired";s:5:"false";s:5:"error";s:0:"";s:4:"hint";s:183:"If your vehicle has a personalised or private registration plate your Retailer can help transfer this to your new car. Please be aware that this may delay your delivery date slightly.";}i:4;a:7:{s:2:"id";s:1:"4";s:5:"title";s:106:"I am the owner of the car- hold a V5C form  and the vehicle has only ever been used for eligible purposes.";s:7:"checked";s:4:"true";s:7:"default";s:4:"true";s:10:"isRequired";s:4:"true";s:5:"error";s:93:"Oh no! Unfortunately we can't accept your car as part of a swap towards buying your new car. ";s:4:"hint";s:153:"I confirm my car has never been used for rental- hire- paid driving lessons or as a police vehicle and has never been written off for insurance purposes.";}i:5;a:7:{s:2:"id";s:1:"5";s:5:"title";s:26:"Your car is not an import.";s:7:"checked";s:4:"true";s:7:"default";s:4:"true";s:10:"isRequired";s:4:"true";s:5:"error";s:335:"Due to the specialist nature of your vehicle we need to understand a few more details to ensure we offer you the best possible valuation. Please proceed without a part exchange and find the car you want to purchase- then contact the retailer to discuss the valuation. You will find Retailer contact details against each car displayed. ";s:4:"hint";s:98:"I confirm my car is not an imported right hand drive vehicle or is a vehicle with left hand drive.";}}s:11:"used_values";a:6:{s:7:"success";b:1;s:12:"errorMessage";s:0:"";s:6:"retail";i:5925;s:5:"clean";i:3700;s:7:"average";i:3350;s:5:"below";i:3025;}s:6:"totals";a:2:{s:9:"cap_total";i:3025;s:5:"total";d:2801.90625;}s:15:"negative_equity";i:0;s:19:"outstanding_finance";s:1:"0";s:19:"part_exchange_value";s:4:"2801";s:5:"px_id";s:2:"30";s:9:"is_active";i:1;s:29:"part_exchange_value_in_future";d:2745;}s:18:"*_hasDataChanges";b:1;s:12:"*_origData";N;s:15:"*_idFieldName";N;s:13:"*_isDeleted";b:0;s:16:"*_oldFieldsMap";a:0:{}s:17:"*_syncFieldsMap";a:0:{}}"

解决方法

1. 清理序列化字符串的多余引号

你提供的序列化字符串首尾有额外的双引号,这会导致解析器无法识别正确的opcode。先去掉首尾的引号:

serialized = serialized.strip('"')

2. 使用php-unserialize库替代

phpserialize库对某些PHP序列化格式的兼容性有限,试试php-unserialize库,它对复杂对象的支持更好:

  • 安装库:
pip install php-unserialize
  • 修改代码:
import php_unserialize

def php_serialized_to_dict(serialized):
    # 去掉首尾多余的引号
    serialized_clean = serialized.strip('"')
    # 直接反序列化为Python字典
    result = php_unserialize.unserialize(serialized_clean.encode('utf-8'))
    # 递归处理字节类型的键值,转为字符串
    def decode_bytes(obj):
        if isinstance(obj, bytes):
            return obj.decode('utf-8')
        elif isinstance(obj, dict):
            return {decode_bytes(k): decode_bytes(v) for k, v in obj.items()}
        elif isinstance(obj, list):
            return [decode_bytes(item) for item in obj]
        else:
            return obj
    return decode_bytes(result)

# 测试转换
for i in df['serialized_object']:
    try:
         print(php_serialized_to_dict(i))
    except Exception as e:
         print(e)

3. 修复序列化字符串中的格式错误

检查序列化字符串中的特殊字符,比如示例里的破折号(-)是否是正常的ASCII破折号,避免非标准字符导致解析失败。如果有转义问题,确保字符串在Python中用原始字符串(r'')包裹。

4. 自定义对象钩子处理PHP对象

如果还是遇到对象解析问题,给php_unserialize传自定义钩子,把PHP对象转为字典:

def object_handler(obj):
    # 将PHP对象转为字典,保留所有属性
    return obj.__dict__ if hasattr(obj, '__dict__') else obj

result = php_unserialize.unserialize(serialized_clean.encode('utf-8'), object_hook=object_handler)

内容的提问来源于stack exchange,提问作者ConQuest Data

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 19:34:50