Server : nginx/1.18.0
System : Linux iZrj9edhd5u5pfsek09o1jZ 3.10.0-957.21.3.el7.x86_64 #1 SMP Tue Jun 18 16:35:19 UTC 2019 x86_64
User : www ( 1000)
PHP Version : 5.6.40
Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
Directory :  /mnt/web/www.neatabattery.com/weapp/PictureCleaning/controller/
Upload File :
Current Directory [ Writeable ] Root Directory [ Writeable ]


Current File : /mnt/web/www.neatabattery.com/weapp/PictureCleaning/controller/PictureCleaning.php
<?php
/**
 * 易优CMS
 * ============================================================================
 * 版权所有 2016-2028 海南赞赞网络科技有限公司,并保留所有权利。
 * 网站地址: http://www.eyoucms.com
 * ----------------------------------------------------------------------------
 * 如果商业用途务必到官方购买正版授权, 以免引起不必要的法律纠纷.
 * ============================================================================
 * Author: 陈风任 <491085389@qq.com>
 * Date: 2018-12-11
 */

namespace weapp\PictureCleaning\controller;

use think\Page;
use think\AjaxPage;
use think\Db;
use think\Config;
use app\common\controller\Weapp;

/**
 * 插件的控制器
 */
class PictureCleaning extends Weapp
{
    /**
     * 实例化对象
     */
    private $db;

    /**
     * 插件基本信息
     */
    private $weappInfo;

    /**
     * 构造方法
     */
    public function __construct() {
        parent::__construct();
        $this->db = Db::name('WeappPictureCleaning');

        /*插件基本信息*/
        $this->weappInfo = $this->getWeappInfo();
        $this->assign('weappInfo', $this->weappInfo);
        /*--end*/
    }

    /**
     * 插件使用说明
     */
    public function doc()
    {
        return $this->fetch('doc');
    }

    // 插件首页
    public function index()
    {
        return $this->fetch('index');
    }

    // 获取未使用文件个数并存入数据库记录
    public function picture_query()
    {
        ini_set("memory_limit", "-1");

        $file_image = $mysql_image = $result = [];

        // 获取项目文件中的图片
        $file_image  = $this->get_file_image();

        // 获取数据库中的所有图片路径
        $mysql_image = $this->get_mysql_image();

        // 对比处理图片,返回差集
        $result = array_diff($file_image, $mysql_image);

        // 图片数据处理
        if (is_array($result) && !empty($result)) {
            // 删除数据库所有未被清理的图片
            $this->db->where('status', 0)->delete(true);

            $saveData = [];
            foreach ($result as $value) {
                $nowData = [
                    'url' => handle_subdir_pic($value),
                    'add_time' => getTime(),
                    'update_time' => getTime()
                ];
                array_push($saveData, $nowData);
                $nowData = [];
                if (count($saveData) >= 3000) {
                    // 3000张图片为一个断点,执行添加数据库后继续循环操作
                    $this->savePicData($saveData);
                    $saveData = [];
                }
            }
        }

        // 存在相片且不足3000时执行
        if (!empty($saveData)) $this->savePicData($saveData);

        // 返回结果
        $count = count($result);
        $this->success('正在加载图片', null, ['count' => $count]);
    }

    // AJAX查看文件-未清理
    public function picture_list()
    {
        // 查询条件
        $where['status'] = 0; // 未清理数据

        // 查询分页
        $Count = $this->db->where($where)->order('id asc')->count('id');
        $pageObj = new AjaxPage($Count, 200); // config('paginate.list_rows')

        // 查询图片数据
        $ResultData = $this->db->where($where)->order('id asc')->limit($pageObj->firstRow.','.$pageObj->listRows)->select();
        $PicArray = ['.gif', '.jpeg', '.png', '.bmp', '.jpg', '.ico', '.webp'];
        foreach ($ResultData as $key => $value) {

            //$PicType = strtolower(substr($value['url'], -4));
            $PicType = '.'.end(explode(".",$value['url']));
            $PicType = strtolower($PicType);

            if (!in_array($PicType, $PicArray)) {
                $ResultData[$key]['url'] = ROOT_DIR . '/public/static/common/images/Archive.png';
            }
        }

        $this->assign('times',  date('Ymd'));
        $this->assign('result', $ResultData);
        $this->assign('Page', $pageObj->show());

        // 查询剩余未处理的图片数量
        $SurplusCount = $this->db->where($where)->count('id');
        $this->assign('surplus_count', $SurplusCount);
        return $this->fetch('picture_list');
    }

