后台站点文件扫描

    • 前言
    • 遍历文件
      • scandir

        • 给定目录
        • 非法使用
      • dir函数
      • 递归法
    • 路径解析
      • 数据结构设计
      • 原理解析
      • 代码实现
    • 演示
      • 当前目录
      • 父级目录
    • 总结

前言

这几天在看easyui,看到树形结构这个组件的时候突发奇想,能不能把站点以目录树的形式展示呢?

然后着手实现了一下,具体的来说是实现了对数据层的获取,还没有附加到tree组件上。下面就来谈谈我对这次文件信息抓取的体会吧。

遍历文件

在PHP中遍历文件有很多方式,但是适用的场景不尽相同。所以在合适的场合适用合适的方法显得至关重要,下面简要的了解一下。

scandir

如果说想找到一款类似于Python中使用os.walk获取文件目录信息的优雅的方法,在PHP中就不是那么的方便了,唯一能称得上简单的就是scandir函数,但是这个函数并不优雅,其作用就是扫描给定目录下的文件信息(如果包含子目录,那就只能显示到子目录的层级,再想查看子目录下的信息,那就不行了,否则会报错的)。

空口无凭,找个实例来看一下就一目了然了。

给定目录

<?php
/**
 * Created by PhpStorm.
 * User: ${郭璞}
 * Date: 2017/2/3
 * Time: 20:25
 * Description: scandir函数测试
 */

$pathinfo = scandir(‘.‘);
var_dump($pathinfo);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

效果如下

非法使用

所谓非法使用,就是指给出非目录文件时的场景,比如我们直接给个文件的路径,就是这样了。

<?php
/**
 * Created by PhpStorm.
 * User: ${郭璞}
 * Date: 2017/2/3
 * Time: 20:25
 * Description: scandir函数测试
 */

$pathinfo = scandir(‘./scandir.php‘);
var_dump($pathinfo);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

所以,使用scandir函数的时候务必明确这一点,传正确的参数!!!

dir函数

既然使用scandir函数不行了,那咱们就换个思路呗。下面介绍一个比较常用的方法。

<?php
/**
 * Created by PhpStorm.
 * User: ${郭璞}
 * Date: 2017/2/3
 * Time: 20:25
 * Description: scandir函数测试
 */

