产品 — FluxFiles

功能

现代文件管理器所需的一切

为需要灵活性的开发者而构建。

多存储

本地、AWS S3、Cloudflare R2, SFTP 通过 Flysystem v3 — 仅改配置即可切换。

嵌入任何地方

iframe + postMessage SDK。独立 UI 使用 Alpine.js(零构建)。适用于任何框架。

JWT认证 + 权限范围

每用户路径前缀、权限声明、磁盘白名单、仅所有者模式——也可从 viewer/editor/admin 角色预设开始。

ACL 角色预设

从 viewer/editor/admin/superadmin 预设中签发令牌——一个参数即可展开正确的权限、磁盘和作用域声明,无需手动拼装。

AI自动标签

Claude / OpenAI vision — 自动alt文本、标题、标签。

图片裁剪

内置裁剪工具,预设宽高比。

图片优化

自动WebP变体 — 缩略图、中等、大图。

预签名上传

浏览器直接上传到S3/R2 — 服务器零带宽消耗。

分片上传

S3 multipart,支持>10MB文件。

全文搜索

对文件名、标题、标签建立索引搜索——默认基于文件,也可选用自己的 SQL 数据库作为后端。

数据库支持的元数据

可选的 FLUXFILES_STORAGE_BACKEND=db 模式——元数据、搜索/文件夹索引和审计日志存储在你自己的 MySQL/PostgreSQL/SQLite 中,而非 JSON 附属文件。无论哪种方式,文件字节都保留在存储端。

批量操作

多选移动、复制、删除、下载。

跨磁盘传输

在本地 ↔ S3 ↔ R2之间复制/移动。

回收站

可恢复删除,自动清理。

SEO元数据

标题、alt、说明、标签 — 云端为 S3 对象元数据,本地为 sidecar JSON。全文搜索。

深色模式

UI 与 SDK 支持浅色 / 深色 / 自动。

16种语言

默认英语。通过 SDK、URL (?locale=) 或 FLUXFILES_LOCALE 设置语言。阿拉伯语 RTL。

审计日志

记录所有写入操作。

速率限制

每用户令牌桶API保护。

存储配额

通过JWT claims设置每用户限制。

BYOB 存储桶

用户自带 S3/R2 — 凭证在 JWT 中加密(AES-256-GCM)。

重复检测

SHA-256 相同则跳过重复上传,除非强制覆盖。

SDK 令牌刷新

401 时 onTokenRefresh — 合并刷新、重试,以及 updateToken() 主动轮换。

存储桶体检

诊断任意 S3/R2 磁盘——凭证、读/写/删、预签名、CORS、分片——并给出可直接粘贴的 IAM 与 CORS 修复方案。几分钟接入 BYOB 存储桶。

SFTP 磁盘

继 S3/R2 之后的第三种驱动——把任意 VPS 或共享主机变成文件管理器。

代码 / 配置编辑器

在浏览器中编辑文本与配置文件(wp-config.php、.env、nginx.conf),类 cPanel。

压缩与解压

将选中项打包为 zip,或就地解压——已防 zip-slip 与压缩炸弹。

水印

实时叠加文字或 Logo 水印以保护预览——绝不修改原文件。

按需 WebP + AVIF

通过一个 URL 以缓存的 AVIF/WebP 提供任意尺寸图片(按 Accept 协商),附带响应式 srcset。

SFTP 权限

用类 cPanel 对话框更改 SFTP 磁盘上的 Unix 文件权限(chmod)。

SSH 终端

通过免费的 terminal_pty_url 声明,在 SFTP 磁盘上嵌入你自己的 ttyd / gotty / wetty 作为应用内终端 —— FluxFiles 本身不自带 shell。

一键 Git 部署

直接从文件管理器在 SFTP 服务器上拉取并重置 Git 仓库——固定形式,非任意 shell,默认关闭 hooks。

用量面板

一目了然的存储用量——配额加按类型和文件夹的细分。

媒体预览

内联预览图片、视频、音频与 PDF;私有本地媒体安全流式传输(支持 Range)。

快速安装

2分钟启动运行

composer require fluxfiles/fluxfiles
cp vendor/fluxfiles/fluxfiles/.env.example vendor/fluxfiles/fluxfiles/.env
# vendor/fluxfiles/fluxfiles/.env  (read only from inside the package)
# Real environment variables win over this file and are preferred in production
# (Composer may remove a vendor .env on update).
FLUXFILES_SECRET=<output of: openssl rand -hex 32>
FLUXFILES_ALLOWED_ORIGINS=https://yourapp.com
<?php
require_once 'vendor/autoload.php';
// embed.php is not autoloaded — require it for fluxfiles_token()
require_once 'vendor/fluxfiles/fluxfiles/embed.php';

