SiteStates – v0.2 beta

前幾天我寫好了一隻程式叫做 SiteStates ,現在新增了一些功能(粗體字表示新增功能),主要簡述如下:

* 支援 PageRank 資訊,並可自訂是否顯示。
* 線上即時人數、當日瀏覽人數、累計總瀏覽人數
* 支援自訂邊框、背景、文字顏色
* 支援隱藏模式
* 支援近 30 日訪客人數紀錄 (大折線圖 580×180 ,小折線圖 110×30)
* 支援以 JavsScript 語法列出在貴站的即時線上使用者的 IP
* 支援簡易密碼重置和自訂訪客人數
* 紀錄最近的到訪者紀錄(IP & 時間 & DNS 反解)

自訂訪客人數的想法是來自於 PTT的 ritandy 和 mewmi 兩位板友,因為他們說:

ritandy:「請問可以新增一個讓計數歸零的的功能嗎?」

mewmi:「另外, 我希望可以自己填”開始人數”…因為也許有人本來就有個total, 轉移到你的計數器使用…」

我覺得很有道理,所以就花了半個晚上寫好自訂人數以及密碼重設的功能。

另外,這篇文章的重點在下面,主要是討論實做遭遇到的問題和解決方法,如果覺得無聊可以跳過 🙂

1. Google PageRank 的 Cache 問題

眾所皆知,取得 PR 最快的方法就是用第三方 API 套在程式裡面直接去問 Google ,但是這個方法很糟糕,我實際測試過後,發現問一次大概要一秒左右,如果每更新一頁面都真的去問一次,那 Google 大概會第一個封鎖我吧。所以必須有 Cache 機制,還好 popstats 一併解決了這個問題,但不支倒是不是作者故意的,這隻程式另外也留下其他的問題,所以我只好手動 Hacking 一下。第一個問題是問不到 PR 回傳 FLASE 的時候,他不會把結果 Cache 起來,更要命的是他會把這件事情記錄下來,所以可想而知, log 檔肥大的速度相當之快。因為毎遇到一個 PR=0 的網站,馬上 log 比數 = 瀏覽次數 = 我的程式去打擾 Google 的次數。自然這樣效率就不會高,所以我把 Cache 的預設時間延長,並且改寫了一下,讓 PR=0 的時候一併寫入 Cache ,更新週期為 7 天(預設是 1 天, 86400秒) 。如此這個問題算是暫告一段落。

2. 儲存日期資料的問題

我之前有考慮過一陣子,要用 explode/implode 還是 serialize/unserialize ,最後決定聽從 whapup 兄的建議,用 serialize/unserialize ,因為這算是真正正規的作法,雖然轉成 String 的時候長度會更長一些,但這影響僅限於儲存和後端操作,對於使用者來說是沒有感覺的(因為看不到)。原本我想多加幾個欄位,或是把陣列設大一點,儲存多一些天數的訪客人次,但後來考慮到這個資訊似乎不是那麼必要 (畢竟用 Analytics 更完整不是嗎?),所以就僅儲存近 30 日的紀錄,增加方式同 MRTG 的 Grow Right ,因為我覺得這樣流動的圖表,很漂亮。

3. 重設密碼的問題

由於我想把系統註冊儘量簡化 (其實最理想是用 OpenID ,之前有提過了) ,可是我遭遇到一些問題,最大的困難在於字串的取得和判斷,後來我想出一個方法,就是讓使用者修改網頁標題,在其中加入我雜湊(HASH)出來的一串數值,這樣我在用程式去讀取他的頁面,以利判斷是否為網站所有人修改密碼。但這衍生出了兩個問題,第一個是正規表示法(Regex)來頗析字串的問題,第二個是利用 file_get_contents() 函數的問題。

第一個問題我就不說了,書上寫很多,資源很豐富,我自己也找很久 XD
第二個是因為 file_get_contents() 必須透過 php.ini 開啟選項(儘管預設似乎是開的),但我覺得不太喜歡這樣,可是又在想用 fopen() 和 file_get_contents() 哪個會比較好,雖然兩者的速度可能僅在伯仲之間。

我在 PHP 問了個問題:

$encode_string = '<title>' . $encode_string;
                  ^^^^^^^ 加上這個是為了防止被插其他地方
$long_string = file_get_contents(urldecode($url));
if(eregi($match_string ,$long_string)) { 開始做事 }

這似乎有危險,如果有人留下含有 $encode_string 的 comment
這樣或許可能會出現問題,儘管機率不高。

