Blogs

使用 Facebook 登入並取得個資

Hank Chen 的照片

facebook,簡稱 fb,一個社群網路服務網站。許多網站結合了 fb, 來做行銷活動,或是快速新增會員人數。如何將自家的網站與 fb 結合,以下做個簡單的範例 ,讓新加入的會員,可以使用fb的登入,就可以登入自家網站,並取得會員資料。
1.API 選擇:
fb官方提供的 API,網頁部份有 javascript、php,手機部份則有 iOS、Android,但由於 fb 好吃新奇又好玩 ,所以,其它語言也各自開發相關的api,如 silverlight、flash、.net、java 等,而本次則是選用 javascript 做為範例。
2.事前準備:
2.1.申請 fb 帳號。
2.2.申請成為開發者人員,如何申請可參考如下網址
http://sofree.cc/fb-app-1/
3.開工
3.1.完成上述 2,進入新建立的應用程式,依序取得 App ID 與 App Secret ,如下圖紅框處,並設定相關資料,如下圖藍框處,本次的測試網站為me.cellopoint.com,故 App 網域與網站位址,分別填入 me.cellopoint.com 與http://me.cellopoint.com,設定好之後,按下儲存鈕

3.2.在 me.cellopoint.com 目錄下,新增 channel.html 與 index.html 兩個檔案,首先開啟 channel.html,裡頭只需加入一段 javascript code
<script src="//connect.facebook.net/en_US/all.js"></script>
3.3.開啟 index.html,貼上如下的 code,並做紅框處的修改,需注意的是javascript code 必須貼於 <body> 標籤內。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:fb="http://www.facebook.com/2008/fbml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login</title>
</head>
<body>
<div id="fb-root"></div>
<script src="//connect.facebook.net/en_US/all.js"></script>
<script>
window.fbAsyncInit = function() {
FB.init({
appId : 'xxxxxxxxxxx', // App ID,請輸入 3.1 所又得的 App ID
channelURL : '//me.cellopoint.com/channel.html', // 請輸入 3.2 所新增的 channel.html 網址

status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
oauth : true, // enable OAuth 2.0
xfbml : true // parse XFBML
});
};
</script>
</body>
</html>
3.4.登入並取得會員資料
新增如下 javascript code,說明如下
a.userID:為個人在 fb 的 id 值,取得如下紅框處,如果個人網站利用fb登入,可以此判別會員。
b.如欲取得 email,則需設定如下綠框處
c.取得 name 與 email,使用 FB.api 的 me,如下藍框處
function FBLogin(){
FB.login(function(response) {
if (response.authResponse) {
alert('登入成功');
alert('UserID' + response.authResponse.userID);
FB.api('/me', function(response) {
alert('UserName' + response.name);
alert('UserEmail' + response.email);
});
} else {
alert('登入失敗');
}
}, {scope: 'email'});
}
3.5.登出:新增如下 javascript code
function FBLoginOut(){
FB.logout(function(response) {
alert('Logged out.');
});
}
4.如果要移除掉該應用程式,於個人的 fb 頁面的應用程式選項,找到該應用程式並移除掉即可。
5.以上參考出處自如下網址
http://developers.facebook.com/docs/reference/javascript/

Libgtop

David Lee 的照片

如何寫一隻程式來判斷這隻程式在執行階段所佔用的 linux 系統資源,例如 CPU 和記憶體使用率呢? 可以去查看系統中的 /proc/<process id>/stat,或是藉由系統 shell 的 top 指令,但是這兩者都必須花費額外的功夫去分析檔案或介面中的資料。在這邊介紹一個 c 語言的開源函式庫: libgtop,可以幫助我們獲取系統或特定線程所佔用的資源量。

libgtop 是 GNOME 計畫中的一個函式庫,用來實現 GNOME 桌面環境中的”top”功能。它依賴於另一個GNOME 的函式庫 glib。目前最新的版本是 2.28,在安裝前必須先安裝 glib 2.6.0 以上版本 以及 intltool 0.35.0 以上版本。

一般來說,CPU 的使用率,是根據 CPU 花費在各種不同模式的時間所計算的。這些時間通常可分為user mode, nice mode, system(kernel) mode 和 idle mode,而使用 libgtop 的 API 可以獲取系統 boot 到目前為止,各種 mode 所佔用的時間(clock click 次數)。舉例而言,可以利用下面的程式碼來計算出系統 CPU 的使用率:

#include <glibtop>
#include <glibtop/cpu.h>

double cpu_rate;
int dt, du, dn, ds;
glibtop_cpu cpu_begin,cpu_end;
glibtop_get_cpu(&cpu_begin);
sleep(1);
glibtop_get_cpu(&cpu_end);
dt = cpu_end.total - cpu.begin.total;
du = cpu_end.user - cpu.begin.user;
dn = cpu_end.nice - cpu.begin.nice;
ds = cpu_end.sys - cpu.begin.sys;
cpu_rate = 100.0 * (du+dn+ds) / dt

