- 增加解析上传IP地址 (使用方法参考提示信息)

* 2023-02-01 v2.7.0 dev
- 增加上传历史记录
- 增加粘贴上传状态
- 增加广场非图片图标
- 增加前端显示缩略图链接
- 增加每日获取Bing图片背景
- 增加图片详细信息管理登录后显示更多信息
- 增加解析上传IP地址 (使用方法参考提示信息)
- 修复图片详细信息中随机图片排版混乱
- 替换访问生成缩略图代码
- 更新一些组件
- 调整前端显示
- 优化代码
pull/141/head
icret 2023-02-01 02:26:09 +08:00
parent a24bc892ff
commit ae21b70a13
12 changed files with 759 additions and 263 deletions

View File

@ -73,12 +73,12 @@ chown -R www:www /安装目录
3. 请关闭防跨站或删除域名文件夹内的`user.ini`文件 如`宝塔面板`|`军哥lnmp`
4. 网站域名与图片域名必须填写,如果只有一个域名请填写成一样的
5. 首次使用会执行安装程序并生成`install.lock` 跳过安装流程请删除`install`目录
6. 首次访问首页会检查环境并在`config`目录下生成`EasyImage.lock`
6. 首次访问首页会检查环境并在`admin`目录下生成`EasyImage.lock`
7. 可以使用谷歌浏览器的调试模式查看错误`F12->console`
8. `upload File size exceeds the maximum value` 调整`PHP`上传大小
9. `undefined function imagecreatefromwebp()`GD没安装webp, 以此类推
10. `Warning: is_dir(): open_basedir restriction in effect`解决方法同`3`
11. 无法上传/访问/不显示验证码: 1. 权限问题见问题`1` 2. CDN缓存了 3. 开防火墙了
8. 提示 `upload File size exceeds the maximum value` 调整`PHP`上传大小
9. 提示 `undefined function imagecreatefromwebp()`GD没安装webp, 以此类推
10. 提示 `Warning: is_dir(): open_basedir restriction in effect`解决方法同`3`
11. 无法上传/访问/不显示验证码: 1. 权限问题见问题`1` 2. CDN缓存了 3. 防火墙拦截
12. 宝塔或者其他环境安装成功但是上传失败,多数原因是防火墙拦截上传,取消拦截即可
13. `Fatal error: Allowed memory size......`主机内存或分配给PHP的内存不够 解决方法百度
14. 开启原图保护功能后打开图片链接显示`404`是因为`nginx`或`Apache`页面缓存导致的,`Nginx`解决办法:
@ -192,7 +192,6 @@ $HTTP["url"] =~ "^/(i|public)/" {
fastcgi.server = ()
}
```
- 或者参考:[https://blog.png.cm/996.html](https://blog.png.cm/996.html)
## 鉴黄
图床支持moderatecontent和nsfwjs方式鉴黄
@ -231,13 +230,14 @@ $HTTP["url"] =~ "^/(i|public)/" {
<details><summary>点击查看2.0版更新日志</summary>
* 2023-01-31 v2.7.0 dev
* 2023-02-01 v2.7.0 dev
- 增加上传历史记录
- 增加粘贴上传状态
- 增加广场非图片图标
- 增加前端显示缩略图链接
- 增加每日获取Bing图片背景
- 增加图片详细信息管理登录后显示更多信息
- 增加解析上传IP地址 (使用方法参考提示信息)
- 修复图片详细信息中随机图片排版混乱
- 替换访问生成缩略图代码
- 更新一些组件

View File

@ -483,7 +483,7 @@ if (isset($_GET['recycle_reimg'])) {
</div>
<div class="tab-pane fade" id="Content6">
<h5 class="header-dividing">上传日志 <small>需要开启上传日志</small></h5>
<form class="form-inline" action="../application/read_log.php" method="post" target="_blank">
<form class="form-inline" action="../application/viewlog.php" method="post" target="_blank">
<div class="form-group">
<label for="logDate" class="text-primary">选择月份: </label>
<input type="text" class="form-control logDate input-sm" id="logDate" name="logDate" value="<?php echo date('Y-m'); ?>" required="required" readonly>
@ -811,41 +811,51 @@ if (isset($_GET['recycle_reimg'])) {
<h5>图床信息</h5>
<hr />
<h6>API 插件</h6>
<a href="https://microsoftedge.microsoft.com/addons/detail/%E7%AE%80%E5%8D%95%E5%9B%BE%E5%BA%8A-edge-version/hdafcoenpmebcjjcccojdlhfnndelefk" target="_blank"><span class="label label-badge label-success" data-toggle="tooltip" title="浏览器插件">Edge</span></a>
<a href="https://github.com/icret/EasyImage-Browser-Extension" target="_blank"><span class="label label-badge label-success" data-toggle="tooltip" title="浏览器插件">Chrome</span></a>
<a href="https://www.kancloud.cn/easyimage/easyimage/2625228" target="_blank"><span class="label label-badge label-success" data-toggle="tooltip" title="使用ShareX上传">ShareX</span></a>
<a href="https://www.kancloud.cn/easyimage/easyimage/2625229" target="_blank"><span class="label label-badge label-success" data-toggle="tooltip" title="使用PicGo上传">PicGo</span></a>
<a href="https://microsoftedge.microsoft.com/addons/detail/%E7%AE%80%E5%8D%95%E5%9B%BE%E5%BA%8A-edge-version/hdafcoenpmebcjjcccojdlhfnndelefk" target="_blank"><span class="label label-badge label-primary" data-toggle="tooltip" title="浏览器插件">Edge</span></a>
<a href="https://github.com/icret/EasyImage-Browser-Extension" target="_blank"><span class="label label-badge label-primary" data-toggle="tooltip" title="浏览器插件">Chrome</span></a>
<a href="https://www.kancloud.cn/easyimage/easyimage/2625228" target="_blank"><span class="label label-badge label-primary" data-toggle="tooltip" title="使用ShareX上传">ShareX</span></a>
<a href="https://www.kancloud.cn/easyimage/easyimage/2625229" target="_blank"><span class="label label-badge label-primary" data-toggle="tooltip" title="使用PicGo上传">PicGo</span></a>
<h6>图床依赖</h6>
<p>
<a href="https://www.openzui.com/" target="_blank"><span class="label label-badge label-primary" data-toggle="tooltip" title="前端框架">ZUI</span></a>
<a href="https://github.com/verot/class.upload.php" target="_blank"><span class="label label-badge label-primary" data-toggle="tooltip" title="图像处理类">Verot</span></a>
<a href="https://tinyfilemanager.github.io/" target="_blank"><span class="label label-badge label-primary" data-toggle="tooltip" title="文件管理">Tinyfilemanager</span></a>
<a href="#Ip2Region" data-toggle="collapse" target="_blank"><span class="label label-badge label-primary" data-toggle="tooltip" title="IP地址数据库">Ip2Region<i class="icon icon-angle-down"></i></span></a>
<?php if (empty($config['TinyPng_key'])) : ?>
<span class="label label-badge label-warning" data-toggle="tooltip" title="图片压缩TinyPng未填写">TinyPng</span>
<span class="label label-badge label-warning" data-toggle="tooltip" title="压缩图片 TinyPng<br/>未填写">TinyPng</span>
<?php else : ?>
<span class="label label-badge label-success" data-toggle="tooltip" title="图片压缩TinyPng已填写">TinyPng</span>
<span class="label label-badge label-primary" data-toggle="tooltip" title="压缩图片 TinyPng<br/>已填写">TinyPng</span>
<?php endif; ?>
<?php if (empty($config['moderatecontent_key'])) : ?>
<span class="label label-badge label-warning" data-toggle="tooltip" title="图片审查moderatecontent未填写">Moderatecontent</span>
<span class="label label-badge label-warning" data-toggle="tooltip" title="监黄 moderatecontent<br/>未填写">Moderatecontent</span>
<?php else : ?>
<span class="label label-badge label-success" data-toggle="tooltip" title="图片审查moderatecontent已填写">Moderatecontent</span>
<span class="label label-badge label-primary" data-toggle="tooltip" title="监黄 moderatecontent<br/>已填写">Moderatecontent</span>
<?php endif; ?>
<a href="https://www.openzui.com/" target="_blank"><span class="label label-badge label-success" data-toggle="tooltip" title="前端框架">ZUI</span></a>
<a href="https://github.com/verot/class.upload.php" target="_blank"><span class="label label-badge label-success" data-toggle="tooltip" title="图像处理类">Verot</span></a>
<a href="https://tinyfilemanager.github.io/" target="_blank"><span class="label label-badge label-success" data-toggle="tooltip" title="文件管理">Tinyfilemanager</span></a>
<span class="label label-badge label-success" data-toggle="tooltip" title="当前版本"><?php echo get_current_version(); ?></span>
<?php if (getVersion() !== get_current_version()) : ?>
<a href="#NewVersion" data-toggle="collapse" class="label label-badge label-warning" title="Github有更新"><?php echo getVersion(); ?></span><i class="icon icon-angle-down"></i></a>
<?php endif; ?>
<a href="https://github.com/icret/EasyImages2.0/blob/master/LICENSE" target="_blank"><span class="label label-badge" data-toggle="tooltip" title="许可证">GPL-2.0</span></a>
<span class="label label-badge label-primary" data-toggle="tooltip" title="当前版本"><?php echo get_current_version(); ?></span>
<a href="https://github.com/icret/EasyImages2.0/blob/master/LICENSE" target="_blank"><span class="label label-badge" data-toggle="tooltip" title="开源许可证">GPL-2.0</span></a>
</p>
<p class="text-muted"><i class="icon icon-certificate"> EasyImage2.0简单图床构建于众多优秀的开源项目之上,非常感谢这些项目!</i></p>
</div>
<div class="collapse" id="NewVersion">
<div class="collapse" id="Ip2Region">
<div class="bg-primary with-padding">
<p>最新版本: <?php echo getVersion('name'); ?> <a href="<?php echo getVersion('zipball_url'); ?>" target="_blank" class="label label-badge">点击下载</a></p>
<p>更新日期: <?php echo getVersion('created_at'); ?></p>
<p>更新内容: <br /><?php echo getVersion('body'); ?></p>
<p>更新后删除<small style="color: black;">/admin/logs/verson/</small>文件夹会自动同步最新版本号</p>
<h4>Ip2region - IP地址数据库 <a href="https://raw.githubusercontent.com/lionsoul2014/ip2region/master/data/ip2region.xdb" target="_blank" class="label label-badge">下载 / 更新</a></h4>
<hr />
<p>
Ip2region (2.0 - xdb) 是一个离线 IP 数据管理框架和定位库,支持亿级别的数据段,10微秒级别的查询性能,提供了许多主流编程语言的 xdb 数据管理引擎的实现。
每个 ip 数据段的 region 信息都固定了格式:国家|区域|省份|城市|ISP, 只有中国的数据绝大部分精确到了城市, 其他国家部分数据只能定位到国家, 后前的选项全部是0。
</p>
<h6>* 下载 ip2region.xdb IP数据库上传到 <small style="color: black;">/application/ip2region/</small> 文件夹, 如遇到下载失败可访问开源地址下载: [ <a href="https://github.com/lionsoul2014/ip2region" target="_blank"><small style="color: black;">Github</small></a> | <a href="https://gitee.com/lionsoul/ip2region" target="_blank"><small style="color: black;">Gitee</small></a> ] 更新方法与此相同。</h6>
</div>
</div>
<?php if (getVersion() !== get_current_version()) : ?>
<div class="bg-warning with-padding">
<h4>最新版本: <?php echo getVersion('name'); ?> <a href="<?php echo getVersion('zipball_url'); ?>" target="_blank" class="label label-badge">下载新版本</a></h4>
<hr />
<p>更新日期: <?php echo getVersion('created_at'); ?></p>
<p>更新内容: <br /><?php echo getVersion('body'); ?></p>
<h6>更新后删除 <small style="color: black;">/admin/logs/verson/</small> 文件夹会自动同步最新版本号</h6>
</div>
<?php endif; ?>
</div>
<div class="tab-pane fade" id="Content9">
<form action="<?php echo $_SERVER['SCRIPT_NAME']; ?>" method="post">

View File

@ -10,10 +10,14 @@
include_once '../config/config.php';
$path = __DIR__ . '/..' . $config['path'] . $config['delDir']; // 设置图片缓存文件夹
$filename = date("Ymd") . '.jpg'; // 用年月日来命名新的文件名
if (!file_exists($path . $filename)) // 如果文件不存在,则说明今天还没有进行缓存
$path = '..' . $config['path'] . $config['delDir']; // 设置图片缓存文件夹
$filename = date("Ymd") . '.jpg'; // 用年月日来命名新的文件名
if (file_exists($path . $filename)) // 如果文件不存在,则说明今天还没有进行缓存
{
header("Content-type: image/jpeg");
exit(file_get_contents($path . $filename, true));
} else {
if (!file_exists($path)) //如果目录不存在
{
mkdir($path, 0777); //创建缓存目录
@ -22,31 +26,6 @@ if (!file_exists($path . $filename)) // 如果文件不存在,则说明
$str = json_decode($str, true);
$imgurl = 'http://cn.bing.com' . $str['images'][0]['url']; //获取图片url
$img = grabImage($imgurl, $path . $filename); //读取并保存图片
/*
$handle = fopen("dat.txt", "a"); //用于存放图片信息,如果不需要保存图片的相关信息,可以把下面这些去掉。
if ($handle) {
$copyright = $str['images'][0]['copyright']; //说明
$startdate = $str['images'][0]['startdate'];
$fullstartdate = $str['images'][0]['fullstartdate'];
$enddate = $str['images'][0]['enddate'];
$urlbase = $str['images'][0]['urlbase'];
$copyrightlink = $str['images'][0]['copyrightlink'];
$quiz = $str['images'][0]['quiz'];
$wp = $str['images'][0]['wp'];
$hsh = $str['images'][0]['hsh'];
$drk = $str['images'][0]['drk'];
$top = $str['images'][0]['top'];
$bot = $str['images'][0]['bot'];
$tempArr = array(
"imgurl" => $imgurl, "copyright" => $copyright, "startdate" => $startdate,
"fullstartdate" => $fullstartdate, "enddate" => $enddate, "urlbase" => $urlbase,
"copyrightlink" => $copyrightlink, "quiz" => $quiz, "wp" => $wp,
"hsh" => $hsh, "drk" => $drk, "top" => $top, "bot" => $bot
); //将相关信息放进数组中
fwrite($handle, json_encode($tempArr) . "\r\n"); //最终以json格式保存在文本文档中
fclose($handle);
}
*/
}
/**
* 远程抓取图片并保存
@ -65,8 +44,7 @@ function grabImage($url, $filename = "")
readfile($url); //输出图片文件
$img = ob_get_contents(); //得到浏览器输出
ob_end_clean(); //清除输出并关闭
$size = strlen($img); //得到图片大小
$fp2 = @fopen($filename, "a");
$fp2 = @fopen($filename, "w+");
fwrite($fp2, $img); //向当前目录写入图片文件,并重新命名
fclose($fp2);
return $filename; //返回新的文件名

View File

@ -6,7 +6,7 @@ if (PHP_VERSION < 7) {
<script>
new $.zui.Messager("当前PHP版本<7.0, 部分功能受限!",{
type: "primary", // 定义颜色主题
time:7000
time:3000
}).show();
</script>
';
@ -19,7 +19,8 @@ foreach ($expand as $val) {
<script>
new $.zui.Messager("扩展:' . $val . '- 未安装,可能导致图片上传失败! 请尽快修复。",{
type: "black", // 定义颜色主题
icon: "exclamation-sign" // 定义消息图标
icon: "exclamation-sign", // 定义消息图标
time:3500
}).show();
</script>
';
@ -32,7 +33,7 @@ if ($config['password'] === 'e6e061838856bf47e1de730719fb2609') {
<script>
new $.zui.Messager("请修改默认密码,否则会有泄露风险! ",{
type: "warning", // 定义颜色主题
time:6000
time:4000
}).show();
</script>
';
@ -43,7 +44,8 @@ if (is_local($config['domain']) || is_local($config['imgurl'])) {
echo '
<script>
new $.zui.Messager("当前使用局域网,可能会导致外网访问异常!",{
type: "black" // 定义颜色主题
type: "black", // 定义颜色主题
time:4500
}).show();
</script>
';
@ -55,7 +57,19 @@ if (file_exists(APP_ROOT . '/.user.ini')) {
<script>
new $.zui.Messager("请关闭防跨目录读写或删除.user.ini文件",{
type: "danger", // 定义颜色主题
time:7000
time:5000
}).show();
</script>
';
}
// 检测是否存在 IP数据库文件 ip2region.xdb
if (!file_exists(__DIR__ . '/ip2region/ip2region.xdb')) {
echo '
<script>
new $.zui.Messager("IP 数据库不存在, 请在系统信息中查看 Ip2region",{
type: "danger", // 定义颜色主题
time:5500
}).show();
</script>
';
@ -67,7 +81,7 @@ if (getVersion() !== get_current_version()) {
<script>
new $.zui.Messager("当前版本与GitHub不一致,请检查当前是否最新版本!",{
type: "danger", // 定义颜色主题
time:9000
time:6000
}).show();
</script>
';
@ -88,7 +102,7 @@ if (!is_file(APP_ROOT . $config['waterImg'])) {
<script>
new $.zui.Messager("水印图片不存在,请检测路径或者文件是否存在!",{
type: "danger", // 定义颜色主题
time:10000
time:6500
}).show();
</script>
';
@ -100,7 +114,7 @@ if (!is_file(APP_ROOT . $config['textFont'])) {
<script>
new $.zui.Messager("水印字体不存在,请检测路径或者文件是否存在!",{
type: "danger", // 定义颜色主题
time:10000
time:6500
}).show();
</script>
';
@ -115,7 +129,8 @@ if ($config['checkImg'] !== 0) {
echo '
<script>
new $.zui.Messager("moderatecontent 鉴黄接口无法ping通! ",{
type: "warning" // 定义颜色主题
type: "warning", // 定义颜色主题
time:7000
}).show();
</script>
';
@ -132,7 +147,8 @@ if ($config['checkImg'] !== 0) {
echo '
<script>
new $.zui.Messager("' . $ip . $port . ' 鉴黄接口无法ping通! ",{
type: "warning" // 定义颜色主题
type: "warning", // 定义颜色主题
time:7000
}).show();
</script>
';
@ -142,7 +158,8 @@ if ($config['checkImg'] !== 0) {
echo '
<script>
new $.zui.Messager("' . $ip . ' 鉴黄接口无法ping通! ",{
type: "warning" // 定义颜色主题
type: "warning", // 定义颜色主题
time:7000
}).show();
</script>
';

View File

@ -1515,3 +1515,43 @@ function get_current_version($file = '/admin/version.php')
return 'No Version File';
}
/**
* IP地址查询
*/
function ip2region(String $IP)
{
$db = __DIR__ . '/ip2region/ip2region.xdb';
if (!is_file($db)) {
return '<a href="https://raw.githubusercontent.com/lionsoul2014/ip2region/master/data/ip2region.xdb" target="_blank"><span class="label label-primary" data-toggle="tooltip" title="点击下载 IP数据库 并上传到<br/><code>/application/ip2region/</code>">IP数据库不存在</span></a>';
}
try {
require_once __DIR__ . '/ip2region/Ip2Region.php';
$ip2region = new Ip2Region();
$location = $ip2region->memorySearch($IP);
$location = $location['region'];
$location = str_replace(array('0', '||'), '', $location);
return $location;
} catch (Exception $e) {
return '查询失败: ' . $e->getMessage();
}
/* 官方查询示例
require 'Ip2Region.php';
$ip2region = new Ip2Region();
$ip = '107.148.129.110';
echo PHP_EOL;
echo "查询IP:{$ip}" . PHP_EOL;
$info = $ip2region->btreeSearch($ip);
var_export($info);
echo PHP_EOL;
$info = $ip2region->memorySearch($ip);
var_export($info);
echo PHP_EOL;
*/
}

View File

@ -28,7 +28,7 @@ include_once __DIR__ . "/header.php";
$('.listNum').append('<div class="col-md-4 col-sm-6 col-lg-3"><div class="card"><li><img src="../public/images/loading.svg" data-image="' + value['thumb'] + '" data-original="" alt="简单图床-EasyImage"></li><div class="bottom-bar"><a href="' + value['url'] + '" target="_blank"><i class="icon icon-picture" data-toggle="tooltip" title="打开" style="margin-left:10px;"></i></a><a href="#" class="copy" data-clipboard-text="' + value['url'] + '" data-toggle="tooltip" title="复制" style="margin-left:10px;"><i class="icon icon-copy"></i></a><a href="info.php?img=' + v_url.path + '" data-toggle="tooltip" title="信息" target="_blank" style="margin-left:10px;"><i class="icon icon-info-sign"></i></a><a href="down.php?dw=' + v_url.path + '" data-toggle="tooltip" title="下载" target="_blank" style="margin-left:10px;"><i class="icon icon-cloud-download"></i></a><a href="' + value['del'] + '" target="_blank"><i class="icon icon-trash" data-toggle="tooltip" title="删除" style="margin-left:10px;"></i></a><a href="#" data-toggle="tooltip" title="文件名" class="copy text-ellipsis" data-clipboard-text="' + value['srcName'] + '" style="margin-left:10px;">' + value['srcName'] + '</a></div></div></div>')
}
})
$('.history_clear').append('<h3 class="header-dividing" style="text-align: center;" data-toggle="tooltip" title="非上传记录|清空缓存|浏览器版本低不显示<br/>点击清空历史上传记录"><button class="btn btn-mini btn-primary" type="button"><i class="icon icon-eye-close"></i> 历史上传记录</button></h3>');
$('.history_clear').append('<h3 class="header-dividing" style="text-align: center;" data-toggle="tooltip" title="非上传记录|清空缓存|浏览器版本低不显示<br/>点击清空历史上传记录"><button class="btn btn-mini btn-primary" type="button"><i class="icon icon-eye-open"></i> 历史上传记录</button></h3>');
} else {
$('.listNum').append('<h2 class="alert alert-danger">上传历史记录不存在~~ <br /><small>非上传记录 | 清空缓存 | 浏览器版本低不显示~!</small></h2>');
};

View File

@ -33,7 +33,7 @@ $logsName = basename($img_url);
if (is_file(APP_ROOT . '/admin/logs/upload/' . $logs . '.php')) {
include APP_ROOT . '/admin/logs/upload/' . $logs . '.php';
} else {
$logs = array($logsName => array('source' => '日志文件不存在', 'date' => '日志文件不存在', 'ip' => '日志文件不存在', 'port' => '日志文件不存在', 'user_agent' => '日志文件不存在', 'path' => '日志文件不存在', 'size' => '日志文件不存在', 'md5' => '日志文件不存在', 'checkImg' => '日志文件不存在', 'from' => '日志文件不存在'));
$logs = array($logsName => array('source' => '日志文件不存在', 'date' => '日志文件不存在', 'ip' => '0.0.0.0', 'port' => '日志文件不存在', 'user_agent' => '日志文件不存在', 'path' => '日志文件不存在', 'size' => '日志文件不存在', 'md5' => '日志文件不存在', 'checkImg' => '日志文件不存在', 'from' => '日志文件不存在'));
}
// 图片真实路径
@ -57,11 +57,11 @@ if ($config['ad_top']) echo $config['ad_top_info'];
<img data-toggle="lightbox" src="<?php echo $img_url; ?>" data-image="<?php echo $img_url; ?>" id="img1" class="img-rounded" height="432px" data-caption="<?php echo pathinfo($img_url, PATHINFO_FILENAME); ?>的详细信息" alt="<?php echo $img_url; ?>" />
</div>
<div class="col-md-6 table-responsive table-condensed" style="margin-top: 10px;">
<table class="table table-hover table-striped table-bordered">
<table class="table table-hover table-striped table-bordered text-nowrap">
<tbody>
<tr>
<td>图片名称</td>
<td> <?php echo pathinfo($getIMG, PATHINFO_FILENAME); ?></td>
<td> <?php echo basename($getIMG); ?></td>
</tr>
<tr>
<td>图片大小</td>
@ -82,7 +82,7 @@ if ($config['ad_top']) echo $config['ad_top_info'];
<?php if (is_who_login('admin')) : ?>
<tr class="text-primary">
<td>原始名称</td>
<td> <?php echo pathinfo($logs[$logsName]['source'], PATHINFO_BASENAME); ?></td>
<td><?php echo $logs[$logsName]['source']; ?></td>
</tr>
<tr class="text-primary">
<td>原始大小</td>
@ -93,12 +93,16 @@ if ($config['ad_top']) echo $config['ad_top_info'];
<td><?php echo $logs[$logsName]['ip'] . ':' . $logs[$logsName]['port']; ?></td>
</tr>
<tr class="text-primary">
<td>是否监黄</td>
<td><?php if ($logs[$logsName]['checkImg'] == 'OFF') {echo "关闭";} else {echo '开启';} ?></td>
<td>上传地址</td>
<td><?php echo Ip2Region($logs[$logsName]['ip']); ?></td>
</tr>
<tr class="text-primary">
<td>上传来源</td>
<td><?php if ($logs[$logsName]['from'] == 'web') {echo "通过网页";} else {echo '通过API';} ?></td>
<td>监黄状态</td>
<td><?php echo strstr('OFF', $logs[$logsName]['checkImg']) ? '未开启' : '已通过'; ?></td>
</tr>
<tr class="text-primary">
<td>上传方式</td>
<td><?php echo is_numeric($logs[$logsName]['from']) ? '通过API | Token ID: ' . $logs[$logsName]['from'] : "通过网页"; ?></td>
</tr>
<tr class="text-primary">
<td>文件路径</td>

View File

@ -0,0 +1,69 @@
<?php
/**
* class Ip2Region
* 为兼容老版本调度而创建
* @author Anyon<zoujingli@qq.com>
* @datetime 2022/07/18
*/
class Ip2Region
{
/**
* 查询实例对象
* @var XdbSearcher
*/
private $searcher;
/**
* 初始化构造方法
* @throws Exception
*/
public function __construct()
{
class_exists('XdbSearcher') || include(__DIR__ . '/XdbSearcher.php');
$this->searcher = XdbSearcher::newWithFileOnly(__DIR__ . '/ip2region.xdb');
}
/**
* 兼容原 memorySearch 查询
* @param string $ip
* @return array
* @throws Exception
*/
public function memorySearch($ip)
{
return ['city_id' => 0, 'region' => $this->searcher->search($ip)];
}
/**
* 兼容原 binarySearch 查询
* @param string $ip
* @return array
* @throws Exception
*/
public function binarySearch($ip)
{
return $this->memorySearch($ip);
}
/**
* 兼容原 btreeSearch 查询
* @param string $ip
* @return array
* @throws Exception
*/
public function btreeSearch($ip)
{
return $this->memorySearch($ip);
}
/**
* destruct method
* resource destroy
*/
public function __destruct()
{
$this->searcher->close();
unset($this->searcher);
}
}

View File

@ -0,0 +1,368 @@
<?php
// Copyright 2022 The Ip2Region Authors. All rights reserved.
// Use of this source code is governed by a Apache2.0-style
// license that can be found in the LICENSE file.
//
// @Author Lion <chenxin619315@gmail.com>
// @Date 2022/06/21
class XdbSearcher
{
const HeaderInfoLength = 256;
const VectorIndexRows = 256;
const VectorIndexCols = 256;
const VectorIndexSize = 8;
const SegmentIndexSize = 14;
// xdb file handle
private $handle = null;
// header info
private $header = null;
private $ioCount = 0;
// vector index in binary string.
// string decode will be faster than the map based Array.
private $vectorIndex = null;
// xdb content buffer
private $contentBuff = null;
// ---
// static function to create searcher
/**
* @throws Exception
*/
public static function newWithFileOnly($dbFile)
{
return new XdbSearcher($dbFile, null, null);
}
/**
* @throws Exception
*/
public static function newWithVectorIndex($dbFile, $vIndex)
{
return new XdbSearcher($dbFile, $vIndex);
}
/**
* @throws Exception
*/
public static function newWithBuffer($cBuff)
{
return new XdbSearcher(null, null, $cBuff);
}
// --- End of static creator
/**
* initialize the xdb searcher
* @throws Exception
*/
function __construct($dbFile = null, $vectorIndex = null, $cBuff = null)
{
// check the content buffer first
if ($cBuff != null) {
$this->vectorIndex = null;
$this->contentBuff = $cBuff;
} else {
// 加载默认数据文件 by Anyon
if (is_null($dbFile)) {
$dbFile = __DIR__ . DIRECTORY_SEPARATOR . 'ip2region.xdb';
}
// open the xdb binary file
$this->handle = fopen($dbFile, "r");
if ($this->handle === false) {
throw new Exception("failed to open xdb file '%s'", $dbFile);
}
$this->vectorIndex = $vectorIndex;
}
}
function close()
{
if ($this->handle != null) {
fclose($this->handle);
}
}
function getIOCount()
{
return $this->ioCount;
}
/**
* find the region info for the specified ip address
* @throws Exception
*/
function search($ip)
{
// check and convert the sting ip to a 4-bytes long
if (is_string($ip)) {
$t = self::ip2long($ip);
if ($t === null) {
throw new Exception("invalid ip address `$ip`");
}
$ip = $t;
}
// reset the global counter
$this->ioCount = 0;
// locate the segment index block based on the vector index
$il0 = ($ip >> 24) & 0xFF;
$il1 = ($ip >> 16) & 0xFF;
$idx = $il0 * self::VectorIndexCols * self::VectorIndexSize + $il1 * self::VectorIndexSize;
if ($this->vectorIndex != null) {
$sPtr = self::getLong($this->vectorIndex, $idx);
$ePtr = self::getLong($this->vectorIndex, $idx + 4);
} elseif ($this->contentBuff != null) {
$sPtr = self::getLong($this->contentBuff, self::HeaderInfoLength + $idx);
$ePtr = self::getLong($this->contentBuff, self::HeaderInfoLength + $idx + 4);
} else {
// read the vector index block
$buff = $this->read(self::HeaderInfoLength + $idx, 8);
if ($buff === null) {
throw new Exception("failed to read vector index at ${idx}");
}
$sPtr = self::getLong($buff, 0);
$ePtr = self::getLong($buff, 4);
}
// printf("sPtr: %d, ePtr: %d\n", $sPtr, $ePtr);
// binary search the segment index to get the region info
$dataLen = 0;
$dataPtr = null;
$l = 0;
$h = ($ePtr - $sPtr) / self::SegmentIndexSize;
while ($l <= $h) {
$m = ($l + $h) >> 1;
$p = $sPtr + $m * self::SegmentIndexSize;
// read the segment index
$buff = $this->read($p, self::SegmentIndexSize);
if ($buff == null) {
throw new Exception("failed to read segment index at ${p}");
}
$sip = self::getLong($buff, 0);
if ($ip < $sip) {
$h = $m - 1;
} else {
$eip = self::getLong($buff, 4);
if ($ip > $eip) {
$l = $m + 1;
} else {
$dataLen = self::getShort($buff, 8);
$dataPtr = self::getLong($buff, 10);
break;
}
}
}
// match nothing interception.
// @TODO: could this even be a case ?
// printf("dataLen: %d, dataPtr: %d\n", $dataLen, $dataPtr);
if ($dataPtr == null) {
return null;
}
// load and return the region data
$buff = $this->read($dataPtr, $dataLen);
if ($buff == null) {
return null;
}
return $buff;
}
// read specified bytes from the specified index
private function read($offset, $len)
{
// check the in-memory buffer first
if ($this->contentBuff != null) {
return substr($this->contentBuff, $offset, $len);
}
// read from the file
$r = fseek($this->handle, $offset);
if ($r == -1) {
return null;
}
$this->ioCount++;
$buff = fread($this->handle, $len);
if ($buff === false) {
return null;
}
if (strlen($buff) != $len) {
return null;
}
return $buff;
}
// --- static util functions ----
// convert a string ip to long
public static function ip2long($ip)
{
$ip = ip2long($ip);
if ($ip === false) {
return null;
}
// convert signed int to unsigned int if on 32 bit operating system
if ($ip < 0 && PHP_INT_SIZE == 4) {
$ip = sprintf("%u", $ip);
}
return $ip;
}
// read a 4bytes long from a byte buffer
public static function getLong($b, $idx)
{
$val = (ord($b[$idx])) | (ord($b[$idx + 1]) << 8)
| (ord($b[$idx + 2]) << 16) | (ord($b[$idx + 3]) << 24);
// convert signed int to unsigned int if on 32 bit operating system
if ($val < 0 && PHP_INT_SIZE == 4) {
$val = sprintf("%u", $val);
}
return $val;
}
// read a 2bytes short from a byte buffer
public static function getShort($b, $idx)
{
return ((ord($b[$idx])) | (ord($b[$idx + 1]) << 8));
}
// load header info from a specified file handle
public static function loadHeader($handle)
{
if (fseek($handle, 0) == -1) {
return null;
}
$buff = fread($handle, self::HeaderInfoLength);
if ($buff === false) {
return null;
}
// read bytes length checking
if (strlen($buff) != self::HeaderInfoLength) {
return null;
}
// return the decoded header info
return [
'version' => self::getShort($buff, 0),
'indexPolicy' => self::getShort($buff, 2),
'createdAt' => self::getLong($buff, 4),
'startIndexPtr' => self::getLong($buff, 8),
'endIndexPtr' => self::getLong($buff, 12)
];
}
// load header info from the specified xdb file path
public static function loadHeaderFromFile($dbFile)
{
$handle = fopen($dbFile, 'r');
if ($handle === false) {
return null;
}
$header = self::loadHeader($handle);
fclose($handle);
return $header;
}
// load vector index from a file handle
public static function loadVectorIndex($handle)
{
if (fseek($handle, self::HeaderInfoLength) == -1) {
return null;
}
$rLen = self::VectorIndexRows * self::VectorIndexCols * self::SegmentIndexSize;
$buff = fread($handle, $rLen);
if ($buff === false) {
return null;
}
if (strlen($buff) != $rLen) {
return null;
}
return $buff;
}
// load vector index from a specified xdb file path
public static function loadVectorIndexFromFile($dbFile)
{
$handle = fopen($dbFile, 'r');
if ($handle === false) {
return null;
}
$vIndex = self::loadVectorIndex($handle);
fclose($handle);
return $vIndex;
}
// load the xdb content from a file handle
public static function loadContent($handle)
{
if (fseek($handle, 0, SEEK_END) == -1) {
return null;
}
$size = ftell($handle);
if ($size === false) {
return null;
}
// seek to the head for reading
if (fseek($handle, 0) == -1) {
return null;
}
$buff = fread($handle, $size);
if ($buff === false) {
return null;
}
// read length checking
if (strlen($buff) != $size) {
return null;
}
return $buff;
}
// load the xdb content from a file path
public static function loadContentFromFile($dbFile)
{
$str = file_get_contents($dbFile, false);
if ($str === false) {
return null;
} else {
return $str;
}
}
public static function now()
{
return (microtime(true) * 1000);
}
}

348
application/read_log.php → application/viewlog.php Executable file → Normal file
View File

@ -1,164 +1,184 @@
<?php
/**
* 读取上传日志
*/
require_once __DIR__ . '/function.php';
// 非管理员不可访问!
if (!is_who_login('admin')) {
exit;
}
// 禁止直接访问
if (empty($_POST['pass']) || $_POST['pass'] !== md5($config['password'] . date('YMDH'))) exit('No permission!');
require_once APP_ROOT . '/application/header.php';
if (isset($_POST['logDate'])) {
$logFile = APP_ROOT . '/admin/logs/upload/' . $_POST['logDate'] . '.php';
} else {
$logFile = APP_ROOT . '/admin/logs/upload/' . date('Y-m') . '.php';
}
try {
if (is_file($logFile)) {
require_once $logFile;
} else {
throw new Exception('<div class="alert alert-info">日志文件不存在!<div>');
}
if (empty($logs)) {
throw new Exception('<div class="alert alert-info">没有上传日志!<div>');
}
} catch (Exception $e) {
echo $e->getMessage();
require_once APP_ROOT . '/application/footer.php';
exit;
}
?>
<div class="col-md-12">
<div id="logs" class="datagrid table-bordered">
<div class="input-control search-box search-box-circle has-icon-left has-icon-right" id="searchboxExample2" style="margin-bottom: 10px;">
<input id="inputSearchExample2" type="search" class="form-control search-input input-sm" placeholder="日志搜索...">
<label for="inputSearchExample2" class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label>
<a href="#" class="input-control-icon-right search-clear-btn"><i class="icon icon-remove"></i></a>
</div>
<div class="datagrid-container"></div>
</div>
<p class="text-muted" style="font-size:10px;"><i class="modal-icon icon-info"></i> 建议使用分辨率 1366*768px; 当前日志文件: <?php echo $logFile; ?></p>
</div>
<link href="<?php static_cdn(); ?>/public/static/zui/lib/datagrid/zui.datagrid.min.css" rel="stylesheet">
<script src="<?php static_cdn(); ?>/public/static/zui/lib/datagrid/zui.datagrid.min.js"></script>
<script>
// 更改页面布局
$(document).ready(function() {
$("body").removeClass("container").addClass("container-fixed-lg");
});
// logs 数据表格
$('#logs').datagrid({
dataSource: {
height: 800,
cols: [{
label: '当前名称',
name: 'orgin',
},
{
label: '源文件名',
name: 'source',
html: true,
},
{
label: '上传时间',
name: 'date',
html: true,
},
{
label: '上传IP及端口',
name: 'ip',
html: true,
},
{
label: 'User-Agent',
name: 'user_agent',
html: true,
},
{
label: '路径',
name: 'path',
html: true,
},
{
label: '大小',
name: 'size',
html: true,
},
{
label: 'FILE-MD5',
name: 'md5',
html: true,
},
{
label: '鉴黄状态',
name: 'checkImg',
html: true,
},
{
label: '来源',
name: 'from',
html: true,
},
{
label: '管理',
name: 'manage',
html: true,
},
],
array: [
<?php foreach ($logs as $k => $v) : ?> {
orgin: '<?php echo $k; ?>',
source: '<input class="form-control input-sm" type="text" value="<?php echo $v['source']; ?>" readonly>',
date: '<?php echo $v['date']; ?>',
ip: '<a href="http://ip.tool.chinaz.com/<?php echo $v['ip']; ?>" target="_blank"><?php echo $v['ip'] . ':' . $v['port']; ?></a>',
// 备用 ip: '<a href="https://www.ip138.com/iplookup.asp?ip=< ?php echo $v['ip']; ?>&action=2" target="_blank">< ?php echo $v['ip'] . ':' . $v['port']; ?></a>',
user_agent: '<input class="form-control input-sm" type="text" value="<?php echo $v['user_agent']; ?>" readonly>',
path: '<input class="form-control input-sm" type="text" value="<?php echo $v['path']; ?>" readonly>',
size: '<?php echo $v['size']; ?>',
md5: '<input class="form-control input-sm" type="text" value="<?php echo $v['md5']; ?>" readonly>',
checkImg: '<?php echo $v['checkImg']; ?>',
from: '<?php echo $v['from']; ?>',
manage: "<div class='btn-group'><a href='<?php echo $config['domain'] . $v['path']; ?>' target='_blank' class='btn btn-mini btn-success'>查看</a> <a href='/application/info.php?img=<?php echo $v['path']; ?>' target='_blank' class='btn btn-mini'>信息</a> <a href='/application/del.php?recycle_url=<?php echo $v['path']; ?>' target='_blank' class='btn btn-mini btn-info'>回收</a> <a href='/application/del.php?url=<?php echo $v['path']; ?>' target='_blank' class='btn btn-mini btn-danger'>删除</a></div>",
},
<?php endforeach; ?>
]
},
sortable: true,
hoverCell: true,
showRowIndex: true,
responsive: true,
height: 666,
// ... 其他初始化选项
configs: {
R1: {
style: {
color: '#00b8d4',
backgroundColor: '#e0f7fa'
}
},
}
});
// 获取数据表格实例
var logMyDataGrid = $('#logs').data('zui.datagrid');
// var myDate = new Date();
// logMyDataGrid.showMessage(myDate.getFullYear() + '年' + (myDate.getMonth() + 1) + '月上传日志已加载完毕...... ', 'primary', 2500);
logMyDataGrid.showMessage('上传日志已加载完毕...... ', 'primary', 2500);
// 按照 `name` 列降序排序
logMyDataGrid.sortBy('date', 'desc');
</script>
<?php
require_once APP_ROOT . '/application/footer.php';
<?php
/**
* 读取上传日志
*/
require_once __DIR__ . '/function.php';
// 非管理员不可访问!
if (!is_who_login('admin')) {
exit;
}
// 禁止直接访问
if (empty($_POST['pass']) || $_POST['pass'] !== md5($config['password'] . date('YMDH'))) exit('Permission denied!');
require_once APP_ROOT . '/application/header.php';
if (isset($_POST['logDate'])) {
$logFile = APP_ROOT . '/admin/logs/upload/' . $_POST['logDate'] . '.php';
} else {
$logFile = APP_ROOT . '/admin/logs/upload/' . date('Y-m') . '.php';
}
try {
if (is_file($logFile)) {
require_once $logFile;
} else {
throw new Exception('<div class="alert alert-info">日志文件不存在!<div>');
}
if (empty($logs)) {
throw new Exception('<div class="alert alert-info">没有上传日志!<div>');
}
} catch (Exception $e) {
echo $e->getMessage();
require_once APP_ROOT . '/application/footer.php';
exit;
}
?>
<div class="col-md-12">
<div id="logs" class="datagrid table-bordered">
<div class="input-control search-box search-box-circle has-icon-left has-icon-right" id="searchboxExample2" style="margin-bottom: 10px;">
<input id="inputSearchExample2" type="search" class="form-control search-input input-sm" placeholder="日志搜索...">
<label for="inputSearchExample2" class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label>
<a href="#" class="input-control-icon-right search-clear-btn"><i class="icon icon-remove"></i></a>
</div>
<div class="datagrid-container"></div>
</div>
<p class="text-muted" style="font-size:10px;"><i class="modal-icon icon-info"></i> 建议使用分辨率 1366*768px; 当前日志文件: <?php echo $logFile; ?></p>
</div>
<link href="<?php static_cdn(); ?>/public/static/zui/lib/datagrid/zui.datagrid.min.css" rel="stylesheet">
<script src="<?php static_cdn(); ?>/public/static/zui/lib/datagrid/zui.datagrid.min.js"></script>
<script>
// 更改页面布局
$(document).ready(function() {
$("body").removeClass("container").addClass("container-fixed-lg");
});
// logs 数据表格
$('#logs').datagrid({
dataSource: {
height: 800,
cols: [{
label: '当前名称',
name: 'orgin',
width: 0.07
},
{
label: '源文件名',
name: 'source',
html: true,
width: 0.08
},
{
label: '上传时间',
name: 'date',
html: true,
width: 0.09
},
{
label: '上传IP及端口',
name: 'ip',
html: true,
width: 0.08
},
{
label: '上传地址',
name: 'ip2region',
html: true,
width: 0.1
},
{
label: 'User-Agent',
name: 'user_agent',
html: true,
width: 0.11
},
{
label: 'FILE-MD5',
name: 'md5',
html: true,
width: 0.1
},
{
label: '文件路径',
name: 'path',
html: true,
width: 0.11
},
{
label: '文件大小',
name: 'size',
html: true,
width: 0.06
},
{
label: '鉴黄?',
name: 'checkImg',
html: true,
width: 0.05
},
{
label: '来源',
name: 'from',
html: true,
width: 0.05
},
{
label: '管理',
name: 'manage',
html: true,
width: 0.1
},
],
array: [
<?php foreach ($logs as $k => $v) : ?> {
orgin: '<?php echo $k; ?>',
source: '<input class="form-control input-sm" type="text" value="<?php echo $v['source']; ?>" readonly>',
date: '<?php echo $v['date']; ?>',
ip: '<a href="http://ip.tool.chinaz.com/<?php echo $v['ip']; ?>" target="_blank"><?php echo $v['ip'] . ':' . $v['port']; ?></a>', // 备用IP查询: https://www.ip138.com/iplookup.asp?ip=
ip2region: '<?php echo ip2region($v['ip']); ?>',
user_agent: '<input class="form-control input-sm" type="text" value="<?php echo $v['user_agent']; ?>" readonly>',
path: '<input class="form-control input-sm" type="text" value="<?php echo $v['path']; ?>" readonly>',
md5: '<input class="form-control input-sm" type="text" value="<?php echo $v['md5']; ?>" readonly>',
size: '<?php echo $v['size']; ?>',
checkImg: '<?php echo strstr('OFF', $v['checkImg']) ? '' : ''; ?>',
from: '<?php echo is_string($v['from']) ? "网页" : 'API: ' . $v['from']; ?>',
manage: "<div class='btn-group'><a href='<?php echo $config['domain'] . $v['path']; ?>' target='_blank' class='btn btn-mini btn-success'>查看</a> <a href='/application/info.php?img=<?php echo $v['path']; ?>' target='_blank' class='btn btn-mini'>信息</a> <a href='/application/del.php?recycle_url=<?php echo $v['path']; ?>' target='_blank' class='btn btn-mini btn-info'>回收</a> <a href='/application/del.php?url=<?php echo $v['path']; ?>' target='_blank' class='btn btn-mini btn-danger'>删除</a></div>",
},
<?php endforeach; ?>
]
},
sortable: true,
hoverCell: true,
showRowIndex: true,
responsive: true,
height: 666,
// ... 其他初始化选项
configs: {
R1: {
style: {
color: '#00b8d4',
backgroundColor: '#e0f7fa'
}
},
}
});
// 获取数据表格实例
var logMyDataGrid = $('#logs').data('zui.datagrid');
var myDate = new Date();
logMyDataGrid.showMessage('已获取 <?php echo pathinfo($logFile, PATHINFO_FILENAME); ?> 月上传日志...... ', 'primary', 2000);
// logMyDataGrid.showMessage('上传日志已加载完毕...... ', 'primary', 2500);
// 按照 `name` 列降序排序
logMyDataGrid.sortBy('date', 'desc');
// 更改网页标题
document.title = "<?php echo pathinfo($logFile, PATHINFO_FILENAME); ?>月上传日志 - <?php echo $config['title']; ?>"
</script>
<?php
require_once APP_ROOT . '/application/footer.php';

View File

@ -60,7 +60,7 @@ $config=Array
'imgRatio_preserve_headers'=>1,
'static_cdn'=>0,
'theme'=>'default',
'static_cdn_url'=>'https://cdn.jsdelivr.net/gh/icret/EasyImages2.0',
'static_cdn_url'=>'https://fastly.jsdelivr.net/gh/icret/EasyImages2.0',
'TinyPng_key'=>'',
'checkImg'=>0,
'checkImg_value'=>50,
@ -112,7 +112,7 @@ $config=Array
'guest_path_status'=>0,
'token_path_status'=>0,
'admin_path'=>'u',
'update'=>'2023-01-30 23:08:30',
'update'=>'2023-02-01 02:10:54',
'footer'=>'<a href="https://github.com/icret/EasyImages2.0" target="_blank" rel="nofollow" data-toggle="tooltip" title="Since 2018 - Github">© Since 2018</a>
<a href="https://png.cm/" target="_blank" data-toggle="tooltip" title="EasyImage 简单图床">EasyImage</a>
<a href="/admin/terms.php" target="_blank" data-toggle="tooltip" title="使用协议">DMCA</a>

View File

@ -185,25 +185,14 @@ $('#btnLinks, #btnBbscode, #btnMarkDown, #btnHtml, #btnThumb, #btnDel').on('clic
xhr.onload = function () {
var result = JSON.parse(this.responseText);
if (result.result === 'success') {
var links = document.getElementById("links");
links.innerHTML += result.url + "\n";
document.getElementById("links").innerHTML += result.url + "\r\n";
document.getElementById("bbscode").innerHTML += "[img]" + result.url + "[/img]\r\n";
document.getElementById("markdown").innerHTML += "![" + result.srcName + "](" + result.url + ")\r\n";
document.getElementById("html").innerHTML += '<img src="' + result.url + '" alt="' + result.srcName + '" />\r\n';
document.getElementById("thumb").innerHTML += result.thumb + "\r\n";
document.getElementById("del").innerHTML += result.del + "\r\n";
var bbscode = document.getElementById("bbscode");
bbscode.innerHTML += "[img]" + result.url + "[/img]\n";
var markdown = document.getElementById("markdown");
markdown.innerHTML += "![](" + result.url + ")\n";
var html = document.getElementById("html");
html.innerHTML += "&lt;img src=\"" + result.url + "\" /&#62;\n";
var del = document.getElementById("thumb");
del.innerHTML += result.thumb + "\n";
var del = document.getElementById("del");
del.innerHTML += result.del + "\n";
$.zui.messager.show('粘贴上传成功...', {
$.zui.messager.show(result.srcName + '上传成功', {
icon: 'bell',
time: 4000,
type: 'success',
@ -226,6 +215,7 @@ $('#btnLinks, #btnBbscode, #btnMarkDown, #btnHtml, #btnThumb, #btnDel').on('clic
});
}
};
xhr.onerror = function () {
$.zui.messager.show('因网络问题导致的上传失败...', {
icon: 'bell',