Si tienes un proyecto en WordPress y cuentas con el complemento Paid Memberships Pro (PMPro), te darás cuenta de que PMPro guarda mucha información útil de tus usuarios, como la fecha de su última visita, la cual puede ser muy valiosa para diversas tareas.
En mi caso, necesitaba exportar todos los usuarios de un proyecto y ordenarlos de forma descendente según su última visita. Fue posible descargar dicha información sin problemas, pero el detalle estaba en el formato, que venía así:
a:9:{s:4:"last";s:18:"30 September, 2024";s:8:"thisdate";N;s:4:"week";i:1;s:8:"thisweek";s:2:"40";s:5:"month";i:1;s:9:"thismonth";s:1:"9";s:3:"ytd";i:1;s:8:"thisyear";s:4:"2024";s:7:"alltime";i:1;}
El formato anterior es PHP Serialized Data, un método utilizado en PHP para convertir datos complejos (como arrays o objetos) en una cadena de texto. Esto permite almacenar estructuras de datos en bases de datos o transmitirlas entre aplicaciones. Este formato es específico de PHP y generalmente se usa para guardar configuraciones, sesiones de usuario o datos estructurados.
Para procesar esta información, desarrollamos el siguiente programa en Python, el cual voy a explicar paso a paso:
Descripción del código
Este código realiza la tarea de leer un archivo CSV con datos serializados en formato PHP (almacenados en la columna last_visit
), deserializarlos, convertir una fecha contenida en esos datos a un formato estándar (YYYY-MM-DD
) y luego escribir los resultados en un nuevo archivo CSV.
Importaciones
csv
: Para manejar archivos CSV, leerlos y escribirlos.phpserialize
: Para deserializar los datos que están en formato PHP serializado.os
: Para manipular rutas de archivos y nombres.datetime
: Para manejar y convertir fechas.
Función deserialize_data
Esta función toma una cadena PHP serializada y realiza las siguientes acciones:
- Deserialización del dato:
- Convierte la cadena PHP serializada en una estructura de Python (diccionario o similar) usando
phpserialize.loads()
. - El dato serializado se pasa como
bytes
, por lo que se convierte destr
abytes
conbytes(serialized_data, 'utf-8')
.
- Convierte la cadena PHP serializada en una estructura de Python (diccionario o similar) usando
- Extracción de la fecha de la última visita:
- Usa la clave
b'last'
(formato de clave serializada en PHP) para obtener la fecha almacenada en el campolast
. - Si no existe, devuelve un mensaje predeterminado (
b'No visit data'
).
- Usa la clave
- Conversión de la fecha al formato estándar:
- Convierte la fecha (formato como
30 September, 2024
) al formatoYYYY-MM-DD
usandodatetime.strptime
ystrftime
. - Si la fecha no es válida, devuelve el texto
'Invalid Date'
.
- Convierte la fecha (formato como
- Retorno de la fecha procesada:
- Si todo funciona, devuelve la fecha en formato
YYYY-MM-DD
. Si falla, devuelve un mensaje de error.
- Si todo funciona, devuelve la fecha en formato
Procesamiento del archivo CSV
- Lectura del archivo de entrada:
- Solicita al usuario la ruta del archivo CSV de entrada usando
input()
. - Genera automáticamente el nombre del archivo de salida agregando
_output.csv
al final del nombre base.
- Solicita al usuario la ruta del archivo CSV de entrada usando
- Lectura y escritura de datos:
- Usa
csv.DictReader
para leer el archivo de entrada como un diccionario. - Prepara el archivo de salida con columnas específicas:
user_id
,user_login
,user_email
,last_visit
. - Escribe cada fila procesada en el archivo de salida tras deserializar y convertir la fecha de
last_visit
.
- Usa
- Manejo de excepciones:
- Captura errores al abrir, leer o escribir archivos y deserializar datos, mostrando mensajes claros sobre el problema.
Código completo
import csv
import phpserialize
import os
from datetime import datetime
# Función para deserializar los datos de 'pmpro_visits' (PHP serializado)
def deserialize_data(serialized_data):
try:
deserialized = phpserialize.loads(bytes(serialized_data, 'utf-8'))
last_visit = deserialized.get(b'last', b'No visit data').decode('utf-8')
try:
last_visit_date = datetime.strptime(last_visit, '%d %B, %Y').strftime('%Y-%m-%d')
except ValueError:
last_visit_date = 'Invalid Date'
return last_visit_date
except Exception as e:
return f"Error deserializando: {e}"
# Ruta del archivo CSV de entrada
input_file_path = input("Ingrese la ruta del archivo CSV de entrada: ")
# Generar nombre del archivo de salida
base_name = os.path.splitext(os.path.basename(input_file_path))[0]
output_file_path = f"{base_name}_output.csv"
try:
with open(input_file_path, 'r', newline='', encoding='utf-8') as input_file:
reader = csv.DictReader(input_file)
fieldnames = ['user_id', 'user_login', 'user_email', 'last_visit']
with open(output_file_path, 'w', newline='', encoding='utf-8') as output_file:
writer = csv.DictWriter(output_file, fieldnames=fieldnames)
writer.writeheader()
for row in reader:
user_id = row['user_id']
user_login = row['user_login']
user_email = row['user_email']
serialized_data = row['last_visit']
last_visit_date = deserialize_data(serialized_data)
writer.writerow({
'user_id': user_id,
'user_login': user_login,
'user_email': user_email,
'last_visit': last_visit_date,
})
print(f"Listo: El archivo de salida fue creado exitosamente como {output_file_path}.")
except Exception as e:
print(f"Error: {e}")
Este programa te permitirá procesar y transformar datos serializados en formato PHP para hacerlos más manejables y útiles.