[教學] 完美將 Discuz 附件、會員頭像、靜態檔案外連至圖床(遠程附件)

最近在研究 Discuz 外連圖床的相關功能,除了官方提供的遠程附件,

還有會員頭像自動遠程、靜態檔案外連...等功能,

自己有先 Google 了一些問題,但發現網路上能找到的資訊屈指可數,

好像這些東西在 Discuz 不是一個很常見的功能,

就連官方論壇上面網友的發問,也沒有正確答案可以參考,

只好發揮自己研究的精神,來完成這些功能了!

適用版本:Discuz X3.x

注:以下教學都是經本人測試過並能正常使用,但可能存在伺服器、風格模版相容問題。

 

Discuz 官方有提供遠程附件的功能,可以將帖內上傳的附件、圖片、圖片縮圖等等,自動傳到遠程伺服器上,

不過在手機版看到的圖片依舊本地圖片,下面也會一一提供解決方法。

 

開啟 Discuz 遠程附件

首先要先從後台開啟 Discuz 的遠程附件功能,進入全局>上傳設置>遠程附件

啟用遠程附件選,接著填入圖床的 FTP 登入資訊,伺服器、帳號、密碼等等,

要特別注意的是遠程附件目錄這個地方要填寫正確,這個目錄是拿來存放遠程檔案的,

如果你的 FTP 帳號登入後,要進入 public_html 或 htdocs 之類的資料夾才能上傳檔案,

那麼遠程目錄裡也要填入(訪問 URL 就不用),否則遠程測試會不成功

這個部分很多人都沒注意到,所以測試都失敗,我自己一開始也忽略了,網路上也沒人給解答...

遠程訪問 URL 是實際連結的網址,要跟隨遠程目錄,不然會連不到檔案,

像我目錄是設定 public_html/data/attachment,所以訪問 URL 就填 http://圖床網址/data/attachment

 

送出前可以先點擊 [測試遠程附件] 測試一下是否正常,若出現遠程附件設置一切正常,就可以放心的提交了。

 

若是全新的 Discuz 論壇,可以直接略過這步驟,若在開啟遠程附件之前已經有附件或圖片紀錄,

請先將本地伺服器(論壇主要伺服器)目錄下 /data/attachment 下的所有目錄先手動傳到你剛剛設定的遠程附件目錄下,

這樣過去所上傳的圖片、附件也能直接連結到圖床上。

 

到此,在帖子內上傳的附件、圖片都會自動傳到圖床,帖子顯示的圖片也是指向圖床網址了。

 

不過你可能也發現了,在手機板模式下,圖片的網址依舊是連結到本地的圖片阿!!

圖片上連結的網址是 forum.php?mod=image&aid=XXX&size=1120x1120&key=XXX&type=fixnone

但實際訪問該連結,依舊是轉向本地的圖片,Discuz 官方論壇也有許多反饋的帖子,但官方的回應都是,不支援、不支援,就是不支援....

竟然官方不支援,那就只好自己修改了!

 

讓手機版圖片也連結到圖床

首先先以文字檔開啟論壇目錄下 source/module/forum/forum_image.php(修改前請先備份),

找到第 24 行:

dheader('location: '.$attachurl.$thumbfile);

在前面加上兩條斜線 //

//dheader('location: '.$attachurl.$thumbfile);

接著找到第 53 行:

dheader('location: '.$attachurl.$thumbfile);

同樣在前面加兩條斜線 //

//dheader('location: '.$attachurl.$thumbfile);

接著在同一行最後方按下 Enter 換新行,加入:

dheader('location: '.$filename);

保存,上傳回伺服器,這時就會發現圖片已經指向圖床瞜!

 

將會員頭像自動遠程到圖床

在 Discuz 論壇中,會員頭像無處不在,而且在同一頁中出現的數量都不少,

所以當初我就想說把頭像一起遠程,不過官方似乎沒有提供這個功能,

上網找也沒有人提供相關教學,因此這裡又要來動手修改文件啦!

 

