2021-02-24 10:55:56 +04:00
#!/usr/bin/env python2
2013-11-14 14:50:37 +04:00
# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
u """ Ce script est prévu pour être utilisé dans un script CGI.
Il enregistre les fichiers uploadés dans le répertoire spécifié , et éventuellement lance une commande avec comme argument les fichiers enregistrés .
2015-12-07 13:10:40 +04:00
Retourner 0 si tous les fichiers ont été traités , 1 si au moins un fichier a été rejeté , 2 si aucun fichier ne correspondait ( ou si aucun fichier n ' a été fourni)
2013-11-14 14:50:37 +04:00
"""
2015-12-07 13:10:40 +04:00
import sys , os , re , types , cgi , tempfile
2013-11-14 14:50:37 +04:00
from os import path
cgitb = None # marqueur pour savoir si le module cgitb a été importé
#import cgitb; cgitb.enable()
class FileManager ( object ) :
2015-12-07 13:10:40 +04:00
fileinfos = None
tries = None
count = None
destdir = None
spec = None
type = None
exitcode = None
def __init__ ( self , destdir = None , spec = None , type = None , parse_env = True ) :
2013-11-14 14:50:37 +04:00
if destdir is None : destdir = ' /tmp '
self . fileinfos = [ ]
2015-12-07 13:10:40 +04:00
self . tries = 0
2013-11-14 14:50:37 +04:00
self . count = 0
self . destdir = destdir
2015-12-07 13:10:40 +04:00
if spec is not None : spec = re . compile ( spec )
self . spec = spec
self . type = type
2013-11-14 14:50:37 +04:00
if parse_env : self . parse_env ( )
def parse_env ( self ) :
class FieldStorage ( cgi . FieldStorage ) :
def make_file ( self , binary = None ) :
2015-12-07 13:10:40 +04:00
outf = self . fm . _new_file ( self )
if outf is not None : return outf
return cgi . FieldStorage . make_file ( self , binary )
2013-11-14 14:50:37 +04:00
FieldStorage . fm = self
self . form = FieldStorage ( )
def _new_file ( self , form ) :
2015-12-07 13:10:40 +04:00
self . tries + = 1
if self . spec is not None and self . spec . match ( form . filename ) is None : return None
if self . type is not None and self . type != form . type : return None
2013-11-14 14:50:37 +04:00
fp = path . join ( self . destdir , ' upload %i ' % self . count )
outf = open ( fp , ' w+b ' )
self . count + = 1
self . fileinfos . append ( ( form . name , form . filename , fp , form . type ) )
return outf
def write_csv ( self , outf ) :
close = False
if type ( outf ) is types . StringType :
outf = open ( outf , ' w+b ' )
close = True
try :
outf . write ( " name,value,file,type \n " )
for fi in self . fileinfos :
outf . write ( " %s , %s , %s , %s \n " % fi )
finally :
if close : outf . close ( )
2015-12-07 13:10:40 +04:00
def exitcode ( self ) :
if self . count == 0 : return 2
elif self . count != self . tries : return 1
else : return 0
2013-11-14 14:50:37 +04:00
# Analyser les options
from optparse import OptionParser
parser = OptionParser ( usage = u " \n \t % prog [options] \n \t % prog [options] -c command [args] " , description = __doc__ )
parser . add_option ( ' -d ' , ' --destdir ' , dest = ' destdir ' ,
help = u " Spécifier le répertoire de destination des fichiers uploadés. Ce répertoire est créé si nécessaire. " )
2015-12-07 13:10:40 +04:00
parser . add_option ( ' -e ' , ' --spec ' , dest = ' spec ' ,
help = u " N ' accepter que des fichiers dont le nom correspond à l ' expression régulière spécifiée " )
parser . add_option ( ' -t ' , ' --type ' , dest = ' type ' ,
help = u " N ' accepter que des fichiers dont le type mime correspond à la valeur spécifiée " )
2013-11-14 14:50:37 +04:00
parser . add_option ( ' -p ' , ' --printcsv ' , action = ' store_true ' , dest = ' printcsv ' ,
help = u " Afficher la liste des fichiers uploadés au format CSV. Chaque ligne est de la forme ' name,value,file,type ' où name est le nom du champ dans le formulaire http, value le nom du fichier tel qu ' il a été fourni par le client, file le chemin complet vers le fichier uploadé, et type le type mime du contenu. " )
parser . add_option ( ' -c ' , ' --cmd ' , action = ' store_true ' , dest = ' cmd ' ,
help = u " Lancer une commande après avoir enregistré les fichiers. Implique --remove " )
parser . add_option ( ' -G ' , ' --infos ' , action = ' store_const ' , const = ' infos ' , dest = ' argtype ' ,
help = u " La commande est lancée avec 4 arguments pour chaque fichier uploadé. Les arguments sont fournis dans l ' ordre donné par l ' option -p. C ' est l ' option par défaut. " )
parser . add_option ( ' -F ' , ' --files ' , action = ' store_const ' , const = ' files ' , dest = ' argtype ' ,
help = u " La commande est lancée avec en argument chaque fichier uploadé, correspondant à la colonne file de l ' option -p " )
parser . add_option ( ' -C ' , ' --csv ' , action = ' store_const ' , const = ' csv ' , dest = ' argtype ' ,
help = u " La commande est lancée avec en argument un fichier au format CSV qui liste les fichiers uploadés. Cf l ' option -p pour le format de ce fichier. " )
parser . set_defaults ( argtype = ' infos ' )
parser . add_option ( ' --remove ' , action = ' store_true ' , dest = ' clear ' ,
help = u " Supprimer les fichiers uploadés. " )
parser . add_option ( ' -k ' , ' --keep ' , action = ' store_false ' , dest = ' clear ' ,
help = u " Ne pas supprimer les fichiers uploadés. Utiliser cette option avec -c pour garder les fichiers uploadés. " )
parser . add_option ( ' --devel ' , action = ' store_true ' , dest = ' devel ' ,
help = u " Activer le mode développement: le module cgitb est chargé et activé. " )
o , args = parser . parse_args ( )
if o . devel and cgitb is None :
import cgitb ; cgitb . enable ( )
# Créer destdir le cas échéant
if o . destdir is not None and not path . isdir ( o . destdir ) :
os . makedirs ( o . destdir )
# Si aucune commande n'est spécifiée, afficher la liste des fichiers au format CSV
if o . printcsv is None and o . cmd is None :
o . printcsv = True
# Avec -c, par défaut supprimer les fichiers
if o . cmd and o . clear is None :
o . clear = True
2015-12-07 13:10:40 +04:00
fm = FileManager ( o . destdir , o . spec , o . type )
2013-11-14 14:50:37 +04:00
if o . printcsv :
fm . write_csv ( sys . stdout )
if o . cmd :
tmpfile = None
if o . argtype == ' infos ' :
for fi in fm . fileinfos :
args . extend ( fi )
elif o . argtype == ' files ' :
args . extend ( map ( lambda fi : fi [ 2 ] , fm . fileinfos ) )
elif o . argtype == ' csv ' :
fd , tmpfile = tempfile . mkstemp ( )
os . close ( fd )
fm . write_csv ( tmpfile )
args . append ( tmpfile )
os . spawnvp ( os . P_WAIT , args [ 0 ] , args )
if tmpfile is not None :
try : os . remove ( tmpfile )
except : pass
if o . clear :
for fi in fm . fileinfos :
try : os . remove ( fi [ 0 ] )
except : pass
2015-12-07 13:10:40 +04:00
sys . exit ( fm . exitcode ( ) )