做網站,我們是認真的!

網站適配電腦+手機端,僅1280元,送2000M阿里云服務器,送com域名+免費備案
網站前端采用靜態系統顯示,后端動態管理,我們承諾網站包收錄,完成網站之后把源碼給客戶!

觀點

互聯網+時代,說建站,談運營與網絡營銷

織夢dedecms文件上傳功能分析教程

時間:2020-12-21

織夢dedecms系統里面的上傳功能比較多,例如有友情連接里的logo上傳、模塊管理里面的上傳模塊和模塊打包、發布新圖集里面的上傳圖片集、發布新軟件里的上傳本地文件、附件管理里面的上傳新文件、文件式管理器里面的文件上傳、織夢會員中心里面的軟件上傳和縮略圖等等,在織夢里面的文件上傳功能到處都有應用。

  我們分析三個有代表性的,一個是logo上傳,這個是一般的應用,但相對復雜一點;另一個是附件管理時面的上傳新文件,這二個一個共同特點是上傳的文件都要保存到數據庫里面,第三個是文件式管理器里面的文件上傳功能,這個與我們之前的教程“php文件(單文件和多文件)上傳詳解教程”講的一樣,都是簡單的上傳文件,沒有用到數據庫知識,我們就以這三個為例子,其它的上傳跟這三個可以說大同小異。

  要分析這三個文件讓傳功能,需要對織夢dedecms文件上傳處理方式,織夢與我們在php文件(單文件和多文件)上傳詳解教程里看到的文件上傳是很不一樣的,畢竟,織夢系統是一比較成熟的cms系統,織夢處理文件上傳,不像我們看的教程一樣寫一個文件就可以了,因為,織夢系統里面用到的文件上傳很多,不光是織夢系統,其它系統一定會用到文件上傳,只要是網站就會用到文件上傳功能。

  織夢是如何處理文件上傳的呢?要了解這個我們就要分析一下文件上傳的共同點,然后,把這公共部分放在一個文件,然后,其它上傳文件就直接引用這個文件就可以了,這樣其它每個上傳功能如logo上傳,圖片集上傳,軟件上傳等各自寫適合自己的代碼,然后,再引用公共部分即可。這種思想正是函數產生的思想,什么是函數簡單而言之,就是把公共功能寫成一段代碼,其它,需要這個功能時直接調用,而本篇講的文件調用也正是如此。

  織夢dedecms文件上傳公共部分在根目錄(http://www.dedebase.com這就是根目錄,如果你在本地的話根目錄就是http://localhost)/include/uploadsafe.inc.php,對就在uploadsafe.inc.php文件里面,這個引用文件功能是:“轉換上傳的文件相關的變量及安全處理、并引用前臺通用的上傳函數?!?。

  織夢是如何把這個文件配置到要引用它的文件里的呢?首頁,要在/include/common.inc.php里面,寫一句如下代碼:

if($_FILES)
{
    require_once(DEDEINC.'/uploadsafe.inc.php');
}

  這段代碼的意思就是,當要上傳文件時,就引用文件uploadsafe.inc.php,如果我們打開例如logo上傳文件friendlink.add.php你會發現,沒有這個uploadsafe.inc.php文件,是的,織夢還配置了一個在根目錄/dede/里面的config.php文件,這個是后臺根目錄/dede/所有php文件共有的,如果你隨便打開個文件,你會發現都引用了這個文件,這個config.php不僅僅包括了上傳文件,還包括了數據庫連接等很多織夢程序所必備的內容。為什么這樣包涵來包涵去?還是為了開發方便,試想如果我們把這些文件里的東西都寫進friendlink.add.php里面,那文件得多大啊,更重要的是重復寫相同的內容,不利于開發。

  我們就拿logo上傳為例子這些文件是這樣相互包括的:friendlink.add.php 引入config.php,config.php引入common.inc.php,common.inc.php引入uploadsafe.inc.php。這樣無論friendlink.add.php如何改變都不影響后面的文件,有利于開發。

  現在我們就要分析一uploadsafe.inc.php是如何轉換上傳的文件變量即$_FILES及安全設置的。

  打開uploadsafe.inc.php文件,找到foreach($_FILES as $_key=>$_value)這句,這句前面是設置強制哪些文件類型可以上傳,并設置了一個數組$keyarr = array('name', 'type', 'tmp_name', 'size');數組$keyarr值正是$_FILES的鍵,這是為后面進行數組遍歷作準備。還對是不是通過編輯器上傳作了判斷。

  在foreach($_FILES as $_key=>$_value)后面是重點了,通過foreach($_FILES as $_key=>$_value)我們可以得到$_key,這個$_key正是我們表單里面的類型為file的name屬性值,這一點非常重要。這句foreach($_FILES as $_key=>$_value)代碼就是為了得到這個$_key。為了進一步說明這個$_key我們把$_FILES數組存儲的內容分析一下,這里以單個文件上傳為例子,多個文件一樣。$_FILES存儲的內容如下。

  Array
(
    [upmyfile] => Array
        (
            [name] => 1440x900wolf.jpg
            [type] => image/jpeg
            [tmp_name] => D:\APMServ5.2.6\tmp\uploadtemp\php6B1.tmp
            [error] => 0
            [size] => 160666
        )

)

  這句代碼foreach($_FILES as $_key=>$_value),正是為了獲得這個$_key就是$_FILES里面的upmyfile。接下來我們就要得到name,type,tmp_name,error,size了,我們完全可以再遍歷一下$_value,因為$_value又是一個數組,包括這些內容,但是大家想一下,這只是單文件上傳,如果是一個多文件上傳,是不是比較重雜?是的,織夢想到了一好辦法就是先定義一個$Keyarr數組,直接從這個數組里面獲取name,type,tmp_name,error,size,既簡單,又方快速。

  代碼foreach($keyarr as $k)這句正是為了獲取name,type,tmp_name,error,size內容。

  接下來這句代碼$$_key = $_FILES[$_key]['tmp_name'];是這個uploadsafe.inc.php里面的重中之重,這個代碼的等價于$upmyfile = D:\APMServ5.2.6\tmp\uploadtemp\php6B1.tmp;以后,我們在引用uploadsafe.inc.php這個文件的文件里看到類似$upmyfile就等于是$_FILES[$_key]['tmp_name']即上傳文件臨時文件名,同理

  ${$_key.'_name'} = $_FILES[$_key]['name'] 等價于 $upmyfile_name = $_FILES[$_key]['name'] = 1440x900wolf.jpg。

  ${$_key.'_type'} = $_FILES[$_key]['type'] 等價于 $upmyfile_type = $_FILES[$_key]['type'] = image/jpeg。

  ${$_key.'_size'} = $_FILES[$_key]['size'] 等價于 $upmyfile_size = $_FILES[$_key]['size'] = 160666。

  之所以通過以上方式處理,就是為了在引用uploadsafe.inc.php文件的文件里面,不出現類似$_FILES[$_key]['size']這樣長的代碼。

  后面的代碼就是對文件上傳的文件名是不是空,是不是我們允許的文件后綴,文件名是不是少個點進行判斷;對文件大小是不是0,如果是我們通過系統函數filesize()獲取,如果更加詳細的判斷還要判斷一下,用戶上傳的內容是不是超出了我們設置的大小,是不是超出了服務器設置的大小,但織夢沒有判斷在上一個教程“php文件(單文件和多文件)上傳詳解教程”我們已經作了詳細判斷。

  最后,對上傳的文件類型進行判斷,強制使用我們設置的文件類型。

  總結:uploadsafe.inc.php用到的系統函數有是否存在函數etmpty(),通過正則來判斷是否匹配preg_match(),檢查數組中是否存在某個值in_array(),將字符串轉化為小寫strtolower(),去除字符串首尾處的空白字符(或者其他字符)trim(),preg_replace — 執行一個正則表達式的搜索和替換等函數,現在我們對uploadsafe.inc.php這個文件已經分析完了。

  一、logo文件上傳如下圖所示。
織夢dedecms文件上傳功能分析教程

  現在我們分析以上傳logo文件,logo上傳處理文件是friendlink.add.php,對應的模板文件是friendlink.add.htm模板文件我們就不用多說了,都是一些html代碼,我們只要找到模板中這二句(簡化后):

  網站Logo: <input name="logo" type="text" id="logo"/>
   
  上傳Logo: <input name="logoimg" type="file" id="logoimg" />

  我們打開friendlink.add.php文件,程序首先用if(is_uploaded_file($logoimg))判斷一下上傳的文件是不是通過http post上傳的?如果是說明是通過本地上傳的logo,也就是上面的<input name="logoimg" type="file" id="logoimg" />這個選擇框上傳的,如果不是則是通過<input name="logo" type="text" id="logo"/>,直接在這個文件框寫上的logo地址。

  若if(is_uploaded_file($logoimg))成立則程序向下執行,注意這句代碼里面的$logoimg指什么?正常的文件框的話,當然是通過$_POLST獲得的,例如上面二行中的網站Logo:就是通過$_POST獲取值,而上傳logo即$logoimg則不是通過$_POST獲得,而是通過$_FILES獲得的,也就是我們在uploadsafe.inc.php里面分析的$upmyfile = D:\APMServ5.2.6\tmp\uploadtemp\php6B1.tmp,只不過現在的$upmyfile變成了$logoimg即,$logoimg = D:\APMServ5.2.6\tmp\uploadtemp\php6B1.tmp。

  如果你看明白了這點,那么,下面的$logoimg_name、$logoimg_type、$logoimg_size分別對應上傳文件的文件名、上傳文件的類型、上傳文件的大小了。那下面的代碼就比較容易了,這是難點也是重點。

  代碼$names = split("\.", $logoimg_name);意思是把上傳的文件名通過正則匹配,模式是通過點分成二部分,存放在數組$name中。

  我給織夢挑一個不算錯誤:函數preg_split()比split()快,而explode()在這三個中運行速度最快,前二個需要正則表達式,最后這個explode()則使用字符串分割。他們三個都返回數組,所以,這里應當換上explode()最好了,我們做個測試一下,看看返回結果。

   $name = "1440x900wolf.jpg";
 $a = split("\.", $name);
 $b = split("\.", $name);
 $c = explode(".",$name);

 print_r($a);

 echo "<br />";

 print_r($b);

 echo "<br />";

 print_r($c);

  這段代碼返回的結果是:

Array ( [0] => 1440x900wolf [1] => jpg )
Array ( [0] => 1440x900wolf [1] => jpg )
Array ( [0] => 1440x900wolf [1] => jpg )

  這充分說明了返回的結果是一樣的,所以,建議大家能用explode()就用這個。

  回到friendlink.add.php文件里,$shortname = ".".$names[count($names)-1];這句里面的$names[count($names)-1]獲取文件類型名,例如上面的例子jpg。整句就得到了.jpg。

  下面這個判斷語句用來判斷,我們上傳的文件名是不是我們允許的,是不是jpg,gif,png,若不是則直接改后綴名為.gif。
    if(!preg_match("#(jpg|gif|png)$#", $shortname))
        {
            $shortname = '.gif';
        }

  下面這句,是對文件名進行重新命名,這樣是為了防止,不同的用戶上傳相同的名子后,前面的會被后面的覆蓋掉。

  $filename = MyDate("ymdHis", time()).mt_rand(1000,9999).$shortname;

  下面這句是設置文件上傳路徑,其中$cfg_medias_dir附件上傳路徑,在common.inc.php已經定義。

  $imgurl = $cfg_medias_dir."/flink";

  下面這句判斷是不是目錄,不是則建立,其中$cfg_basedir是根目錄,$cfg_dir_purview是權限,在common.inc.php已經定義。

          if(!is_dir($cfg_basedir.$imgurl))
        {
            MkdirAll($cfg_basedir.$imgurl, $cfg_dir_purview);
            CloseFtp();
        }

  下面這句是要把臨時文件轉移到對應路徑和文件名。

  $imgurl = $imgurl."/".$filename;

  移動文件:下面這個函數是重點,我們上面所做的工作完全就是為這個文件轉移函數服務的。

   move_uploaded_file($logoimg,$cfg_basedir.$imgurl)
 
  刪除臨時文件@unlink($logoimg);@這個抑制符意思是不顯示錯誤。

      //強制檢測用戶友情鏈接分類是否數據結構不符
    if(empty($typeid) || preg_match("#[^0-9]#", $typeid))
    {
        $typeid = 0;
        $dsql->ExecuteNoneQuery("ALTER TABLE `dede_flinktype` CHANGE `ID` `id` MEDIUMINT( 8 ) UNSIGNED DEFAULT NULL AUTO_INCREMENT; ");
    }
 
  這句看似不重要,實際上這句非常重要,如果這個$typeid錯誤,直接導致,logo出問題。

  現在就要把友情鏈接添加到數據庫了,請注意我們上傳的logo是把路徑保存到數據庫里面的,而不是把圖片保存到數據庫里面,有沒有把圖片保存到數據庫里面的?有,以前聽老師講課時,講到過,但是極少,一般都是保存圖片路徑的,這樣程序只需要查詢一下數據庫就知道圖片在哪里了,目前,本人從沒有見過圖片保存到數據庫里的。

  目前為止,我們已經把logo上傳分析完了。


  二、附件管理——>上傳文件如下圖所示。

織夢dedecms文件上傳功能分析教程
  與logo文件上傳功能相比,這個文件上傳功能需要標題,附加參數,還有一個最大的不同就是,這個功能可以批量上傳文件,而且不僅僅是圖片,還有flash,音頻/視頻等。多文件上傳,與單文件上傳沒有多大區別,只不過在單文件上

傳的基礎上曾加個循環而已。

  重點看這三句代碼

  $filesize = ${"upfile".$i."_size"};
  $upfile_type = ${"upfile".$i."_type"};
  $upfile_name = ${"upfile".$i."_name"};

  這不正是我們在upoadsafe.inc.php里面重點分析的嗎,在上傳logo功能里我們也作了分析,這里不再作過多分析。從代碼for($i=0; $i<=40; $i++)開里,當條件if(isset(${"upfile".$i}) && is_uploaded_file(${"upfile".$i}))成立,即已經上傳了文件并且是通過http post上傳的,那么,程序就判斷上傳文件類型在不在我們前面定義的二個數組$sparr_image,$sparr_flash里面,如果在則設置存儲路徑$savePath,若不存在就建立路徑,若是非flash類型則打上水印,接下來沒有問題,就把數據插入到數據庫表dede_uploads,在這個處理程序中用到了取得圖像大小的函數getImagesize(),這個函數,不僅可以獲得圖像的大小,還有高、寬、字節大小、mime類型,為什么要用這個函數?
因為,我們后面的保存數據到數據庫表時,要保存高和寬。

  三、文件式管理器 ——>上傳文件分析如下圖所示。

織夢dedecms文件上傳功能分析教程

  文件file_manage_control.php就是對上傳的文件進行處理的程序,這個更簡單,既不用把上傳的文件路徑插入到數據庫,也不用作過多的判斷,代碼非常簡單。它與logo相比多了多個文件上傳,與附件管理文上傳,少了不需要保存路徑,連上傳的文件名都不用改,直接用if(!file_exists($cfg_basedir.$activepath."/".$upfile_name))來判斷是不是上傳的文件名與已經有的文件名重名,結束。

  總結:我們總結一下,如果讓我們自己開發一個上傳文件功能,如何開發?

  開發上傳文件程序步驟:

   1.設置限制文件類型,一般用數組來設定。
 
   2.判斷文件大小,判斷錯誤友好提示信息。

   3.處理$_FILES文件里面的內容,像織夢那樣專門做個程序文件upoadsafe.inc.php。

   4.用函數is_uploaded_file()判斷上傳的臨時文件是不是存在,存放則移動文件,用到的函數是move_uploaded_file()。

   5.若要保存到數據庫,則插入數據庫表。

   6.多個文件處理,這個要用到js,或jquery。使上傳效果更酷。
0
首頁
案例
關于
聯系
凯时平台