注意 CPU 使用率的計算必須根據兩個時間點的 click 次數的差,所以必須截取兩次這個資訊後再相減。而memory 的觀測就比較單純,可以一次獲得。例如:

#include <glibtop>
#include <glibtop/mem.h>

double mem_rate;
glibtop_mem memory;
glibtop_get_mem(&memory);
mem_rate = 100.0 * memory.used / memory.total;

libgtop 可以觀測的資源種類相當多,除了上例中介紹的系統 CPU 和記憶體以外,還包括特定線程的 CPU 和記憶體、swap、檔案系統、網路介面等等。詳細的 API 及資料結構可以參考 GNOME 的官方網站: http://developer.gnome.org/libgtop/

Google File System 介紹

David Lee 的照片

Google 之所以能獨霸搜尋引擎市場,一方面是依靠 PageRank 技術所提供的優良搜尋排序,另一方面則仰賴其文件儲存系統的優良效率。Google 設計了一套獨特的分散式檔案系統以滿足其龐大的儲存需求,也就是所謂的 Google File System (簡稱 GFS)。Google 並沒有將 GFS 當做開源軟體釋出,不過還是公布了一些技術細節,包含一篇官方論文。

與傳統的分散式檔案系統相比,GFS 有兩個主要的不同點。首先,設備的失效被視為正常的現象而非意外。所謂的失效包括了應用程式的錯誤、作業系統的錯誤、人為操作的錯誤、乃至於硬體或網路的問題。既然連昂貴的硬碟設備也不可能百分之百排除發生錯誤的可能性,Google乾脆使用多個廉價的磁碟機來組成他們的儲存設備。而為了對抗設備的失效,GFS 包含了監視、錯誤偵測、容錯以及自動修復的機制。

其次,資料大多只會被追加到文件的末端,鮮少會修改或刪除原本存在的檔案。已寫入的資料通常只需要可讀 (readable) 不需要可寫 (writable),而且通常是按照順序且大規模的讀取,一次操作便可能讀取數百 KB甚至 MB 以上的資料。要特別注意到的是,GFS 預期所保存的檔案通常都是數百 MB 甚至 GB 以上的文件,小型的文件會被支持但不會被優化。

GFS 處理客戶端所下要求的方式是採類似 supernode (Master) 與分散式結點 (Chunkserver) 的架構。真正的數據資料儲存在 Chunkserver上,並且定期將其狀態報告給 Master。當客戶端需要讀取某個檔案時,要先向 Master 發出要求,Master 會考慮 Chunkserver 是否為閒置狀態,若為閒置則將 Chunkserver 的位置回報給 client,於是 client 就可以對 Chunkserver 中的檔案進行操作。

GFS 支持了必需提供超大文件量與超大流量的 Google 搜尋引擎服務,同時建構於 GFS 之上的 BigTable 資料庫技術也是 Gmail、Google Maps、Youtube 乃至於其他許多 Google 應用軟體或雲端服務的基礎,可以說是雲端時代的殺手級技術。

礙於篇幅,更多的 GFS 細節可以參考: http://labs.google.com/papers/gfs.html

PHP 函數實作 Semaphore

Ruby Lin 的照片

Semaphore 是一個可變或抽象的資料型態,在並行計算環境中,若有多個行程對一個共用資源,將可提供簡單有用的控制存取。

可以把 semaphore 想成是一個記錄,有多少單位的特殊資源是可使用的,加上操作安全地(即沒有競爭危害)調整那個紀錄,且那是有需要等待的直到一個單位的資源變得可使用。

Semaphore是有用的工具來預防競爭危害和死鎖; 然而,他們的用途絕不是保證程式可以從這些問題中解脱。資源允許任意數量的 semaphore 叫 counting semaphores;值只有 1 或 0 的 semaphore (或 locked/unlocked、unavailable/available)稱 binary semaphores。

下面為 PHP 的 semaphore 函數
int ftok (string $pathname, string $proj) – 將可存取的路徑和方案編號轉換成 System V 可存取的 IPC key。

bool sem_acquire (resource $sem_identifier) - 向信號機要求,信號機會減少一個資源數,並進入臨界區。

resource sem_get (int $key [, int $max_acquire = 1 [, int $perm = 0666 [, int $auto_release = 1 ]]]) - 取得一個新的信號機。

bool sem_release (resource $sem_identifier) - 向信號機通知釋放一個資源數,並離開臨界區。

bool sem_remove (resource $sem_identifier) - 移除一個信號機。

resource shm_attach (int $key [, int $memsize [, int $perm ]]) - 回傳一個可以存取 system V 共享記憶體的編號。

bool shm_detach (resource $shm_identifier) - 中止對共享記憶體的連結。

mixed shm_get_var (resource $shm_identifier, int $variable_key) - 取得共享記憶體中指定的變數值。

bool shm_has_var (resource $shm_identifier, int $variable_key) - 檢查共享記憶體裡是否存在該鍵值。