$token = fluxfiles_token([
    'user'   => 'user-123',
    'perms'  => ['read', 'write', 'delete'],
    'disks'  => ['local'],     // s3 / r2 need their own credentials in .env
    'prefix' => 'user-123/',
    'ttl'    => 3600,
]);
php vendor/bin/fluxfiles serve --port=8080
# then open http://127.0.0.1:8080/public/
composer require fluxfiles/laravel
php artisan vendor:publish --tag=fluxfiles-config
php artisan storage:link
# .env — proxy mode is the default: the API runs through your Laravel routes,
# no separate FluxFiles server is needed.
FLUXFILES_SECRET=<output of: openssl rand -hex 32>

# Only for FLUXFILES_MODE=standalone (FluxFiles on its own server):
# FLUXFILES_MODE=standalone
# FLUXFILES_ENDPOINT=https://fm.yourdomain.com
<?php
// app/FluxFiles/TenantClaims.php — REQUIRED: without a claims resolver
// <x-fluxfiles> renders "not available".
namespace App\FluxFiles;

use FluxFiles\Laravel\ClaimsResolver;
use Illuminate\Contracts\Auth\Authenticatable;

class TenantClaims implements ClaimsResolver
{
    public function resolve(Authenticatable $user): array
    {
        return [
            'prefix' => 'users/' . $user->getAuthIdentifier(),
        ];
    }
}
// config/fluxfiles.php
'claims_resolver' => \App\FluxFiles\TenantClaims::class,
// Laravel 11 / 12 — bootstrap/app.php: exclude the proxy routes from CSRF (else 419)
->withMiddleware(function (Middleware $middleware) {
    $middleware->validateCsrfTokens(except: ['api/fm/*']);
})

// Laravel 10 — app/Http/Middleware/VerifyCsrfToken.php
// protected $except = ['api/fm/*'];
<x-fluxfiles disk="local" mode="picker" height="600px" />
# Not yet on WordPress.org — install the release zip:
# 1. Download fluxfiles-<version>.zip from https://github.com/thai-pc/fluxfiles/releases
# 2. Plugins -> Add New -> Upload Plugin -> Activate
# 3. Settings -> FluxFiles: set the JWT secret (>= 32 bytes) and storage
# 4. Add the shortcode (or the FluxFiles block) to any page or post:
[fluxfiles]
npm install @fluxfiles/node   # Node >= 16
// Express / Next.js route — mint a token from your JS backend (no PHP)
import { createToken } from '@fluxfiles/node';

app.get('/fluxfiles-token', (req, res) => {
    const token = createToken({
        secret: process.env.FLUXFILES_SECRET, // >= 32 bytes
        userId: req.user.id,
        perms: ['read', 'write', 'delete'],
        prefix: `users/${req.user.id}`,
        ttl: 3600,
    });
    res.json({ token });
});
pip install fluxfiles-token
# FastAPI / Django / Flask route — mint a token from your Python backend (no PHP)
import os

from fastapi import Depends
from fluxfiles_token import create_token

@app.get("/fluxfiles-token")
def fluxfiles_token(user=Depends(current_user)):
    token = create_token(
        secret=os.environ["FLUXFILES_SECRET"],  # >= 32 bytes
        user_id=user.id,
        perms=["read", "write", "delete"],
        prefix=f"users/{user.id}",
        ttl=3600,
    )
    return {"token": token}
{
  "mcpServers": {
    "fluxfiles": {
      "command": "npx",
      "args": ["-y", "@fluxfiles/mcp"],
      "env": {
        "FLUXFILES_URL": "<your FluxFiles URL>",
        "FLUXFILES_TOKEN": "<scoped JWT>"
      }
    }
  }
}
# Claude Code (Node >= 18)
claude mcp add fluxfiles -e FLUXFILES_URL=<your FluxFiles URL> -e FLUXFILES_TOKEN=<scoped JWT> -- npx -y @fluxfiles/mcp
# Read-only by default. Opt in to writes:
FLUXFILES_MCP_WRITE=1
# and to move_to_trash:
FLUXFILES_MCP_DELETE=1

智能体只能访问其 JWT 允许的范围——磁盘、路径前缀和权限。请为它签发一个范围窄、只读的令牌。

