2009年10月27日 星期二

多重Singleton時的問題,與嘗試解決

一樣是寫遊戲時遇到的狀況。因為越來越複雜了,不寫下來搞不好過一段時間我就忘了。(關於Singleton是什麼我就不在這邊介紹了,請參閱「Design Pattern」,有中文版)

首先是一開始。我的遊戲需要以PHP提供的標準函式庫連接SQL資料庫,其中需要保管該次連接唯一的connection。最早是在最上層開一個connection,然後逐層傳下去。想也知道這樣缺乏效率(主要是每個function都需要有那麼一個傳入欄位),所以後來改的作法是採用Singleton。要的function自己去拿一份reference出來。

我的Singleton的實作方式是將reference以static member的形式存在class中,然後每次需要時就去拿該object的reference出來。PHP的object是在沒有人reference到他時才釋放。因此在這裡,該object的release是在全部程式碼執行完要釋放static member的Shutdown階段。



##ReadMore##
好了,SQL connection的問題解決,再來是SQL的table(跟row)。我把SQL各table取名為XxxxDB(xxxx是table名),例如:CharDB ,BattleDB。每個object代表一個row。construct的時候讀出資料存入row,destruct的時候檢查有哪些值被更新了,寫入資料庫後才結束。

這樣的作法運作正常,但有個問題:在多層的function call裡面,容易造成資料不同步的情形。比如說現在的狀況是,function a呼叫b然後b呼叫c。在a跟b跟c裡面都各自造出了CharDB的同一個row的object。c裡面那個object改動了數值,並在離開c的scope後寫入了資料庫。但a跟b裡面持有的還是舊的資料,並沒有跟資料庫同步到。

在這邊一開始要寫Singleton時遭遇到困難(後述),因此採用的是別的方法。那時最後的作法是當c的值更新時,他會去通知a跟b之後要記得取得新值。

這個做法彆扭了些,而且某些狀況下需要手動處理。(想一下上面的a,b,c的狀況,但是這次是a在呼叫b之前造出該object並改動了值。在這裡a還沒有到scope結束所以不會寫入資料庫,但不寫入資料庫b就得用錯誤的資料。因此,a得手動進行寫入)因此我又開始想Singleton的作法了。



在這邊講一下XxxxDB也用Singleton時的問題。如上所述,Singleton的object,釋放時機是Shutdown階段。可是我們現在用到了兩類用途不同的class。其中一個會用到另一個。XxxxDB在釋放時有可能會更新資料到資料庫,因此這時SQL connection不能被釋放。但是這兩個都是Singleton...

所以看來我們得控制Shutdown階段,release的順序了。有人可能想到,在XxxxDB的object裡面存放一個SQL connection的reference如何?嗯,我試過了,不過顯然Shutdown階段release時不會去管還有沒有reference。所以SQL connection還是有可能在XxxxDB之前釋放,失敗。另外,PHP沒有辦法讓你調整Shutdown階段釋放資源的順序。(我懷疑有哪個程式語言有)



後來我找到的作法是,標準函式庫的register_shutdown_function()。這個函式會讓你註冊一到數個function,並在Shutdown開始前依序呼叫它們。所以我利用這個函式,在Shutdown開始前把各XxxxDB來自static member的reference清掉。這樣,object的reference就斷光並開始自動release。XxxxDB在Shutdown開始前release完畢,SQL connection則在Shutdown時release。順序正確。



不過有那麼簡單我就不會想發這篇了。新的問題是出在一個名為BattleDB的class。因為Web Game的某些特性,單場戰鬥的資料不能只放在記憶體還得寫入資料庫,而這就是對應的class。

BattleDB的重點在於,為了操作方便,他存有兩個CharDB的object的reference。然後還有一個名為BattleAct的class。這是為了處理行動回數等資料方便而造出的class。每個BattleDB的object持有一個BattleAct的object。為了方便,每個BattleAct也同樣持有對應的BattleDB的object(的reference)。而在我將XxxxDB處理的部份改為Singleton後,BattleDB這邊動作出了問題。

我原本以為是CharDB的object的reference釋放上的問題,不過後來發現不是。重點在於BattleAct持有的BattleDB object reference。想像一下。原本BattleDB object是在Shutdown階段前,因為register_shutdown_function()的呼叫而切斷static member的reference。釋放。但是現在BattleAct還有它的reference。而BattleAct object本身的reference被BattleDB object持有,也不會自動釋放。所以變成得到Shutdown,釋放所有資源時才release。若這時SQL connection已經release,自然的問題就出現了。