    // 移动选中图片至插件本身的回收站
    public function image_deal_with()
    {
        if (IS_AJAV_POST) {
            $post = input('post.');
            if (empty($post) || empty($post['pic_arr']) || empty($post['type'])) $this->error("请正确选择操作");
            
            // 查询图片清理查询数据表数据,已扫描但未处理文件
            $where = [
                'status' => 0,
                'id' => ['IN', $post['pic_arr']]
            ];
            $ResultData = $this->db->field('id, url')->where($where)->select();

            // 执行图片删除或移动操作
            $DelNum = 0;
            $DeleteID = [];
            if ('Delete' == $post['type']) {
                // 删除操作
                if (is_array($ResultData) && !empty($ResultData)) {
                    foreach ($ResultData as $value) {
                        if (!empty($value['url'])) {
                            // 处理文件的路径
                            $url = substr($value['url'], strlen(ROOT_DIR));
                            $url = iconv('UTF-8', 'GB2312', ROOT_PATH . $url);
                            if (@unlink($url)) {
                                $DelNum++;
                                array_push($DeleteID, $value['id']);
                            }
                        }
                    }
                    if (!empty($DelNum) && !empty($DeleteID)) {
                        // 删除数据中的数据
                        $where['id'] = ['IN', $DeleteID];
                        $this->db->where($where)->delete();

                        // 返回提示
                        $this->success('成功删除' . $DelNum . '个文件');
                    }
                } else {
                    $this->error("请选择需要删除的文件");
                }

            } else if ('CleanUp' == $post['type']) {
                // 移动操作
                if (is_array($ResultData) && !empty($ResultData)) {
                    // 移动相片的目录
                    $times = date('Ymd');

                    // 处理文件移动
                    foreach ($ResultData as $value) {
                        // 处理文件的路径
                        $url = substr($value['url'], strlen(ROOT_DIR));
                        $url = iconv('UTF-8', 'GB2312', ROOT_PATH . $url);

                        // 获取需要创建的文件夹路径
                        $path  = substr($value['url'], 0, strrpos($value['url'], "/"));
                        $datapath = DATA_PATH . 'tempimg/' . $times . $path;

                        // 创建文件夹,权限0777,true表示创建多级文件夹
                        @mkdir($datapath, 0777, true);

                        // 移动文件夹
                        if (@rename($url, DATA_PATH . 'tempimg/' . $times . $value['url'])) {
                            $DelNum++;
                            array_push($DeleteID, $value['id']);
                        }
                    }
                    if (!empty($DeleteID) && !empty($DelNum)) {
                        // 修改数据中的数据
                        $where['id'] = ['IN', $DeleteID];
                        $saveData = [
                            'status' => '1',
                            'update_time' => getTime(),
                            'table_of_ontents' => $times
                        ];
                        $this->db->where($where)->update($saveData);

                        // 返回提示
                        $this->success('成功移动' . $DelNum . '个文件');
                    }

                } else {
                    $this->error("请选择需要移动的文件");
                }
            }
        }
    }

    // 获取项目文件中的图片
    private function get_file_image()
    {
        $filenames = [];
        $public_path = 'public/upload/';
        if (is_dir($public_path)) {
            $upload    = $this->getDirFile($public_path, '/public/upload');
            $filenames = $upload;
        }

        $uploads_path = 'uploads/';
        if (is_dir($uploads_path)) {
            $uploads   = $this->getDirFile($uploads_path, '/uploads');
            $filenames = $uploads;
        }

        if (!empty($upload) && !empty($uploads)) {
            $filenames = array_merge($upload, $uploads);
        }
        
        if (!empty($filenames)) {
            $ImagesArray = array('.gif', '.jpeg', '.png', '.bmp', '.jpg', '.ico', '.webp');
            $ReturnFiles = [];
            foreach ($filenames as $key => $value) {
                $type = strtolower(substr($value, -4));
                if(in_array($type, $ImagesArray)) array_push($ReturnFiles, $value);
            }
            return $ReturnFiles;
        } else {
            return $filenames;
        }
    }

