原文:用php做圖片臉部偵測
這是自己在ithelp網站上分享的文章,想一想如果需要在圖片上針對臉部特徵做一些處理的話,可以做參考,所以在這裡提一下,不另外寫文章了。
This page looks plain and unstyled because you're using a non-standard compliant browser. To see it in its best form, please visit upgrade to a browser that supports web standards. It's free and painless.
原文:用php做圖片臉部偵測
這是自己在ithelp網站上分享的文章,想一想如果需要在圖片上針對臉部特徵做一些處理的話,可以做參考,所以在這裡提一下,不另外寫文章了。
22 元月, 2010 17:16
之前想要熟悉一下PHP Extension的開發,剛好看到LightCloud,他是基於另外一個專案Tokyo Tyrant,Tokyo Tyrant的底層則是一個高速Key-Value pair資料庫,叫做Tokyo Cabinet。TokyoTyrant已經有不少專案支援,包括純php以及extension,但是Tokyo Cabinet似乎還沒有,所以就拿他來開刀。
結果在這裡:http://www.fillano.idv.tw/tokyocabinet3-0.1.src.tar.gz
其實我之前是根據TokyoCabinet 1.4.X的TCADB這個介面來開發,不過最近都在使用Ubuntu,他安裝的套件是1.3.X版本的,之前許多功能不能使用...所以就先把他改成與1.3.X相容,也稍微調整一下程式碼再釋出。
這個Extension主要是提供幾個東西:TokyoCabinet的Hash及B+ Tree格式的資料庫檔案及Hash的記憶體資料庫的支援,可以開啟(如果apache有讀寫權限,那檔案不存在時會產生檔案)、寫入、查詢、讀出等功能。另外雖然可以支援記憶體資料庫,但是用php extension的方式使用不太有意義,我當初寫這個extension除了練習之外,還順便拿來做檔案資料庫來測試使用。
要安裝,必須先安裝php的developer功能,解開檔案後,在目錄中執行phpize,然後./configure -> make -> make install等。mytest目錄中有兩個php檔案可以用來做測試。當然,在安裝前要先裝好tokyocabinet。
Tokyo Cabinet的key與value都是binary safe的,而且不限長度,所以拿來存放大檔案來做streaming也許是個不錯的用法。
因為是習作,所以歡迎指教囉,有些地方其實不太確定就硬上了,心有點虛......
除了透過memcached的協定來存取TokyoTyrant,PECL上面已經有extension支援TokyoTyrant,作者還在持續更新中:
http://pecl.php.net/package/tokyo_tyrant
開發的主站在github:
http://github.com/mkoppanen/php-tokyo_tyrant
作者的blog有不少好物:
http://valokuva.org/
07 十月, 2009 10:43
推文( 2 )
為了測試自己寫的PHP Tokyo Cabinet Extension是否在多人運作下不會有問題,興起了利用Web Worker來做測試的念頭。
(按:我自己寫的extension只是包裝他的tcadb函式庫,這樣就可以做local access他的資料庫檔案或是記憶體資料庫。其實透過Tokyo Tyrant才是最好方法,Plurk的LightCloud也是基於Tokyo Tyrant的。Tokyo Tyrant已經有初期的PECL Connector可以支援,同時也有純PHP實現的Connector。)
(閱讀全文)22 七月, 2009 00:00
PHP 5.3.0開始,有一個重要的特性正式加到PHP裡面,就是匿名函數。(請參考:Anonymous functions。手冊還有提到,匿名函數目前是用 Closure內部類別實作,但是不要管他,因為實作方式有可能修改。)
在提到匿名函數之前,先看看PHP的callback應用。callback是php非常好用的功能,可以利用他來用自訂的方式處理資料,例如array_map,就可以用一個callback函數一次處理陣列中所有元素,不用iteration,也不用loop。下面是用callback函數處理一個整數陣列,傳回每個元素的平方:
(閱讀全文)06 七月, 2009 11:08
Plurk沒有提供api,但是有提供使用IM來收發訊息的功能,透過簡單的語法,就可以透過IM做出plurk機器人。
我自己是使用Google Talk來收發Plurk,Google Talk使用從XMPP標準延伸出來的協定,所以要利用XMPP來使用Google Talk不必花太多功夫。稍微找了一下,就在google code上面找到一個雖然還在開發中,但是已經可以使用的專案,叫做XMPPHP。
要讓他可以跑,還需要打開PHP的openssl模組,因為Google Talk會用到TLS以及SASL。另外,就算功能正常使用,我還是碰到許多無法fclose資源的訊息...沒辦法,還在開發中的東西吧...
接下來,只要修改一下他的範例(sendmessage_example.php):
(閱讀全文)19 六月, 2009 12:56
之前用Quercus嘗試將CodeIgniter放到Google App Engines上執行,仿照Google提供的留言板例子,把程式放到CodeIgniter上跑。但是後來發現,在留言板上輸入中文會出現問題。
我的資料是放在一個java bean裡面(拿google的範例,所以叫做Greeting),資料存取透過jdo,存入時使用servlet,取出則用php。結果存入中文資料沒問題,取出中文資料就...一堆亂碼。
比較一下取出的資料,發現似乎字串長度是對的,但是編碼不對,每個中文字元長度似乎都被裁成一個位元組,而不是UTF-8的三個位元組。在java bean裡面動了一下手腳,把getter回傳的資料型態改成byte array,然後用getBytes("UTF-8")回傳,結果就是正確的了。(另外一個方法是用&#number;這樣的格式來處理每個字元)
看起來Quercus處理java與php資料型別轉換的方法(unmarshal)似乎怪怪的...要不然就是他內建的Env.createString()方法有點問題...另外,如果不使用GoogleQuercusServlet也會有一些問題,我把script_encoding改成iso-8859-1就正常顯示php程式中的中文???但是我用binary editor確認過,檔案編碼是UTF-8耶???真奇怪。我還特別修改unicode.semantics、unicode.script_encoding、unicode.runtime_encoding、unicode.output_encoding等選項耶,但是沒啥用處。
Quercus的功能感覺還不夠穩定...
15 五月, 2009 13:07
其實如前篇,並沒有什麼進度,不過反正一步一步測試。
目前是先把Quercus on the Google App Engine的例子porting到CodeIgniter然後放到google app engine跑跑看。urlrewrite的部份透過UrlRewrite Filter來做。
datastore還是用google app engine官網的例子與Quercus on the Google App Engine的php程式整合出來的,只是把MVC分開,用CodeIgniter來跑。
有興趣可以玩玩看:http://fillanocode.appspot.com/。
要改資料庫方法跟ActiveRecord方法,可能需要做一些抉擇。google提供的datastore其實是一個ORM的東西,跟直接操作關聯式資料庫的方法頗有差距,與其porting上去(但是背後要重組query),也許不如透過JDO去操作...,不然要實作到可以直接透過sql操作,要花不少功夫。
12 五月, 2009 20:19
怕標題太聳動,所以先聲明一下,我只是想讓CodeIgniter根目錄下的index.php會動。(怎麼在Google App Engine跑php,請參考前篇用Google App Engine跑php ,至於為何挑CodeIgniter?因為他架構比較簡單,似乎比較容易改...)
Google App Engine有一個限制,就是無法寫入檔案系統,這對於許多framework及php有很大殺傷力。尤其是cache機制,需要可以動態產生、更新cache,這樣在Google App Engine跑php就有很多問題。例如想要跑CodeIgniter,就會出現一堆錯誤訊息,主要來自無法寫入檔案。
Quercus有一個很方便的地方,就是可以自己寫QuercusModule,QuercusModule的公有方法就會成為php函數。使用自訂的函數,配合Google App Engine的datastore服務,就有可能把datastore當作檔案系統來使用。
(閱讀全文)02 五月, 2009 11:53
Google App Engine開始測試java的支援了。由於java透過他的scripting可以支援php,所以可以用這個方式間接在Google App Engine跑php。之前在請問一下有人在玩google app engine嗎? 討論串討論了一下,自己又找資料做了一些測試,果然可以,但是有少許語法似乎會有問題。
主要的參考資料可以看下面幾個連結:
詳細的配置使用方法可以參考上面的連結,但是web.xml不要用第二個連結裡面的,他改過QuercusServlet,使用GoogleQuercusServlet,但是以發行的quercus.jar裡面沒有這個東西,所以配置會有問題。只要把google的guestbook範例跟第二個連結中的php範例結合起來理論上應該就ok......不過我直接用那個php範例會出現錯誤......稍微除錯一下php,發現php裡面的
foreach ($greetings as $g) {
......
for ($i=0; $i<count($greetings); $i++) {
$g = $greetings[$i];
......
需要注意的是,目前google appengine datastore的使用與資料庫大大不同,他是一個object data store,目前java可以透過他提供的jdo/jpa方式來存取,存入的entity class必須用java來實作,用php做不出來。參考上面第二個連結可以看到短期可能出現的一些解法(透過H2模擬mysql),長期恐怕還是需要等google推出原生的支援。
上了resin的官網仔細看了一下,resin-4.0.0裡面可以找到resin.jar,這裡面就有GoogleQuercusServlet(如同blog上說的)。另外測試了一下,建議使用resin.jar而不是quercus.jar + resin-util.jar + script-10.jar + jetty-util-6.1.0.jar這個solution。這樣使用foreach也不會出現錯誤訊息。
17 元月, 2008 16:22
龐大的switch case常常讓程式不好維護,需要增加新功能時就得去改switch case所在的程式,讓維護比較麻煩。之前看到可以用command pattern來改進這個狀況,所以就用來試一試。
大致的構想如下:
class CommandExecuter {
var $command=array();
function addCommand($command,&$obj) {
$this->command[$obj->cmdName] =& $obj;
}
function getAllCommand() {
return array_keys($this->command);
}
function render($command) {
$this->command[$command]->render();
}
function deal($command) {
$this->command[$command]->deal();
}
}
上面是主要的程式,用來執行所有表單產生以及回傳搜尋結果。
class Command {
var $cmdName="";
function Command ($str) {
$this->cmdName = $str;
}
function render() {
產生表單
echo "<input type='hidden' name='COMMAND' value='".$this->cmdName."'>";
......
echo "</form>";
}
function deal() {
處理表單資料,產生搜尋結果並回傳
}
}
以上是實際產生表單以及處理搜尋結果的命令類別。
class CommandAssembler {
function getCommandExecuter(){
$tmp = new CommandExecuter();
$tmp->addCommand("search1",new Command("search1"));
return $tmp;
}
}
用這個類別組出完整的設計。
使用方法(產生搜尋表單):
$cmd = CommandAssembler::getCommandExecuter();
$keys = $cmd->getAllCommand();
foreach ($keys as $k) {
$cmd->render($k);
}
使用方法(產生搜尋結果):
$cmd = CommandAssembler::getCommandExecuter(); $cmd->deal($_POST['COMMAND']);
這是大略的想法。
25 十月, 2007 13:07
方法及程式發表在[酷!學園 -> PHP程式設計]論壇中,這個網址:http://www.ez2.us/~ricky/RobotAway/則有範例與程式下載,也可以線上檢視原始碼。使用起來十分簡單。
他的原理是用一些javascript的混淆技術,包括隨機變數名稱、隨機註解、程式內容編碼等方法,讓機器人難以即時破解,來達到防止灌水的目的。(這些也是病毒上常見的變形、混淆技術)
最大的好處是,對於一般的網頁用戶來說,不會感覺到這個程式的存在,不像一般的captcha需要額外輸入文數字來驗證。對於程式設計師來說,只要用到三個方法,配合網頁程式,就可以做出來,非常簡單。
在上述的連結,Ricky兄有提供使用的範例。不過因為使用簡單,所以也不太需要繁雜的說明。另外,程式是寫成php5的類別,對於php4的用戶來說,只要拿掉private關鍵字,把constructor函數從__construct改名為RobotAway就可以了。
使用步驟大致如下:
應用一些方法,還可以讓這個程式更難捉摸。就是在要輸入表單的地方,用隨機產生的SITEKEY與INPUTNAME來產生$ra物件,然後把SITEKEY與INPUTNAME存入session,要做Verify時,再從session中取出SITEKEY與INPUTNAME來產生$ra物件,因為每次欄位名稱與sitekey都不一樣,會更增加機器人灌水的難度。
17 十月, 2007 14:25
昨天檢視了一下以前寫的程式,想要改良一下程式的效率,並且讓程式清晰易懂。這個時候發現一個問題,就是依照條件建構SQL的過程太複雜,需要許多if/else判斷,使得程式容易不小心出錯。
仔細觀察了一下,問題發生的主要原因在於兩個地方:
結果為了依照SQL的規則來產生SQL語句,就會讓程式流程變得很複雜。
想到的方法是,將sql語法的邏輯與產生sql的邏輯分開,寫一個類別,任意將各種條件傳入,等到需要用到SQL語句時,再依照SQL語法來將各種條件組合成SQL語句。依照這個想法,寫了一個簡單的SQL Builder類別:
class QueryBuilder {
var $table;
var $columns;
var $active;
var $order;
var $where;
var $limit;
function QueryBuilder ($table, $columns) {
$this->__construct ($table, $columns);
}
function __construct ($table, $columns) {
$this->table = $table;
if (strpos($columns,':')===false) {
$this->columns = array($columns);
} else {
$this->columns = explode(':',$columns);
}
$this->where = array();
$this->order = "";
$this->limit = "";
}
function setActive ($active) {
$this->where[] = " $active=1";
}
function setOrder ($order, $sort="ASC") {
$this->order = sprintf(" ORDER BY %s %s", $order, $sort);
}
function setWhereInt ($col, $val) {
$this->where[] = sprintf(" %s=%u", $col, intval($val));
}
function setWhereStr ($col, $val) {
$this->where[] = sprintf("%s='%s'", $col, $val);
}
function setSearch ($col, $val) {
$this->where[] = sprintf("%s LIKE '%%s%'", $col, $val);
}
function setSearchLt ($col, $val) {
$this->where[] = sprintf("%s < %u", $col, intval($val));
}
function setSearchGt ($col, $val) {
$this->where[] = sprintf("%s > %u", $col, intval($val));
}
function setLimit ($offset,$rowcount) {
$this->limit = " LIMIT $offset, $rowcount";
}
function compose () {
$ret = sprintf("SELECT %s FROM %s", implode(',',$this->columns), $this->table);
if ($this->where) {
$ret .= sprintf(" WHERE %s", implode(' AND ', $this->where));
}
$ret .= $this->order;
$ret .= $this->limit;
return $ret;
}
}
這個類別還很粗糙,但是剛好滿足我的需求,也讓程式流程看起來比較清楚了。
12 十月, 2007 09:04
檔案上傳進度資訊是PHP5.2才新增的功能。但是最近在逛phpclass.org時,發現有人做了PHP4的patch。patch及說明的出處:http://www.phpclasses.org/blog/post/61-File-upload-progress-meter-for-PHP-4-at-last.html
作者是早期PHP的核心開發人員,跟據他的說明,其實在php4就已經有人做了patch,但是不知為何到了PHP5.2,PHP團隊才把這個功能正式加進來。PHP5已經問世好幾年了,但是市面上大部分的網站,其實都還在用PHP4,主要是因為移植的複雜度以及潛在問題,所以許多人裹足不前。所以為了廣大的PHP4用戶,他做了Patch,使用這個patch就可以支援PHP5.2的檔案上傳進度資訊功能。
看到這個資訊很興奮,不過他patch的rfc1867.c是屬於PHP的核心,所以非得重新編譯不可。另外,PHP4已經不再更新了,末代版本是4.4.7,作者patch的版本是4.3.11以及4.4.4,在PHP官方網站上已經找不到原始碼的套件,所以只好用4.4.7來試試看。
以下是大致的過程中以及我碰到的一些問題:
如果大家想要測試的話,以下是我patch過的rfc1867.c以及rfc1867.h:下載(注意:只能給php-4.4.7用,我是用它的source來patch的喔)
另外是幾個測試的圖片:
(我把畫面中的網址拿掉,因為我測試完就把測試用的apache關掉了。其實效果應該跟demo網站是一樣的。)
前一陣子找到的資料,使用VeriWord類別來做文字圖片驗證(Captcha)可以讓圖片驗證具有較高的安全性。所以就來試試看了。
VeriWord(官方網站在phpclasses上)看起來已經很久沒有人維護了(最後的日期是2004年,有一點久了).....手冊也找不到,不過使用起來很簡單。主要的功能包括:
大概介紹到這裡,先來試試吧。
先來看看怎麼安裝設定:
大概就這樣吧,用起來很簡單的,程式碼也不多,很容易了解,要整合到不同的程式裡面不會花很大功夫。
以下是sample.php跑出來的畫面:
這一張的captcha比較清楚,套用他的RandomNoise,有時候字會看不清楚....如果不是搭配BackgroundNoise的話,我想使用的字型最好挑選過,效果比較好。
這個程式已經沒人在維護,官方的manual連結也找不到了,但是我有google到還有別的網站有,檔名叫做manualveriword.pdf,參考一下。
19 七月, 2007 13:57
xoops2定義了XoopsObject這個核心類別,用陣列來儲存一系列的值,並用XoopsObjectHandler類別來與資料表做映射。XoopsObject定義好了初始化、存取值的方法,讓我們很方便地使用。更方便的是,由於在XoopsObject類別內,只使用了TextSanitizer物件來做字串檢查,而XoopsObjectHandler類別只是一個抽象類別,並沒有定義好實作,所以只要把XoopsObject(放在/kernel/opject.php檔案內)以及TextSanitizer(放在/class/module.textsanitizer.php檔案內)從Xoops2中取出,就可以當作自己開發的核心。
使用XoopsObject如何達到快速開發呢?因為XoopsObject裡面定義好了資料型別與處理方法,利用他定義好的型別,可以設計好一些類別,輸入XoopsObject即可產生相對應的網頁。舉例來說,製作表單是一件相當煩瑣的工作,可以設計一個表單類別,輸入XoopsObject後,可以針對相對應的xoops資料型別產生表單。
另外使用XoopsObject搭配Smarty(或其他樣板引擎)來做MVC模式開發,就可以看到快速開發的效果。由XoopsObject以及XoopsObjectHandler負責Model,Smarty負責View,程式開發只要專注在Controller上就可以。
由於XoopsObjectHandler其實並沒有實作他定義的方法,所以在應用的時候還需要自己撰寫他的create、get、insert、delete方法,如果要偷懶,更好的方法是寫一個類別產生器,類似PDO。這樣在開發上,只要設計出data schemas,就可以自動產生箱對應的物件。(也許有一天可以跟phpMyAdmin結合)目前Xoops有設計好的database類別可用,但是只有支援mysql。如果要抽換資料庫,或是改成用pear的db套件等,類別產生器都需要修改,這是比較麻煩的地方。
另外一個問題是,XoopsObject並沒有比較好的處理關聯性的方法,如果資料關係複雜,處理起來會花費比較大的功夫。如何讓XoopsObject能自動處理類別之間的關係(1:n、n:m等等),而不用花費controller的功夫,是類別產生器需要下的另一個功夫。
如果XoopsObjectHandler的方法是一致的(例如,僅限於create、get、insert、delete),還有另一個好處,就是容易做權限控管。可以利用類似Static Proxy的方式,控制這些方法的使用。
會有這些想法,其實是自己懶的緣故(已經熟悉xoops2,但是懶得學cake),另外一個原因是希望不會因為使用一個framework讓程式大幅增加,並留給自己一些Mashup的空間。