FileUtil.java

  1. /*
  2.  * Copyright (c) 2002-2022, City of Paris
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  *  1. Redistributions of source code must retain the above copyright notice
  10.  *     and the following disclaimer.
  11.  *
  12.  *  2. Redistributions in binary form must reproduce the above copyright notice
  13.  *     and the following disclaimer in the documentation and/or other materials
  14.  *     provided with the distribution.
  15.  *
  16.  *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
  17.  *     contributors may be used to endorse or promote products derived from
  18.  *     this software without specific prior written permission.
  19.  *
  20.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  21.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
  24.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  25.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  26.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  27.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  29.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30.  * POSSIBILITY OF SUCH DAMAGE.
  31.  *
  32.  * License 1.0
  33.  */
  34. package fr.paris.lutece.util.file;

  35. import java.io.File;
  36. import java.io.IOException;
  37. import java.io.InputStream;
  38. import java.nio.file.Files;
  39. import java.nio.file.Path;
  40. import java.util.zip.ZipEntry;
  41. import java.util.zip.ZipOutputStream;

  42. import org.apache.commons.lang3.StringUtils;

  43. import fr.paris.lutece.portal.service.util.AppLogService;
  44. import fr.paris.lutece.portal.service.util.AppPropertiesService;
  45. import fr.paris.lutece.util.string.StringUtil;

  46. /**
  47.  * Utility class for files
  48.  */
  49. public final class FileUtil
  50. {
  51.     public static final String CONSTANT_MIME_TYPE_ZIP = "application/zip";
  52.     public static final String CONSTANT_MIME_TYPE_CSV = "application/csv";
  53.     public static final String EXTENSION_ZIP = ".zip";
  54.     public static final String EXTENSION_CSV = ".csv";
  55.     private static final String PROPERTY_ALLOWED_IMAGES_EXTENSIONS = "lutece.files.allowedImagesExtentions";
  56.     private static final String PROPERTY_ALLOWED_HTML_EXTENSIONS = "lutece.files.allowedHtmlExtentions";
  57.     private static final String DEFAULT_IMAGES_EXTENSION = "webp,png,jpg,jpeg,svg";
  58.     private static final String DEFAULT_HTML_EXTENSION = "html,htm,xhtml";
  59.     private static final String FREEMARKER_EXTENSION = "ftl";
  60.     private static final String CONSTANT_POINT = ".";
  61.     private static final String CONSTANT_COMMA = ",";

  62.     /**
  63.      * Private constructor
  64.      */
  65.     private FileUtil( )
  66.     {
  67.     }

  68.     /**
  69.      * Check if the extension of the file is an image extension
  70.      *
  71.      * @param strImageFileName
  72.      *            The file name to check
  73.      * @return True if the extension is correct, false otherwise
  74.      */
  75.     public static boolean hasImageExtension( String strImageFileName )
  76.     {
  77.         String strImagesExtentions = AppPropertiesService.getProperty( PROPERTY_ALLOWED_IMAGES_EXTENSIONS, DEFAULT_IMAGES_EXTENSION );

  78.         return hasExtension( strImageFileName, strImagesExtentions );
  79.     }

  80.     /**
  81.      * Check if a file has a valid html extension
  82.      *
  83.      * @param strFileName
  84.      *            The file name to check
  85.      * @return True if the file name is valid, false otherwise
  86.      */
  87.     public static boolean hasHtmlExtension( String strFileName )
  88.     {
  89.         String strImagesExtentions = AppPropertiesService.getProperty( PROPERTY_ALLOWED_HTML_EXTENSIONS, DEFAULT_HTML_EXTENSION );

  90.         return hasExtension( strFileName, strImagesExtentions );
  91.     }

  92.     /**
  93.      * Check if a file has a valid Freemarker extension
  94.      *
  95.      * @param strFileName
  96.      *            The file name to check
  97.      * @return True if the file name is valid, false otherwise
  98.      */
  99.     public static boolean hasFreemarkerExtension( String strFileName )
  100.     {
  101.         return hasExtension( strFileName, FREEMARKER_EXTENSION );
  102.     }

  103.     /**
  104.      * Check if a file name match extensions in a given list
  105.      *
  106.      * @param strFileName
  107.      *            The file name to check
  108.      * @param strAllowedExtensions
  109.      *            The comma separated list of allowed extensions
  110.      * @return True of the extension of the file exists in the extension list
  111.      */
  112.     private static boolean hasExtension( String strFileName, String strAllowedExtensions )
  113.     {
  114.         int nIndex = strFileName.lastIndexOf( CONSTANT_POINT );

  115.         if ( ( nIndex >= 0 ) && ( strFileName.length( ) > ( nIndex + 2 ) ) )
  116.         {
  117.             String strExtension = strFileName.substring( nIndex + 1 );

  118.             if ( StringUtils.isNotEmpty( strExtension ) )
  119.             {
  120.                 for ( String strAllowedExtention : strAllowedExtensions.split( CONSTANT_COMMA ) )
  121.                 {
  122.                     if ( StringUtils.equalsIgnoreCase( strExtension, strAllowedExtention ) )
  123.                     {
  124.                         return true;
  125.                     }
  126.                 }
  127.             }
  128.         }

  129.         return false;
  130.     }

  131.     /**
  132.      * creates a zip file
  133.      *
  134.      * @param zipFile
  135.      *            the zipfile to create
  136.      * @param files
  137.      *            to add to the Zip
  138.      * @throws IOException
  139.      */
  140.     public static void zipFiles( Path zipFile, Path... paths ) throws IOException
  141.     {
  142.         if ( zipFile.toFile( ).exists( ) )
  143.         {
  144.             deleteFile( zipFile.toFile( ) );
  145.         }

  146.         try ( ZipOutputStream zos = new ZipOutputStream( Files.newOutputStream( zipFile ) ) )
  147.         {
  148.             for ( Path file : paths )
  149.             {
  150.                 addEntryToZip( zos, file );
  151.             }
  152.         }
  153.     }

  154.     private static void addEntryToZip( ZipOutputStream zos, Path file ) throws IOException
  155.     {
  156.         try ( InputStream fis = Files.newInputStream( file ) )
  157.         {
  158.             ZipEntry zipEntry = new ZipEntry( file.toFile( ).getName( ) );
  159.             zos.putNextEntry( zipEntry );

  160.             byte [ ] bytes = new byte [ 1024];
  161.             int length;
  162.             while ( ( length = fis.read( bytes ) ) >= 0 )
  163.             {
  164.                 zos.write( bytes, 0, length );
  165.             }
  166.             zos.closeEntry( );
  167.         }
  168.     }

  169.     /**
  170.      * Converts French diacritics characters into non diacritics. <br />
  171.      * Replace whitespaces by underscores <br />
  172.      * Keep only underscores and alphanum characters <br />
  173.      * Transform to lowercase
  174.      *
  175.      * @param string
  176.      * @return
  177.      */
  178.     public static final String normalizeFileName( String string )
  179.     {
  180.         return StringUtil.replaceAccent( string ).replace( ' ', '_' ).replaceAll( "[^a-zA-Z0-9_]+", "" ).toLowerCase( );
  181.     }

  182.     /**
  183.      * Delete the file. <br />
  184.      * Logs an error if the delete is not succesful.
  185.      *
  186.      * @param pathname
  187.      */
  188.     public static void deleteFile( File file )
  189.     {
  190.         if ( file == null )
  191.         {
  192.             AppLogService.error( "Error deleting file, file null" );
  193.             return;
  194.         }
  195.         try
  196.         {
  197.             if ( file.exists( ) )
  198.             {
  199.                 Files.delete( file.toPath( ) );
  200.             }
  201.         }
  202.         catch( IOException e )
  203.         {
  204.             AppLogService.error( "Error deleting file", e );
  205.         }
  206.     }

  207. }