    // 递归读取文件夹文件
    private function getDirFile($directory = '', $dir_name = '', &$arr_file = array())
    {
        if (!file_exists($directory)) return false;

        $mydir = dir($directory);
        while($file = $mydir->read())
        {
            if ('weapp' != $file && 'thumb' != $file) {
                if((is_dir("$directory/$file")) AND ($file != ".") AND ($file != "..")) {
                    if (!empty($dir_name)) {
                        getDirFile("$directory/$file", "$dir_name/$file", $arr_file);
                    } else {
                        getDirFile("$directory/$file", "$file", $arr_file);
                    }
                    unset($file);
                } else if(($file != ".") AND ($file != "..")) {
                    if (!empty($dir_name)) {
                        $arr_file[] = "$dir_name/$file";
                    } else {
                        $arr_file[] = "$file";
                    }
                }
            }
            unset($file);
        }
        $mydir->close();
        return $arr_file;
    }

    // 获取数据库中的所有图片路径
    private function get_mysql_image()
    {
        // 获取数据库表名和字段
        $array = $this->get_array();
        $database_data = $this->getDatabaseData($array);
        return $database_data;
    }

    // 拼装数据库表和字段
    private function get_array()
    {
        // 自定义字段获取逻辑
        $where = 'a.ifsystem = 0 and (a.dtype = "img" || a.dtype = "imgs" || a.dtype = "htmltext")';
        $result = Db::name('channelfield')->field('a.channel_id, a.name as field, a.dtype, b.table')
            ->alias('a')
            ->join('__CHANNELTYPE__ b', 'a.channel_id = b.id', 'LEFT')
            ->order('a.channel_id desc')
            ->where($where)
            ->select();
        foreach ($result as $key => $value) {
            if (Config::get('global.arctype_channel_id') == $value['channel_id']) { 
                $result[$key]['table'] = 'arctype'; 
            } else {
                $result[$key]['table'] = $value['table'] . '_content';
            }
        }

        // 获取内置的config配置中的数据表和字段
        $array = Config::get('global.get_tablearray');
        // 合并两个数组
        $data_new = array_merge($result, $array);

        // 返回结果集
        return $data_new;
    }

    // 获取数据中指定数据表的图片和文件路径

