1,下载文件: S3.php 源代码 (GitHub) 操作: 打开链接后,按下 Ctrl + S 保存文件,命名为 class_s3.php 。上传到 /source/class/ 目录下
2,修改source/class/discuz/discuz_ftp.php文件,记得备份。
X3.5
<?php
/**
* [Discuz!] (C)2001-2099 Comsenz Inc.
* Cloudflare R2 Adapter for Discuz! X3.5 (Final Clean Version)
* Created by OLEOU
*/
if(!defined('IN_DISCUZ')) {
exit('Access Denied');
}
class discuz_ftp {
public $enabled = false;
public $config = array();
public $s3 = null;
public static $obj = null;
// --- Cloudflare R2 核心配置 ---
private $accessKey = '改成你的';
private $secretKey = '改成你的';
private $bucket = '改成你的';
private $endpoint = '改成你的.r2.cloudflarestorage.com';
// ----------------------------
public static function instance($config = array()) {
if(empty(self::$obj)) {
self::$obj = new self($config);
}
return self::$obj;
}
public function __construct($config = array()) {
$this->config = $config;
if(!class_exists('S3')) {
$s3_file = DISCUZ_ROOT.'./source/class/class_s3.php';
if(file_exists($s3_file)) {
require_once $s3_file;
}
}
if(class_exists('S3')) {
// R2 必须使用 SSL 握手
$this->s3 = new S3($this->accessKey, $this->secretKey, true, $this->endpoint);
$this->enabled = true;
}
}
public function connect() {
return ($this->enabled && $this->s3) ? 1 : 0;
}
public function upload($source, $target) {
if(!$this->enabled || !$this->s3) return false;
// 路径清洗,确保存储路径规范
$target = preg_replace('/^(./|/)/', '', $target);
// 执行上传,不带 ACL 参数以适配 R2 权限体系
if($this->s3->putObjectFile($source, $this->bucket, $target)) {
return true;
}
return false;
}
public function delete($path) {
if(!$this->enabled || !$this->s3) return false;
$path = preg_replace('/^(./|/)/', '', $path);
return $this->s3->deleteObject($this->bucket, $path);
}
// 接口兼容性占位方法
public function mkdir($directory) { return true; }
public function chdir($directory) { return true; }
public function ftp_mkdir($directory) { return true; }
public function ftp_chdir($directory) { return true; }
public function ftp_site($cmd) { return true; }
public function ftp_chmod($filename, $mode) { return true; }
public function set_option($key, $value) { return true; }
public function close() { return true; }
}X5.0
<?php
/**
* [Discuz!] (C)2001-2099 Discuz! Team
* Optimized for Cloudflare R2 by OLEOU (for X5.0)
*/
if(!defined('IN_DISCUZ')) {
exit('Access Denied');
}
// 保持 X5.0 新增的错误常量定义
if(!defined('FTP_ERR_SERVER_DISABLED')) {
define('FTP_ERR_SERVER_DISABLED', -100);
define('FTP_ERR_CONFIG_OFF', -101);
define('FTP_ERR_CONNECT_TO_SERVER', -102);
define('FTP_ERR_USER_NO_LOGGIN', -103);
define('FTP_ERR_CHDIR', -104);
define('FTP_ERR_MKDIR', -105);
define('FTP_ERR_SOURCE_READ', -106);
define('FTP_ERR_TARGET_WRITE', -107);
define('FTP_ERR_OSS_CONNECT_ERROR', -200);
}
class discuz_ftp {
public $enabled = false;
public $config = [];
public $s3 = null;
public static $obj = null;
// --- Cloudflare R2 核心配置 ---
private $accessKey = '改成你的';
private $secretKey = '改成你的';
private $bucket = '改成你的';
private $endpoint = '改成你的.r2.cloudflarestorage.com';
// ----------------------------
public static function &instance($config = []) {
if(empty(self::$obj)) {
self::$obj = new self($config);
}
return self::$obj;
}
function __construct($config = []) {
$this->config = !$config ? getglobal('setting/ftp') : $config;
// 自动加载 S3 类库
if(!class_exists('S3')) {
$s3_file = DISCUZ_ROOT.'./source/class/class_s3.php';
if(file_exists($s3_file)) {
require_once $s3_file;
}
}
if(class_exists('S3')) {
$this->s3 = new S3($this->accessKey, $this->secretKey, true, $this->endpoint);
$this->enabled = true;
}
}
function upload($source, $target) {
if(!$this->enabled || !$this->s3) return 0;
// 适配 X5.0 的路径清洗
$target = preg_replace('/^(./|/)/', '', $target);
// 执行上传到 R2
if($this->s3->putObjectFile($source, $this->bucket, $target)) {
return 1;
}
return 0;
}
function connect() {
// 告诉 X5.0 连接永远成功,直接进入上传环节
return $this->enabled ? 1 : 0;
}
// 适配 X5.0 的删除逻辑
function ftp_delete($path) {
if(!$this->enabled || !$this->s3) return false;
$path = preg_replace('/^(./|/)/', '', $path);
return $this->s3->deleteObject($this->bucket, $path);
}
// --- 以下为 X5.0 要求的兼容性空方法 ---
function ftp_chdir($directory) { return 1; }
function ftp_mkdir($directory) { return 1; }
function ftp_chmod($filename, $mod = 0777) { return 1; }
function ftp_pwd() { return '/'; }
function ftp_close() { return 1; }
function set_error($code = 0) { }
function error() { return 0; }
function clear($str) { return str_replace(["n", "r", '..'], '', $str); }
}3,设置路径:后台 -> 全局 -> 上传设置 -> 远程附件。
强制参数:
启用远程附件:选 是。
FTP 服务器地址:随便填(如 127.0.0.1),但不能不填。
FTP 端口:默认 21。
FTP 帐号/密码:随便填,不为空即可。
被动模式:选 是。
远程访问 URL:填写你的 R2 自定义域名,如 https://img.xxxx.com。
结束:测试上线吧!