Guest User

Untitled

a guest
May 15th, 2025
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.62 KB | None | 0 0
  1. package Marica::Base::Rapports::export_raw_data ;
  2.  
  3. use utf8 ;
  4.  
  5. use strict ;
  6.  
  7. use POSIX 'setsid';
  8.  
  9. use Time::HiRes qw(gettimeofday tv_interval);
  10.  
  11. use Apache2::Const -compile => qw(OK REDIRECT) ;
  12.  
  13. sub handler {
  14.  
  15. binmode(STDOUT, ":utf8") ;
  16.  
  17. my $r = shift ;
  18.  
  19. my $req = Apache2::Request->new($r) ;
  20.  
  21. #récupérer les arguments
  22. my ( %args, @args ) ;
  23.  
  24. @args = $req->param ;
  25.  
  26. for (@args) {
  27.  
  28. $args{$_} = Encode::decode_utf8( $req->param($_) ) ;
  29.  
  30. #nix those sql injection/htmlcode attacks!
  31. $args{$_} =~ tr/<>;/-/ ;
  32.  
  33. #les double-quotes viennent interférer avec le html
  34. $args{$_} =~ tr/"/'/ ;
  35.  
  36. }
  37.  
  38. my $id_client = $r->pnotes('session')->{id_client} ;
  39.  
  40. my $content = '<h1 style="text-align: center;">' . _( 'Exportation des données', $r ) . '</h1>' ;
  41.  
  42. #nom du répertoire de collecte des fichiers/données/documents dans /base/listing
  43. my $token_id = map +(0..9,"a".."z","A".."Z")[rand(10+26*2)], 1..32 ;
  44.  
  45. my $recipient_dir = $r->document_root() . '/base/listing/' . $r->pnotes('session')->{_session_id} ;
  46.  
  47. my $result_file_name = $r->pnotes('session')->{_session_id} ;
  48.  
  49. my $final_file_name = '' ;
  50.  
  51. #effacer les listings précédents de la session pour démarrer propre
  52. #il faut le faire avant de lancer le fork, sinon le test -e détecte le fichier précédent encore présent
  53. $ENV{'PATH'} = '/bin:/usr/bin' ;
  54.  
  55. delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
  56.  
  57. my @args = ( 'rm', '-r', $r->document_root() . '/base/listing/' . $r->pnotes('session')->{_session_id} ) ;
  58.  
  59. system(@args) == 0 or warn "system @args failed: $?" ;
  60.  
  61. my @args = ( 'rm', $r->document_root() . '/base/listing/' . $r->pnotes('session')->{_session_id} . '.tar.gz' ) ;
  62.  
  63. system(@args) == 0 or warn "system @args failed: $?" ;
  64.  
  65. if ( defined $args{go_for_it} ) {
  66.  
  67. $ENV{'PATH'} = '/bin:/usr/bin' ;
  68.  
  69. delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
  70.  
  71. $r->content_type('text/html; charset=utf-8') ;
  72.  
  73. $r->print('<!DOCTYPE html><html lang = "fr"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>' . $r->hostname . '</title></head><body><h3>Building tar file</h3><p>*') ;
  74.  
  75. $r->rflush ; #clear the request buffer
  76.  
  77. my $t0 = [gettimeofday];
  78.  
  79. #on sélectionne la base qui va bien
  80. my @databases = $r->dir_config->get('db_name') ;
  81.  
  82. my $demo_user_name = $r->dir_config('demo_username') ;
  83.  
  84. my $database = ( $r->pnotes('session')->{username} =~ /$demo_user_name/ ) ? $databases[1] : $databases[0] ;
  85.  
  86. #on fait un fork pour lancer le long process
  87. #le fork crée le .tar.gz à télécharger
  88. $SIG{CHLD} = 'IGNORE';
  89.  
  90. defined (my $kid = fork) or die "Cannot fork: $!\n" ;
  91.  
  92. if ($kid) {
  93.  
  94. #print "Parent $$ has finished, kid's PID: $kid\n" ;
  95.  
  96. } else {
  97.  
  98. # chdir to '/' stops the process from preventing an unmount
  99. chdir '/' or die "Can't chdir to /: $!" ;
  100.  
  101. open STDIN, '/dev/null' or die "Can't read /dev/null: $!" ;
  102.  
  103. open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!" ;
  104.  
  105. open STDERR, '>/tmp/log' or die "Can't write to /tmp/log: $!" ;
  106.  
  107. setsid or die "Can't start a new session: $!" ;
  108.  
  109. my $oldfh = select STDERR ;
  110.  
  111. local $| = 1 ;
  112.  
  113. select $oldfh ;
  114. # warn "started\n" ;
  115.  
  116. #créer les répertoires de stockage
  117. mkdir $recipient_dir ;
  118. mkdir '/tmp/marica_data' ;
  119.  
  120. #dump du schéma de la base
  121. my @args = ('pg_dump', '-s', '-f', $recipient_dir . '/marica.out', $database) ;
  122.  
  123. system(@args) == 0 or warn "system @args failed: $?" ;
  124.  
  125. #la commande d'exportation des données du client ressemble à ça:
  126. #psql -f /home/lib/Marica/Base/Procedures/Reversibility/export_raw_data.sql -v id_client=13 -v database=marica postgres
  127. #on crée provisoirement les fichiers data dans /tmp/marica_data
  128. @args = ('psql', '-f', '/home/lib/Marica/Base/Procedures/Reversibility/export_raw_data.sql', '-v', 'id_client=' . $r->pnotes('session')->{id_client}, '-v', 'database=' . $database, 'postgres') ;
  129.  
  130. system(@args) == 0 or warn "system @args failed: $!" ;
  131.  
  132. #if faut les déplacer dans $recipient_dir
  133. @args = ('mv', '/tmp/marica_data', $recipient_dir . '/data') ;
  134.  
  135. system(@args) == 0 or warn "system @args failed: $!" ;
  136.  
  137. #copier le fichier create_db.sh et remplacer =id_client par la bonne valeur
  138. my $id_client = $r->pnotes('session')->{id_client} ;
  139.  
  140. my $script ;
  141.  
  142. open (my $fh_in, "<:encoding(UTF-8)", '/home/lib/Marica/Base/Procedures/Reversibility/create_db.sh') or die "Can't open create_db.sh : $!" ;
  143.  
  144. while ( <$fh_in> ) {
  145.  
  146. $script .= $_;
  147.  
  148. }
  149.  
  150. $script =~ s/=id_client/=$id_client/ ;
  151.  
  152. close $fh_in ;
  153.  
  154. #création du fichier pour le client
  155. my $out_file = $recipient_dir . '/create_db.sh' ;
  156.  
  157. open (my $fh_out, ">:encoding(UTF-8)", $out_file) or warn "Can't open $out_file : $!" ;
  158.  
  159. #ajouter le BOM pour que les tableurs s'ouvrent avec le bon encodage (utf8)
  160. #on peut aussi utiliser chr(65279);
  161. #MS-Office a besoin de ça pour identifier l'encodage
  162. print $fh_out chr(0xFEFF) ;
  163.  
  164. print $fh_out $script ;
  165.  
  166. close $fh_out ;
  167.  
  168. #copier le fichier import_raw_data.sql
  169. @args = ('cp', '/home/lib/Marica/Base/Procedures/Reversibility/import_raw_data.sql', $recipient_dir) ;
  170.  
  171. system(@args) == 0 or warn "system @args failed: $!" ;
  172.  
  173. #création du fichier tar compressé
  174. my $temp_name = $result_file_name . '.tmp' ;
  175.  
  176. @args = ( 'tar', '-czf', $r->document_root() . '/base/listing/' . $temp_name, $recipient_dir) ;
  177.  
  178. system(@args) == 0 or warn "system @args failed: $!" ;
  179.  
  180. #renommer proprement le fichier tar pour détection par la boucle do { }
  181. $final_file_name = $result_file_name . '.tar.gz' ;
  182.  
  183. rename $r->document_root() . '/base/listing/' . $temp_name , $r->document_root() . '/base/listing/' . $final_file_name ;
  184.  
  185. CORE::exit(0); # terminate the process
  186.  
  187. } # if ($kid)
  188.  
  189. #pendant que le fork travaille, on vérifie si le fichier .tar.gz final existe
  190. #tant qu'il n'est pas présent, on envoie un nouvel élément toutes les secondes
  191. my $i = 1 ;
  192.  
  193. do {
  194.  
  195. my $final_result = $r->document_root() . '/base/listing/' . $result_file_name . '.tar.gz' ;
  196.  
  197. $i = 0 if -e $final_result ;
  198.  
  199. $r->print('*') ;
  200.  
  201. $r->rflush; #clear the request buffer
  202.  
  203. sleep( 1 ) ;
  204.  
  205. } while ( $i ) ;
  206.  
  207. $r->print( '</p>' ) ;
  208.  
  209. $r->rflush; #clear the request buffer
  210.  
  211. my $t1 = [gettimeofday] ;
  212.  
  213. my $t0_t1 = tv_interval $t0, $t1 ;
  214.  
  215. my $file_size = -s $r->document_root() . '/base/listing/' . $result_file_name . '.tar.gz' ;
  216.  
  217. $content = '<pre>
  218. using db : ' . $database . '
  219. recipient_dir : ' . $recipient_dir . '
  220. file size : ' . $file_size . '
  221. interval : ' . $t0_t1 . '
  222. </pre>' ;
  223.  
  224. my $download_link = '<a href="/base/listing/' . $result_file_name . '.tar.gz">Télécharger ' . $result_file_name . '.tar.gz</a>' ;
  225.  
  226. my $download_zone = '
  227. <h3>Lien</h3>
  228. <p>' . $download_link . '
  229. </p></body>' ;
  230.  
  231. $content .= $download_zone ;
  232.  
  233. $r->print( $content ) ;
  234.  
  235. return Apache2::Const::OK ;
  236.  
  237. } else {
  238.  
  239. $content .= presentation($r) ;
  240.  
  241. } # if ( defined $args{go_for_it} )
  242.  
  243. $r->content_type('text/html; charset=utf-8') ;
  244.  
  245. $r->no_cache(1) ;
  246.  
  247. print $content ;
  248.  
  249. return Apache2::Const::OK ;
  250.  
  251. }
  252.  
  253. 1 ;
  254.  
  255.  
  256. sub presentation {
  257.  
  258. my $r = shift ;
  259.  
  260. my $content = '<h2>Instructions</h2>' ;
  261.  
  262. $content .= '<p>Cette procédure crée un fichier contenant toutes les données stockées dans la base pour votre compte</p>' ;
  263.  
  264. $content .= '<p>Ce fichier est une archive tar contenant :</p>' ;
  265.  
  266. $content .= '
  267. <ul>
  268. <li>le fichier create_db.sh qui crée la base de données Postgresql pour accueillir les données (nommée "import_raw_data")</li>
  269. <li>le fichier marica.out contenant le schema de la base de données</li>
  270. <li>le fichier import.sql qui importe les données</li>
  271. <li>le répertoire data qui contient les données (séparateur de données "TAB")</li>
  272. </ul>' ;
  273.  
  274. $content .= '<h3>Utilisation</h3>
  275. <ul>
  276. <li>Créer le répertoire /tmp/marica</li>
  277. <li>Extraire de l\'archive tar les 4 éléments ci-dessus, et les placer dans /tmp/marica </li>
  278. <li>Rendre create_db.sh executable</li>
  279. <li>Executer create_db.sh en tant que super-utilisateur</li>
  280. </ul>' ;
  281.  
  282.  
  283. my $form = '
  284. <form action=export_raw_data method=POST>
  285. <p><input type=submit value="Exporter les données"><input type=hidden name=go_for_it value=0></p>
  286. </form>
  287. ' ;
  288.  
  289. $content .= $form ;
  290.  
  291. return $content ;
  292.  
  293.  
  294. } #sub presentation
  295.  
  296.  
Advertisement
Add Comment
Please, Sign In to add comment