Helper File.
Funciones de manipulación de archivos

Code Helper

Helpers – File – Archivos

Libreria para la ulización de archivos de texto o binario. Detectar propiedades de los archivos, renombrar, eliminar y copiar archivos.

/**
 * HelperFile.php
 * @author      Code Develium
 */

namespace Helpers;

use Exception;

/**
 * Class HelperFile
 */
abstract class HelpFile
{
    /**
     * Escribe texto en un archivo. Se puede indica un máximo a 
     * escribir.
     * Devuelve los bytes escritos.
     *
     * @param resource $handle_archivo
     * @param mixed    $texto
     * @param int      $max_bytes
     *
     * @return int
     * @throws Exception
     */
    public static function write( $handle_archivo, 
                                  $texto, 
                                  $max_bytes = null)
    {
        if (is_null($max_bytes)) {
            $ret = fwrite($handle_archivo, $texto);
        } else {
            $ret = fwrite($handle_archivo, $texto, $max_bytes);
        }
        if ($ret === false) {
            throw new Exception('No se puede escribir en el archivo');
        }
        self::flush($handle_archivo);
        return $ret;
    }

    /**
     * Desbloquea un archivo bloqueado.
     * Al hacer un close, también se desbloquea
     *
     * @param resource $handle_archivo
     *
     * @throws Exception
     */
    public static function ubLock($handle_archivo)
    {
        if (flock($handle_archivo, LOCK_UN) === false) {
            throw new Exception('Imposible desbloquear el archivo');
        }
    }

    /**
     * Trunca un archivo a un determinado tamaño
     *
     * @param resource $handle_archivo
     * @param int      $tamanio
     *
     * @throws Exception
     */
    public static function truncateContent($handle_archivo, $tamanio)
    {
        if (ftruncate($handle_archivo, $tamanio) === false) {
            throw new Exception('No se puede truncar el archivo');
        }
    }