npm install fluxfiles
<!-- or load a pinned CDN build (never @latest) -->
<script src="https://unpkg.com/fluxfiles@1.0.1/fluxfiles.js"></script>
<div id="file-picker" style="height:600px"></div>

<script>
FluxFiles.open({
    endpoint: 'https://your-fluxfiles-host',
    token: 'eyJhbGci...',   // JWT minted by your backend
    disk: 'local',
    mode: 'picker',
    container: '#file-picker',
    onSelect: function(file) {
        console.log('Selected:', file.url);
    },
    async onTokenRefresh() {
        const r = await fetch('/api/auth/refresh-fluxfiles-token');
        const { token } = await r.json();
        return token;
    }
});
</script>
npm install @fluxfiles/react
import { FluxFilesModal } from '@fluxfiles/react';

<FluxFilesModal
    open={open}
    endpoint="https://your-api.com"
    token={token}
    onSelect={(file) => console.log(file)}
    onClose={() => setOpen(false)}
/>
npm install @fluxfiles/vue
<script setup>
import { FluxFilesModal } from '@fluxfiles/vue';
</script>

<FluxFilesModal
    v-model:open="open"
    endpoint="https://your-api.com"
    :token="token"
    @select="onSelect"
    @close="open = false"
/>
docker run -p 8080:80 \
  -e FLUXFILES_SECRET="$(openssl rand -hex 32)" \
  -e FLUXFILES_ALLOWED_ORIGINS=https://yourapp.com \
  -v fluxfiles-data:/app/packages/core/storage \
  ghcr.io/thai-pc/fluxfiles:1.1
# UI: http://localhost:8080/public/
git clone https://github.com/thai-pc/fluxfiles.git
cd fluxfiles/packages/core
composer install
cp .env.example .env
# packages/core/.env — the placeholder secret is rejected, set a real one
FLUXFILES_SECRET=<output of: openssl rand -hex 32>
FLUXFILES_ALLOWED_ORIGINS=http://localhost:8080
# print dev tokens (run from the repo root)
php packages/core/tests/generate-token.php
php -S localhost:8080 router.php

# UI: http://localhost:8080/public/index.html?token=<token>
# ?token= is dev-only — it is stripped from the URL on boot.
# Real apps pass the JWT via the SDK / postMessage, never in a URL.

上线前:设置至少 32 字节的 FLUXFILES_SECRET 以及 FLUXFILES_ALLOWED_ORIGINS(或 FLUXFILES_FRAME_ANCESTORS)。将包根目录作为网站文档根目录,并在 nginx 中拒绝访问 /_fluxfiles/ 和 .env。切勿把主 JWT 放进 URL —— 适配器通过 postMessage 传递它。 DEPLOYMENT.md

兼容

Laravel WordPress React / Next.js Vue / Nuxt CKEditor 4 CKEditor 5 TinyMCE Summernote Any framework

集成

适配你技术栈的即插即用适配器

官方适配器可将 FluxFiles 原生嵌入你已经在用的框架和编辑器中。

将 CKEditor 或 TinyMCE 与您自己的存储搭配使用——无需订阅 CKBox 或 Tiny Drive。FluxFiles 提供一个用于浏览和插入文件的工具栏按钮;它并非这些产品的逐项功能替代品。

Laravel
PHP
WordPress
Plugin
React
Component
Vue / Nuxt
Component
CKEditor 4
Plugin
CKEditor 5
Plugin
TinyMCE
Plugin
Summernote
Plugin

嵌入

几行代码即可嵌入

加载 fluxfiles.js,传入由服务端签发的 JWT,即可把完整的文件管理器(或文件选择弹窗)放进任意页面。

<!-- npm install fluxfiles, or a pinned CDN build -->
<script src="https://unpkg.com/fluxfiles@1.0.1/fluxfiles.js"></script>

FluxFiles.open({
  endpoint: 'https://fm.example.com',
  token: 'eyJhbGci...',   // JWT from your backend
  disk: 'local',
  mode: 'picker',         // select & close
  theme: 'auto',
  onSelect(file) {
    // { url, key, name, size, disk, meta, variants }
    document.querySelector("#img").src = file.url;
  },
});
<div id="fm" style="height:600px"></div>

FluxFiles.open({
  endpoint: 'https://fm.example.com',
  token: 'eyJhbGci...',
  mode: 'browser',          // full manager, stays open
  container: '#fm',         // omit for a modal overlay
  disks: ['local', 's3', 'r2'],
});