結果以前中正的 dinos 學長幫我回答了,他採用 fopen 的解法,比較漂亮的解法是不用 retrive 整個 content 回來,只要讀到了第一次 match 到正規表示法的地方迴圈就會 break ,然後進行更進一步的處理:

function getRemoteTitle($url){
  $fr=@fopen($url,"r");
  if(!$fr)return false;
  $content='';
  while(($line=fgets($fr))!=false){
    content.=trim($line);
    if(preg_match('/<title\s*>[^<]*<\/title>/i',$line) ||
      strstr(strtolower($line),'</title>')){
      break;
    }
  }
  fclose($fr);
  preg_match('/<title\s*>[^<]*<\/title>/i',$content,$matches);
  if(isset($matches[0][1]))return $matches[0][1];
  else return false;
}

這樣可以減少傳輸的位元數,更快的取得結果,而且第一次 Match 到的一定是標題(當然,用 file_get_contents() retrive 回來的整份文件中,可能包含不只一次 HASH 的字串(在其他地方被惡意插入)。所以在 preg_match() 的時候,只要判斷第一個結果就好(array[0][1]) ,但這樣始終回傳太多資料了,我覺得不需要比對這麼多資料。

4. 自訂人數的問題:

在自訂人數上倒是還好,就是把資料表的欄位重新 UPDATE 即可,我另外寫了一個小函數專於做 Error Handler ,並且 echo 出錯誤訊息,登入錯誤、 Session 錯誤、認證碼錯誤..等等。

5. 折線圖的問題:

在用程式繪製折線圖上,其實我之前就做過類似的嘗試,也畫出來了,但是困難的地方在於分配欄位以及配置,這也是花我最多時間的地方,最後我決定畫兩張折線圖,大張的可以看出詳細資訊,小張的則是像 Site Meter 的小圖那樣,可以看個大概(不過即時產生小張圖片程式的我還沒寫好)。

6. 系統效率與記憶體的問題:

我用 free 看了系統的記憶體使用量,發現 Debian Linux 並不會把所有的記憶體都 Buffer 起來,在系統總共 2GB 的記憶體中,實際使用約 100MB ,然後 Buffer 大概 1GB 左右,還有 1GB 左右的記憶體閒置。至於 SWAP 使用率一直都在 0% 。

7. 流量的問題:

經過觀察,發現流量大約平均在 10KB 左右,這算是意料中的事情,因為動態生成一張圖片大概也才 1KB 多而已,所以在人少的時候流量還不至於太高影響到我平時的網路速度。

8. Apache2 效能的問題:

之前我搞不太清楚 MaxKeepAliveRequests 和 MaxClients 的關係,以及 MinSpareServers 和 MaxSpareServers 的關係,所以在效能的調校上一直無法動手,另外我也想知道有沒有拒絕 DDoS 的 module 。這方面 dinos 學長也一併解決了我的問題。

MaxClients 是伺服器啟動時要啟動多少個 httpd 來等待連接,在 apache2 預設值裡,每多一個大約會多使用 20~40MB ,對於同時連線人數越多的站是開越多越好。

MaxKeepAliveRequests 只有在 KeepAlive On 時才有效, KeepAlive 是說在一個 httpd 每處理完一個 MaxRequestsPerChild 後要不要繼續等待下一個子請求,所以 MaxKeepAliveRequests 就是指定每個 httpd 在等待期間可以處理多少個子請求。

MinSpareServers 和 MaxSpareServers 這兩個是指備用的 httpd 數量,也就是除了被用掉的以外還要開啟多少個。當然一定會影響效能囉,對於載入多個 mod 的 Apache httpd 而言,每要啟動一個 httpd 是要花上很多時間(約莫 3~8 seconds),所以設置一些備用的減少當使用者連結上時需要等待 httpd 啟動的時間

另外對於 DDoS 的阻斷服務攻擊,則是可以用 mod_evasive 來嘗試保護系統。

這次的問題檢討大致是以上幾點。

refer:
1. SiteStates 網站

Posted in computers
2 comments on “SiteStates – v0.2 beta
  1. qfang says:

    謝謝你的簡訊
    我都哭了我
    整個有很感動:_;

    也謝謝你~

  2. roga says:

    呵呵..別哭啦..

    這個程式我自己也滿想寫寫看的,這是一個很好的練習 🙂

    另外也祝妳以後在國外一切都可以很順利。

Leave a Reply

Your email address will not be published.