需要修改到的文件

  • uc_server/avatar.php
  • uc_server/control/user.php
  • source/function/function_core.php(若有開啟「使用靜態地址調用頭像」)
※ 修改前請記得先備份原始文件!

 

事前準備

(更新)為了讓遠程伺服器的資料夾和本機端同步,需要多做一些 FTP 操作,

請先將以下代碼全部複製,存為 ftp.php,並傳到 uc_server/control/ 下。

<?php
class Ftp {
	//FTP 连接资源
	private $link;
	//FTP连接时间
	public $link_time;
	//错误代码
	private $err_code = 0;
	//传送模式{文本模式:FTP_ASCII, 二进制模式:FTP_BINARY}
	public $mode = FTP_BINARY;
	
	/** 
	 * 连接FTP服务器 
	 * @param string $host   服务器地址 
	 * @param string $username   用户名 
	 * @param string $password   密码 
	 * @param integer $port     服务器端口,默认值为21 
	 * @param boolean $pasv是否开启被动模式 
	 * @param boolean $ssl      是否使用SSL连接 
	 * @param integer $timeout 超时时间  
	 */
	public function connect($host, $username = '', $password = '', $port = '21', $pasv = false, $ssl = false, $timeout = 60) {
		$start = time();
		if ($ssl) {
			if (!$this->link = @ftp_ssl_connect($host, $port, $timeout)) {
				$this->err_code = 1;
				return false;
			}
		} else {
			if (!$this->link = @ftp_connect($host, $port, $timeout)) {
				$this->err_code = 1;
				return false;
			}
		}
		
		if (@ftp_login($this->link, $username, $password)) {
			if ($pasv)
				ftp_pasv($this->link, true);
			$this->link_time = time() - $start;
			return true;
		} else {
			$this->err_code = 1;
			return false;
		}
		register_shutdown_function(array(&$this, 'close'));
	}
		
	/** 
	 * 创建文件夹 
	 * @param string $dirname 目录名, 
	 */
	public function mkdir($dirname) {
		if (!$this->link) {
			$this->err_code = 2;
			return false;
		}
		$dirname = $this->ck_dirname($dirname);
		$nowdir = '/';
		foreach ($dirname as $v) {
			if ($v && !$this->chdir($nowdir . $v)) {
				if ($nowdir)
					$this->chdir($nowdir);
				@ftp_mkdir($this->link, $v);
			}
			if ($v)
				$nowdir .= $v . '/';
		}
		return true;
	}
		
	/** 
	 * 上传文件 
	 * @param string $remote 远程存放地址 
	 * @param string $local 本地存放地址 
	 */
	public function put($remote, $local) {
		if (!$this->link) {
			$this->err_code = 2;
			return false;
		}
		$dirname = pathinfo($remote, PATHINFO_DIRNAME);
		if (!$this->chdir($dirname)) {
			$this->mkdir($dirname);
		}
		if (@ftp_put($this->link, $remote, $local, $this->mode)) {
			return true;
		} else {
			$this->err_code = 7;
			return false;
		}
	}
		
	/** 
	 * 删除文件夹 
	 * @param string $dirname目录地址 
	 * @param boolean $enforce 强制删除 
	 */
	public function rmdir($dirname, $enforce = false) {
		if (!$this->link) {
			$this->err_code = 2;
			return false;
		}
		$list = $this->nlist($dirname);
		if ($list && $enforce) {
			$this->chdir($dirname);
			foreach ($list as $v) {
				$this->f_delete($v);
			}
		} elseif ($list && !$enforce) {
			$this->err_code = 3;
			return false;
		}
		@ftp_rmdir($this->link, $dirname);
		return true;
	}
		
	/** 
	 * 删除指定文件 
	 * @param string $filename 文件名 
	 */
	public function f_delete($filename) {
		if (!$this->link) {
			$this->err_code = 2;
			return false;
		}
		if (@ftp_delete($this->link, $filename)) {
			return true;
		} else {
			$this->err_code = 4;
			return false;
		}
	}
		
