Sản phẩm — FluxFiles
Mọi thứ một trình quản lý file hiện đại cần
Xây dựng cho lập trình viên cần sự linh hoạt.
Đa lưu trữ
Local, AWS S3, Cloudflare R2, SFTP qua Flysystem v3 — đổi bằng config, không sửa code.
Nhúng mọi nơi
iframe + SDK postMessage. UI độc lập dùng Alpine.js (không build). Dùng được với mọi framework.
JWT auth + phân quyền
Prefix đường dẫn theo user, quyền, whitelist disk, chế độ owner-only — hoặc bắt đầu từ preset vai trò viewer/editor/admin.
Preset vai trò ACL
Cấp token từ các preset viewer/editor/admin/superadmin — chỉ một tham số là mở ra đúng các claim quyền, disk và phạm vi truy cập, khỏi phải ráp tay từng cái.
AI auto-tag
Claude / OpenAI vision — tự động alt text, tiêu đề, tags.
Cắt ảnh
Công cụ cắt ảnh với tỷ lệ khung hình sẵn.
Tối ưu ảnh
Tự tạo biến thể WebP — thumb, medium, large.
Upload presigned
Trình duyệt upload trực tiếp lên S3/R2 — không tốn bandwidth server.
Upload phân mảnh
S3 multipart cho file > 10MB.
Tìm kiếm toàn văn
Tìm kiếm có index theo tên, tiêu đề, tags — mặc định dựa trên file, hoặc dùng database SQL riêng (tùy chọn).
Metadata lưu trong database
Chế độ tùy chọn FLUXFILES_STORAGE_BACKEND=db — metadata, index tìm kiếm/thư mục và audit log được lưu trong MySQL/PostgreSQL/SQLite của riêng bạn thay vì file JSON. Dữ liệu file vẫn nằm trên storage trong cả hai trường hợp.
Thao tác hàng loạt
Chọn nhiều file để di chuyển, sao chép, xóa, tải.
Chuyển giữa các disk
Sao chép/di chuyển giữa Local ↔ S3 ↔ R2.
Thùng rác
Xóa mềm có thể khôi phục, tự dọn dẹp.
SEO metadata
Title, alt, caption, tags — metadata object S3 (cloud) hoặc sidecar JSON (local). Tìm kiếm full-text.
Chế độ tối
Sáng / tối / tự động trong UI và SDK.
16 ngôn ngữ
Mặc định tiếng Anh. Đặt locale qua SDK, URL (?locale=), hoặc FLUXFILES_LOCALE. RTL cho tiếng Ả Rập.
Nhật ký kiểm toán
Ghi log tất cả hành động ghi.
Giới hạn tốc độ
Token bucket cho mỗi người dùng.
Hạn mức lưu trữ
Giới hạn dung lượng theo JWT claims.
BYOB bucket
Người dùng gắn S3/R2 riêng — credential mã hóa trong JWT (AES-256-GCM).
Phát hiện trùng file
Khớp SHA-256 bỏ qua upload trùng trừ khi bạn force ghi đè.
Làm mới token SDK
onTokenRefresh khi 401 — gộp refresh, thử lại, và updateToken() để đổi token chủ động.
Bucket Doctor
Chẩn đoán disk S3/R2 bất kỳ — credentials, đọc/ghi/xóa, presign, CORS, multipart — kèm bản vá IAM & CORS dán là chạy. Onboard bucket BYOB trong vài phút.
Ổ đĩa SFTP
Driver thứ 3 sau S3/R2 — biến mọi VPS hay shared host thành trình quản lý tệp.
Sửa code / config
Sửa tệp văn bản và cấu hình (wp-config.php, .env, nginx.conf) ngay trên trình duyệt.
Nén & Giải nén
Tải lựa chọn dưới dạng zip, hoặc giải nén tại chỗ — chống zip-slip & zip-bomb.
Đóng dấu watermark
Thêm watermark chữ hoặc logo theo thời gian thực để bảo vệ — không đụng tệp gốc.
WebP + AVIF theo yêu cầu
Phục vụ mọi kích thước ảnh dạng AVIF/WebP cache qua 1 URL (theo Accept), kèm srcset responsive.
Phân quyền SFTP
Đổi quyền tệp Unix (chmod) trên ổ SFTP bằng hộp thoại kiểu cPanel.
SSH terminal
Nhúng ttyd / gotty / wetty của riêng bạn làm terminal trong ứng dụng trên đĩa SFTP qua claim miễn phí terminal_pty_url — FluxFiles không đi kèm shell riêng.
Deploy Git một chạm
Pull và reset repo Git trên server SFTP ngay từ trình quản lý tệp — hình dạng cố định, không phải shell tuỳ ý, hooks tắt mặc định.
Bảng dung lượng
Xem dung lượng tức thì — quota cùng phân tích theo loại và theo thư mục.
Xem trước media
Xem trực tiếp ảnh, video, audio & PDF; media local riêng tư stream an toàn (hỗ trợ Range).
Chạy trong 2 phút
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 Agent chỉ chạm được vào những gì JWT của nó cho phép — disk, path prefix và quyền. Hãy cấp cho nó một token phạm vi hẹp, chỉ đọc.
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. Khi lên production: đặt FLUXFILES_SECRET dài ít nhất 32 byte và FLUXFILES_ALLOWED_ORIGINS (hoặc FLUXFILES_FRAME_ANCESTORS). Dùng thư mục gốc của package làm document root và chặn /_fluxfiles/ cùng .env trong nginx. Không bao giờ đặt JWT chính vào URL — các adapter truyền nó qua postMessage. DEPLOYMENT.md
Tương thích với
Tích hợp
Adapter cắm-là-chạy cho stack của bạn
Các adapter chính thức nhúng FluxFiles trực tiếp vào framework và trình soạn thảo bạn đang dùng.
Dùng CKEditor hoặc TinyMCE với kho lưu trữ của riêng bạn — không cần đăng ký CKBox hay Tiny Drive. FluxFiles thêm một nút trên thanh công cụ để duyệt và chèn tệp; đây không phải sản phẩm thay thế tương đương từng tính năng.
Nhúng
Nhúng chỉ với vài dòng
Tải fluxfiles.js, truyền JWT do server cấp, và đặt nguyên một trình quản lý file — hoặc một modal chọn file — vào bất kỳ trang nào.
<!-- 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)}
/>
);
} Token được cấp ở phía server — đừng bao giờ đưa secret ra trình duyệt.
Xây dựng cho những gì người khác bỏ quên
| Tính năng | FluxFiles | elFinder | Laravel-FM | RichFilemanager | Responsive FM |
|---|---|---|---|---|---|
| S3 + R2 + Local + SFTP | ✓ | ⚠ | ⚠ | ⚠ | ✗ |
| Nhúng mọi framework | ✓ | ⚠ | ✗ | ⚠ | ✗ |
| JWT auth + phân quyền | ✓ | ✗ | ✗ | ✗ | ✗ |
| SEO metadata | ✓ | ✗ | ✗ | ✗ | ✗ |
| AI auto-tag | ✓ | ✗ | ✗ | ✗ | ✗ |
| Cắt ảnh | ✓ | ✓ | ✗ | ✗ | ✗ |
| Upload phân mảnh | ✓ | ✗ | ✗ | ✗ | ✗ |
| Tìm kiếm toàn văn | ✓ | ✗ | ✗ | ✗ | ✗ |
| Chế độ tối | ✓ | ✗ | ⚠ | ✗ | ✗ |
| 16 ngôn ngữ | ✓ | ✓ | ✗ | ✗ | ✗ |
| PHP ≥ 8.1 | ✓ | ✓ | ✗ | ✓ | ✓ |
| Đang maintain | ✓ | ✓ | ⚠ | ✗ | ✗ |
| UI hiện đại | ✓ | ✗ | ⚠ | ✗ | ✗ |
| Khả năng | FluxFiles | Filestack | Uploadcare | Cloudinary | Supabase Storage |
|---|---|---|---|---|---|
| Self-hosted (chạy trong hạ tầng của bạn) | ✓ | ✗ | ✗ | ✗ | ⚠ |
| BYOB — bucket riêng của từng khách | ✓ | ⚠ | ⚠ | ✗ | ✗ |
| UI file manager nhúng được | ✓ | ✓ | ✓ | ⚠ | ✗ |
| Mã nguồn mở (MIT) | ✓ | ✗ | ✗ | ✗ | ✓ |
| Không phí SaaS theo storage / upload | ✓ | ✗ | ✗ | ✗ | ⚠ |
| Đa storage (S3 / R2 / local) | ✓ | ⚠ | ✗ | ✗ | ✗ |
| Scope token theo từng tenant sẵn có | ✓ | ⚠ | ⚠ | ⚠ | ⚠ |
So sánh phản ánh gói mặc định thông thường; mỗi sản phẩm mạnh ở mảng riêng. Niche của FluxFiles là bộ ba nhúng-được, self-hosted, bring-your-own-bucket.
So sánh tính đến November 2026, không liên kết với các bên — xem repo GitHub để báo lỗi cần chỉnh sửa.
Hỏi đáp