2007年01月3日

將資料和程式分離

有位 jocosn 網友問了一個我覺得很棒的問題,我把我的觀點提出來供大家參考。

註:以下我會以引用區塊的方式來標示該網友的問題,然後以回答該問題的語氣說明。且基於本人龜毛的個性,也會把內容稍作排版。

如果我有一個 welcome.php,它的樣版檔是 welcome.tpl.htm,但是兩個檔案的編碼不相同,也就是 php 使用 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> , tpl.htm 使用 <meta http-equiv="Content-Type" content="text/html; charset=big5">,結果螢幕顯示時會以 utf-8 編碼格式顯示 tpl.htm 檔案,必須再手動挑選 big5,請問這種情況有辦法解決嗎?還是程式這種架構有問題?

使用 big5 是因為 tpl.htm 檔案有用到 mailto,像這樣:

<a href='mailto:h...@yahoo.com.tw?subject=其他問題&body=問題描述:%0A%0A%0A%0A聯絡方式%0A地址:%0A電話:%0A聯絡人:%0A'>寫信連絡</a>

如果改用 utf8,點下 mailto 開啟 outlook 6 會出現亂碼。所以採用 big5 才會正常顯示中文字。但是 php 檔案因有些部份未使用樣板處理一些簡單的小訊息 (如顯示"檔案建立成功") ,所以採用 utf8,以免顯示中文像「功」字會出現問題。

像這種情況下,請問該怎麼處理,或是有更好的解決方式嗎?

事實上你的 template 還是可以用 utf-8 的,只不過有些地方要做一些手腳。

在這之前,先給你一個觀念:把資料和程式分離。怎麼說呢?直接給你看例子好了:

首先我把 mailto 會用到的中文字另存成一個 ini 檔:

[mailto]
subject = "其他問題"
body = "問題描述:\n\n\n\n聯絡方式\n地址:\n電話:\n聯絡人:\n"

特別要注意的是,這個 ini 檔是用 big5 來存檔的。

然後我在 index.php 裡把它載入:

<?php
$mailto = parse_ini_file('mailto.ini');
  
$subject = urlencode($mailto['subject']);
$body = str_replace('%250A', '%0A', urlencode(str_replace('\n', '%0A',  $mailto['body'])));
  
include('template.php');

這邊要特別注意的是 php 檔是用 utf-8 來存檔 (事實上你也可以用 ANSI 來存) 。

最後來看看 template.php :

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>測試 mailto</title>
</head>

<body>
<a href="mailto:jxxxxxxxxx@gmail.com?subject=<?php echo $subject; ?>&body=<?php echo $body; ?>">寫信連絡</a>
</body>
</html>

這裡一樣也是用 utf-8 存檔。

執行它看看,跑出來的結果是不是符合你的需要呢?

這裡就導出一個觀念了: PHP 在處理資料時,其程式檔案的編碼是不會影響資料本身的編碼的。

在上面的例子裡, parse_ini_file 取得的資料就是 mailto.ini 本身的編碼 (也就是 big5) ,而 PHP 也不會因為自己的檔案編碼是 utf-8 而改變 parse_ini_file 所取得的資料編碼。因此這時候的「其他問題」和「問題描述...」都能夠用在 template 上...

不過等一下,如果你直接把 $mailto['subject'] 和 $mailto['body'] 套入 template.php 的話,那就慘了。為什麼呢?因為 big5 編碼的內容在 utf-8 編碼的網頁裡,瀏覽器不知道該怎麼解釋它們 (也就是一堆亂碼啦) 。所以這裡我們要利用 urlencode 這個函式,來將 big5 的文字做 URL 編碼。

至於 \n 的部份只是個表示方式,實際上我們還是要手動將它換成 %0A (雖然我換的方式還滿醜的) 。

當然不只是文字檔案,就連資料庫中取出的資料也是相同的道理。這點你可以參考我先前寫的 MySQL 中文編碼徹底研究,裡面有詳細的內容。

再請問,如果用 smarty 時,php 檔案是不是應該儘量只有 php 程式碼?

依照上面的觀念,你認為我這裡會給什麼樣的答案呢?想想看吧 :)

另外 php 檔案存成 utf-8 或 big5 有差嗎?還是說網頁儘量不要存成 big5,以免特殊中文字會出現錯誤?

例如 php 檔案中像這樣 $mysmarty->assign('myVar1','許蓋功') ,存成 big5,我在測試時,就會出現錯誤 Parse error: parse error, unexpected T_STRING

PHP 引擎會對 <?php ?> 裡面的特殊字元很敏感,所以上面的觀念一樣適用在這裡;當然如果是在 <?php ?> 外的話 (通常是 HTML ) 就沒問題了。

希望上面的說明能讓你清楚相關的觀念 :)



Posted by jaceju at 樂多Roodo! │16:38 │Web 開發
樂多分類:網路/3C 共同主題:PHP 程式設計 工具:編輯本文
Ads by Roodo! 
回應文章
感謝 jaceju 大這麼精彩的解法,還特別加以重新排版,很感動。
Posted by jocosn at 2007年01月3日 23:56
等等 我記得
$body = str_replace('%250A', '%0A', urlencode(str_replace('\n', '%0A', $mailto['body'])));

寫成 '\n' 是沒有作用的吧?
好像應該寫成 "\n"才對
Posted by sdcgf at 2007年01月26日 04:05
To sdcgf:

你要從上到下看完我說明的文字呀!

這裡的 \n 只是用來表示換行意義的,不是真的換行字元,所以不用雙引號。
Posted by jaceju at 2007年01月26日 08:59
嗯 抱歉是我耍寶了

另外 記得以前可以在html網頁裡面插入一種代碼
例如 title="name[代碼]pass"
用瀏覽器看之後 會變成

name
pass

跟\n不盡相同的東西
突然忘了那個代碼是什麼 請問站長知道嗎?
Posted by sdcgf at 2007年02月9日 04:37
thunderbird 不能用 urlencode 有其他方法嗎?
Posted by micmic3 at 2007年08月7日 17:56
To mimic3:

目前沒有用 ThunderBird 耶,我有空試試看好了。
Posted by jaceju at 2007年08月7日 18:35