	/** 
	 * 返回给定目录的文件列表 
	 * @param string $dirname目录地址 
	 * @return array 文件列表数据 
	 */
	public function nlist($dirname) {
		if (!$this->link) {
			$this->err_code = 2;
			return false;
		}
		if ($list = @ftp_nlist($this->link, $dirname)) {
			return $list;
		} else {
			$this->err_code = 5;
			return false;
		}
	}
		
	/** 
	 * 在 FTP 服务器上改变当前目录 
	 * @param string $dirname 修改服务器上当前目录 
	 */
	public function chdir($dirname) {
		if (!$this->link) {
			$this->err_code = 2;
			return false;
		}
		if (@ftp_chdir($this->link, $dirname)) {
			return true;
		} else {
			$this->err_code = 6;
			return false;
		}
	}
		
	/** 
	 * 获取错误信息 
	 */
	public function get_error() {
		if (!$this->err_code)
			return false;
		$err_msg = array(
			'1' => 'Server can not connect',
			'2' => 'Not connect to server',
			'3' => 'Can not delete non-empty folder',
			'4' => 'Can not delete file',
			'5' => 'Can not get file list',
			'6' => 'Can not change the current directory on the server',
			'7' => 'Can not upload files'
		);
		return $err_msg[$this->err_code];
	}
		
	/** 
	 * 检测目录名 
	 * @param string $url 目录 
	 * @return 由 / 分开的返回数组 
	 */
	private function ck_dirname($url) {
		$url = str_replace('', '/', $url);
		$urls = explode('/', $url);
		return $urls;
	}
		
	/** 
	 * 关闭FTP连接 
	 */
	public function close() {
		return @ftp_close($this->link);
	}
}
?>

