Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
50.00% covered (warning)
50.00%
4 / 8
CRAP
36.67% covered (warning)
36.67%
22 / 60
FileIt
0.00% covered (danger)
0.00%
0 / 1
50.00% covered (warning)
50.00%
4 / 8
242.65
36.67% covered (warning)
36.67%
22 / 60
 jsonFileSave
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 13
 fileNameSanitize
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
9 / 9
 fileNameValid
100.00% covered (success)
100.00%
1 / 1
9
100.00% covered (success)
100.00%
7 / 7
 fileNameValidExtension
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 fileExists
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 2
 fileNameNextVersion
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 17
 directoryPathSlashEnd
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
4 / 4
 directoryEnsureExists
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 6
<?php
namespace ia\Util;
// https://www.cloudways.com/blog/the-basics-of-file-upload-in-php/
/*
mime_content_type('css/images/loading.gif')
Pa config
// zend.assertions  0: production mode. generate code but jump around it at runtime
// zend.assertions  1: development mode generate and execute code
// zend.assertions -1: production mode. do not generate code, needs php 7
ini_set('zend.assertions',1);
// assert.exception 0: WARN use or generate a Throwable as described above, but only generate a warning based on that object rather than throwing it (compatible with PHP 5 behaviour)
// assert.exception 1: ERROR throw when the assertion fails, either by throwing the object provided as the exception or by throwing a new AssertionError object if exception wasn't provided
ini_set('assert.exception', 0);
assert(is_numeric("3"), 'Not numeric');
Pa tools
    https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
    https://stackoverflow.com/questions/18299806/how-to-check-file-mime-type-with-javascript-before-upload  or from the browser
    function generateUpToDateMimeArray($url){
        $s=array();
        foreach(@explode("\n",@file_get_contents($url))as $x)
            if(isset($x[0])&&$x[0]!=='#'&&preg_match_all('#([^\s]+)#',$x,$out)&&isset($out[1])&&($c=count($out[1]))>1)
                for($i=1;$i<$c;$i++)
                    $s[]='&nbsp;&nbsp;&nbsp;\''.$out[1][$i].'\' => \''.$out[1][0].'\'';
        return @sort($s)?'$mime_types = array(<br />'.implode($s,',<br />').'<br />);':false;
    }
    define('APACHE_MIME_TYPES_URL','http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types');
    echo generateUpToDateMimeArray(APACHE_MIME_TYPES_URL);
Pa uploader
     // array('jpeg', 'jpg', 'jpe')
   ** https://github.com/ralouphie/mimey
    https://github.com/xobotyi/php-mime-type
*/
use Exception;
use URLify;
/**
 * Class FileIt
 * Sanitize and validate file name, standardize end slash in path, create dir recursively, save json file
 * @package ia\Util
 */
class FileIt {
    /**
     * Save an array as a json file
     *
     * @param string $fullFileName
     * @param array $array
     * @param int $jsonOptions
     * @return bool true ok
     */
    public static function jsonFileSave($fullFileName, $array, $jsonOptions = JSON_HEX_QUOT) {
        $ignore_user_abort = ignore_user_abort();
        try {
            ignore_user_abort(1);
            $tempFile = $fullFileName . mt_rand(1, 9999);
            $bytes = file_put_contents($tempFile, json_encode($array, $jsonOptions), LOCK_EX);
            $renamed = $bytes !== false && $bytes >0 && rename($tempFile, $fullFileName);
            if(!$renamed) {
                @unlink($tempFile);
            }
            clearstatcache(true, $fullFileName);
            ignore_user_abort($ignore_user_abort);
            return $renamed;
        } catch(Exception $e) {
            ignore_user_abort($ignore_user_abort);
            return false;
        }
    }
    /** Files */
    protected static $invalidCharacters = ['/', '\\', '|', '>', '<', ';', ':', '?' , '*', '"', "'", '&', ' ','~','-' ];
    /**
     * Make the file name safe
     *
     * @param string $fileName
     * @return string
     */
    public static function fileNameSanitize($fileName) {
        $fileName = str_replace(self::$invalidCharacters, '_',
            str_replace('..', '.', Str::strim($fileName))
        );
        $fileName = preg_replace('/_{2,}/m','_',$fileName);
        while($fileName[0]=='.') {
            $fileName = substr($fileName,1);
        }
        $fileName = str_ireplace(['.jpeg', '.jpe'], '.jpg', $fileName);
        $dotExtension = strrchr($fileName, '.');
        $fileName = str_ireplace($dotExtension, strtolower($dotExtension), $fileName);
        return URLify::downcode( $fileName );
    }
    /**
     * Is $fileName a valid file name
     *
     * @param string $fileName
     * @return bool
     */
    public static function fileNameValid($fileName) {
        $c1 = $fileName[0];
        if($c1 === '' || $c1 === '.' || $c1 === '/' || $c1 === '\\' || $c1 === '~' || $c1 === '`') {
            return false;
        }
        foreach(self::$invalidCharacters as $c) {
            if(strpos($fileName, $c) !== FALSE) {
                return false;
            }
        }
        return true;
    }
    /**
     * @param string $fileName
     * @param array $allowedExtensions
     * @return bool
     */
    public static function fileNameValidExtension($fileName, $allowedExtensions) {
        $extension = strtolower(substr(strrchr($fileName, '.'),1));
        return array_key_exists($extension, array_flip($allowedExtensions) );
    }
    /**
     * @param string $fileNamePath
     * @return bool
     */
    public static function fileExists($fileNamePath) {
        clearstatcache(true, $fileNamePath);
        return file_exists($fileNamePath);
    }
    /**
     * @param string $dirPath
     * @param string $fileName
     * @return string
     */
    public static function fileNameNextVersion($dirPath, $fileName) {
        $dirPath = self::directoryPathSlashEnd($dirPath);
        $fileNamePath = $dirPath . $fileName;
        clearstatcache(true, $fileNamePath);
        if(!file_exists($fileNamePath)) {
            return $fileName;
        }
        $rightPos = strrpos($fileName, '.');
        if($rightPos === false || $rightPos <= 0) {
            return $fileName;
        }
        $baseName = substr($fileName, 0, $rightPos);
        $extension = substr($fileName, $rightPos);
        foreach(range(0x1, 0xFFFF) as $versionNum) {
            $versionName = $baseName.'_'.str_pad(dechex($versionNum), 4, '0', STR_PAD_LEFT).$extension;
            $fileNamePath = $dirPath . $versionName;
            clearstatcache(true, $fileNamePath);
            if(!file_exists($fileNamePath)) {
                return $versionName;
            }
        }
        return $versionName = $baseName.'_'.str_pad(1, 4, '0', STR_PAD_LEFT).$extension;
    }
    /** Directories */
    /**
     * @param string $dirPath
     * @return string
     */
    public static function directoryPathSlashEnd($dirPath) {
        $dirPath = str_replace('\\','/', $dirPath);
        if(substr($dirPath, -1) !== '/') {
            return $dirPath . '/';
        }
        return $dirPath;
    }
    /**
     * @param string $dirPath
     * @param int $permission octal
     * @return bool
     */
    public static function directoryEnsureExists($dirPath, $permission = 0660) {
        if(empty($dirPath) ) {
            return false;
        }
        clearstatcache(true, $dirPath);
        if(!file_exists($dirPath)) {
            return mkdir($dirPath,  $permission, true);
        }
        return true;
    }
}