使用 python (正则) 替换 php 序列化内的字符串
在 PHP 中,序列化用于存储或传递 PHP 的值的过程中,同时不丢失其类型和结构。
序列化函数如下:
string serialize ( mixed $value )
php 的序列化是将变量(数字,字符,数组,对象)转为字符串的函数,其格式如下:
class CC { public $data; private $pass; public function __construct($data, $pass) { $this->data = $data; $this->pass = $pass; } } $number = 34; $str = 'uusama'; $bool = true; $null = NULL; $arr = array('a' => 1, 'b' => 2); $cc = new CC('uu', true); var_dump(serialize($number)); var_dump(serialize($str)); var_dump(serialize($bool)); var_dump(serialize($null)); var_dump(serialize($arr)); var_dump(serialize($cc));
输出结果:
string(5) "i:34;" string(13) "s:6:"uusama";" string(4) "b:1;" string(2) "N;" string(30) "a:2:{s:1:"a";i:1;s:1:"b";i:2;}" string(52) "O:2:"CC":2:{s:4:"data";s:2:"uu";s:8:" CC pass";b:1;}"
字符串的格式为:
s:{0-9}:”…”;
前面的数字正好是后面字符串的长度(strlen,而不是 mb_strlen),如果字符串内容改变了,而字符前的数字对不上的时候,反序列化的时候会报错
wordpress 自身会将很多变量函数之类,甚至是 html,css,js 代码都使用 serialize 序列化成字符串存入 mysql 中
导致的一个问题就是如果我们要更换网站域名或者其他配置信息的时候,不能直接更改内容,造成很多不便
网上查了很多资料也没有解决这个的方法,无非是用 php 反序列化成相应的字符串,数组,对象,然后更改值之后,再序列化成字符串,这样面对小范围的数据修改是可行的,但是如果面对大数据量的时候就有点不够看了
如果能有个正则,一下子替换整个 sql 文件就完美了,思考良久,于是有了如下方法,仅供大家参考
在这里分享一个用 python 写的使用正则替换序列化后字符串内容的方法
代码如下:
#!/usr/bin/python # -*- coding: utf-8 -*- import io import re import os import sys import time if len(sys.argv) != 5: print '\033[1;31;40m' print '*' * 50 print '参数不全' print '*' * 50 exit() old_str = sys.argv[3] new_str = sys.argv[4] sql_file = sys.argv[1] new_file = sys.argv[2] if not os.path.isfile(sql_file): print '\033[1;31;40m' print '*' * 50 print 'sql 文件不存在' print '*' * 50 exit() old_str_arr = old_str.split("|") if len(old_str_arr) > 1: pattern = "(" for domain in old_str_arr: if domain[-2:] == "co": pattern += "(?<!.)"+domain+"(?!m)|" else: pattern += "(?<!.)"+domain+"|" pattern = pattern[:-1] pattern += ")" else: pattern = "(?<!.)"+old_str_arr[0] pattern = pattern.replace('.','\.') pattern = pattern.replace('-','\-') pattern = pattern.replace('_','\_') if os.path.isfile(new_file): os.system("echo > "+new_file) def change_domain(match): old = match.group(2) old_len = match.group(1) new = re.sub(pattern,new_str,old,0,re.I) new_len = len(new) return "s:"+str(new_len)+":\""+new+'";' start_time = time.time() n_file = open(new_file,"a") n = 0 with open(sql_file,"r") as f: while True: line = f.readline() new_line = re.sub(r"(?:s\:)(\d+)(?:\:\")([\s\S]*?)(?:\"\;)",change_domain,line,0,re.I) new_line = re.sub(pattern,new_str,new_line,0,re.I) n_file.write(new_line) n+=1; print "已替换"+str(n)+"行" if not line: break n_file.close() end_time = time.time() cut_time = int(end_time-start_time) fen = round(cut_time/60,2) print "替换成功!共用时"+str(fen)+"分钟!"
使用方式:
#将 old.sql 文件里的 a.com,b.com,a.co 统一替换为 abc.cn change_domain.py old.sql new.sql 'a.com|b.com|a.co' 'abc.cn'
该脚本的核心就是 re.sub 可以使用一个回调函数来修改为需要复杂处理的字符串,而在回调函数中还可以使用正则去替换我们需要替换的字符串,相同的方式 php,js,java,shell 等其他语言也可以做到