FluxFiles.on('FM_EVENT', (e) => console.log(e.event));
FluxFiles.navigate('/photos/2024');
import { FluxFilesModal } from '@fluxfiles/react';

function Picker({ open, setOpen, token }) {
  return (
    <FluxFilesModal
      open={open}
      endpoint="https://fm.example.com"
      token={token}
      onSelect={(file) => console.log(file.url)}
      onClose={() => setOpen(false)}
    />
  );
}

令牌在服务端签发——切勿把密钥发送到浏览器。

为什么选择FluxFiles

为他人遗忘之处而构建

滑动查看对比
功能 FluxFiles elFinder Laravel-FM RichFilemanager Responsive FM
S3 + R2 + Local + SFTP ✓ ⚠ ⚠ ⚠ ✗
嵌入任何框架 ✓ ⚠ ✗ ⚠ ✗
JWT认证 + 权限范围 ✓ ✗ ✗ ✗ ✗
SEO元数据 ✓ ✗ ✗ ✗ ✗
AI自动标签 ✓ ✗ ✗ ✗ ✗
图片裁剪 ✓ ✓ ✗ ✗ ✗
分片上传 ✓ ✗ ✗ ✗ ✗
全文搜索 ✓ ✗ ✗ ✗ ✗
深色模式 ✓ ✗ ⚠ ✗ ✗
16种语言 ✓ ✓ ✗ ✗ ✗
PHP ≥ 8.1 ✓ ✓ ✗ ✓ ✓
积极维护中 ✓ ✓ ⚠ ✗ ✗
现代UI ✓ ✗ ⚠ ✗ ✗
能力 FluxFiles Filestack Uploadcare Cloudinary Supabase Storage
自托管(运行在你的基础设施) ✓ ✗ ✗ ✗ ⚠
BYOB——每个客户自有存储桶 ✓ ⚠ ⚠ ✗ ✗
可嵌入的文件管理器 UI ✓ ✓ ✓ ⚠ ✗
开源(MIT) ✓ ✗ ✗ ✗ ✓
无按存储/上传的 SaaS 费用 ✓ ✗ ✗ ✗ ⚠
多存储(S3 / R2 / 本地) ✓ ⚠ ✗ ✗ ✗
内置按租户令牌作用域 ✓ ⚠ ⚠ ⚠ ⚠

对比反映各产品的典型默认能力;每款产品在各自领域都很出色。FluxFiles 的定位是可嵌入、自托管、自带存储桶三者的组合。

对比数据截至 November 2026,非官方关联——如需纠正请前往 GitHub 仓库反馈。

常见问题

常见问题解答

身份验证如何工作?
无状态 JWT(HS256):你在服务端签发带有细粒度声明(权限、磁盘、路径范围、限额)的令牌,因此每个用户只能看到你允许的内容。
我的用户需要 FluxFiles 账号吗?
不需要。FluxFiles 信任你自己应用签发的 JWT,可直接接入你现有的认证——无需单独的用户系统。
运行它需要什么?
PHP 8.1+(已测试 8.1–8.5),需 gd、curl、json、openssl、mbstring、fileinfo(解压功能另需 zip)和 Composer 2 —— 或使用 ghcr.io/thai-pc/fluxfiles Docker 镜像。指向一个磁盘,设置密钥和允许的来源后启动即可 —— 一台小型 VPS 就能运行。
不同用户可以拥有不同权限吗?
可以。你可以用细粒度的 claims(读/写/删除、磁盘、路径前缀、上传限制、允许的扩展名、owner-only)签发 token,也可以直接使用四种内置角色预设之一——viewer、editor、admin、superadmin——一行代码限定 token 范围,无需逐条罗列 claim。
我需要自己运行数据库吗?
不需要。默认情况下,所有元数据(文件信息、搜索索引、审计日志)都以 JSON 附属文件的形式存放在文件旁边——无需额外部署或备份。如果你更想把这些记录保存在自己的 MySQL、PostgreSQL 或 SQLite 中,可选的 FLUXFILES_STORAGE_BACKEND=db 模式会把它们迁移过去;无论哪种方式,文件本体始终留在你的存储中。
有使用限制吗?
核心本身没有人为设限——没有月活用户上限,也不会强制提示升级。你可以通过 JWT claims 自行设置限制:按用户的存储配额、上传大小/扩展名限制,以及内置的速率限制器(默认每分钟 60 次读取/10 次写入,可配置)。