分類彙整: 網路科技

從 Media Center 上市漫談 DVR 與 EPG 的結合

微軟正準備從您家裡的書房攻佔您家的客廳 - Media Center 中文版正式上市了!

Media Center 全名為 Microsoft Windows XP Media Center Edition 2005
這是微軟所最新推出、整合各項家庭娛樂裝置的作業系統

Media Center 除了具備原有 Windows XP 的所有功能之外,還加上整合電視節目錄影、播放等功能,以及專為遙控器設計的操作介面

事實上,單純影音的錄製與播放在原本的 Windows XP 配合電視卡、電視盒等也可以運作得很好,同時,市面上也有很多 DVR (Digital Video Recorder) 數位錄影機或者 DVD 錄放影機等廉價的單機解決方案

這些方式都可以直接錄製電視節目,並可提供預約錄影、邊看邊錄、即時倒帶的功能

不過,在國內,DVR 距離真正普及還是有一大段路要走,因此微軟的 Media Center 還是有一些的機會可以獨占市場

有一個蠻重要的關鍵在:「電視節目錄影」缺少了一個很重要的輔助功能!

有人可能會懷疑:「不就只要能錄影就好了嗎?」

TiVo 是 DVR 這一個市場(主要是北美地區)的成功範例

TiVo 有販售自己的 DVR,它叫做 TiVo Box,系統是跑 Linux,內含一顆硬碟,拆開內部其實跟一般 PC 差不多..

TiVo Box 的單機零售價格大約在 200 美元左右 (可錄製 40 小時節目),不過如果配合特定綁約一年的優惠方案,一台只要不到 49.99 美元

這台機器擁有一般市面上 DVR 錄放影機的全部功能,擁有預約錄影、邊看邊錄等各種功能

這麼便宜的價錢,想當然 TiVo 不會是靠賣這台 DVR 賺錢的,甚至,這台機器應該是賠錢在賣的

那 TiVo 靠什麼賺錢呢? 它靠的其實是每個月收 12.95 美元的 TiVo Service

TiVo Service 是什麼呢? 其實它最主要就是一份「電子節目表」的各式應用 (EPG – Electronic Program Guide)

傳統的單機 DVR 如果要作預約錄影,你要先自己查閱紙本節目表或從網路搜尋資料,找到自己有興趣的節目後,把節目頻道編號及播放起迄時間記下來,最後再手動到 DVR 裡面設定預約錄影

而 TiVo 把節目表與 DVR 結合在一起,TiVo Box 的機器上面有個 RJ11 電話線插孔,每天深夜 TiVo Box 會自己撥接上網,去下載及更新最近兩週的電視節目表

如果你有寬頻,不想使用撥接方式,也可以另外購買 USB 的有線或無線的網卡來下載節目表

TiVo Service 會依據您設定的地區有線電視(第四台)業者資訊,自動把頻道號碼與節目表作連結,例如 HBO 電影頻道,A 業者放在 65 台,而 B 業者可能就放在 66 台

在有了 EPG 的資訊之後,TiVo Box 就可以提供各種強大的索引功能了

你可以像一般操作電視遙控器一樣,用 TiVo 提供的遙控器來轉台。但是不同的地方是,每轉到一個頻道,TiVo 都會告訴你現在正在播放的節目名稱是什麼、播放起迄時間,甚至主要演員是誰以及電影的大綱介紹,當然下一個節目是什麼、何時開始也不會錯過

你可以在螢幕上查看任何時間任一個頻道的節目表,也可以依據各類分類索引功能,來找到你喜歡的節目

你不需要手動設定錄影起迄時間,只要用上下左右按鈕選擇你想錄影的節目名稱,按下預約錄影按鈕,就可以設定好預約錄影了!

你還可以直接設定針對某個帶狀節目作錄影,例如假設你很喜歡「民視異言堂」這個節目,只要稍微設定一下,就會不漏掉任何一集而把每個禮拜的「民視異言堂」都錄下來,不需要辛苦地每個禮拜去作設定,即使某一個禮拜節目時間有更改也不怕,只要你有定期更新 EPG

這就是 EPG 的強大威力,通常體驗過 TiVo 的 EPG 整合服務後,都很難忘懷它的功能