bool shm_put_var (resource $shm_identifier, int $variable_key, mixed $variable) - 增加或修改共享記憶體中的變數值。

bool shm_remove_var (resource $shm_identifier, int $variable_key) - 移除指定的變數名稱。

bool shm_remove (resource $shm_identifier) – 移除共享記憶體。

GNU libextractor

Shawn Lin 的照片

Introduction

GNU libextractor 是一個種用來從 file 中提取 meta data 的 library。他的設計為以輔助程式庫的方式來執行提取文件實際內容,Meta data 格式的資料有下列 (mime type, image dimensions, color depth, recording frequency),GNU libextractor 主要是被我們用來提取 meta data 之用。目前,GNU libextractor 支持以下格式:HTML, PDF, PS, OLE2 (DOC, XLS, PPT), OpenOffice (sxw), StarOffice (sdw), DVI, MAN, FLAC, MP3 (ID3v1 and ID3v2), NSF(E) (NES music), SID (C64 music), OGG, WAV, EXIV2, JPEG, GIF, PNG, TIFF, DEB, RPM, TAR(.GZ), ZIP, ELF, S3M (Scream Tracker 3), XM (eXtended Module), IT (Impulse Tracker), FLV, REAL, RIFF (AVI), MPEG, QT and ASF. 此外,還有各種額外的 MIME 類型檢測。

GNU libextractor 是免費軟件,可以下載下來修改以及發布。
GNU libextractor 使用 plugin 來處理各種文件格式。從技術上講一個 plugin 可以支持多種文件格式,但大多數 plugin 只支持一個特定的格式。默認情況下,GNU libextractor 將使用所有在安裝目錄下發現的可用 plugin。應用程序可以要求使用特定 plugin 或只有排除某些 plugin。

Example for using dynamic library

// hello.c
#include <extractor.h>
int main()
{
struct EXTRACTOR_PluginList *el;
el = EXTRACTOR_plugin_load_defaults (EXTRACTOR_OPTION_DEFAULT_POLICY);
// ...
EXTRACTOR_plugin_remove_all (el);
return 0;
}

執行以下指令 compile
$ gcc \ -I/Library/Frameworks/Extractor.framework/Versions/Current/include \
-o hello hello.c \
-L/Library/Frameworks/Extractor.framework/Versions/Current/lib \
-lextractor

Plugin management

C Struct: EXTRACTOR_PluginList
建立一組 plugin

Function: void EXTRACTOR_plugin_remove_all (struct EXTRACTOR_PluginList *plugins)
刪除所有給定 plugin 列表

Function: struct EXTRACTOR_PluginList * EXTRACTOR_plugin_remove (struct EXTRACTOR_PluginList *plugins, const char*name)
刪除給定 plugin 列表例如 mime 中的 mpeg

Function: struct EXTRACTOR_PluginList * EXTRACTOR_plugin_add (struct EXTRACTOR_PluginList *plugins, const char* name,const char* options, enum EXTRACTOR_Options flags)
增加給定 plugin 列表

Function: struct EXTRACTOR_PluginList * EXTRACTOR_plugin_add_config (struct EXTRACTOR_PluginList *plugins, const char* config, enum EXTRACTOR_Options flags)
根據 config string load 或是 unload 或是修改已存在的列表

Function: struct EXTRACTOR_PluginList * EXTRACTOR_plugin_add_defaults (enum EXTRACTOR_Options flags)
載入所有在 plugin 資料夾下的預設 plugin 列表

Example for a minimal extract method

以下範例告訴我們如何利用 plugin 解讀出 MIME type

int
EXTRACTOR_mymime_extract
(const char *data,
size_t data_size,
EXTRACTOR_MetaDataProcessor proc,
void *proc_cls,
const char * options)
{
if (data_size < 4)
return 0;
if (0 != memcmp (data, "\177ELF", 4))
return 0;
if (0 != proc (proc_cls,
"mymime",
EXTRACTOR_METATYPE_MIMETYPE,
EXTRACTOR_METAFORMAT_UTF8,
"text/plain",
"application/x-executable",
1 + strlen("application/x-executable")))
return 1;
/* more calls to 'proc' here as needed */
return 0;
}

Internal utility functions

有些實用的內部開發 API
“convert_numeric.h” 定義了各種數字的轉換功能(特別是轉換為浮點數)。
“unzip.h” 定義了一個訪問壓縮文件的 API。
“pack.h” 可以把有 integer 的 struts 分解順便也可以把 big/little endian 轉成 host byte order。
“convert.h” 提供了一個函數進行所需之字符集轉換。
Function: char * EXTRACTOR_common_convert_to_utf8 (const char *input, size_t len, const char * charset) 可以用來方便地從任何字符集轉換為 UTF - 8 文本。

Conclusion

總之,對於訊息解析平凡的我們來說,GNU libextractor 不只幫助了我們找到檔案的正確格式,還可以撰寫各種 plugin 工具,分析各種文字格式,找到相對應的 MIME type。這對 email 這塊領域而言,可說是不可或缺的一項工具。