[PHP] 自製金錢分攤函式

近日在工作上應該會需要計算金錢分攤,簡單寫了個 PHP 函式備用。

function shareAmount( $amount , $shares ) {
        $arr = array();
        if ( is_numeric($amount) && is_int($shares) ) {
                $precision = is_int($amount) ? 0 : strlen(substr($amount, strpos($amount, '.')+1));
                for ( $i = $shares; $i > 0; $i-- ) {
                        $val = round( $amount / $i , $precision );
                        array_push( $arr , $val );
                        $amount -= $val;
                }
        }
        return $arr;
}

執行結果大概像這樣:

// var_dump( shareAmount(101,3) );
array(3) {
  [0]=>
  float(34)
  [1]=>
  float(34)
  [2]=>
  float(33)
}

// var_dump( shareAmount(0.5101,3) );
array(3) {
  [0]=>
  float(0.17)
  [1]=>
  float(0.1701)
  [2]=>
  float(0.17)
}

我在資料庫沒看到大數,所以就沒考慮 BC Math,直接用 is_numeric() 了... :p

Technorati Tags:

Javascript 的變數範圍

最近在微調部門某個 PHP 專案程式,該專案使用 ExtJS 作前端介面 framework ...
整理這個專案內的 Javascript 程式讓我覺得... 應該有不少人忽略,或是不在意 Javascript 的變數定義方式。

先來看這串程式碼:
Javascript variable scope (test code)
執行結果:
Javascript variable scope (test result)

這張圖有趣就在第 40, 41 行程式碼執行的結果差異,以及 42, 43 行程式碼執行的結果差異。
在 Javascript 不透過 var 進行定義之變數,皆為全域變數;但透過 var 定義之變數就有變數範圍。
這兩種變數定義方式影響瀏覽器開啟網頁後的記憶體耗用量,以及 Javascript engine 進行 GC 的效率與結果,不得不慎呀...

Technorati Tags: , , ,

Sencha Touch 使用心得

這陣子在進行一個 mobile web 開發專案;我們對 Ext JS 還算熟悉,故選擇採用同公司的產品:Sencha Touch
我們沒使用過,決定先進行 prototyping,看能挖出多少可用、好用的元件。
目前第一版趨近完成,我先寫篇心得分享,順道幫自己留個筆記;請路過看到的前輩、高手們不吝給予指教啦~ (羞)

目前是 2014 年 3 月初,已釋出的 Sencha Touch 最新 GPL 版本是 2.3.1,但堪用的是 2.1.1。
Sencha Touch 僅支援 WebKit based 網頁瀏覽器,大致上就是這些

More

Technorati Tags: , , ,

[Apache Tomcat] Enhance security

我沒有在使用 Apache Tomcat 的後台,佈署軟體/程式都是透過 scp/sftp/ftp 等方式做傳輸。
所以在解開 Apache Tomcat 的壓縮檔之後,我會執行以下指令,把不必要的檔案清掉,增強安全性:

