<?php
// +----------------------------------------------------------------------
// | ShopXO 国内领先企业级B2C免费开源电商系统
// +----------------------------------------------------------------------
// | Copyright (c) 2011~2099 http://shopxo.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://opensource.org/licenses/mit-license.php )
// +----------------------------------------------------------------------
// | Author: Devil
// +----------------------------------------------------------------------
namespace base;

use app\service\ResourcesService;

/**
 * 例子：
 * CreateDir('a/1/2/3');                  建立文件夹 建一个a/1/2/3文件夹
 * CreateFile('b/1/2/3');                 建立文件        在b/1/2/文件夹下面建一个3文件
 * CreateFile('b/1/2/3.exe');             建立文件        在b/1/2/文件夹下面建一个3.exe文件
 * CopyDir('b','d/e');                    复制文件夹 建立一个d/e文件夹，把b文件夹下的内容复制进去
 * CopyFile('b/1/2/3.exe','b/b/3.exe');   复制文件        建立一个b/b文件夹，并把b/1/2文件夹中的3.exe文件复制进去
 * MoveDir('a/','b/c');                   移动文件夹 建立一个b/c文件夹,并把a文件夹下的内容移动进去，并删除a文件夹
 * MoveFile('b/1/2/3.exe','b/d/3.exe');   移动文件        建立一个b/d文件夹，并把b/1/2中的3.exe移动进去                   
 * UnlinkFile('b/d/3.exe');               删除文件        删除b/d/3.exe文件
 * UnlinkDir('d');                        删除文件夹 删除d文件夹
 */

/**
 * 操纵文件类
 * @author   Devil
 * @blog    http://gong.gg/
 * @version 1.0.0
 * @date    2018-06-28
 * @desc    支持所有文件存储到硬盘
 */
class FileUtil
{
    /**
     * 建立文件夹
     * @author   Devil
     * @blog    http://gong.gg/
     * @version 1.0.0
     * @date    2018-06-29
     * @desc    description
     * @param   [string]     $aim_url   [目录地址]
     * @return  [boolean]               [true | false]
     */
    public static function CreateDir($aim_url)
    {
        // 根目录前不参与，避免虚拟机没有权限
        $aim_dir = ROOT;
        $aim_url = str_replace($aim_dir, '', $aim_url);

        // 空转成目录
        $aim_url = str_replace('', '/', $aim_url);
        $arr = explode('/', $aim_url);
        $result = true;
        foreach($arr as $str)
        {
            if(stripos($str, ':') === false)
            {
                $aim_dir .= $str . '/';
                if($aim_dir != '/' && !is_dir($aim_dir))
                {
                    $result = mkdir($aim_dir);
                }
            }
        }
        return $result;
    }

    /**
     * 建立文件
     * @author   Devil
     * @blog    http://gong.gg/
     * @version 1.0.0
     * @date    2018-06-29
     * @desc    description
     * @param   [string]     $aim_url       [目录地址]
     * @param   [boolean]    $over_write    [该参数控制是否覆盖原文件]
     * @return  [boolean]                   [true | false]
     */
    public static function CreateFile($aim_url, $over_write = false)
    {
        if(file_exists($aim_url) && $over_write == false)
        {
            return false;
        } elseif(file_exists($aim_url) && $over_write == true)
        {
            self::UnlinkFile($aim_url);
        }
        $aim_dir = dirname($aim_url);
        if(!empty($aim_dir) && $aim_dir != '.')
        {
            self::CreateDir($aim_dir.'/');
        }
        touch($aim_url);
        return true;
    }

    /**
     * 移动文件夹
     * @author   Devil
     * @blog    http://gong.gg/
     * @version 1.0.0
     * @date    2018-06-29
     * @desc    description
     * @param   [string]     $old_dir       [原地址]
     * @param   [string]     $aim_dir       [新地址]
     * @param   [boolean]    $over_write    [该参数控制是否覆盖原文件]
     * @return  [boolean]                   [true | false]
     */
    public static function MoveDir($old_dir, $aim_dir, $over_write = false)
    {
        $aim_dir = str_replace('', '/', $aim_dir);
        $aim_dir = substr($aim_dir, -1) == '/' ? $aim_dir : $aim_dir . '/';
        $old_dir = str_replace('', '/', $old_dir);
        $old_dir = substr($old_dir, -1) == '/' ? $old_dir : $old_dir . '/';
        if(!is_dir($old_dir))
        {
            return false;
        }
        if(!file_exists($aim_dir))
        {
            self::CreateDir($aim_dir);
        }
        @$dir_handle = opendir($old_dir);
        if(!$dir_handle)
        {
            return false;
        }
        while(false !== ($file = readdir($dir_handle)))
        {
            if($file == '.' || $file == '..')
            {
                continue;
            }
            if(!is_dir($old_dir . $file))
            {
                self::MoveFile($old_dir . $file, $aim_dir . $file, $over_write);
            } else {
                self::MoveDir($old_dir . $file, $aim_dir . $file, $over_write);
            }
        }
        closedir($dir_handle);
        return rmdir($old_dir);
    }