    /**
     * @param array $array 二维数组 所有含有图片的数据字段类型
     * @return array
     */
    private function getDatabaseData($array = [])
    {
        $data = $hello = array();
        $i = 0;
        foreach ($array as $value) {
            $where  = "`".$value['field']."`" . "<> '' ";
            $result = M($value['table'])->field($value['field'])->where($where)->select();
            // 查找多余未使用文件
            foreach ($result as $vv) {
                if ('litpic' == $value['field']) {
                    $path = parse_url($vv['litpic']);
                    if ($path['host']) {
                        $data[$i] = $path['path'];
                    } else {
                        $data[$i] = $this->images_remove_sub($path['path']);
                    }
                    $i++;
                }
                else if ('image_url' == $value['field']) {
                    $path = parse_url($vv['image_url']);
                    if ($path['host']) {
                        $data[$i] = $path['path'];
                    } else {
                        $data[$i] = $this->images_remove_sub($path['path']);
                    }
                    $i++;
                }
                else if ('logo' == $value['field']) {
                    $path = parse_url($vv['logo']);
                    if ($path['host']) {
                        $data[$i] = $path['path'];
                    } else {
                        $data[$i] = $this->images_remove_sub($path['path']);
                    }
                    $i++;
                }
                else if ('file_url' == $value['field']) {
                    $path = parse_url($vv['file_url']);
                    if ($path['host']) {
                        $data[$i] = $path['path'];
                    } else {
                        $data[$i] = $this->images_remove_sub($path['path']);
                    }
                    $i++;
                }
                else if ('head_pic' == $value['field']) {
                    $path = parse_url($vv['head_pic']);
                    if ($path['host']) {
                        $data[$i] = $path['path'];
                    } else {
                        $data[$i] = $this->images_remove_sub($path['path']);
                    }
                    $i++;
                }
                else if ('intro' == $value['field']) {
                    $str = htmlspecialchars_decode($vv['intro']);
                    $str = strip_tags($str, '<img>');
                    preg_match_all('/\<img(.*?)src\=[\'|\"]([\w:\/\.\-]+)[\'|\"]/i', $str, $matches);
                    $match = $matches[2];
                    foreach ($match as $vvv) {
                        $data[$i] = $vvv;
                        $i++;
                    }
                }
                else if ('content' == $value['field']) {
                    $str = htmlspecialchars_decode($vv['content']);
                    $str = strip_tags($str, '<img>');
                    preg_match_all('/\<img(.*?)src\=[\'|\"]([\w:\/\.\-]+)[\'|\"]/i', $str, $matches);
                    $match = $matches[2];
                    foreach ($match as $vvv) {
                        $data[$i] = $vvv;
                        $i++;
                    }
                }
                else if ('config' == $value['table']) {
                    $strlen = strlen(ROOT_DIR);
                    if (substr($vv['value'], $strlen, 7 ) == '/public' || substr($vv['value'], $strlen, 7 ) == '/upload') {
                        $data[$i] = $vv['value'];
                        $i++;
                    }
                }
                else if ('ui_config' == $value['table']) {
                    $values = json_decode($vv['value'],true);
                    $str = htmlspecialchars_decode($values['info']['value']);
                    $str = strip_tags($str, '<img>');
                    preg_match_all('/\<img(.*?)src\=[\'|\"]([\w:\/\.\-]+)[\'|\"]/i', $str, $matches);
                    $match = $matches[2];
                    foreach ($match as $vvv) {
                        $data[$i] = $vvv;
                        $i++;
                    }
                }
                else if ($value['channel_id']) {
                    if ('imgs' == $value['dtype']) {


                        //$hello = explode(',',$vv[$value['field']]);

                        // start 注释上面用 explode 分割数据, v1.4.3的版本 imgs 类型的储存是 serialize 序列化储存数组数据 格式
                        $new_imgs_arr = unserialize($vv[$value["field"]]);

                        $image_url_arr = array_column($new_imgs_arr,"image_url");
                        if(!empty($image_url_arr)) $hello = array_merge($hello,$image_url_arr);
                        // end



                    } else if ('img' == $value['dtype']) {
                        $path = parse_url($vv[$value['field']]);
                        if ($path['host']) {
                            $data[$i] = $path['path'];
                        } else {
                            $data[$i] = $this->images_remove_sub($path['path']);
                        }
                        $i++;
                    } else if ('htmltext' == $value['dtype']) {
                        $str = htmlspecialchars_decode($vv[$value['field']]);
                        $str = strip_tags($str, '<img>');
                        preg_match_all('/\<img(.*?)src\=[\'|\"]([\w:\/\.\-]+)[\'|\"]/i', $str, $matches);
                        $match = $matches[2];
                        foreach ($match as $vvv) {
                            $data[$i] = $vvv;
                            $i++;
                        }
                    }
                }
            }
        }

        $data = array_merge($data, $hello);
        $data = array_unique($data);

        return $data;
    }

    // 在图片清理插件读取数据库图片时,删除子目录前缀
    private function images_remove_sub($images = null)
    {
        $images = preg_replace('#^(/[/\w]+)?(/public/upload/|/uploads/)#i', '$2', $images);
        return $images;
    }

    // 批量添加传入的图片
    private function savePicData($saveData = [])
    {
        if (!empty($saveData)) $this->db->insertAll($saveData);
    }



    // 图片回收站列表页
    public function lists()
    {
        $list = array();
        $keywords = input('keywords/s');

        $map = array();
        if (!empty($keywords)) {
            $map['table_of_ontents'] = array('LIKE', "%{$keywords}%");
        }

        $map['status'] = 1; // status=1为被清理数据

        $count = $this->db->where($map)
            ->group('table_of_ontents')
            ->count('id');// 查询满足要求的总记录数
        $pageObj = new Page($count, config('paginate.list_rows'));// 实例化分页类 传入总记录数和每页显示的记录数
        $result = $this->db->field('*, count(id) AS count')
            ->where($map)
            ->group('table_of_ontents')
            ->order('id desc')
            ->limit($pageObj->firstRow.','.$pageObj->listRows)
            ->select();
        $pageStr = $pageObj->show(); // 分页显示输出
        $this->assign('result', $result); // 赋值数据集
        $this->assign('pageStr', $pageStr); // 赋值分页输出
        $this->assign('pageObj', $pageObj); // 赋值分页对象

        return $this->fetch('lists');
    }