(程式碼來自:http://blog.csdn.net/yanhui_wei/article/details/17616171

 

開始修改文件

首先先修改 user.php,這裡要修改的內容是,當用戶更換頭像時,要自動同步到圖床去。

找到第 357 行:

@fclose($fp);

在下方加上:

/*
	Discuz 自動遠程頭像
*/
include 'ftp.php';
$ftps = new Ftp();
$dir = '遠程目錄';

// 連結 FTP 伺服器
$ftps->connect('伺服器位置', 'FTP帳號', 'FTP密碼', '21', true);

// 上傳檔案
$ftps->put($dir.$this->get_avatar($uid, 'big', $avatartype), $bigavatarfile);
$ftps->put($dir.$this->get_avatar($uid, 'middle', $avatartype), $middleavatarfile);
$ftps->put($dir.$this->get_avatar($uid, 'small', $avatartype), $smallavatarfile);

// 關閉連線
$ftps->close();

說明:

需自行填入圖床的伺服器位置、FTP 帳號、FTP 密碼、遠程目錄,類似剛剛遠程附件填寫的內容,

遠程目錄是你要存放頭像的位置,建議放在 ./data/avatar,注意這裡填寫的目錄,也要注意是否有 public_html、htdocs 等目錄存在

修改完畢存檔上傳,如此一來當用戶更換頭像時,除了本地會跟著新增及更換外,圖床上的圖片也會一起更新了!

 

修改文件後,記得先將本地伺服器目錄 uc_server/data/avatar 下的所有檔案(都是會員頭像),移動到圖床上,注意目錄要和上面填寫的相同。

 

接下來繼續修改 avatar.php,這是調用頭像網址的文件。

找到第 21 行:

$avatar = './data/avatar/'.get_avatar($uid, $size, $type);

若你剛剛設定的遠程目錄不是 ./data/avatar(路徑前綴為 public_html、htdocs 等等除外),這裡的 './data/avatar/' 就要自行更改,

接著在下方加上:

$remoteURL = '圖床網址';

這裡的圖床網址是要實際連結到圖片的網址,必須以 http:// 開頭,不必填寫目錄名,

接著找到第 23 行:

if(file_exists(dirname(__FILE__).'/'.$avatar)) {

修改為:

if(remote_file_exists($remoteURL.$avatar)) {

接著找到第 45 行:

header('Location: '.UC_API.'/'.$avatar_url);

修改為:

header('Location: '.$remoteURL.$avatar_url);

 

最後找到最後一行:

?>

在前一行加上:

function remote_file_exists($file) { // 檢測遠程文件是否存在
	if(preg_match('/^http:\/\//',$file)) {
		if(ini_get('allow_url_fopen')) {
			if(@fopen($file, 'r')) return true;
		}
		else {
			$parseurl = parse_url($file);
			$host = $parseurl['host'];
			$path = $parseurl['path'];
			$fp = fsockopen($host,80, $errno, $errstr, 10);
			if(!$fp) return false;
			fputs($fp,"GET {$path} HTTP/1.1 \r\nhost:{$host}\r\n\r\n");
			if(preg_match('/HTTP\/1.1 200/', fgets($fp, 1024))) return true;
		}
		return false;
	}
	return file_exists($file);
}

修改完後保存上傳,這樣論壇上顯示的頭像就都連結到圖床了!

 

不過若你有開啟「使用靜態地址調用頭像」這功能,要額外修改 function_core.php,讓靜態網址也指向圖床,

開啟檔案,找到第 426 行:

$file = $ucenterurl.'/data/avatar/'.$dir1.'/'.$dir2.'/'.$dir3.'/'.substr($uid, -2).($real ? '_real' : '').'_avatar_'.$size.'.jpg';

修改為:

//$file = $ucenterurl.'/data/avatar/'.$dir1.'/'.$dir2.'/'.$dir3.'/'.substr($uid, -2).($real ? '_real' : '').'_avatar_'.$size.'.jpg';

接著換新行,加上:

$file = '目錄連結網址'.$dir1.'/'.$dir2.'/'.$dir3.'/'.substr($uid, -2).($real ? '_real' : '').'_avatar_'.$size.'.jpg?';

目錄連結網址為圖床網址 + 頭像存放目錄,像以剛剛建議的目錄來說,就是填寫 http://圖床網址/data/avatar/

修改完畢後保存上傳,到此,遠程頭像的功能已經大功告成啦~

 

 

將靜態目錄移動到圖床上

最後要將靜態目錄(static/)移動到遠程伺服器上,

首先將本地伺服器 static/ 目錄下所有的檔案移動到圖床上,

建議也是放到根目錄的 static 資料夾內。

 

接著開啟 config/config_global.php

找到第 48行:

$_config['output']['staticurl'] = 'static/';

修改為:

$_config['output']['staticurl'] = 'http://圖床網址/static目錄名稱/';

將引號裡的內容修改為你剛剛上傳到圖床的目錄連結即可,修改完畢後保存上傳。

 

接著到 Discuz 後台全局>性能優化>服務器優化,找到 JS 文件目錄

選擇自定義目錄,後方填寫 http://圖床網址/static目錄名稱/js,提交後即可。

 

編輯完所有文件後,記得先到後台工具>更新緩存清理一下快取,

這樣一來,所有的遠程工作就已經告一段落了,

但可能有些文件沒辦法完美遠程,要自己手動一一去修改,這裡就不額外提了,

不過這樣應該已經能大幅的降低論壇消耗的資源了!

以上就是本次分享的教學,若有任何問題歡迎提出討論~

想隨時追蹤最新資訊?歡迎使用 RSS 訂閱最新文章 »

您或許會感興趣的文章

隨機推薦

共有 26 則迴響

  1. Mixseilm

    #9 @

    Thank you very much for the invitation :). Best wishes.
    PS: How are you?

  2. upsskeemo

    #10 @

    How do I move a thread to a different topic?
    hi all :)

  3. hornyatkonor

    #11 @

    Hello.

Mixseilm 發表迴響

點擊這裡以取消回覆
*