    /**
     * 移动文件
     * @author   Devil
     * @blog    http://gong.gg/
     * @version 1.0.0
     * @date    2018-06-29
     * @desc    description
     * @param   [string]     $file_url      [原文件]
     * @param   [string]     $aim_url       [新文件]
     * @param   [boolean]    $over_write    [该参数控制是否覆盖原文件]
     * @return  [boolean]                   [true | false]
     */
    public static function MoveFile($file_url, $aim_url, $over_write = false)
    {
        if(!file_exists($file_url))
        {
            return false;
        }
        if(file_exists($aim_url) && $over_write = false)
        {
            return false;
        } elseif(file_exists($aim_url) && $over_write = true)
        {
            self::UnlinkFile($aim_url);
        }
        $aim_dir = dirname($aim_url);
        if(!empty($aim_dir) && $aim_dir != '.')
        {
            self::CreateDir($aim_dir.'/');
        }
        rename($file_url, $aim_url);
        return true;
    }

    /**
     * 删除文件夹
     * @author   Devil
     * @blog    http://gong.gg/
     * @version 1.0.0
     * @date    2018-06-29
     * @desc    description
     * @param   [string]     $aim_dir      [地址]
     * @param   [boolean]    $is_del_dir   [是否删除目录]
     * @return  [boolean]                  [true | false]
     */
    public static function UnlinkDir($aim_dir, $is_del_dir = true)
    {
        $aim_dir = str_replace('', '/', $aim_dir);
        $aim_dir = substr($aim_dir, -1) == '/' ? $aim_dir : $aim_dir . '/';
        if(!is_dir($aim_dir))
        {
            return false;
        }
        $dir_handle = opendir($aim_dir);
        while(false !== ($file = readdir($dir_handle)))
        {
            if($file == '.' || $file == '..')
            {
                continue;
            }
            if(!is_dir($aim_dir . $file))
            {
                self::UnlinkFile($aim_dir . $file);
            } else {
                self::UnlinkDir($aim_dir . $file, $is_del_dir);
            }
        }
        closedir($dir_handle);
        return $is_del_dir ? rmdir($aim_dir) : true;
    }