TiVo Service 的定價是每個月 12.96 美元,或者你也可以一次付清 299 美元終身有效,同時,除了 TiVo Box 之外,也有其他廠商(如 Sony、Toshiba 等)販售支援 TiVo Service 的 DVR

沒有訂閱 TiVo Service 的 TiVo Box 也是可以正常運作,不過就會少了很多輔助的資訊

在北美地區,事實上也有不需月費的 EPG 可以接收,有部分 DVR 就支援接收這些 EPG 資訊來源,不過 EPG 的品質可能仍比不上 TiVo Service 來得正確與完整

國內目前一直還沒有大規模的 EPG 應用,據說未來的數位電視廣播將會內建 EPG 資訊,如果連上百個頻道的有線電視也能提供這個電子節目表,那 VOD、MOD、互動電視等這些推好些年、卻仍發展不起來的服務,更將面臨極大的考驗

儘管 DVR 加上電子節目表,功能不同於 VOD/MOD 及互動電視,但是其實已經可以滿足大多數人的需求看電視就是要來休閒的,大多數人看電視還是習慣被動式的隨機接收,不習慣主動式的互動操作功能

看電視還是要能夠享受亂轉遙控器的快感才對啊!而如果能配合 EPG,這種快感更會加倍!

就如同絕大多數的人拿手機就是來講電話,什麼照相、發送簡訊甚至上網功能根本就用不到啊!

在上面一長串介紹過 TiVo DVR 的功能之後,回到本篇的主題,微軟的 Media Center 其實和市面上販賣的 DVR 機器一樣,如果缺少了對 EPG 的支援,就好像失去了靈魂一樣

只是多了一個錄影功能,而且可能還是只有少數人會設定的錄影功能,絕大部分的人只會用遙控器來選台和調大小聲,更複雜的功能即使有說明書也不想看或看不懂

而你家有線電視每個月贈送的那本節目表,可能也不曉得被你丟到哪去了

有了 EPG,操作錄影功能可以更加簡單,這才是決戰客廳的市場真正起飛的時候

期待有一天在台灣可以看到具備 EPG 功能的 DVR 出現!

最後,關於 DVR+EPG 的美夢,除了技術問題,其實還是有很多障礙

首先就是,DVR+EPG 有很多各式各樣的專利,一個不小心可能就會採到地雷、被告到脫褲子 XD 另外就是由於 DVR+EPG 直接提供了針對節目的錄影功能,有可能被影片商或頻道商告上法庭,但風險應該沒有像早期的 Napster 那麼高就是了

【本文轉載前,請先取得作者同意,謝謝!】

WebAMP 改版囉

WebAMP 改版囉,這一次改版多了很多新功能,網站首頁也變得比較專業一點了… 之前的實在有點醜 XD

最重要的功能就是新增加 webamp.cc 的免費網域名稱,每個註冊的網站都可以獲得一組免費的網域名稱,名字可以自己取,只要不要跟別人重複就可以了… 所以沒有買網址的個體戶也可以架站了

然後還有一個大改進就是,就算你的網站架設在免費網頁空間裡面,也一樣可以提供服務喔

例如你的網頁空間網址是: http://home.kimo.com.tw/XXXXX/
那你可以針對此網址申請一個 WebAMP 服務,並同時設定一個 webamp.cc 免費網址(例如 XXXXX)

如此一來,您就可以用 http://XXXXX.webamp.cc/ 來連結您原來的網址,同時享受到 WebAMP 流量超頻的好處,而不需要擔心流量超過限制而被停用

改版後管理網頁裡面也增加一些新功能,例如防盜連等,這邊就不再贅述,有興趣的人可以來玩看看

URL 含中文路徑名稱的終極解法

URL 含中文路徑名稱的終極解法 – 利用 mod_fileiri 解決中文檔名問題

當然,對付中文檔名問題的最好的解決方法就是「絕對不要用中文檔名」,然而在許多不得已的狀況下,我們還是被迫要使用中文檔名,這時候問題就來了….

在 Web Server 上使用中文檔名最常遇到的問題就是會發生無法存取的錯誤

發生這種狀況最主要的原因就是在 URL 的定義當中,並沒有任何關於字元集(Charset)的資訊。只有要求對於 URL 中的非 ASCII 符號,要用百分比符號的方式去編碼 (例如: %A4 )

