lista - ¿Cómo implementar archivos zip(u otros binarios) a través de cgi en Python?
leer archivos bin en python (3)
El encabezado está mal formado porque, por alguna razón, Python lo envía después de enviar el archivo.
Lo que debe hacer es eliminar el stdout inmediatamente después del encabezado:
sys.stdout.flush()
Luego ponga la copia del archivo
Estoy codificando un pequeño sitio web con Python y CGI donde los usuarios pueden cargar archivos zip y descargar archivos cargados por otros usuarios. Actualmente puedo subir correctamente el zip, pero tengo problemas para enviar correctamente los archivos al usuario. Mi primer acercamiento fue:
file = open(''../../data/code/'' + filename + ''.zip'',''rb'')
print("Content-type: application/octet-stream")
print("Content-Disposition: filename=%s.zip" %(filename))
print(file.read())
file.close()
Pero pronto me di cuenta de que tenía que enviar el archivo como binario, así que lo intenté:
print("Content-type: application/octet-stream")
print("Content-Disposition: filename=%s.zip" %(filename))
print(''Content-transfer-encoding: base64/r'')
print( base64.b64encode(file.read()).decode(encoding=''UTF-8'') )
Y diferentes variantes de eso. Simplemente no funciona; Apache genera el error "encabezado mal formado del script", así que supongo que debería codificar el archivo de alguna otra manera.
Debe imprimir una línea vacía después de los encabezados, y su encabezado Content-disposition no tiene el tipo ( attachment
):
print("Content-type: application/octet-stream")
print("Content-Disposition: attachment; filename=%s.zip" %(filename))
print()
Es posible que también desee utilizar un método más eficiente para cargar el archivo resultante; use shutil.copyfileobj()
para copiar los datos a sys.stdout.buffer
:
from shutil import copyfileobj
import sys
print("Content-type: application/octet-stream")
print("Content-Disposition: attachment; filename=%s.zip" %(filename))
print()
with open(''../../data/code/'' + filename + ''.zip'',''rb'') as zipfile:
copyfileobj(zipfile, sys.stdout.buffer)
No debe usar print()
para datos binarios en ningún caso; todo lo que obtienes es b''...''
byte sintaxis literal. El objeto sys.stdout.buffer
es el búfer de E / S binario subyacente, copia datos binarios directamente a eso.
Esto es lo que funcionó para mí, estoy ejecutando Apache2 y cargando este script a través de cgi. Python 3 es mi lenguaje.
Es posible que deba reemplazar la primera línea con la ruta de su pitón 3 bin.
#!/usr/bin/python3
import cgitb
import cgi
from zipfile import ZipFile
import sys
# Files to include in archive
source_file = ["/tmp/file1.txt", "/tmp/file2.txt"]
# Name and Path to our zip file.
zip_name = "zipfiles.zip"
zip_path = "/tmp/{}".format(zip_name)
with ZipFile( zip_path,''w'' ) as zipFile:
for f in source_file:
zipFile.write(f);
# Closing File.
zipFile.close()
# Setting Proper Header.
print ( ''Content-Type:application/octet-stream; name="{}"''.format(zip_name) );
print ( ''Content-Disposition:attachment; filename="{}"/r/n''.format(zip_name) );
# Flushing Out stdout.
sys.stdout.flush()
bstdout = open(sys.stdout.fileno(), ''wb'', closefd=False)
file = open(zip_path,''rb'')
bstdout.write(file.read())
bstdout.flush()