    /**
     * 删除文件
     * @author   Devil
     * @blog    http://gong.gg/
     * @version 1.0.0
     * @date    2018-06-29
     * @desc    description
     * @param   [string]     $aim_url      [文件]
     * @return  [boolean]                  [true | false]
     */
    public static function UnlinkFile($aim_url)
    {
        $aim_url = str_replace('//', '/', $aim_url);
        if(file_exists($aim_url) && is_writable($aim_url))
        {
            @unlink($aim_url);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 复制文件夹
     * @author   Devil
     * @blog    http://gong.gg/
     * @version 1.0.0
     * @date    2018-06-29
     * @desc    description
     * @param   [string]     $old_dir       [原地址]
     * @param   [string]     $aim_dir       [新地址]
     * @param   [boolean]    $over_write    [该参数控制是否覆盖原文件]
     * @return  [boolean]                   [true | false]
     */
    public static function CopyDir($old_dir, $aim_dir, $over_write = false)
    {
        $aim_dir = str_replace('', '/', $aim_dir);
        $aim_dir = substr($aim_dir, -1) == '/' ? $aim_dir : $aim_dir . '/';
        $old_dir = str_replace('', '/', $old_dir);
        $old_dir = substr($old_dir, -1) == '/' ? $old_dir : $old_dir . '/';
        if(!is_dir($old_dir))
        {
            return false;
        }
        if(!file_exists($aim_dir))
        {
            self::CreateDir($aim_dir);
        }
        $dir_handle = opendir($old_dir);
        while(false !== ($file = readdir($dir_handle)))
        {
            if($file == '.' || $file == '..')
            {
                continue;
            }
            if(!is_dir($old_dir . $file))
            {
                self::CopyFile($old_dir . $file, $aim_dir . $file, $over_write);
            } else {
                self::CopyDir($old_dir . $file, $aim_dir . $file, $over_write);
            }
        }
        closedir($dir_handle);
        return is_dir($aim_dir);
    }

    /**
     * 复制文件
     * @author   Devil
     * @blog    http://gong.gg/
     * @version 1.0.0
     * @date    2018-06-29
     * @desc    description
     * @param   [string]     $file_url      [原文件]
     * @param   [string]     $aim_url       [新文件]
     * @param   [boolean]    $over_write    [该参数控制是否覆盖原文件]
     * @return  [boolean]                   [true | false]
     */
    public static function CopyFile($file_url, $aim_url, $over_write = false)
    {
        if(!file_exists($file_url))
        {
            return false;
        }
        if(file_exists($aim_url) && $over_write == false)
        {
            return false;
        } elseif(file_exists($aim_url) && $over_write == true)
        {
            self::UnlinkFile($aim_url);
        }
        $aim_dir = dirname($aim_url);
        if(!empty($aim_dir) && $aim_dir != '.')
        {
            self::CreateDir($aim_dir.'/');
        }
        copy($file_url, $aim_url);
        return true;
    }

    /**
     * 文件下载
     * @author   Devil
     * @blog    http://gong.gg/
     * @version 1.0.0
     * @date    2019-03-25
     * @desc    description
     * @param   [string]          $file_path [文件地址]
     * @param   [string]          $show_name [显示名称]
     * @param   [boolean]         $is_del    [是否需要删除文件]
     */
    public static function DownloadFile($file_path, $show_name, $is_del = false)
    {
        if(is_file($file_path))
        {
            //打开文件
            $file = fopen($file_path, "r");

            //返回的文件类型
            Header("Content-type: application/octet-stream");

            //按照字节大小返回
            Header("Accept-Ranges: bytes");

            //返回文件的大小
            Header("Accept-Length: ".filesize($file_path));

            //这里设置客户端的弹出对话框显示的文件名
            Header("Content-Disposition: attachment; filename=".$show_name);

            // 清除前面输出的内容
            if(ob_get_length() > 0)
            {
                ob_clean();
                flush();
            }

            //一次性将数据传输给客户端
            //echo fread($file, filesize($file_path));
            //一次只传输1024个字节的数据给客户端
            //向客户端回送数据
            $buffer = 1024;

            //判断文件是否读完
            while(!feof($file))
            {
                //将文件读入内存
                $file_data = fread($file, $buffer);
                //每次向客户端回送1024个字节的数据
                echo $file_data;
            }
            // 是否删除文件
            if($is_del)
            {
                self::UnlinkFile($file_path);
            }
            die;
        }
        return false;
    }

    /**
     * 上传文件内容安全验证
     * @author  Devil
     * @blog    http://gong.gg/
     * @version 1.0.0
     * @date    2025-03-09
     * @desc    description
     * @param   [string]          $value        [文件内容，临时地址]
     * @param   [boolean]         $is_temp_file [是否为临时地址]
     */
    public static function FileContentSecurityCheck($value, $is_temp_file = true)
    {
        if(!empty($value))
        {
            // 临时文件读取
            if($is_temp_file)
            {
                $value = @file_get_contents($value);
            }

            // 包含php代码
            // 包含 script 脚本（含普通标签与 XML 命名空间形式如 <x:script>，防 ueditor catchfile 存 XSS）
            // 包含src引入文件
            // 包含href跳转地址
            // 包含iframe引入外部地址
            if(preg_match('#<\?php#i', $value)
                || preg_match('#<script\b#i', $value)
                || preg_match('#<[a-z0-9_-]+:script\b#i', $value)
                || preg_match('#src=#i', $value)
                || preg_match('#href=#i', $value)
                || preg_match('#<iframe\b#i', $value))
            {
                return DataReturn(MyLang('common_extend.base.fileupload.file_illegal_tips'), -1);
            }
        }
        return DataReturn('success', 0);
    }

    /**
     * 获取文件内容、仅支持本地文件
     * @author  Devil
     * @blog    http://gong.gg/
     * @version 1.0.0
     * @date    2025-06-04
     * @desc    description
     * @param   [string]          $file [文件地址]
     */
    public static function FileContent($file)
    {
        $value = '';
        if(file_exists($file))
        {
            $value = @file_get_contents($file);
        } else  {
            $file = ROOT_PATH.ResourcesService::AttachmentPathHandle($file);
            if(file_exists($file))
            {
                $value = @file_get_contents($file);
            }
        }
        return $value;
    }

    /**
     * 获取文件md5、仅支持本地文件
     * @author  Devil
     * @blog    http://gong.gg/
     * @version 1.0.0
     * @date    2025-06-04
     * @desc    description
     * @param   [string]          $file [文件地址]
     */
    public static function FileMd5($file)
    {
        $value = '';
        if(file_exists($file))
        {
            $value = @md5_file($file);
        } else {
            $file = ROOT_PATH.ResourcesService::AttachmentPathHandle($file);
            if(file_exists($file))
            {
                $value = @md5_file($file);
            }
        }
        return $value;
    }
}
?>