[教學] 完美將 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. carry

    #1 @

    貌似不行呢....我是x3.2的,我按測試後一直出現訪問url有問題..

  2. carry

    #2 @

    貌似不行呢...我設置後一直出現訪問url有問題...
    測試版本:X3.2 TC UTF-8

    • Lay

      # @

      麻煩提出具體的問題喔,哪個步驟出了問題呢?

      後台的遠程附件測試正常嗎?

  3. PP

    #3 @

    SFTP好像無法使用 :cry: :cry: :cry:
    DZ3.2

    • Lay

      # @

      嗨,沒錯 Discuz 只支援一般 FTP,不支援 SSH~

  4. Lazer

    #4 @

    我也是不行 不知到會不會跟主機不支援遠程附件有關係呢?

    • Lay

      # @

      基本上可以使用 FTP 登入的主機都可以當遠程伺服器喔~

      • Lazer

        # @

        那請問有無可以私下可以與你聯絡的方式呢? 想請你幫我測試看看是哪一個環節有錯誤 導致我無法遠程附件測試成功 謝謝

        • Lay

          # @

          可以直接在這裡回應,我會回覆喔~
          測試時出現錯誤訊息是?

  5. 路過

    #5 @

    您好,請問一下,您說的手機瀏覽的一樣還是本地圖片,是指原本就存在的本地圖片上傳到遠程?還是指設定遠程之後,新上傳的圖片?

    • Lay

      # @

      遠程附件會在附件上傳到本地主機後,透過 FTP 複製一份到遠程主機(所以會有兩份),
      電腦版顯示的是遠程主機上的圖片(靜態圖片網址),手機版是顯示本地主機的圖片(forum.php?mod=image&aid=xxxx),
      這是預設值,如果要修改可能就要從 Discuz 源碼下手~

      • 路過

        # @

        謝謝您回覆,要早點休息哦~ :laughing:
        所以遠程附件是兩邊都上傳,電腦上網讀的是遠程的附件,是這樣吧?
        我以為是全部傳到遠程了...

        • Lay

          # @

          對,本地會保留一份

  6. 不會程式的人

    #6 @

    您好,請問一下,附件上傳如果不使用縮略圖,而是開啟直接把圖縮小...
    那麼,
    圖片是在上傳之前被電腦端或手機端壓縮後,才上傳?
    還是上傳之後,由租用的主機端做壓縮縮圖的動作?

    • Lay

      # @

      不太懂你的意思,Discuz 好像沒有只壓縮圖片的功能吧?
      只有要不要產生略縮圖的選項,如果不產生略縮圖那就是直接保存原圖。

      • 不會程式的人

        # @

        我是開啟「直接縮放原圖」,上傳後,附件不留原圖,只有縮小後的圖,主機存放的資料夾(data/attachment)裡也找不到原圖,只有縮小後的圖。

        所以,不知道是怎麼壓縮的...,如果是上傳到主機才壓縮,怕吃流量...。如果電腦或手機端壓縮後才上傳,就不擔心流量了...

        • Lay

          # @

          那可能就要針對這部分直接改 Discuz 本身的系統文件了。

  7. Calvin

    #7 @

    您好,v3.4-20191201 版本中的 avatar.php 有更改過代碼,導致第 23 行找不到,請問這部份要怎麼修改呢?謝謝。

    • Lay

      # @

      現在應該在第 27 行:
      if(file_exists($avatar_file)) {
      更改為:
      if(remote_file_exists($remoteURL.$avatar)) {

  8. Calvin

    #8 @

    感謝回覆,已設置成功。

    另外還有個問題想請教的,我本來是使用 X3.2 版本,設置 HTTPS 都正常的。
    最近升級到 X3.4 之後,頭像那邊依然使用 HTTP,網絡搜尋得知改成「使用靜態地址調用頭像」就正常了,
    但是又變了第二個問題出現......就是如果會員沒有上傳頭像的話都會顯示死圖,並沒有調用到顯示默認頭像,
    而我把頭像改成遠程之後,查看沒有上傳頭像的會員連結,發現變成 http://圖床/data/avatar/000/00/25/19_avatar_big.jpg
    可是他就沒有上傳頭像呀,這個連結是404也是正常,請問要怎樣才能正常顯示默認頭像呢? :thinking:

    • Lay

      # @

      1. http 的問題應該要找一下跟 avatar 有關的函式,可能是 ucenter url 沒有改成 https
      2. 404 的問題可以用 onerror="this.src=''" 這種方式讓無法載入的圖片載入預設圖,可以參考文中 function_core.phpavatar() 最後一行 $returnsrc

      • Calvin

        # @

        頭像的 HTTPS 問題終於解決了,原來 avatar.php 有一處需要更改。

        不過我再次依教學設置,還是不成功,在頭像使用動態地址的情況下,設置完之後全部人的頭像都變成預設的,
        而在靜態地址的情況下,依然像上面所說的,預設頭像變成死圖,已經參考了 function_core.php $returnsrc 的改法。

        看來我要放棄把頭像設成遠程了,不過還是感謝 Lay 耐心回覆。 :laughing: :thumbsup:

Lay 發表迴響

點擊這裡以取消回覆
*