代码拉取完成,页面将自动刷新
app/admin/view/config/index.html
<div class="think-box-shadow margin-bottom-15">
<span class="color-green font-w7 text-middle">文件存储方式:</span>
{foreach ['local'=>'本地服务器存储','ftp'=>'FTP服务器存储','qiniu'=>'七牛云对象存储','alioss'=>'阿里云OSS存储'] as $k => $v}
{if sysconf('storage.type') eq $k}
{if auth('storage')}<a data-title="配置{$v}" data-modal="{:url('storage')}?type={$k}" class="layui-btn layui-btn-sm">{$v}</a>{else}<a class="layui-btn layui-btn-sm">{$v}</a>{/if}
{else}
{if auth('storage')}<a data-title="配置{$v}" data-modal="{:url('storage')}?type={$k}" class="layui-btn layui-btn-sm layui-btn-primary">{$v}</a>{else}<a class="layui-btn layui-btn-sm">{$v}</a>{/if}
{/if}
{/foreach}
</div>
app/admin/view/config/storage-ftp.html
<form onsubmit="return false" data-auto="true" action="{:url()}" method="post" class='layui-form layui-card' autocomplete="off">
<div class="layui-card-body">
<div class="color-text margin-left-40 margin-bottom-20 layui-code text-center layui-bg-gray" style="border-left-width:1px">
<p class="margin-bottom-5 font-w7">文件将上传到公司FTP文件服务器存储</p>
</div>
{include file='config/storage-0'}
<div class="layui-form-item">
<label class="layui-form-label label-required">
<span class="color-green font-w7">访问协议</span><br><span class="nowrap color-desc">Protocol</span>
</label>
<div class="layui-input-block">
{foreach ['http','https','auto'] as $pro}
<label class="think-radio">
{if sysconf('storage.ftp_http_protocol') eq $pro}
<input checked type="radio" name="storage.ftp_http_protocol" value="{$pro}" lay-ignore> {$pro}
{else}
<input type="radio" name="storage.ftp_http_protocol" value="{$pro}" lay-ignore> {$pro}
{/if}
</label>
{/foreach}
<p class="help-block">FTP服务器访问协议,其中 https 需要配置证书才能使用(auto 为相对协议)</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.ftp_host">
<span class="color-green font-w7">服务器</span><br><span class="nowrap color-desc">Host</span>
</label>
<div class="layui-input-block">
<input id="storage.ftp_host" type="text" name="storage.ftp_host" required value="{:sysconf('storage.ftp_host')}" placeholder="请输入服务器IP地址" class="layui-input">
<p class="help-block"></p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.ftp_port">
<span class="color-green font-w7">端口号</span><br><span class="nowrap color-desc">Port</span>
</label>
<div class="layui-input-block">
<input id="storage.ftp_port" type="text" name="storage.ftp_port" required value="{:sysconf('storage.ftp_port')}" placeholder="请输入服务器端口号" class="layui-input">
<p class="help-block">填写服务器端口号,如:21</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.ftp_bucket">
<span class="color-green font-w7">空间目录</span><br><span class="nowrap color-desc">Bucket</span>
</label>
<div class="layui-input-block">
<input id="storage.ftp_bucket" type="text" name="storage.ftp_bucket" required value="{:sysconf('storage.ftp_bucket')}" placeholder="请输入FTP服务器授权存储空间名" class="layui-input">
<p class="help-block">请输入FTP服务器授权存储空间名,如:img</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.ftp_http_domain">
<span class="color-green font-w7">访问域名</span><br><span class="nowrap color-desc">Domain</span>
</label>
<div class="layui-input-block">
<input id="storage.ftp_http_domain" type="text" name="storage.ftp_http_domain" required value="{:sysconf('storage.ftp_http_domain')}" placeholder="请输入服务器 Domain (访问域名)" class="layui-input">
<p class="help-block">填写服务器存储访问域名,如:0img.xxx.com,1img.xxx.com,2img.xxx.com,3img.xxx.com,4img.xxx.com</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.ftp_user">
<span class="color-green font-w7">访问账号</span><br><span class="nowrap color-desc">User</span>
</label>
<div class="layui-input-block">
<input id="storage.ftp_user" type="text" name="storage.ftp_user" required value="{:sysconf('storage.ftp_user')}" placeholder="请输入FTP账号" class="layui-input">
<p class="help-block"></p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.ftp_pass">
<span class="color-green font-w7">访问密码</span><br><span class="nowrap color-desc">Password</span>
</label>
<div class="layui-input-block">
<input id="storage.ftp_pass" type="text" name="storage.ftp_pass" required value="{:sysconf('storage.ftp_pass')}" maxlength="50" placeholder="请输入FTP账号密码" class="layui-input">
<p class="help-block"></p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<input type="hidden" name="storage.type" value="ftp">
<div class="layui-form-item text-center padding-left-40">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
</div>
</div>
</form>
app/admin/controller/api/Upload.php 修改如下方法
use think\admin\storage\FtpStorage;
/**
* 获取文件上传方式
* @return string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getType()
{
$this->uptype = strtolower(input('uptype', ''));
if (!in_array($this->uptype, ['local', 'ftp', 'qiniu', 'alioss'])) {
$this->uptype = strtolower(sysconf('storage.type'));
}
return strtolower($this->uptype);
}
/**
* 检查文件上传已经上传
* @login true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function state()
{
$this->name = input('name', null);
$this->safe = boolval(input('safe'));
$data = ['uptype' => $this->getType(), 'xkey' => input('xkey')];
$log = new Log($this->app);
$action="上传文件-检查";
$content = $this->name;
$log->info("操作人:".$this->app->session->get('user.username', '').",行为:".$action.',操作内容:'.$content);
if ($info = Storage::instance($data['uptype'])->info($data['xkey'], $this->safe, $this->name)) {
$data['url'] = $info['url'];
$this->success('文件已经上传', $data, 200);
} elseif ('local' === $data['uptype']) {
$data['url'] = LocalStorage::instance()->url($data['xkey'], $this->safe, $this->name);
$data['server'] = LocalStorage::instance()->upload();
}elseif ('ftp' === $data['uptype']) {
$data['url'] = FtpStorage::instance()->url($data['xkey'], $this->safe, $this->name);
$data['server'] = FtpStorage::instance()->upload();
} elseif ('qiniu' === $data['uptype']) {
$data['url'] = QiniuStorage::instance()->url($data['xkey'], $this->safe, $this->name);
$data['token'] = QiniuStorage::instance()->buildUploadToken($data['xkey'], 3600, $this->name);
$data['server'] = QiniuStorage::instance()->upload();
} elseif ('alioss' === $data['uptype']) {
$token = AliossStorage::instance()->buildUploadToken($data['xkey'], 3600, $this->name);
$data['url'] = $token['siteurl'];
$data['policy'] = $token['policy'];
$data['signature'] = $token['signature'];
$data['OSSAccessKeyId'] = $token['keyid'];
$data['server'] = AliossStorage::instance()->upload();
}
$data['safe'] = intval($this->safe);
$this->success('获取上传参数', $data, 404);
}
think-library/src/storage/FtpStoreage.php
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2020 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://gitee.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 仓库地址 :https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 :https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
namespace think\admin\storage;
use Exception;
use think\admin\Storage;
use think\admin\extend\HttpExtend;
use think\admin\extend\FtpExtend;
use think\facade\Log;
/**
* FTP存储支持
* Class FtpStorage
* @package think\admin\storage
*/
class FtpStorage extends Storage
{
private $host;
private $port;
private $user;
private $pass;
private $domain;
private $bucket;
private $ftp;
private $authFile;
/**
* 初始化入口
* @return FtpStorage
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function initialize(): Storage
{
// 读取配置文件
$this->host = sysconf('storage.ftp_host');
$this->port = sysconf('storage.ftp_port');
$this->user = sysconf('storage.ftp_user');
$this->pass = sysconf('storage.ftp_pass');
$this->domain = sysconf('storage.ftp_http_domain');
$this->bucket = sysconf('storage.ftp_bucket');
$this->ftp = new FtpExtend($this->host, $this->port, $this->user, $this->pass);
$this->authFile = "upload";
//多个域名情况随机一个
$domains = explode(",", $this->domain);
if (count($domains) > 0) {
$idx = mt_rand(0, count($domains)-1);
$this->domain = $domains[$idx];
}
// 计算链接前缀
$type = strtolower(sysconf('storage.ftp_http_protocol'));
if ($type === 'auto') {
$this->prefix = "//{$this->domain}/".$this->bucket."/".$this->authFile;
} elseif ($type === 'http') {
$this->prefix = "http://{$this->domain}/".$this->bucket."/".$this->authFile;
} elseif ($type === 'https') {
$this->prefix = "https://{$this->domain}/".$this->bucket."/".$this->authFile;
} else {
throw new \think\Exception('未配置FTP服务器访问域名哦');
}
// 初始化配置并返回当前实例
return parent::initialize();
}
protected function getPrefixs(){
$ftp_http_domain = sysconf('storage.ftp_http_domain');
$ftp_bucket = sysconf('storage.ftp_bucket');
$authFile = $this->authFile;
$type = strtolower(sysconf('storage.ftp_http_protocol'));
$domains = explode(",", $ftp_http_domain);
$prefixs = [];
if (count($domains) > 0) {
foreach($domains as $domain){
if ($type === 'auto') {
$prefix = "//{$domain}/".$ftp_bucket."/".$authFile;
} elseif ($type === 'http') {
$prefix = "http://{$domain}/".$ftp_bucket."/".$authFile;
} elseif ($type === 'https') {
$prefix = "https://{$domain}/".$ftp_bucket."/".$authFile;
} else {
throw new \think\Exception('未配置FTP服务器访问域名哦');
}
$prefixs[] = $prefix;
}
}
return $prefixs;
}
/**
* 获取当前实例对象
* @param null $name
* @return FtpStorage
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public static function instance($name = null): Storage
{
return parent::instance('ftp');
}
/**
* 上传文件内容
* @param string $name 文件名称
* @param string $file 文件内容
* @param boolean $safe 安全模式
* @param string $attname 下载名称
* @return array
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function set($name, $file, $safe = false, $attname = null)
{
try {
//判断是否已经存在
if ($this->has($name, $safe)) {
return $this->info($name, $safe, $attname);
}
$path = $this->path($name, $safe);
if (!file_exists($path)) {
@file_exists(dirname($path)) || mkdir(dirname($path), 0755, true);
@file_put_contents($path, $file);
}
//上传到ftp
$this->ftp->upFile($this->path($name, $safe), $this->ftpPath($name, $safe));
//删除本地临时文件
@unlink($this->path($name, $safe));
return $this->info($name, $safe, $attname,true);
} catch (\think\Exception $e) {
echo $e->getMessage();
exit;
} finally {
$this->ftp->close(); // 关闭FTP连接
}
}
/**
* 根据文件名读取文件内容
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
*/
public function get($name, $safe = false)
{
$url = $this->url($name, $safe) . "?e=" . time();
return file_get_contents($url);
}
/**
* 删除存储的文件
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean|null
*/
public function del($name, $safe = false)
{
if ($this->has($name, $safe)) {
return $this->ftp->delFile($this->ftpPath($name, $safe));
} else {
return false;
}
}
/**
* 检查文件是否已经存在
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return boolean
*/
public function has($name, $safe = false)
{
return $this->ftp->hasFile($this->ftpPath($name, $safe));
}
/**
* 获取文件当前URL地址
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param string $attname 下载名称
* @return string
*/
public function url($name, $safe = false, $attname = null)
{
return "{$this->prefix}/{$this->delSuffix($name)}{$this->getSuffix($attname)}";
}
/**
* 获取文件当前URL地址
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param string $attname 下载名称
* @return string
*/
public function urls($name, $safe = false, $attname = null)
{
$prefixs = $this->getPrefixs();
$urls = [];
foreach($prefixs as $prefix){
$urls[] = "{$prefix}/{$this->delSuffix($name)}{$this->getSuffix($attname)}";
}
return $urls;
}
/**
* 获取FTP文件存储路径
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
*/
public function ftpPath($name, $safe = false)
{
return $this->authFile."/".$name;
}
/**
* 获取本地文件存储路径
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @return string
*/
public function path($name, $safe = false)
{
$root = $this->app->getRootPath();
$path = $safe ? 'safefile' : 'public/upload';
return strtr("{$root}{$path}/{$this->delSuffix($name)}", '\\', '/');
}
/**
* 获取文件存储信息
* @param string $name 文件名称
* @param boolean $safe 安全模式
* @param string $attname 下载名称
* @return array
*/
public function info($name, $safe = false, $attname = null,$checkAll= false)
{
$urls = $checkAll?$this->urls($name, $safe, $attname):[$this->url($name, $safe, $attname)];
Log::info("是否全面检测:". $checkAll .",待检测列表:".json_encode($urls));
$url_pass = $this->check_remote_file_exists($urls,$checkAll?true:false);
if ($url_pass) {
return ['file' => $name, 'url' => $url_pass, 'key' => $name];
} else {
return [];
}
}
/**
* 获取文件上传地址
* @return string
*/
public function upload()
{
return url('@admin/api.upload/file')->build();
}
private function execWithRetry($url,$curl,$maxTimes,$currTimes,&$found){
Log::info("请求:".$url.",第". $currTimes ."次,最大请求次数:".$maxTimes);
$result = curl_exec($curl);
Log::info("请求:".$url.",第". $currTimes ."次,result:".$result);
if ($result !== false) {
/** 再检查http响应码是否为200 */
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
Log::info("请求:".$url.",第". $currTimes ."次,statusCode:".$statusCode);
if ($statusCode == 200) {
$found = true;
}
else{
$currTimes++;
if($currTimes<=$maxTimes){
sleep(2*$currTimes-1);
//请求状态不为200,等待2n-1秒后重试
$this->execWithRetry($url,$curl,$maxTimes,$currTimes,$found);
}
}
}
else{
Log::info("请求:".$url.",第". $currTimes ."次");
$currTimes++;
if($currTimes<=$maxTimes){
sleep($currTimes);
//请求发送失败,等待n秒后重试
$this->execWithRetry($url,$curl,$maxTimes,$currTimes,$found);
}
}
}
private function check_remote_file_exists($urls,$retry=false)
{
$url_pass = "";
foreach($urls as $url){
$curl = curl_init($url); // 不取回数据
curl_setopt($curl, CURLOPT_NOBODY, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET'); // 发送请求
// 在尝试连接时等待的秒数
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT , 5);
// 最大执行时间
curl_setopt($curl, CURLOPT_TIMEOUT, 120);
// $result = curl_exec($curl);
// $found = false; // 如果请求没有发送失败
// if ($result !== false) {
// /** 再检查http响应码是否为200 */
// $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
// if ($statusCode == 200) {
// $found = true;
// }
// }
$found = false; // 如果请求没有发送失败
if($retry){
$this->execWithRetry($url,$curl,4,1,$found);
}
else{
$this->execWithRetry($url,$curl,1,1,$found);
}
curl_close($curl);
if($found){
$url_pass = $url;
break;
}
}
return $url_pass;
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
登录 后才可以发表评论