舉個例子來說,對於下面這個含中文檔名的 URL

http://bbs.giga.net.tw/fileiri/中文.html

由於「中文」兩個字並非合法的 ASCII 字元,因此當你在瀏覽器的網址列輸入上面這串 URL 時,瀏覽器會把非 ASCII 字元部分轉換成 %HH 的形式輸出
(關於 URL 的編碼方式,可參閱 Non-ASCII characters in URI attribute values 一文的說明)

但是,URL 中的中文字到底要用 BIG5 還是用 UTF-8 字元集來表示並編碼呢?

在微軟的 IE 裡面,工具→網際網路選項→進階 有個選項「永遠將 URL 傳送成 UTF-8
如果是英文版則是「Always send URLs as UTF-8

這個選項打勾的時候(這也是大部分電腦內定的狀況),URL 中的中文字會被當成 Unicode,並用 UTF-8 編碼方式送出,因此 URL 會被瀏覽器偷偷轉成:

http://bbs.giga.net.tw/fileiri/%E4%B8%AD%E6%96%87.html

也就是說,「中文」這兩個字會被瀏覽器用 UTF-8 編碼成「%E4%B8%AD%E6%96%87」的型式後,再把這個編碼過的 URL 送去給伺服器

大部分的中文字用 UTF-8 編碼會變成 3 個 bytes,所以「中文」兩字就變成上面這 6 個 bytes 的編碼「%E4%B8%AD%E6%96%87

但如果前述的「永遠將 URL 傳送成 UTF-8」選項是沒有打勾的,那情況就不一樣了,
這時候 URL 中的中文字會以 BIG5 的形式編碼送出,URL 就會變成這樣:

http://bbs.giga.net.tw/fileiri/%A4%A4%A4%A5.html

每個中文字用 BIG5 編碼會變成 2 個 bytes,所以「中文」這兩個字就變成上面這 4 個 bytes 的編碼「%A4%A4%A4%A5

這是在用戶端瀏覽器的亂象,不同的瀏覽器或甚至只是不同的設定,對同樣中文檔名所送出的 URL 編碼格式都可能會不一樣

那伺服器收到這串 URL 要怎麼處理呢?

如同前面所述,URL 網址本身並不含字元集(Charset)的資訊,因此伺服器當然也無法知道用戶端瀏覽器採用那個字元集來對 URL 中的中文檔名解釋、編碼

所以伺服器的標準動作就變成「收到什麼檔名就去讀什麼檔案」

收到 UTF-8 編碼的 URL,就用這個 UTF-8 的檔案名稱去 File System 找檔案,收到 BIG5 編碼的 URL,就用這個 BIG5 的檔案名稱去 File System 找檔案

所以如果檔案系統中的檔名是採用 UTF-8 編碼,那用 BIG5 編碼的 URL 去找檔案就會找不到… 相反的,如果檔案系統中的檔名是採用 BIG5 編碼,那麼用 UTF-8 編碼的 URL 也會找不到檔案!

尤其在 Apache/UNIX 的環境下,從 Windows 用 FTP 把檔案上傳時,中文檔案名稱大多會使用 BIG5 的檔名格式上傳儲存

所以大多數這類的系統都會要求用戶不要在上述「永遠將 URL 傳送成 UTF-8」這個選項打勾,這樣存取 BIG5 的中文檔名就不會有問題了

不過,這種方式不是很友善,對於大多數的網友而言,要去改瀏覽器設定是很不方便的!

那有沒有辦法讓瀏覽器不用更改設定就可以完美解決呢?

其實是有的,那就是這篇文章要介紹的 mod_fileiri 這個 Apache module

mod_fileiri 的最主要功用就是讓伺服器可以想辦法去判斷 URL 的編碼,然後幫忙做轉碼、轉址的動作,讓伺服器可以同時處理 UTF-8 及其他字元集的 URL 編碼

以下是在 FreeBSD 下安裝及設定 mod_fileiri 的方法:

首先是從 CVS 中取得這個 module:

# fetch http://dev.w3.org/cvsweb/~checkout~/apache-modules/mod_fileiri/mod_fileiri.c

然後用 apxs 來編譯及安裝這個 module… (請用 root 身份執行)

