Sản phẩm — FluxFiles

Tính năng

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

Terminal chạy lệnh stateless trên ổ SFTP — công cụ quản trị kiểu cPanel, có sẵn miễn phí (hoặc nhúng ttyd riêng để có PTY đầy đủ).

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).

Cài đặt nhanh

Chạy trong 2 phút

composer require fluxfiles/fluxfiles
cp .env.example .env

# .env
FLUXFILES_SECRET=your-random-32-char-secret
FLUXFILES_ALLOWED_ORIGINS=https://yourapp.com

require_once 'vendor/autoload.php';

$token = fluxfiles_token(
    userId: 'user-123',
    perms: ['read', 'write', 'delete'],
    disks: ['local', 's3', 'r2'],
    prefix: 'user-123/',
    maxUploadMb: 10,
    allowedExt: null,
    ttl: 3600
);
composer require fluxfiles/laravel
php artisan vendor:publish --tag=fluxfiles-config

# .env — point the adapter at your FluxFiles server
FLUXFILES_ENDPOINT=https://fm.yourdomain.com
FLUXFILES_SECRET=your-secret-min-32-chars

# Optional: match CORS on the FluxFiles host
# FLUXFILES_ALLOWED_ORIGINS=https://yourapp.com

# Config: config/fluxfiles.php
npm install @fluxfiles/node

// 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)
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}
<!-- Demo: unpkg. In production, serve fluxfiles.js from your FluxFiles host -->
<script src="https://unpkg.com/fluxfiles@latest/fluxfiles.js"></script>

<script>
FluxFiles.open({
    endpoint: 'https://your-api.com',
    token: 'eyJhbGci...',
    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"
/>
git clone https://github.com/thai-pc/fluxfiles.git
docker build -f fluxfiles/docker/Dockerfile.prod -t fluxfiles fluxfiles

docker run -p 8080:80 \\
  -e FLUXFILES_SECRET=your-random-32-char-secret \\
  fluxfiles

# UI: http://localhost:8080/public/index.html
git clone https://github.com/thai-pc/fluxfiles.git
cd fluxfiles
composer install -d packages/core
cp .env.example .env

cd packages/core
php -S localhost:8080 router.php

# UI:  http://localhost:8080/public/index.html
# API: http://localhost:8080/api/fm/list?disk=local&path=

Tương thích với

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

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.

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

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.

<script src="https://fm.example.com/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.

Tại sao FluxFiles

Xây dựng cho những gì người khác bỏ quên

Vuốt để so sánh
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 September 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

Câu hỏi thường gặp

Xác thực hoạt động thế nào?
JWT phi trạng thái (HS256): bạn cấp token ở server với các claim chi tiết (quyền, disk, phạm vi đường dẫn, giới hạn), nên mỗi user chỉ thấy đúng phần bạn cho phép.
Người dùng có cần tài khoản FluxFiles không?
Không. FluxFiles tin tưởng JWT do chính ứng dụng của bạn cấp, nên gắn thẳng vào hệ thống auth sẵn có — không cần hệ thống user riêng.
Cần gì để chạy?
PHP 8.1+ với vài extension phổ biến và Composer. Trỏ tới một disk, đặt secret và allowed origins, rồi chạy — nhẹ tới mức chạy được trên VPS nhỏ.
Các người dùng khác nhau có thể có quyền khác nhau không?
Có. Bạn có thể tạo token với các claim chi tiết (đọc/ghi/xóa, disk, path prefix, giới hạn upload, đuôi file được phép, owner-only), hoặc dùng một trong bốn preset vai trò dựng sẵn — viewer, editor, admin, superadmin — để giới hạn token chỉ trong một dòng thay vì liệt kê từng claim.
Tôi có cần chạy database không?
Không. Mặc định, mọi metadata (thông tin file, chỉ mục tìm kiếm, audit log) đều nằm cạnh file của bạn dưới dạng JSON sidecar — không cần dựng hay backup gì thêm. Nếu muốn lưu phần sổ sách này trong MySQL, PostgreSQL hoặc SQLite của riêng bạn, chế độ tùy chọn FLUXFILES_STORAGE_BACKEND=db sẽ chuyển nó sang đó; dữ liệu file luôn nằm trong storage của bạn dù dùng chế độ nào.
Có giới hạn sử dụng nào không?
Bản core không đặt ra giới hạn nhân tạo nào — không giới hạn số người dùng hoạt động hàng tháng, không thúc ép nâng cấp. Bạn tự đặt giới hạn của mình qua JWT claims: hạn mức lưu trữ theo từng user, giới hạn dung lượng/đuôi file upload, và bộ giới hạn tốc độ tích hợp sẵn (mặc định 60 lượt đọc / 10 lượt ghi mỗi phút, có thể tùy chỉnh).