問題的解法呢。目前的作法是每次BattleDB用完時就呼叫自訂函式Close(),在裡面把BattleAct釋放掉。幸好BattleDB使用到的時機挺單純的。不過當然了,這樣做彆扭又可能對未來的擴充造成影響,之後可能還是得改。一個做法是把BattleAct併回BattleDB內部,取消相互reference問題。

這次的教訓是:注意相互reference的dead lock...尤其在記憶體自動回收的程式語言中。

2009年5月31日 星期日

[書評]Web安全測試錦囊妙技

電腦書,題材如其名,出版社歐萊禮。

這本的主題是教你如何用各種免費軟體搞掛....噢不,測試Web應用程式。要注意的是,這本主要採用的是測試員的角度,也就是說「你沒有完整的Server端程式碼也沒有相關知識,也許你可以跟工程師要,但是不太可能太頻繁或詳細」的立場。如果你自己就是Web應用程式的撰寫者,會免去不少麻煩,但其中幾個也會不那麼需要做。當然,相關知識先有總是好的。

內容上,書中詳細的提到了各種基礎動作跟比較具體的攻擊法。更詳細的深入的話,書中有介紹網站跟書籍。

如果對Web安全議題沒有多少了解的話,這本相信是很不錯的入門書籍。

2009年5月21日 星期四

Web Security測試用工具

以下是從「Web安全測試錦囊妙計」第二章擷取出來的(歐萊禮出版,原書名Web Security Testing Cookbook)。目的是為了我不用每次都打網址...XD

下面列表我會寫上必要的註解,不過還是建議需要的話自己去看原書

工具列表:
  1. Firefox

  2. Fx Extension:
    1. View Source Chart (不適用Fx3,但有適用的實驗版本)
    2. Firebug
    3. Tamper Data
    4. Edit Cookies (適用於Fx3的是新版:Add N Edit Cookies)
    5. User Agent Switcher (不知為何裝起來沒作用...)
    6. SwitchProxy

  3. WebScarab (需要Java Runtime)

  4. Perl (Windows: ActivePerl)

  5. CAL9000
    注意:原作者有警告,不要把這東西放在網路Server上,請在本機端環境操作他

  6. ViewState Decoder

  7. cURL

  8. Pronzilla (這是一組而非一個工具)
    注意:這些是為了情色目的開發的工具,但只要你不針對該方向使用,工具本身事「純真無邪」的(書上就這麼寫XD)。
    1. RefSpoof: 修改HTTP Referer
    2. Digger: 目錄橫跨(Directory traversal)工具
    3. Spiderzilla: Website Spider
    4. Increment & Decrement: 竄改URL參數

  9. Cygwin (建議加裝Perl)

  10. Nikto 2 (需要Perl & Cygwin, 需要LibWhisker)

  11. Burp Suite (非完全免費,但免費的部份就有用)

  12. Apache HTTP Server

2009年5月12日 星期二

以索引的方式取用Smarty的config變數

