美文网首页Android Tips涛锅锅的Android资料Android开发
以SQL注入的方式高效查询Android设备上所有图片所在的文件

以SQL注入的方式高效查询Android设备上所有图片所在的文件

作者: carlos23 | 来源:发表于2017-09-20 22:34 被阅读213次

图片选择器相信很多人一定不会陌生,现在只要带点图片功能的app都会做一个选择图片的功能,这就很有可能会遇到这样一个需求,就是先展示出所有图片所在的文件夹,再点击进入文件夹后展示该文件夹下的所有图片,在这里如何获取到Android设备上所有图片所在的文件夹便是一个棘手的问题。

MediaStore没有提供查询文件夹的方法,只有一个关于文件夹的属性:MediaStore.Files.FileColumns.PARENT,官方文档的解释是:

The index of the parent directory of the file
Type: INTEGER

虽然并不知道这个index值的实际含义,但至少可以用它来区分不同的文件是不是在同一个文件夹下了。

另外,在使用ContentResolver查询MediaStore的数据时,如果参数写错了,异常信息中会暴露出系统编译的SQL语句。

例如执行以下的查询:

context.getContentResolver().query(
        MediaStore.Files.getContentUri("external"),
        new String[]{"abc", "def"},
        MediaStore.Files.FileColumns.MEDIA_TYPE + " = " + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE,
        null,
        MediaStore.Files.FileColumns.DATE_MODIFIED + " DESC"
);

会报出这样的崩溃:

android.database.sqlite.SQLiteException: no such column: abc (code 1): , while compiling: SELECT abc, def FROM files WHERE (media_type = 1) ORDER BY date_modified DESC

观察这个SQL语句的结构:

SELECT abc, def FROM files WHERE ( media_type = 1 ) ORDER BY date_modified DESC

我们可以知道调用query()方法时传入的参数的对应位置,以上加粗的字是系统生成的(包括WHERE那里的一对小括号),非加粗部分是我们自己传入的参数。

我们不难通过SQL注入的方式,拼凑复杂的查询语句得出我们想要的东西。

现在想要查询出所有图片所在的文件夹,我们只要对MediaStore.Files.FileColumns.PARENT使用group by关键字即可,具体的SQL语句如下:

SELECT COUNT(parent), _data
FROM files
WHERE (media_type = 1) 
GROUP BY (parent)

其中parent就是MediaStore.Files.FileColumns.PARENT的取值;media_typeMediaStore.Files.FileColumns.MEDIA_TYPE_dataMediaStore.Files.FileColumns.DATA,表示文件的路径,我们可以通过截取文件的路径获取到文件夹的路径。

转换为Java代码便是如下的查询:

Cursor cursor = context.getContentResolver().query(
        MediaStore.Files.getContentUri("external"),
        new String[]{
                "COUNT(" + MediaStore.Files.FileColumns.PARENT + ")",
                MediaStore.Files.FileColumns.DATA,
        },
        MediaStore.Files.FileColumns.MEDIA_TYPE + " = " + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE
                + " ) GROUP BY (" + MediaStore.Files.FileColumns.PARENT,
        null,
        null
);
if (cursor != null) {
    while (cursor.moveToNext()) {
        int imageFileCountInFolder = cursor.getInt(0);
        String imageFilePath = cursor.getString(1);
        File folderFile = new File(imageFilePath).getParentFile();
        Log.d("test", String.format(Locale.getDefault(), "文件夹路径:%s, 文件夹中的图片个数:%d", folderFile.getAbsolutePath(), imageFileCountInFolder));
    }
    cursor.close();
}

这里顺便把每个文件夹中的图片个数也查询到了。然而,往往我们还要显示文件夹的封面图片,而且还要是文件夹里最新的一张图片。上面的查询得到的图片是任意的,并没有保证是最新的一张图片。

能否在一次查询中解决这个问题?否则如果多次查询数据库导致多次IO操作,或是在Java代码中处理,都耗时、耗内存。答案是可以的,不过语句要复杂一点。