    /**
     * Modifica la fecha del último acceso al archivo
     *
     * @param $nombre_archivo
     *
     * @throws Exception
     */
    public static function touch($nombre_archivo)
    {
        if (touch($nombre_archivo) === false) {
            throw new Exception("No se puede realizar un touch al 
                                 archivo {$nombre_archivo}");
        }
    }

    /**
     * Posiciona el cursor al final del archivo
     *
     * @param resource $handle_archivo
     *
     * @throws Exception
     */
    public static function seekToEnd($handle_archivo)
    {
        $ret = fseek($handle_archivo, 0, SEEK_END);
        if ($ret === false || $ret == -1) {
            throw new Exception('No se puede desplazar el cursor al 
                                 final del archivo');
        }

    }

    /**
     * Posiciona el cursor al inicio del archivo
     *
     * @param $handle_archivo
     *
     * @throws Exception
     */
    public static function seekToBegin($handle_archivo)
    {
        if (rewind($handle_archivo) === false) {
            throw new Exception('No se puede desplazar el cursor al 
                                 inicio del archivo');
        }

    }

    /**
     * Posiciona el cursor dentro de un archivo partiendo de la
     * posición actual del cursor
     *
     * @param resource $handle_archivo
     * @param int      $offset
     *
     * @throws Exception
     */
    public static function seekIncrement($handle_archivo, $offset)
    {
        $ret = fseek($handle_archivo, $offset, SEEK_CUR);
        if ($ret === false || $ret == -1) {
            throw new Exception('No se puede desplazar el cursor en el
                                 archivo');
        }
    }

    /**
     * Posiciona el cursor dentro de un archivo partiendo desde el 
     * final
     *
     * @param resource $handle_archivo
     * @param int      $offset
     *
     * @throws Exception
     */
    public static function seekFromEnd($handle_archivo, $offset)
    {

        $ret = fseek($handle_archivo, (-1 * $offset), SEEK_END);

        if ($ret === false || $ret == -1) {
            throw new Exception('No se puede desplazar el cursor desde 
                                 el final del archivo');
        }
    }

    /**
     * Posiciona el cursor dentro de un archivo partiendo desde el 
     * inicio
     *
     * @param resource $handle_archivo
     * @param int      $offset
     *
     * @throws Exception
     */
    public static function seekFromBegin($handle_archivo, $offset)
    {
        $ret = fseek($handle_archivo, $offset, SEEK_SET);

        if ($ret === false || $ret == -1) {
            throw new Exception('No se puede desplazar el cursor desde 
                                 dede el inicio del archivo');
        }
    }

    /**
     * Renombra un archivo a otro nombre. Puede sobreescribir el 
     * destino
     * Por defecto no lo sobreescribe. Lanza una excepción si hay 
     * algún error
     *
     * @param string $archivo_origen
     * @param string $archivo_destino
     * @param bool   $sobreescribir
     *
     * @throws Exception
     */
    public static function rename( $archivo_origen, 
                                   $archivo_destino, 
                                   $sobreescribir = false)
    {
        if (!$sobreescribir && file_exists($archivo_destino)) {
            throw new Exception("El archivo destino {$archivo_destino}
                              ya existe y no se ha de sobreescribir");
        }
        if (rename($archivo_origen, $archivo_destino) === false) {
            throw new Exception("No se ha podido sobreescribir el
                            archivo origen {$archivo_origen} con el
                            archivo destino {$archivo_destino}");
        }
    }

    /**
     * Elimina todos los archivos de un directorio que cumplan un 
     * determinado patrón.
     * Lanza excepciones si algún archivo no se ha podido eliminad
     *
     * @param string $pattern
     *
     */
    public static function removeByPattern($pattern)
    {
        array_map(function ($nombre_archivo)
        {
            self::remove($nombre_archivo);
        }, glob($pattern));
    }

    /**
     * Elimina físicamente un archivo.
     * Si no existe, no pasa nada, pero si existe y no se ha podido
     * eliminar, se lanza una excepción.
     *
     * @param $path_archivo
     *
     * @throws Exception
     */
    public static function remove($path_archivo)
    {
        if (!file_exists($path_archivo)) {
            return;
        }
        if (unlink($path_archivo) === false) {
            throw new Exception("No se puede eliminar el archivo 
                                {$path_archivo}");
        }
    }

    /**
     * Lee el contenido de un archivo en función de un formato
     *
     * @param resource $handle_archivo
     * @param string   $formato
     *
     * @return array|int
     */
    public static function readScan($handle_archivo, $formato)
    {
        return fscanf($handle_archivo, $formato);
    }

    /**
     * Lee una linea de un archivo abierto. Hasta encontrar un \r\n
     * La línea tambén incluye el salto de línea.
     * Si no puede leer del archivo, lanza una excepción
     * Si el archivo a leer esta vacío, lanza una excepción
     *
     * @param resource $handle_archivo
     *
     * @return string
     * @throws Exception
     */
    public static function readLine($handle_archivo)
    {
        $ret = fgets($handle_archivo);
        if ($ret === false) {
            throw new Exception('No se puede leer la linea del 
                                 archivo');
        }
        return $ret;
    }

    /**
     * Lee una cantidad de char de un archivo. Por defecto 1.
     * Saltos de línea (\r\n) son dos chars.
     * Si no puede leer del archivo, lanza una excepción
     * Si el archivo a leer esta vacío, lanza una excepción
     *
     * @param resource $handle_archivo
     * @param int      $max_bytes
     *
     * @return string
     * @throws Exception
     */
    public static function readChars($handle_archivo, $max_bytes = 1)
    {
        $ret = fread($handle_archivo, $max_bytes);
        if ($ret === false) {
            throw new Exception("Imposible leer {$max_bytes} bytes del 
                                 archivo");
        }
        return $ret;
    }

    /**
     * Abre una conexión contra un archivo de texto
     * Si se abre, devuelve el handle de la conexion, si hay error 
     * lanza excepción
     * r
     *     Sólo permite leer. No se puede escribir mientras esta 
     *     abierto
     *     Puntero al inicio del archivo al abrir.
     *     Falla si el archivo no existe.
     * r+
     *     Se puede leer i escribit.
     *     Puntero al inicio del archivo al abrir.
     *     Falla si el archivo no existe. Es obligatorio que exista
     * w
     *     Sólo permite escribir. No leer
     *     Puntero al inicio del archivo al abrir.
     *     Si el archivo no existe, se crea. Si está credo 
     *     sobreescribe.
     * w+
     *     Se puede leer i escribit.
     *     Puntero al inicio del archivo al abrir.
     *     Si el archivo no existe, se crea. Si está credo 
     *     sobreescribe.
     * a
     *     Sólo permite escribir. No leer
     *     Puntero al final del archivo al abrir.
     *     Si el archivo no existe, se crea.
     * a+
     *     Se puede leer i escribit.
     *     Puntero al final del archivo al abrir.
     *     Si el archivo no existe, se crea.
     *
     * @param string $path_archivo
     * @param string $modo_acceso
     *
     * @return resource
     * @throws Exception
     */
    public static function openText($path_archivo, $modo_acceso)
    {
        $handle = @fopen($path_archivo, $modo_acceso);
        if (!$handle) {
            throw new Exception("Imposible abrir archivo 
                             {$path_archivo} en modo {$modo_acceso}");
        }
        return $handle;
    }

    /**
     * Abre una conexión contra un archivo binario
     * Si se abre, devuelve el handle de la conexion, si hay error 
     * lanza excepción
     * r
     *     Sólo permite leer. No se puede escribir mientras esta 
    *      abierto
     *     Puntero al inicio del archivo al abrir.
     *     Falla si el archivo no existe.
     * r+
     *     Se puede leer i escribit.
     *     Puntero al inicio del archivo al abrir.
     *     Falla si el archivo no existe. Es obligatorio que exista
     * w
     *     Sólo permite escribir. No leer
     *     Puntero al inicio del archivo al abrir.
     *     Si el archivo no existe, se crea. Si está credo 
     *     sobreescribe.
     * w+
     *     Se puede leer i escribit.
     *     Puntero al inicio del archivo al abrir.
     *     Si el archivo no existe, se crea. Si está credo 
     *     sobreescribe.
     * a
     *     Sólo permite escribir. No leer
     *     Puntero al final del archivo al abrir.
     *     Si el archivo no existe, se crea.
     * a+
     *     Se puede leer i escribit.
     *     Puntero al final del archivo al abrir.
     *     Si el archivo no existe, se crea.
     *
     * @param string $path_archivo
     * @param string $modo_acceso
     *
     * @return resource
     * @throws Exception
     */
    public static function openBinary($path_archivo, $modo_acceso)
    {
        $handle = @fopen($path_archivo, $modo_acceso .'b'); 
                         /* b => Abre un binario */
        if (!$handle) {
            throw new Exception("Imposible abrir archivo 
                             {$path_archivo} en modo {$modo_acceso}");
        }
        return $handle;
    }

    /**
     * Bloquea un archivo en modo exclusivo, tanto para leer como para
     * escribir
     *
     * @param resource $handle_archivo
     *
     * @throws Exception
     */
    public static function lock($handle_archivo)
    {
        if (flock($handle_archivo, LOCK_EX) === false) {
            throw new Exception('Imposible bloquear el archivo 
                                  origen');
        }
    }

    /**
     * Indica si el archivo se puede escribir.
     * Si el archivo no existe, devuelve false.
     * No es necesario estar abierto.
     *
     * @param string $nombre_archivo
     *
     * @return bool
     */
    public static function isWritable($nombre_archivo)
    {
        if (!file_exists($nombre_archivo)) {
            return false;
        }
        return is_writable($nombre_archivo);
    }

    /**
     * Indica si el archivo se puede leer.
     * Si el archivo no existe, devuelve false.
     * No es necesario estar abierto.
     *
     * @param string $nombre_archivo
     *
     * @return bool
     */
    function archivo_leible($nombre_archivo)
    {
        if (!file_exists($nombre_archivo)) {
            return false;
        }
        return is_readable($nombre_archivo);
    }

    /**
     * Devuelve el tamaño en bytes de un archivo.
     * Si el archivo no existe, devuelve -1
     *
     * @param $nombre_archivo
     *
     * @return false|int
     * @throws Exception
     */
    public static function getSizeBytes($nombre_archivo)
    {
        if (!file_exists($nombre_archivo)) {
            return -1;
        }
        $ret = filesize($nombre_archivo);
        if ($ret === false) {
            throw new Exception("No se puede obtener el tamaño del
                                 archivo {$nombre_archivo}");
        }
        return $ret;
    }

    /**
     * Devuelve la posición actual del cursor
     *
     * @param resource $handle_archivo
     *
     * @return false|int
     * @throws Exception
     */
    public static function getSeekPosition($handle_archivo)
    {
        $ret = ftell($handle_archivo);
        if ($ret === false) {
            throw new Exception('Imposible obtener la posición del 
                                cursor de dentro del archivo');
        }
        return $ret;
    }

    /**
     * Reemplaza los separadores de directorio "\\" por "/" y elimina 
     * los innecesarios
     *
     * @param string $path_archivo
     *
     * @return string
     */
    public static function getSanitizedPath($path_archivo)
    {
        $path = HelpString::replaceAll($path_archivo, '\\', '/');
        $path = HelpString::replaceAll($path, '//', '/');
        return HelpString::replaceAll($path, '/./', '/');
    }

    /**
     * Función que devuelde sólo el nombre del archivo, sin extensión 
     * ni directorio.
     * Separador de directorio = '/'
     * Si sólo hay un directorio (último carácter es '/') implica que 
     * no hay nombre de archivo y devuelve ''
     *
     * @param string $path_archivo
     *
     * @return string
     */
    public static function getOnlyFileName($path_archivo)
    {
        $path_archivo = self::getSanitizedPath($path_archivo);
        $pos_ultimo   = strlen($path_archivo) - 1;
        if ($path_archivo[ $pos_ultimo ] == '/') {
            return '';
        }
        return pathinfo($path_archivo, PATHINFO_FILENAME);
    }

    /**
     * Función que devuelve sólo la extensión de un archivo
     * Si tiene más de una, devuelve la última y si no 
     * tiene devuelve ""
     *
     * @param string $path_archivo
     *
     * @return string
     */
    public static function getOnlyExtension($path_archivo)
    {
        return pathinfo($path_archivo, PATHINFO_EXTENSION);
    }

    /**
     * Función que devuelde sólo el directorio del archivo con path.
     * Si sólo hay el nombre del archivo, el directorio es ""
     * Si sólo hay directorio (sin nombre de archivo) devuelve el 
     * mismo directorio
     *
     * @param string $path_archivo
     *
     * @return string
     */
    public static function getOnlyDirName($path_archivo)
    {
        $path_archivo = self::getSanitizedPath($path_archivo);
        $pos_ultimo   = strlen($path_archivo) - 1;
        if ($path_archivo[ $pos_ultimo ] == '/') {
            return substr($path_archivo, 0, $pos_ultimo);
        }
        if ($path_archivo[ 0 ] == '/') {
            $path_archivo = substr($path_archivo, 1);
        }

        $dir = pathinfo($path_archivo, PATHINFO_DIRNAME);

        if ($dir == "\\") {
            $dir = '/';
        } elseif ($dir == '.') {
            $dir = '';
        }
        return $dir;
    }


    /**
     * Devuelve el nombre del archivo al que apunta el link.
     * No es necesario estar abierto.
     * Si no es un link, devuelve ''
     *
     * @param string $nombre_link
     *
     * @return string
     */
    public static function getLinkTarget($nombre_link)
    {
        if (!is_link($nombre_link)) {
            return '';
        }
        return ''.readlink($nombre_link);
    }

    /**
     * Devuelve el nombre, path, tamaño y fechas de un archico
     * Opciones name, server_path, size, date, readable, writable, 
     * executable, fileperms
     *
     * @param string   path to file
     * @param mixed    array or comma separated string of information 
     * returned
     *
     * @return   array
     */
    public static function getInfo( $file, 
                               $returned_values = array('name',
                                                       'server_path',
                                                       'size',
                                                       'date')
                                  )
    {
        $fileinfo = [];
        if (!file_exists($file)) {
            return $fileinfo;
        }

        if (is_string($returned_values)) {
            $returned_values = explode(',', $returned_values);
        }

        foreach ($returned_values as $key) {
            switch ($key) {
                case 'name':
                    $fileinfo[ 'name' ] = substr( strrchr( $file,
                                                DIRECTORY_SEPARATOR),
                                          1);
                    break;
                case 'server_path':
                    $fileinfo[ 'server_path' ] = $file;
                    break;
                case 'size':
                    $fileinfo[ 'size' ] = filesize($file);
                    break;
                case 'date':
                    $fileinfo[ 'date' ] = filectime($file);
                    break;
                case 'readable':
                    $fileinfo[ 'readable' ] = is_readable($file);
                    break;
                case 'writable':
                    // There are known problems using is_weritable on 
                    // IIS.  It may not be reliable - consider 
                    // fileperms()
                    $fileinfo[ 'writable' ] = is_writable($file);
                    break;
                case 'executable':
                    $fileinfo[ 'executable' ] = is_executable($file);
                    break;
                case 'fileperms':
                    $fileinfo[ 'fileperms' ] = fileperms($file);
                    break;
            }
        }

        return $fileinfo;
    }

    /**
     * Crea y devuelve un nombre único de un archivo temporal en el 
     * directorio temporal del sistema
     * Se le puede añadir un prefijo de 3 caracteres como máximo.
     * Lanza una excecpión si no se puede crear
     *
     * @param string $prefijo
     *
     * @return string
     * @throws Exception
     */
    public static function getFileTmp($prefijo = '')
    {
        $nombre = tempnam(sys_get_temp_dir(), $prefijo);
        if ($nombre === false) {
            throw new Exception('Imposible crear archivo temporal');
        }
        return $nombre;
    }

    /**
     * Función que devuelde el nombre completo (nombre + extensión) 
     * del archivo, sin directorio
     * Si el archivo sólo tiene directorio, devuelve ""
     * SI el archivo sólo contiene nombre de vuelve el mismo nombre
     *
     * @param string $path_archivo
     *
     * @return string
     */
    public static function getFileNameFull($path_archivo)
    {
        $path_archivo = self::getSanitizedPath($path_archivo);
        $pos_ultimo   = strlen($path_archivo) - 1;
        if ($path_archivo[ $pos_ultimo ] == '/') {
            return '';
        }
        return pathinfo($path_archivo, PATHINFO_BASENAME);
    }

    /**
     * Devuelve el contenido de un archivo.
     * Se puede indicar un offset y un máximi de bytes a devolver
     * Si el archivo no existe, lanza una excepción.
     * Saltos de línea son \r\n
     * Si hay un offset es obligatorio un máximo de bytes a devolver
     *
     * @param string   $path_archivo
     * @param int|null $offset
     * @param int|null $max_bytes
     *
     * @return false|string
     * @throws Exception
     */
    public static function getAllContent($path_archivo, 
                                         $offset = null, 
                                         $max_bytes = null)
    {
        if (!is_null($offset) && !is_null($max_bytes)) {
            $ret = file_get_contents( $path_archivo, 
                                      null, 
                                      null, 
                                      $offset, 
                                      $max_bytes);
        } else {
            $ret = file_get_contents($path_archivo);
        }
        if ($ret === false) {
            throw new Exception("Imposible leer el contenido del 
                                 archivo {$path_archivo}");
        }
        return $ret;
    }

    /**
     * Fuerza la escritura del bufer al archivo.
     * Lanza una excepción si no puede realizarlo
     *
     * @param resource $handle_archivo
     *
     * @throws Exception
     */
    public static function flush($handle_archivo)
    {
        if (fflush($handle_archivo) === false) {
            throw new Exception('No sd puede formazar la escriptura
                                del archivo')
        }
    }

    /**
     * Indica si un archivo existe
     *
     * @param string $path_archivo
     *
     * @return mixed
     */
    public static function exists($path_archivo)
    {
        return file_exists($path_archivo);
    }

    /**
     * Detecta el End Of File de un archivo
     *
     * @param $handle_archivo
     *
     * @return bool
     */
    public static function eof($handle_archivo)
    {
        return feof($handle_archivo);
    }

    /**
     * Crea un link simbólico de un archio. No es necesario que esté 
     * abierto
     * Lanza una excepción si no se ha podido crear
     *
     * @param string $nombre_archivo_origen
     * @param string $nombre_link_destino
     *
     * @throws Exception
     */
    public static function createLink( $nombre_archivo_origen, 
                                       $nombre_link_destino)
    {
        $ret = symlink($nombre_archivo_origen, $nombre_link_destino);
        if ($ret === false) {
            throw new Exception("Imposible crear link destino
                                {$nombre_link_destino} del archivo 
                                origen {$nombre_archivo_origen}");
        }
    }

    /**
     * Copa un archivo a otro. Por defecto no se sobreescribe.
     * Lanza una excecpión si no se ha copiado por algún motivo
     * Se puede copiar entre diferentes directorios
     *
     * @param string $archivo_origen
     * @param string $archivo_destino
     * @param bool   $sobreescribir
     *
     * @throws Exception
     */
    public static function copy( $archivo_origen, 
                                 $archivo_destino, 
                                 $sobreescribir = false)
    {
        if (!$sobreescribir && file_exists($archivo_destino)) {
            throw new Exception("El archivo destino {$archivo_destino}
                              ya existe y no se ha de sobreescribir");
        }
        if (copy($archivo_origen, $archivo_destino) === false) {
            throw new Exception("No se puede copiar el archivo origen 
                                 {$archivo_origen} en el archivo
                                 destino {$archivo_destino}");
        }
    }

    /**
     * Cierra el fichero
     *
     * @param $handle_file
     */
    public static function close($handle_file)
    {
        @fclose($handle_file);
    }

    /**
     * Cambiamos la extensión de un archivo.
     * Si no tiene extensión, le asignamos la nueva.
     *
     * @param string $nombre_archivo
     * @param string $nueva_extension
     *
     * @return string
     */
    public static function archivo_cambiar_extension($nombre_archivo, 
                                                     $nueva_extension)
    {
        if (HelpValidate::isEmpty($nueva_extension)) {
            return $nombre_archivo;
        }

        if ($nueva_extension[ 0 ] != '.') {
            $nueva_extension = '.'.$nueva_extension;
        }

        $dir = self::getOnlyDirName($nombre_archivo);

        $solo_nombre = self::getOnlyFileName($nombre_archivo);

        if ($solo_nombre == '') {
            return $nombre_archivo;
        }

        if ($dir == '' && $nombre_archivo[ 0 ] != '/') {
            return $dir.$solo_nombre.$nueva_extension;
        }

        return $dir.'/'.$solo_nombre.$nueva_extension;
    }

}