cd apache-tomcat-* && \
/bin/rm -rf webapps/docs webapps/examples webapps/host-manager webapps/manager && \
/bin/rm -f webapps/ROOT/*.gif webapps/ROOT/*.xml webapps/ROOT/*.ico webapps/ROOT/*.txt webapps/ROOT/*.svg && \
/bin/cat /dev/null > webapps/ROOT/index.jsp &&
/bin/cat /dev/null > webapps/ROOT/index.html

Technorati Tags: ,

[實測] Plextor M5M 256GB mSATA SSD (PX-256M5M) on Lenovo T420s

前幾天幫我在家用的 Lenovo T420s 裝上新的 mSATA SSD,用 AS SSD Benchmark 跑了些數據,貼在這裡做個紀錄。

受限於 T420s 的介面速度,Plextor M5M 256GB mSATA SSD 的效能沒有完全發揮。
PX-256M5M benchmarkPX-256M5M I/O

對照組,T420s 原廠給的 7mm 2.5" 7200rpm HDD。
HTS723232A7A364 benchmarkHTS723232A7A364 I/O

雖然 SSD 的效能沒有完全發揮,用來當系統碟的爽度依然很高啊... 8-)

Technorati Tags: , , , , ,

[PHP] HTTP 連線的資料共用

我相信有許多 Web 應用程式開發者與我類似,常常想辦法預存一些經常存取、變動頻率不高的資料,提昇程式效能。
透過這類的資料預存,可以降低資料庫存取頻率,並減少 server 的 file I/O 次數。

在 .Net 與 JAVA 的領域,程式語言都提供了相關的物件/變數,讓 Web 應用程式儲存資料,而該應用程式的所有連線使用者皆可以存取。
.Net 用的是 System.Web.Caching.Cache;JAVA Servlet 是 javax.servlet.ServletContext,而 JSP 的 Application 物件便是其實作。
但在常見的環境(eg. Apache HTTPD w/MPM prefork + mod_php),也沒有額外的模組(eg. APCmemcache),PHP 難以提供這種物件/變數讓人使用,開發者只能硬幹。 :p

因為 COOKIE 的 size 有限,在 PHP 大概只能用 SESSION 硬幹。
我是這樣做的...

存入/更新

function writeAppCache( $app_name , $data ) {
	// 紀錄原本的 session ID
	$orig_session_id = session_id();

	// 如果已有 session 存在
	if ( !empty($orig_session_id) ) {

		// 存放原本的 session 資料
		session_write_close();

		// 切換到自己定義的 application session,存放/更新資料
		session_id($app_name);
		$_SESSION = $data;
		session_write_close();

		// 切換回原本的 session
		session_id($orig_session_id);
		session_start();
	}
}

讀取

function readAppCache( $app_name ) {
	$data = null;
	// 紀錄原本的 session ID

	$orig_session_id = session_id();
	// 如果已有 session 存在
	if ( !empty($orig_session_id) ) {

		// 存放原本的 session 資料
		session_write_close();

		// 切換到自己定義的 application session,讀取資料
		session_id($app_name);
		$data = $_SESSION;
		session_write_close();

		// 切換回原本的 session
		session_id($orig_session_id);
		session_start();
	}
	return $data;
}

因為所有程式都能存取 session 內的資料,不建議在 session 內儲存私密/機密資料。
若要避免資料不小心被同一台 server 的其他程式,可以加上 session_name() 作區隔。

Technorati Tags: , , , ,

PHP 樣板引擎(templating engines)

翻文件翻到這篇
雖然時間有點久了(2009 年的文章),但我覺得該文仍具參考價值。

該文裡面提到了一些樣板引擎;排除已經不存在的 Calypso,目前仍存在的有這些:

該文作者沒提到 Template LiteZend View,倒是給了些數據。
PHP templating engine benchmark (Year 2009)

PHP templating engine benchmark (Year 2009)

網路上有許多 Smarty 2、Smarty 3、Dwoo 的效能評測資訊,由快至慢列舉的話,幾乎都是 Dwoo -> Smarty 2 -> Smarty 3。
但是 Dwoo 已經宣告 EOL 了。官方網站直接放上這段文字:

Important Notice - Dwoo End Of Life
This library is not being maintained anymore for quite a while, so if you are starting a new project you should consider using Twig instead.

Twig 官方的安裝文件給了數種安裝方式,不知道文章作者用的是哪一種。 O_o
( 如果是 compile 成 PHP extension 的話,效能肯定是比較好的呀... )

PS. Twig 的 for ... in ... 挺有趣啊,我看到 Perl 的影子。 XD

Technorati Tags: , , , , , , ,

[FreeBSD] 讓 Postfix 使用 Gmail 的 SMTP server 送信

數月前,我在 Amazon EC2 開了一個跑 FreeBSD 的 Micro Instance 來 maintain ports。
我認為這台虛擬機器隨時都可以重造,所以我在 Security Groups 的設定中只幫 Inbound 綁了幾個特定的 IP,讓我可以 ssh 登入就好。
於是我就讓這台虛擬機器跑 Postfix,透過 gmail 的 SMTP server 幫我送 PR 。

目前在網路上找到的說明,大多都會提到 SSL/TLS certificate 的設定,我倒是跳過了這段,而且就目前看來是運作良好。
步驟大致如下:

  1. 用以下指令作 Postfix 的編譯設定:
    # cd /usr/ports/mail/postfix && make config

    其中 TLS 選項一定要勾。
    postfix ports config

  2. 安裝(或重新安裝) postfix。
  3. 在 /usr/local/etc/postfix/main.cf 放進以下的設定:
    relayhost = smtp.gmail.com:587
    smtp_sasl_auth_enable = yes
    smtp_sasl_password_maps = hash:/usr/local/etc/postfix/gmail_passwd
    smtp_sasl_security_options =
    smtp_use_tls = yes
    
  4. 編輯 /usr/local/etc/postfix/gmail_passwd ,內容大致如下(記得填上自己的 gmail 帳號與密碼):
    smtp.gmail.com:587 帳號@gmail.com:密碼
  5. 用以下指令製作 hash map:
    # postmap /usr/local/etc/postfix/gmail_passwd
  6. 啟動(或重新啟動)Postfix:
    # /usr/local/etc/rc.d/postfix restart

PS1. 以上的設定只適合單人用機,因為所有外寄的郵件都會透過同一個 gmail 位址寄出。 :p
PS2. 記得刪掉 /usr/local/etc/postfix/gmail_passwd ,或是作 chmod 。

Technorati Tags: , ,

[Ubuntu] 安裝 & 設定 libapache2-mod-auth-mysql

這兩天試著在 Ubuntu serverApache HTTP authentication with MySQL backend 。
記一下幾個要注意的地方:

  • 設定參數在 /usr/share/doc/libapache2-mod-auth-mysql/DIRECTIVES.gz ,可以透過以下這個指令查:
    # dpkg-query --listfiles libapache2-mod-auth-mysql
    
  • 為避免 Apache 混合使用驗證而導致驗證失敗,加上這行比較保險:
    AuthBasicAuthoritative Off
    

.htaccess 檔內容大概像這樣:

AuthName "JoeHorn's Secret Web"
AuthType Basic
AuthBasicAuthoritative Off
AuthUserFile /dev/null
Auth_MySQL on
Auth_MySQL_User DB_USERNAME
Auth_MySQL_Password DB_PASSWORD
Auth_MySQL_DB AUTH_INFO_DB
Auth_MySQL_Password_Table AUTH_INFO_TABLE
Auth_MySQL_Username_Field USERNAME_FIELD
Auth_MySQL_Password_Field PASSWORD_FIELD
Auth_MySQL_Empty_Passwords off
Auth_MySQL_Encryption_Types MySQL
Require valid-user

Technorati Tags: , , , ,

Subversion 1.8

Subversion 1.8 又更改 client 端的 metadata 結構了... orz

1.7 的結構如下:
Subversion 1.7 metadata structure

1.8 則是長這樣:
Subversion 1.8 metadata structure

差異就是... 原本獨立用純文字檔紀錄的 format 跟 entries 被整併到 wc.db 了。
( 而 wc.db 是 SQLite 的資料庫檔 )

PS. 我在用的 NetBeans 7.3.1 尚未支援新結構,所以出來唉唉叫一下... (死

Technorati Tags: , ,