先写好SQL语句:

SELECT COUNT(parent) AS fileCount, _data
FROM (SELECT * FROM files WHERE (media_type = 1) ORDER BY date_modified)
GROUP BY (parent)
ORDER BY fileCount DESC

这里使用子查询是因为最外层的ORDER BY针对的是分组后的数据进行排序。组内排序有多种方式,这里我们就使用子查询。转换为Java代码如下:

Cursor cursor = context.getContentResolver().query(
        MediaStore.Files.getContentUri("external"),
        new String[]{
                "COUNT(" + MediaStore.Files.FileColumns.PARENT + ") AS fileCount",
                MediaStore.Files.FileColumns.DATA + " FROM (SELECT *",
        },
        MediaStore.Files.FileColumns.MEDIA_TYPE + " = " + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE + ")"
                + " ORDER BY " + MediaStore.Files.FileColumns.DATE_MODIFIED + " )"
                + " GROUP BY (" + MediaStore.Files.FileColumns.PARENT,
        null,
        "fileCount DESC"
);
if (cursor != null) {
    while (cursor.moveToNext()) {
        int imageFileCountInFolder = cursor.getInt(0);
        String latestImageFilePath = cursor.getString(1);
        File folderFile = new File(latestImageFilePath).getParentFile();
        
        Log.d("test", "文件夹路径:" + folderFile.getAbsolutePath());
        Log.d("test", "文件夹中的图片个数:" + imageFileCountInFolder);
        Log.d("test", "文件夹中最新的一张图片的路径:" + latestImageFilePath);
    }
    cursor.close();
}

查询某个文件夹下的所有图片的代码:

String folderPath = "/storage/emulated/0/Pictures";
Cursor cursor = getContext().getContentResolver().query(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        null,
        MediaStore.Images.ImageColumns.DATA + " like '%" + folderPath + "%'",
        null,
        MediaStore.Images.ImageColumns.DATE_MODIFIED + " DESC"
);

相关文章

  • 以SQL注入的方式高效查询Android设备上所有图片所在的文件

    图片选择器相信很多人一定不会陌生,现在只要带点图片功能的app都会做一个选择图片的功能,这就很有可能会遇到这样一个...

  • SQL注入漏洞案例实践学习记录(2018.7-2018.8)

    一、SQL注入简述 SQL注入漏洞测试的方式总结 SQL注入常用的内置函数整理(以MySql为例) 二、测试环境&...

  • 2019-11-13

    mysql手工注入 一、SQL注入的理解 将特殊SQL语句添加到查询url后面,以获取非法的数据的操作。 ...

  • Attack(OWASP翻译1)

    攻击活动 SQL(结构化查询语言)注入 概述 一个SQL注入攻击包含了从应用客户端的输入数据中注入或嵌入的方式,一...

  • sql注入风险

    SQL注入攻防入门详解 如何从根本上防止 SQL 注入 教您使用参数化SQL语句 参数化查询为什么能够防止SQL注...

  • DVWA之sql injection

    Sql Injection:sql注入,指通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQ...

  • Android教程-屏幕方向-横竖屏切换

    方式一:配置清单文件 标签中设置:android:screenOrientationActivity 在设备上的显...

  • mysql 慢查询原因总结

    定位慢查询sql语句 可以通过开启慢查询来将所有的慢查询记录到某个文件里面,这里以slow-query.log为例...

  • SQL注入

    1. SQL注入的概念 SQL注入是一种注入攻击,可以执行恶意SQL语句。它通过将任意SQL代码插入数据库查询,使...

  • Web 开发常见安全问题

    前端安全 XSS漏洞 CSRF漏洞 后端安全 SQL 注入漏洞 所有 SQL 语句都使用参数化查询(推荐)或对参数...

网友评论

    本文标题:以SQL注入的方式高效查询Android设备上所有图片所在的文件

    本文链接:https://www.haomeiwen.com/subject/vunnsxtx.html