$path = ".";
if(is_dir($path)) {
    $dirinfo = dir($path);
    while($file = $dirinfo->read()) {
        echo "<mark>".$file."</mark><br />";
    }
    $dirinfo->close();
}else if (is_file($path)) {
    echo "<font color=‘green‘>".$path."</font>";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

如果将$path=‘.‘换成$path=‘./scandir.php‘。将出现如下结果。

当然,这两个方法都没能实现我们想要的效果。不能突破子目录的情况,没办法遍历到最底层的文件信息。

递归法

既然如此,那就得另寻他法了。我个人觉得递归的方法不赖,应该可以灵活地处理这些问题,说做就做。

使用面向过程的PHP编码方法需要处理外部数组引用问题,显得代码不是很容易理解,所以我选择面向对象的方法,将外部数组封装到一个类中,专门用于处理这类问题。

<?php
/**
 * Created by PhpStorm.
 * User: ${郭璞}
 * Date: 2017/2/3
 * Time: 9:32
 * Description: 读取给定目录及子目录下文件路径信息
 */

class FileWatcher{
    public $fileinfo;
    /**
     * FileWatcher constructor.
     * @param $path 给定路径
     */
    function __construct(){
        $this->fileinfo = array();
    }

    /**
     * 去除路径设置信息,析构方法
     */
    function __destruct()
    {
        // TODO: Implement __destruct() method.
        $this->fileinfo = null;
    }

    public function scanDir($path) {
        if(is_dir($path)) {
            $tmpdir = dir($path);
            while($tmpfile = $tmpdir->read()) {
                if($tmpfile!=‘.‘ && $tmpfile!=‘..‘)
                    $this->scanDir($path."/".$tmpfile);
            }
            $tmpdir->close();
        }
        if(is_file($path)) {
            array_push($this->fileinfo, $path);
        }
        return $this->fileinfo;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

下面是测试时使用的代码。

$fileWatcher = new FileWatcher();
$result = $fileWatcher->scanDir(‘.‘);

var_dump($result);
  • 1
  • 2
  • 3
  • 4

最终实现的效果为:

路径解析

单单是这样,不是很好用。我就想着能不能实现类似于Python中os.walk那样优雅的获取相关的信息呢?

数据结构设计

使用过那个方法的应该都了解,获取到的元组信息非常的详细,包括路径啊,目录级啊什么的非常的详细。

但是我这边为了以后使用easyui的tree组件,可能需要处理一下目录深度的问题,所以我设计了下面的数据结构。比较简单,但是实用性感觉还是挺强的。

class FileInfo{
    // 目录深度
    public $level;
    // 文件经过的路径,以数组形势依次填充
    public $pathstep;
    // 文件的完整路径
    public $fullpath;

    public function __construct()
    {
        //pathstep 存储当前路径经过的文件夹信息
        $this->pathstep = array();
    }

    public function __destruct()
    {
        // TODO: Implement __destruct() method.
        $this->pathstep = null;
        $this->level = null;
        $this->fullpath = null;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

原理解析

我个人认为原理还是比较简单的了,那就是以文件分隔符作为计算标准。当然了,需要处理一大堆的路径适配问题,尤其是./../这样的相对路径。

处理完这些之后就轻松多了,使用explode函数将字符串进行分割,装填到数组中即可。

代码实现

class PathParser{
    private $patharray;

    private $resultSet;

    public function __construct($patharray)
    {
        // 从外部获取到处理结果集
        $this->patharray = $patharray;
        // 初始化结果集数组
        $this->resultSet = array();
        // bean类对象
        $this->fileinfo = new FileInfo();
    }

    public function __destruct()
    {
        // TODO: Implement __destruct() method.
        $this->resultSet = null;
        $this->level = null;
        $this->fullpath = null;
    }

    public function parse() {
        for ($index=0; $index<count($this->patharray); $index++) {
            // 赋予完整路径
            $fileinfo = new FileInfo();
            $fileinfo->fullpath = $this->patharray[$index];
            //计算level
            $fileinfo->level = $this->parseLavel($fileinfo->fullpath);
//            echo $fileinfo->level."<------->";

            // 计算经过的路径并进行存储
            $fileinfo->pathstep = $this->parseStep($fileinfo->fullpath);
//            echo $fileinfo->pathstep."<br />";

//            var_dump($fileinfo->pathstep);

            array_push($this->resultSet, $fileinfo);

        }
        //返回计算结果,整体作为结果集返回
        return $this->resultSet;
    }

    /**
     * 获取给定路径所经过的路径的结果集,将用于分级目录展示
     * @param $fileinfo
     * @return int
     */
    public function parseStep($fileinfo) {
        if(!$fileinfo) {
            echo "<mark>".$fileinfo." path error!</mark>";
            exit();
        }
        // 判断是否为相对路径是的话去掉第一级目录。 啊好烦,windows上和linux上差别还这么大,怎么处理好呢。。。
        // 还是按照文件在服务器上的位置来进行来处理好了。判断是不是相对路径然后再针对“路径分隔符”计算路径的level
        if($this->isRelativePath($fileinfo) == 1) {
            // 相对路径处理
            // 去掉相对路径符号
            $fileinfo = substr($fileinfo,2, strlen($fileinfo));

            // 按照目录分隔符 作为切割标准,结果就是路径本身包含的路径信息
            return explode("/", $fileinfo);
        }else if($this->isRelativePath($fileinfo) == 2){
            $fileinfo = substr($fileinfo, 3, strlen($fileinfo));
            return explode("/", $fileinfo);
        }else if ($this->isAbsolutePath($fileinfo)) {
            // 绝对路径处理
        }else{
            // 文件路径非法
            echo "<mark>".$fileinfo." 文件路径非法</mark>";
            exit();
        }
    }

    public function parseLavel($fileinfo) {
        if(!$fileinfo) {
            echo "<mark>".$fileinfo." path error!</mark>";
            exit();
        }
        //按照文件在服务器上的位置来进行来处理好了。判断是不是相对路径然后再针对“路径分隔符”计算路径的level
        if($this->isRelativePath($fileinfo) == 1) {
            // 相对路径处理
            // 去掉当前相对路径符号
            $fileinfo = substr($fileinfo,2, strlen($fileinfo));
            // 通过计算 路径分隔符来作为level的判断标准
//            echo "<mark>".count(explode("/", $fileinfo))."</mark>";
            return count(explode("/", $fileinfo));
        }else if ($this->isRelativePath($fileinfo) == 2 ) {
            //去掉父级目录信息
            $fileinfo = substr($fileinfo, 3, strlen($fileinfo));
            return count(explode("/", $fileinfo));
        }else if ($this->isAbsolutePath($fileinfo)) {
            // 绝对路径处理
            // 算了,先不做这块了,貌似偏离了我这个需求。
        }else{
            // 文件路径非法
            echo "<mark>".$fileinfo." 文件路径非法</mark>";
            exit();
        }

    }

    /**
     * 判断是否为相对路径
     * @param $path
     * @return bool
     *
     */
    private function isRelativePath($path) {
        // 父级目录拥有更高的优先级
        $prefix = substr($path, 0, 3);
        if($prefix == "../") {
            return 2;
        }

        // 处理 当前目录情况
        $prefix = substr($path, 0, 2);
        if ($prefix == "./"){
            return 1;
        }else{
            return false;
        }
    }

    /**
     * 判断给定路径是否为绝对路径
     * @param $path
     * @return bool
     */
    private function isAbsolutePath($path) {
        $prefix = substr($path, 0, 1);
        if($prefix=="/"){
            return true;
        }else{
            return false;
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145

演示

下面演示一下实现的效果吧。

当前目录

测试代码如下


//获取全部文件以及路径信息
$fileWatcher = new FileWatcher();
$result = $fileWatcher->scanDir(‘.‘);

$pathParser = new PathParser($result);
$resultSet = $pathParser->parse();
echo json_encode($resultSet);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

结果图

父级目录

对于父级目录信息获取,也是非常方便的。之前网上下载了easyui的压缩包,解压后扔到了apache服务器上,下面来看看对这个大文件信息集的获取情况吧。

测试代码把路径中的那个.改成../easyui即可。

结果还行吧。我看着挺详细的了。那么到这里就差不多实现预期的效果了。

总结

回顾一下,今天主要是对于文件目录信息的遍历。

显示通过通用的scandir 函数和dir循环读取方式对目录进行了读取,但是效果不佳,于是转战递归实现。

为了达到一个更加优雅的信息获取效果,又设计了一个专门针对于文件的类,用于存储相关数据。

为了处理相对路径中本级目录和父级目录等特殊情况,又使用了substr和explode函数,最后封装成了一个通用的类,效果还不错。

缺点嘛,显而易见。代码的风格不是很好,命名什么的也是按照我自己的套路来的,不是很正规。

其他的貌似也没什么了,那就先这样好了。

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

原文地址:https://www.cnblogs.com/djuwcnhwbx/p/10325861.html

时间: 2024-11-08 12:21:38

后台站点文件扫描的相关文章

wget下载站点文件

非常简单的指令,只需要: wget -c -r -p -k -np [URL] 下面解释下个参数的意义: -c 断点续传 -r 递归下载,可遍历整个站点的结构 -p 网页显示所需要的素材(图片\css\js之类) -k 将下载的网页里的连接转换为本地连接(这个功能很赞) -np 仅下载当前站点的文件(否则你可能会把整个互联网装在你的硬盘里) 下面贴出wget的帮助文件: [[email protected] ~]#wget --help GNU Wget 1.12,非交互式的网络文件下载工具.

Gxlcms时间盲注+后台任意文件删除读取下载+getshell

前台SQL时间盲注 在前台作品评分处 Lib\Home\Action/CommAction.class.php 第56行 $ting_id = $_GET["id"]; 第133行 $ting_gold = $mod->where("ting_id='$ting_id'")->getField("ting_gold"); 导致了可以时间盲注 因为回显不明确 后台GetShell 后台附件设置处 fuzz过程 输入php  被过滤成空

Python实现随机延迟WEB目录文件扫描

搬了一年的砖,手糙得不会写代码了.闲来无聊写了个WEB目录文件扫描的小py,实现延迟随机时间,单线程,有WAF时挂个字典随机延迟扫着就行. 后期准备持续完善功能,集成一些常用的测试项,代码多了改成OO. 功能单一,主要练手,欢迎指正,代码如下: 1 # -*- coding: iso-8859-1 -*- 2 __author__ = 'BT' 3 4 import urllib2 5 import sys 6 import getopt 7 import time 8 import rando

android媒体文件扫描

项目中可能有这样的需求:下载或导入.导出的图片.音乐等媒体文件,需要马上能在图库或本地视屏播放器中显示出来,或者要能在媒体数据库中查询到媒体文件的相关信息,这时我们就得主动通知系统扫描新的媒体文件了.我整理了一个扫描的工具类,分享下. 具体代码: public class MediaScanner { private volatile static MediaScanner instance; private MediaScanner(){ } public static MediaScanne

DW如何打开已经关闭的站点文件提示框

DW在已经新建成功站点后,若将站点文件提示框关闭后,如何重新打开呢?即如下图所示的提示框: 点击站点下拉菜单中的'在站点定位'即可打开关闭的提示框.

ecshop后台admin文件夹任意更改名

为了ecshop网站安全起见或不想泄露后台的路径,那么我们必须修改后台admin文件夹名称. 方法和步骤如下: 把原admin文件夹名改成edait为例来说明 首先,把商城根目录下的admin文件夹重命名为gkadmin 其次,找到商城根目录下面的data/config.php文件,查找define('ADMIN_PATH','admin');把里面的admin改成gkadmin 再次,找到商城根目录下面的admin/includes/init.php文件,查找define('ADMIN_PAT

Android中AsyncTask进行后台下载文件并在下拉菜单显示下载进度

在开发过程中,总会需要从网络上下载文件,有时候还需要将下载进度显示在下拉菜单中. 现在写了一个Demo,封装了AsyncTask下载文件和进度显示的代码,以后在做项目的时候能够直接进行使用. 效果图: 主界面只有一个按钮,比较简单: / layout / activity_main.xml : <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="h

dede换空间或换服务器后,后台站点设置无法保存中文的处理办法

因业务的需要,有一个网站需要换服务器,把数据库及程序都备份好,打包传到新的服务器里. 并在服务器上安装php的环境,一切看起来很美好. 安装过程也很顺利. 但最后的结果是后台站点设置无法显示数据.大部分显示空白. 不明白为什么会这样,然后把程序及数据都删除了,重新在服务器上进行安装,然后再从后台进行恢复数据 但问题还是无法解决. 这里有几个现象: 1.数据其实是存在的,查看数据库里的数据是有的.但就是无法显示. 2.在站点设置里输入英文或数字是可以正常保存及显示的.就是填写中文后无法显示出来.

结合Dynamic .NET TWAIN和Jetty,实现基于网页的TWAIN文件扫描

网页TWAIN扫描是通过多种技术结合实现的,看下流程图: 准备工作 阅读: 如何通过jni4net,在Java应用中调用C#接口 使用Jetty搭建Java Websocket Server,实现图像传输 如何运行 在Eclipse中运行Java Application,选择UIMain        当这个窗口启动的时候,Websocket Server已经初始化完成. Load:加载本地图片 Send:把图片推送到网页客户端 Scan:通过扫描仪扫描文件,把图像自动发送到网页客户端 在Chr