    // 查看文件-已清理
    public function clean_up_list()
    {
        $table_of_ontents = (int)input('param.table_of_ontents');
        if(!empty($table_of_ontents)) {
            $ResultData = [];

            // 查询条件
            $where = [
                // 已清理数据
                'status' => 1,
                // 查看目录
                'table_of_ontents' => $table_of_ontents,
            ];

            // 查询分页
            $Count = $this->db->where($where)->order('id asc')->count('id');
            $pageObj = new Page($Count, 56); // config('paginate.list_rows')

            // 查询图片数据
            $ResultData = $this->db->where($where)->order('id asc')->limit($pageObj->firstRow.','.$pageObj->listRows)->select();
            $PicArray = ['.gif', '.jpeg', '.png', '.bmp', '.jpg', '.ico', '.webp'];
            foreach ($ResultData as $key => $value) {
                $PicType = '.' . array_pop(explode('.', $value['url']));
                if (in_array($PicType, $PicArray)) {
                    $ResultData[$key]['url'] = ROOT_DIR . '/data/tempimg/' . $table_of_ontents . $value['url'];
                } else {
                    $ResultData[$key]['url'] = ROOT_DIR . '/public/static/common/images/Archive.png';
                }
            }
            
            $this->assign('path', 'data/tempimg/' . $table_of_ontents);
            $this->assign('result', $ResultData);
            $this->assign('Page', $pageObj->show());
        }
        return $this->fetch('clean_up_list');
    }

    // 还原文件
    public function recovery()
    {
        $table_of_ontents = input('param.table_of_ontents');
        if (!empty($table_of_ontents)) {
            $result = $this->db->where("table_of_ontents", $table_of_ontents)->select();
            $url = get_arr_column($result[0], 'url');

            $DeleteID = $this->db->where("table_of_ontents", $table_of_ontents)->delete();
            if(!empty($DeleteID)) {
                recurse_copy(DATA_PATH . 'tempimg/' . $table_of_ontents . ROOT_DIR, ROOT_PATH);
                delFile(DATA_PATH . 'tempimg/' . $table_of_ontents . ROOT_DIR, true);
                adminLog('还原' . $this->weappInfo['name'] . ':' . implode(',', $url));
                $this->success('还原成功!');
            } else {
                $this->error('还原失败!');
            }
        } else {
            $this->error('参数错误!');
        }
    }
    
    // 单个删除文件
    public function del()
    {
        $table_of_ontents = input('param.table_of_ontents');
        if (!empty($table_of_ontents)) {
            $result = $this->db->where("table_of_ontents" ,$table_of_ontents)->select();
            $url = get_arr_column($result['0'], 'url');

            $DeleteID = $this->db->where("table_of_ontents", $table_of_ontents)->delete();
            if (!empty($DeleteID)) {
                delFile(DATA_PATH . 'tempimg' . DS . $table_of_ontents, true);
                adminLog('删除' . $this->weappInfo['name'] . ':' . implode(',', $url));
                $this->success('删除成功!');
            } else {
                $this->error('删除失败!');
            }
        } else {
            $this->error('参数错误!');
        }
    }

    // 批量删除文件
    public function batch_del()
    {
        $table_arr = input('param.table_of_ontents/a');
        $table_arr = eyIntval($table_arr);
        if(!empty($table_arr)){
            $result = $this->db->where("table_of_ontents", 'IN', $table_arr)->select();
            $url = get_arr_column($result['0'], 'url');

            $DeleteID = $this->db->where("table_of_ontents",'IN',$table_arr)->delete();
            if(!empty($DeleteID)){
                foreach ($table_arr as $value) {
                    delFile(DATA_PATH . 'tempimg' . DS . $value, true);
                }
                adminLog('删除' . $this->weappInfo['name'] . ':' . implode(',', $url));
                $this->success("操作成功!");
            } else {
                $this->error("操作失败!");
            }
        } else {
            $this->error("参数有误!");
        }
    }
}