我遇到的狀況是這樣。假設我在Smarty的config檔裡面寫了這樣的內容:
level1 = 等級一
level2 = 等級二
level3 = 等級三
一般來說在template裡面,我要呼叫上述內容的寫法是:
{#level1#}

問題來了,如果我現在要依照PHP檔輸入的內容動態的取用上述內容的話呢?
比如說,透過PHP檔內的動作,現在template裡有個變數$para,內容是"level1"。
我想用它來取得config檔內同名的變數的數值。

很直覺的想法會是
{#$para#}
之類的對吧?不過很可惜,Smarty不支援這種語法。
Smarty的config檔的變數(已讀入的)也會以$smarty->config->level1之類的方式儲存,
不過當然的,我也不能寫成$smarty->config->$para。

另一種想法是config裡面能不能直接寫陣列?
我自己嘗試不行,我也沒看到哪個範例可以的。

最後達成的作法是藉由template內嵌php程式碼。
將config的內容重組成template variables的陣列,傳入template中。
$ar = array('level1', 'level2', 'level3');
foreach($ar as $v)
{
$ar2[$v] = $this->get_config_vars($v);
}
$this->assign('ar', $ar2);
然後在template裡面使用。
$ar[$para]


雖然是相當拐彎抹角的作法,不過會比在template裡面寫一堆重複的程式碼好多了。

2009年5月5日 星期二

如何建立單機性質的SVN版本控管

單機性質SVN


版本控管以及備份的重要性應該不用多講了,而SVN有多麼優秀也不用多提。
只是一般聽到的SVN都是需要一個網路上的SVN Server,
那自己寫點小東西,沒有SVN Server又想要版本控管的話該怎麼辦呢?
這就是這篇文章的主題。建立一個個人的SVN版本控管。
基本上是參考這篇的,不過我會用中文口語的講出來。

步驟:
  1. 下載TortoiseSVN最新版。我是用Windows版
  2. 選擇你要拿來存放版本控管的內容的目錄(最好是空的),
    檔案管理員右鍵->TortoiseSVN->Create Repository here...
  3. 接下來就可以使用Repository Browser連到該目錄了,
    位址類似這樣:file:///Q:/THBRsvntest
  4. 在把該目錄作最初的整理後(比如trunk/branches/tags三分法),將初始的程式檔案import進來。
    在你要載入的資料夾上,檔案管理員右鍵->TortoiseSVN->Import...。
    注意該資料夾不會一併import,只有資料夾的內容會。
    還有,被你指定import的資料夾並不會因此就有版本控管。要再進行checkout才行
  5. 進入Repository Browser,對你要checkout的資料夾右鍵->Checkout...。
    注意一樣,只有資料夾內的內容會被checkout。
  6. checkout出來的資料已經有了版本控管了。剩下的跟一般TortoiseSVN用法相同。

以隨身碟做為存放Repository的裝置


上述作法我遇到的主要問題之一是,如果你在兩個以上的地方都有電腦而且都會寫程式,使用頻率還差不多怎麼辦?分別建立單機SVN是個辦法,但是版本控管不能統一。

另一種作法是,同樣分別建立單機SVN,但是建立在同一個隨身碟上。兩台(或以上)的電腦對同一個隨身碟做checkout跟commit,所以版本控管的來源只有一個。比較有問題的是隨身碟的代號可能每次放入時不一樣(已經插了其他裝置導致代號改變...之類的),每次都來一次Relocate又太麻煩了。我的作法是將隨身碟的代號改為一個較少用的代號,這樣就比較不容易被其他會插拔的裝置影響到。(更改代號可以從我的電腦->管理->磁碟管理裡面著手)

2009年4月24日 星期五

(要錢的)軟體開發工具小調查

UltraEdit:
49.95美金。目前v.15版。還沒仔細試過與129.95美金的UEStudio的差異....
PChome商店街Yahoo奇摩購物中心有代理版。

Visual Studio系列:
目前2008。最便宜的Standard版本似乎是10590台幣。(原價記得是300美金)
有免費的Express版,但不支援ATL跟MFC。想用到這些東西的話請買Standard版本。
不知道該說他黑心還是慷慨。

Visual Assist系列:
Whole Tomato Software出的,跟Visual Studio搭配提昇功能用的輔助套件。
正常可大量授權可續約的版本一套249美金,個人版本則是99美金。
在價格不怎麼便宜外,這套軟體不支援Express版。
(不過用習慣了就會覺得想要繼續使用...)

主要的功能....
  • 提示功能的加強。Visual Studio原本只會對class的method跟variable名作提示而已,裝了Visual Assist後打任何關鍵字都會自動提示。
  • Refatoring。諸如一次大量改名之類的....
  • 上色。把巨集/變數/常數等加以不同的上色。

2009年4月23日 星期四

Doxygen補充

原本主要是看Documenting the code頁面來寫相關註解,
不過發現有一些指令他沒有詳加解釋...就去找了command的完整頁面

個人來說比較有用的是下面的Section indicators的部份就是了...
諸如\param, \sa, \return, \retval之類的。

2009年4月1日 星期三

Doxygen 細項設定memo

把幾個重要的細項列出來....
這邊指的是Windows版的GUI的Wizard/Expert tab下面的項目。
不過其他版本應該很容易依樣畫葫蘆。

Wizard
  • Project
    • Scan recursively:讓他搜尋到子目錄

  • Mode
    • "Select the desired extraction mode:":除非已經做了完整的註解,否則All Entities才能列出足夠的資料
    • "Include cross-referenced source code in the output":勾起來則會把原始碼一起文件化並加上link。建議勾選

  • Output
    • HTML→"with frames and a navigation tree":會在左邊以frame建立索引連結

##ReadMore##
Expert
  • Project
    • CREATE_SUBDIRS:建立複數個目錄。怕同一目錄裡檔案太多的選項
    • INLINE_INHERITED_MEMB:將子類別從父類別那邊繼承來的method也列出。不包括constructor、destrcutor跟assignment operators
    • STRIP_FROM_PATH:將原本完整列出的檔案位置消去指定的path

  • Build
    • EXTRACT_PRIVATE:列出private成員
    • EXTRACT_STATIC:列出(C/C++)檔案的static內容
    • SHOW_DIRECTORIES:列出目錄結構。適合依照目錄分層的project

  • Source Browser
    • SOURCE_BROWSER:產生頁面詳列Source code。強烈建議。
    • INLINE_SOURCES:是否將原本只包含declaration的文件改成顯示完整的definition。注意資料太多反而會模糊焦點。建議不要。
    • REFERENCED_BY_RELATION:將用到此成員的method等列出。強烈建議
    • REFERENCES_RELATION:將此成員用到的method/variables等列出。強烈建議。
    • REFERENCES_LINK_SOURCE:若勾選,則上述兩個項目列出的連結連往Source code頁面,否則連往文件。看個人需求。

  • HTML
    • GENERATE_TREEVIEW:跟Wizard的"with frames and a navigation tree"同作用
    • TREEVIEW_WIDTH:上述TreeView的寬度

2009年3月26日 星期四

從程式碼自動生成說明文件 - Doxygen

官方網站:Doxygen

可以生成HTML、LaTeX、Man Pages、RTF跟XML,不過我只有用HTML。
支援C/C++/Java/C#/PHP/Fortran/VHDL,
會將你的程式碼讀入,生成簡明易懂的說明文件,
並將交互參照的部份自動建立連結。
當然,沒有註解的話它並不會自己幫你生成註解,註解還是得你自己寫 XD
註解該怎麼寫才會被讀到,請參考官網文件

不確定其他版本狀況,不過Windows版有一個有GUI的Wizard,
可以經過簡單的設定之後就生成文件出來。
如果想要自己詳細設定的話,Expert Tab裡也可以調。

以下註記一些比較需要注意或是容易忘記的memo...

  • Source code directory可以有複數個。要在Expert→Input→INPUT調。
  • 對於某些source code不能寫成UTF-8的project,可以用它的轉碼功能。
    • 像部分C/C++ compiler不吃UTF-8原始檔,要轉碼成UTF-8再生成文件又大費周章
    • 但要注意有些狀況轉碼會失敗....比如說,我從big5轉UTF-8,內含「/」好像就會失敗。不確定為什麼。
  • 如果要顯示Static function或private method/member,要到Expert → Build → EXTRACT_PRIVATE / EXTRACT_STATIC調。
  • 要顯示目錄(比如說,如果文件包括好幾個小project,彼此是用目錄來區分的),要到Expert → Build → EXTRACT_PRIVATE/SHOW_DIRECTORIES調。
  • 原本是設計給英文語系用的,所以一部份地方要注意一下。比如說,他會自動將class name/file name等辨識並加連結,但是如果這些跟中文連在一起的話就不會識別出來(英文的字是以空格分開的嘛),所以最好這類名稱前後都各加空格格開。

2009年3月22日 星期日

協助HTML/JavaScript/CSS開發的Firefox擴充套件

之前搞Firefox擴充套件開發的survey時找到幾個不錯的,
連同之前在用的一併列出。

DOM Inspector
觀察DOM tree用的套件。原本是Fx內建,Firefox 3還哪時候開始變成額外擴充。
(變額外擴充也好,因為原本內建但是要在安裝時特地選起來,很容易漏過)
雖然說底下要介紹的Firebug比他強大些....

Firebug
同樣是觀察DOM tree用的,不同的是它有簡單明顯的UI,
當游標移到tree的某條敘述上,對應的顯示的部份會以遮罩突顯出來,
所以能很快的找到自己要的部份的code的位置。
必備套件。

JavaScript Debugger
這套強大的地方在於,他是個可以逐步執行並下中斷點的JavaScript Debugger。
就這樣,不過也夠強悍了。

Web Developer
可以進行很多網頁細部設定。比如說關掉Javascript、對Cookie的操縱、取得JavaScript內容等等。
很多項目不會很常用,不過需要時就會覺得蠻好用的。

Console²
將錯誤主控台的UI稍稍改裝。
老實講改的不多(而且稍微有點醜....),不過有比沒有好。

Extension Developer
很多輔助Extension開發用的功能,不過也有助於網頁開發。
比如說Extension的包裝、即時的Javascript command line、
即時的HTML Editor和Regular Expression Evaluator。