# /usr/local/sbin/apxs -i -a -c mod_fileiri.c
/usr/local/share/apache2/build/libtool .....
/usr/local/share/apache2/build/libtool .....
/usr/local/share/apache2/build/libtool .....
cp .libs/mod_fileiri.so /usr/local/libexec/apache2/mod_fileiri.so
----------------------------------------------------------------------
Libraries have been installed in:
   /usr/local/libexec/apache2

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,--rpath -Wl,LIBDIR' linker flag

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
grep: /usr/local/libexec/apache2/mod_fileiri.la: No such file or directory
grep: /usr/local/libexec/apache2/mod_fileiri.la: No such file or directory
Warning!  dlname not found in /usr/local/libexec/apache2/mod_fileiri.la.
Assuming installing a .so rather than a libtool archive.
chmod 755 /usr/local/libexec/apache2/mod_fileiri.so
[activating module `fileiri' in /usr/local/etc/apache2/httpd.conf]

apxs 不但會產生 mod_fileiri.so 並把它複製到 /usr/local/libexec/apache2/ 下面,
甚至還會幫你把 httpd.conf 的設定改好喔!

然後你只要重新啟動 Apache 就完成了,簡單吧!

# /usr/local/etc/rc.d/apache2.sh restart

接下來就要開始設定 mod_fileiri 的工作了…

mod_fileiri 有三個 directives 可用,分別是 FileIRIFilenameCharsetOldFilenameCharset,位置可以放在 Server Config / Directory / Virtual Host 裡面,甚至 .htaccess 裡面也可..

FileIRI 有四個選項: Off、On、Backwards、Only

Off 就不用說了,設定成 Off 等於是沒有設定的狀況

On 則是指檔案系統上面的目錄或檔案名稱使用的是比較舊的編碼方式(Legacy Encoding),例如 BIG5,然後提供檔案給所有採用 UTF-8 編碼過的 URL,同時,如果 mod_fileiri 發現 URL 並不是採用 UTF-8 編碼,就會對該 URL 做一個 HTTP/1.0 301 Moved Permanently,把它 redirect 到 UTF-8 型式的 URL

如果以前述的例子來看,設定應該是這樣的 (我習慣直接設在目錄的 .htaccess 下面)

<IfModule mod_fileiri.c>
  FileIRI          On
  FilenameCharset  Big5
</IfModule>

這樣設定之後,我們用 wget 來測試一下:

# wget -S -O /dev/null http://bbs.giga.net.tw/fileiri/中文.html
--10:29:34--  http://bbs.giga.net.tw/fileiri/%A4%A4%A4%E5.html
           => `/dev/null'
Resolving bbs.giga.net.tw... 203.187.29.180
Connecting to bbs.giga.net.tw|203.187.29.180|:80... connected.
HTTP request sent, awaiting response...
  HTTP/1.0 301 Moved Permanently
  Date: Thu, 08 Sep 2005 02:29:37 GMT
  Server: Apache/2.0.54 (FreeBSD) PHP/5.0.4
  Location: http://bbs.giga.net.tw/fileiri/%e4%b8%ad%e6%96%87.html
  Content-Length: 354
  Content-Type: text/html; charset=iso-8859-1
  X-Cache: MISS from WebAmpRP@GIGAMEDIA
  Connection: keep-alive

Location: http://bbs.giga.net.tw/fileiri/%e4%b8%ad%e6%96%87.html [following]
--10:29:34--  http://bbs.giga.net.tw/fileiri/%e4%b8%ad%e6%96%87.html
           => `/dev/null'
Reusing existing connection to bbs.giga.net.tw:80.
HTTP request sent, awaiting response...
  HTTP/1.0 200 OK
  Date: Wed, 07 Sep 2005 12:36:30 GMT
  Server: Apache/2.0.54 (FreeBSD) PHP/5.0.4
  Last-Modified: Wed, 07 Sep 2005 12:31:33 GMT
  ETag: "30bd3-14-b986f340;bc359880"
  Accept-Ranges: bytes
  Content-Length: 20
  Content-Type: text/html
  Age: 451
  X-Cache: HIT from WebAmpRP@GIGAMEDIA
  Connection: keep-alive
Length: 20 [text/html]

100%[====================================>] 20

10:29:34 (1.59 MB/s) - `/dev/null' saved [20/20]

從上面可以看到,原本用 BIG5 編碼的 URL,被 redirect 成 UTF-8 型式的 URL,然後就可以正確取得檔案,而這個檔案「中文.html」在檔案系統上是用 BIG5 型式命名的

因此,利用 FileIRI On 就可以順利解決大部分的中文檔名問題了!

那如果你的檔案名稱是採用 UTF-8 命名的呢?這時候你就需要使用 Backwards 這個選項,例如:

<IfModule mod_fileiri.c>
  FileIRI             Backwards
  OldFilenameCharset  Big5
</IfModule>

上述設定的意思是說,所有檔案系統上的檔案都是用 UTF-8 命名,但是對於不是使用 UTF-8 編碼方式的 URL,就會把它 redirect 到 UTF-8 的版本,一樣可以提供服務

FileIRI 還有另外一個選項 Only,這個選項則是設定只提供服務給 UTF-8 編碼過的 URL,而檔案系統上的檔案則是使用 Legacy Encoding。這個方式較不常用,就不多作介紹了

各種設定組合產生的效果可以參考 mod_fileiri 原始網站上面的說明:

http://www.w3.org/2003/06/mod_fileiri/

關於 URL 的字元集編碼問題,可以參考下面這篇更詳細的說明:

An Introduction to Multilingual Web Addresses – Handling the path

動態網頁也可以被快取喔! (Part II)

接續前面那一篇「動態網頁也可以被快取喔!

前面這樣的修改事實上仍不太夠,在某些狀況下仍無法節省頻寬,甚至有些時候會發生檔案更新後,抓到的檔案還是舊的 🙁

這一篇作法嘗試進一步解決這些問題,我們把前面的程式再作一些修改:

<?
#   http://bbs.giga.net.tw/demo/dl-test3.php

    $filename = 'Peacock.jpg';
    $ims = preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
    $mod_time = gmdate('D, d M Y H:i:s', filemtime($filename)) . ' GMT';
    if( $mod_time == $ims ) {
            header( 'HTTP/1.0 304 Not Modified' );
            exit;
    }
    header( 'Cache-Control: max-age=60' );
    header( 'Last-Modified: ' . $mod_time );
    header( 'Content-Type: application/octet-stream' );
    header( 'Content-Length: ' . filesize($filename) );
    header( 'Content-Transfer-Encoding: binary' );
    header( 'Content-Disposition: attachment; filename="'.$filename.'"' );
 
    $fp = fopen( $filename, 'rb' );
    while( !feof($fp) ) {
            echo fread( $fp, 1024 );
    }
    fclose($fp);
?>

這邊作一些說明:

WebAMP 對於已經存取過的檔案,會對 Web Server 發出 If-Modified-Since 的請求,要求 Web Server 確認該檔案是否已經修改過了

所以程式首先抓取 $_SERVER[‘HTTP_IF_MODIFIED_SINCE’] 變數,與 Last-Modified 比較,如果發現兩者相同,就回傳 HTTP/1.0 304 Not Modified 告知 WebAMP 這個檔案沒更新過然後直接結束程式 ( exit ),避免耗費頻寬

另外就是加上 Cache-Control: max-age=60 這個指令:

max-age 的效用等同以前的 Expires: header,但是使用起來更方便一點 (只須指定秒數)

max-age=60 是告知 WebAMP 該檔案 60 秒內都不會更新

這個設定會讓 WebAMP 在 60 秒內都不會來問 Web Server 是否有更新,可以降低 Server 的一些負載,超過 60 秒以後,WebAMP 會用 If-Modified-Since 的方式去問 Web Server 該檔案是否有更新

你可以依據需求以及檔案更新的頻率來適當調整這個數值

修改之後,除了第一次之外,結果當然是讓人滿意的囉:

# wget -v -S 'http://bbs.giga.net.tw/demo/dl-test3.php'
--15:12:36--  http://bbs.giga.net.tw/demo/dl-test3.php
           => `dl-test3.php'
Resolving bbs.giga.net.tw... done.
Connecting to bbs.giga.net.tw[203.187.29.180]:80... connected.
HTTP request sent, awaiting response...
 1 HTTP/1.0 200 OK
 2 Date: Mon, 01 Aug 2005 07:04:49 GMT
 3 Server: Apache/2.0.54 (FreeBSD) PHP/5.0.4
 4 X-Powered-By: PHP/5.0.4
 5 Cache-Control: max-age=60
 6 Last-Modified: Tue, 18 May 2004 08:53:23 GMT
 7 Content-Length: 1474750
 8 Content-Transfer-Encoding: binary
 9 Content-Disposition: attachment; filename="Peacock.jpg"
10 Content-Type: application/octet-stream
11 X-Cache: HIT from WebAmpRP@GIGAMEDIA
12 Connection: close

100%[====================================>] 1,474,750      1.32M/s

最後,我們回過頭來看看 Web Server 端的 LOG (access.log)

第一次下載 dl-test3.php 時,當然是 MISS 的,這時候的狀態碼是 200 :

203.187.29.181 - - [01/Aug/2005:14:51:01 +0800] "GET /demo/dl-test3.php HTTP/1.0"
               200 1474750 "http://bbs.giga.net.tw/" "Wget/1.8.2"

由於我們前面設定了 max-age=60,因此在 60 秒之內重複下載 dl-test3.php,都會由 WebAMP 直接處理掉,而不會在 Web Server 上面看到任何 LOG

但超過 60 秒後,你就會在 Web Server 上面看到 304 的狀態碼 (要求確認是否更新過):

203.187.29.181 - - [01/Aug/2005:14:52:06 +0800] "GET /demo/dl-test3.php HTTP/1.0"
               304 - "http://bbs.giga.net.tw/" "Wget/1.8.2"

確認過後,一樣要再隔 60 秒才會再向 Web Server 問一次 If-Modified-Since

最後,想瞭解更進一步資訊的,下面幾個連結可以參考看看:

歡迎大家都來試用看看 WebAMP 的服務!

以上這些作法不只適用於 WebAMP,只要您想要讓動態網頁可以被 Proxy 快取,都可以使用上述方法來修改程式

動態網頁也可以被快取喔!

話說 GIGAWebAMP 服務推出有一陣子了

很多人都以為 WebAMP 只能給靜態網頁使用,動態網頁無法得到任何加速效果

但其實只要程式設計得宜,動態網頁也有可能可以享受到 WebAMP 的網站超頻加速的效果喔

以下我們用一個簡單的例子來說明:

首先,我們先看這個原始圖片,大小約為 1.4 MBytes:

http://bbs.giga.net.tw/demo/Peacock.jpg

由於這個檔案是靜態檔案,因此理所當然會被 WebAMP 加速 (HIT),我們用 wget 來驗證看看:

# wget -v -S 'http://bbs.giga.net.tw/demo/Peacock.jpg'
--10:07:00--  http://bbs.giga.net.tw/demo/Peacock.jpg
           => `Peacock.jpg'
Resolving bbs.giga.net.tw... done.
Connecting to bbs.giga.net.tw[203.187.29.180]:80... connected.
HTTP request sent, awaiting response...
 1 HTTP/1.0 200 OK
 2 Date: Sat, 12 Mar 2005 15:25:22 GMT
 3 Server: Apache/2.0.52 (FreeBSD) PHP/5.0.3
 4 Last-Modified: Tue, 18 May 2004 08:53:23 GMT
 5 ETag: "51b65-1680be-12ff86c0"
 6 Accept-Ranges: bytes
 7 Content-Length: 1474750
 8 Content-Type: image/jpeg
 9 Age: 259658
10 X-Cache: HIT from WebAmpRP@GIGAMEDIA
11 Connection: close

100%[====================================>] 1,474,750    974.42K/s

接下來,我們測試一下用程式來動態輸出這個圖片,首先我們寫了一支 PHP 程式:

<?
#   http://bbs.giga.net.tw/demo/dl-test1.php

    $filename = 'Peacock.jpg';
 
    header( 'Content-Type: application/octet-stream' );
    header( 'Content-Length: ' . filesize($filename) );
    header( 'Content-Transfer-Encoding: binary' );
    header( 'Content-Disposition: attachment; filename="'.$filename.'"' );
 
    $fp = fopen( $filename, 'rb' );
    while( !feof($fp) ) {
            echo fread( $fp, 1024 );
    }
    fclose($fp);
?>

然後,我們用 wget 測試幾次看看:

# wget -v -S 'http://bbs.giga.net.tw/demo/dl-test1.php'
--10:14:29--  http://bbs.giga.net.tw/demo/dl-test1.php
           => `dl-test1.php'
Resolving bbs.giga.net.tw... done.
Connecting to bbs.giga.net.tw[203.187.29.180]:80... connected.
HTTP request sent, awaiting response...
 1 HTTP/1.0 200 OK
 2 Date: Mon, 01 Aug 2005 02:14:33 GMT
 3 Server: Apache/2.0.54 (FreeBSD) PHP/5.0.4
 4 X-Powered-By: PHP/5.0.4
 5 Content-Length: 1474750
 6 Content-Transfer-Encoding: binary
 7 Content-Disposition: attachment; filename="Peacock.jpg"
 8 Content-Type: application/octet-stream
 9 X-Cache: MISS from WebAmpRP@GIGAMEDIA
10 Connection: close

100%[====================================>] 1,474,750      325.21K/s

我們會發覺不管測試幾次,都會是 MISS 的情形!

接下來,我們稍微修改一下程式,加上 Last-Modified: 的 HTTP header …

<?
#   http://bbs.giga.net.tw/demo/dl-test2.php

    $filename = 'Peacock.jpg';
 
    header( 'Last-Modified: ' .
            gmdate('D, d M Y H:i:s', filemtime($filename) ) . ' GMT');
    header( 'Content-Type: application/octet-stream' );
    header( 'Content-Length: ' . filesize($filename) );
    header( 'Content-Transfer-Encoding: binary' );
    header( 'Content-Disposition: attachment; filename="'.$filename.'"' );
 
    $fp = fopen( $filename, 'rb' );
    while( !feof($fp) ) {
            echo fread( $fp, 1024 );
    }
    fclose($fp);
?>

上面 filemtime($filename) 主要是拿檔案的修改時間來當作 Last-Modified: 時間,不過要用 gmdate() 把 UNIX Timestamp 轉換成 GMT 格林威治時區的時間

加了上面 Last-Modified 這一行之後,我們再來測試一下:

% wget -v -S 'http://bbs.giga.net.tw/demo/dl-test2.php'
--09:56:23--  http://bbs.giga.net.tw/demo/dl-test2.php
           => `dl-test2.php'
Resolving bbs.giga.net.tw... done.
Connecting to bbs.giga.net.tw[203.187.29.180]:80... connected.
HTTP request sent, awaiting response...
 1 HTTP/1.0 200 OK
 2 Date: Mon, 01 Aug 2005 01:56:25 GMT
 3 Server: Apache/2.0.54 (FreeBSD) PHP/5.0.4
 4 X-Powered-By: PHP/5.0.4
 5 Last-Modified: Tue, 18 May 2004 08:53:23 GMT
 6 Content-Length: 1474750
 7 Content-Transfer-Encoding: binary
 8 Content-Disposition: attachment; filename="Peacock.jpg"
 9 Content-Type: application/octet-stream
10 X-Cache: MISS from WebAmpRP@GIGAMEDIA
11 Connection: close

100%[====================================>] 1,474,750    350.20K/s

第一次當然還是 MISS,不過第二次以後就都是 HIT

# wget -v -S 'http://bbs.giga.net.tw/demo/dl-test2.php'
--09:56:26--  http://bbs.giga.net.tw/demo/dl-test2.php
           => `dl-test2.php'
Resolving bbs.giga.net.tw... done.
Connecting to bbs.giga.net.tw[203.187.29.180]:80... connected.
HTTP request sent, awaiting response...
 1 HTTP/1.0 200 OK
 2 Date: Mon, 01 Aug 2005 01:56:25 GMT
 3 Server: Apache/2.0.54 (FreeBSD) PHP/5.0.4
 4 X-Powered-By: PHP/5.0.4
 5 Last-Modified: Tue, 18 May 2004 08:53:23 GMT
 6 Content-Length: 1474750
 7 Content-Transfer-Encoding: binary
 8 Content-Disposition: attachment; filename="Peacock.jpg"
 9 Content-Type: application/octet-stream
10 Age: 4
11 X-Cache: HIT from WebAmpRP@GIGAMEDIA
12 Connection: close

100%[====================================>] 1,474,750    950.12K/s

以上是以圖片作例子,你也可以代換成要被下載的檔案 (有些人會用這種方式來計算檔案被下載的次數)

甚至,討論區的文章如果能被正確貼上 Last-Modified: 的 header,也有可能可以享受到 WebAMP 加速的好處喔

更進一步的資訊,請參考下一篇「動態網頁也可以被快取喔! (Part II)

unicode 中的 KK 音標符號

颱風天在家上網,偶然之下看到了 CMU 製作的一個音標資料庫:

The CMU Pronouncing Dictionary

雖然資料已經有點舊了,不過既然資料庫的版權說明寫著可以免費散佈使用,就想說把他拿來放進 cdict.net 裡面好了

網頁是使用 BIG5 編碼的,而顯示這些音標符號時,我又不想跟 YAHOO 字典 一樣,直接用小圖組成音標,所以就找了些資料,想辦法在 BIG5 的網頁下面利用 unicode 顯示這些音標符號

CMU 的資料庫中共用到 40 個音標符號,不過似乎並不是標準的 KK 音標,每個音標符號各以一或兩個英文字母的代碼表示,整份列表是長這個樣子的:

HARBESON  HH AA1 R B IH0 S AH0 N
HARBIN  HH AA1 R B IH0 N
HARBINGER  HH AA1 R B IH0 N JH ER0
HARBINGERS  HH AA1 R B IH0 NG ER0 Z
HARBINSON  HH AA1 R B IH0 N S AH0 N
HARBISON  HH AA1 R B IH0 S AH0 N
HARBOLD  HH AA1 R B OW2 L D
HARBOR  HH AA1 R B ER0

經過與 unicode 比對之後,整理出來的對應表如下:

代碼 音標 Unicode 顯示方式 代碼 音標 Unicode 顯示方式
AA ɑ U+0251 &#x251; K k k
AE æ U+00E6 &#xE6; L l l
AH ʌ U+028C &#x28C; M m m
AH0 ə U+0259 &#x259; N n n
AO ɔ U+0254 &#x254; NG ŋ U+014B &#x14B;
AW ɑʊ U+0251
U+028A
&#x251;
&#x28A;
OW o o
AY ɑɪ U+0251
U+026A
&#x251;
&#x26A;
OY ɔɪ U+0254
U+026A
&#x254;
&#x26A;
B b b P p p
CH t U+0283 t&#x283; R r r
D d d S s s
DH ð U+00F0 &#xF0; SH ʃ U+0283 &#x283;
EH ɛ U+025B &#x25B; T t t
ER ɚ U+025A &#x25A; TH θ U+03B8 &#x3B8;
  ɝ U+025D &#x25D;        
EY e e UH ʊ U+028A &#x28A;
F f f UW u u
G g g V v v
HH h h W w w
IH ɪ U+026A &#x26A; Y j j
IY i i Z z z
JH d U+0292 d&#x292; ZH ʒ U+0292 &#x292;

其中 ɝ 這個音標並沒有被 CMU 這個資料庫用到,我也不知為什麼,可能是它用的並不是標準的 KK 音標吧

另外,比較奇怪的一點是,使用 Firefox 瀏覽這些 unicode 音標符號都沒有問題,但是使用 Internet Explorer 的話,有部分符號會顯示出不出來(變成一個空白的框框)

經過試驗之後,把字型設定成 Lucida Sans Unicode 就可以了

CMU 這個音標資料庫中還有重音符號在內,只是由於它是標在母音的地方,所以如果沒有經過特殊判斷,直接顯示出來會跟一般字典上的音標表示法不太一樣

  音標 Unicode 顯示方式
重音 ˈ U+02C8 &#x2C8;
次重音 ˌ U+02CC &#x2CC;

這兩個重音符號,在 Firefox 下面一樣沒有問題,但是在 IE 下面,就算用 Lucida Sans Unicode 也是顯示不出來…XD 要用 Arial Unicode MS 才能顯示出來,但是 Arial Unicode MS 反而顯示不出上面的音標符號…

有興趣的人可以到 http://cdict.net/ 上面試用看看