2012年3月27日 星期二

[MySQL] 資料庫、資料表、連線編碼 @ Ubuntu 10.04

最近接觸 MySQL,一直以來都不太熟,只記得幾年前曾透過 PhpMyAdmin 建過幾張表。最近則因為開發環境是 MySQL,加上資安設定,變成必須透過某台機器才能連線,於是我就"搞鋼"地透過 SSH Tunnel 和 MySQL command line 來使用(其實可以配合GUI來使用就好),隨後碰到資料庫、資料表及連線編碼問題。


首先是連線問題,要避開 mysql-client 的編碼問題,可採用以下指令強制使用 utf8 連線:


$ mysql -h 127.0.0.1 -u root -p --default-character-set=utf8


查詢當前環境的編碼資訊:


mysql> show variables like "char%";
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

其中 character_set_database、character_set_server 和 character_set_system 為 MySQL Server 端的設定,使用 mysql-client 連線時,設定 --default-character-set=utf8 影響的僅有 character_set_client 、character_set_connection 和 character_set_results,若 mysql-client 不設定使用 utf8 編碼時,在 Ubuntu 10.04 環境下,很有可能預設採用 latin1:


mysql> show variables like "char%";
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_results | latin1 |
+--------------------------+----------------------------+

接要要留意的還有 character_set_database 這個變數資訊,在 Ubuntu 10.04 server 環境預設也是 latin1,並且這個變數會跟你使用的資料庫有關:


mysql> CREATE DATABASE `MyDBDefault`;
mysql> use `MyDBDefault`;
mysql> show variables like "char%";
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_database | latin1 |
+--------------------------+----------------------------+

mysql> CREATE DATABASE `MyDB` DEFAULT CHARACTER SET utf8;
mysql> use `MyDB`;
mysql> show variables like "char%";
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_database | utf8 |
+--------------------------+----------------------------+

當資料庫 character_set_database 為 utf-8 時,這時在其裡頭建立的資料表預設就會是 utf8 了,如果建立資料庫沒指定並且系統環境也沒設定,那大概很有機會是 latin1 編碼。


總結一下,假使開發環境大家都默認是 utf8 編碼:


使用 mysql-client 操作時,多加 --default-character-set=utf8 使用,可避開 mysql-client 端環境變因(特別是不熟的機器):


$ mysql -h 127.0.0.1 -u root -p --default-character-set=utf8


建立資料庫時,可指定 DEFAULT CHARACTER SET utf8 來避開 server 端預設環境的問題:


mysql> CREATE DATABASE `MyDBUTF8` DEFAULT CHARACTER SET utf8;


建立資料表時,可指定 DEFAULT CHARSET=utf8 來避開資料庫預設非 utf8:


mysql> CREATE TABLE `MyTable` ( `MyID` INT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY ) DEFAULT CHARSET=utf8;


其他部分:


如何透過指令查詢資料表、資料欄位的編碼 how-do-i-see-what-character-set-a-database-table-column-is-in-mysql


2012年3月25日 星期日

春思

2012-03-25


春天看起來好像來了,卻又快過了?記得老家常說清明過後氣溫會越來越熱,端午過後,焰日更盛。


最近周邊親朋好友紛紛轉換跑道,對於自己的未來似乎越來越明確,只是與人閒聊交談,除了活在不確定性的規劃中,還得應付著別人的觀感,想起來也滿累的。例如跑到新創公司,不被看好的甚多。這種現象早在兩年前我也就感受過,當時周邊有個 team (被迫?!)以 spinoff 的方向進行中,可是單位內幾乎沒人認同,永遠的數落。


最近職場上又被 Push 了一把,說的很不錯:「人生總有犧牲,但要記得自己的犧牲是為了獲取什麼。」不然工作或生活上總只剩得抱怨兩字,只記得自己苦了什麼。有人存錢存了一整年,只為那幾天的出國旅遊;有人打拼二三十年,為了買個房讓妻兒溫暖。想想,這些都是挺有意義的事,何必說別人省吃儉用過的很苦呢?


今年花了不少時間在思考,看到周邊有人追求 CP 值、追求名聲、追求金錢,我想,我漸漸地知道自己要的是什麼。規劃一塊自己認為有意義的嘗試,不用為了滿足別人的眼光而回話、做事,別忘了真正為你負責的還是自己啊,單純為自己的生活之道努力吧!


2012年3月21日 星期三

[PHP] CodeIgniter (PHP Framework) 筆記


圖片來源:http://codeigniter.com/


最近因工作上的關係,重溫 PHP & MySQL 的懷抱。說真的,我上一次寫 PHP & MySQL 已經是 2005 年的事情,但我離 PHP 還沒那麼遠,至少 2009 年還有寫過。最近工作上採用 CodeIgniter Framework,算是第一個我接觸的 PHP Framework 了。我記得在 2009 年時,我還很討厭 framework 這類的東西,但工作幾年後,我發現 framework 在某個角度來說是很有用的,例如工作交接、維護與傳承。


老實說用 framework 開發速度不見得快,但好處之一就是可以讓一群人依循某種共同的開發架構(MVC)撰寫程式,如此一來要接手的人比較不會太痛苦,至少痛苦的機率小了那麼一丁點。這邊就先簡短記錄一些筆記。


效能:


參考 Google Search 的第一筆資料 - PHP Framework 的效能比較。簡單的說,在一些常見的 framework 中,CodeIgniter 效能不算差的,但與原生 PHP 來比,效能還是差了一大截。


架構:


稱得上很標準的 MVC 吧?目錄結構有 application/controllers、application/models 和 application/views ,如其名的架構,其中寫 controller 時,大部分都是用一個  class 的架構,依照該 class 來實作:


class Welcome extends CI_Controller {
        public function index()
        {
                echo "Page at /welcome";
        }
        public function test()
        {
                echo "Page at /welcome/test";
        }
        public function update($x = NULL)
        {
                echo "Page at /welcome/update";
        }


所以,你的網頁上就有 http://domain/index.php/welcome、http://domain/index.php/welcome/test、http://domain/index.php/welcome/update 和 http://domain/index.php/welcome/update/x 四種網址位置(其中最後的 x 是變數)。


接著 Models 的部分,也是繼承某個 class 的寫法:


class MyModel extends CI_Model {
        function get_all_entries()
       {
                $query = $this->db->get('mytable');
                return $query->result();
       }
}


如此一來,在 controller 裡頭就可以用:


class Welcome extends CI_Controller {
        public function index()
        {
                $this->load->model('MyModel');
                $this->MyModel->get_all_entries();
        }
}


而 views 比較像傳統 PHP 用法,不用是個 class 而是像以前寫 PHP 那樣夾雜 HTML、PHP、CSS 和 Javascript 等,而這個 view 能接收的參數需要從 controller 傳進來:


class Welcome extends CI_Controller {
        public function index()
        {
                $x = array('123','456');
                $this->load->view( 'myview' , array( 'data' => $x ) );
        }


接著在 application/views/myview.php 中,就可以透過 global 變數 $data 取得資料。


 缺點:


錯誤訊息不見得會顯示


有道是越難除錯的錯誤,通常是最蠢的問題,對於 CodeIgniter 來說,像 controller 和 models 這種 class 架構來說,不小心漏寫{}時,系統不見得會顯示錯誤,此時只會看到 500 internal server error 這種訊息,這跟直接用 PHP 會顯示錯誤訊息來說,實在很不方便。除此之外,如果使用 MySQL 時,未安裝 php5-mysql 相關套件時,也一樣空白一片。


這些真的還滿糟糕的。


Session 預設為 client side session 架構


對 PHP 來說,原先有 $_SESSION 使用,但在 CodeIgniter 必須改用 $this->session->all_userdata() 這類的存取方式,但真正棘手的是它的實作方式,預設是把 session 資料進行加密儲存在 cookie 裡頭,除了安全問題外,本身 cookie 就跟瀏覽器的實作有關,所以不見得所有資料都可以正常透過 setcookie 方式儲存起來,例如 $session['中文字'] = true 在 2.1.0 版就會發生問題!更別說 cookie 資料被破解、使用限制等等的。


另一個作法是把 session 資訊儲存在 Databases 裡頭,如此也可能導致 DB 連線頻繁而產生效能危機。


更多資訊可以參考:Session 的瓶頸與解決方法,在此就是文中第三種方式。


 以上算是目前粗淺使用的經驗。


2012年3月15日 星期四

[Linux] 使用 Tarball 更新 OpenSSL @ Ubuntu 10.04

又到了一年一度機器被掃的時刻了,這次碰到的問題是 OpenSSL 版本太舊,有資安疑慮。


然而在 Ubuntu 上安裝時,直接用 ./config 後,安裝完的路徑卻不太對。網路上有看到別人用 ln -s 的方式強制切換位置,但安裝其他軟體時,一樣容易碰到 openssl header 跟 openssl library 版本不合的問題,摸索一下才找到正確的解法。


$ sudo apt-get remove openssl libssl-dev


$ tar -xvf openssl-w.x.yz.tar.gz
$ cd openssl-w.x.yz
$ ./config --prefix=/usr
$ sudo make install


如此一來才安全地搞定了。確認 OpenSSL 版本:


$ openssl version -a


只是更新完還有一堆東西要重編 Orz


2012年3月13日 星期二

[Python] 使用 PyPNG (Python PNG encoder/decoder) 產生 PNG 圖檔

sequential color random color


因研究關係,需要產生一些圖片像素有特殊規則的圖檔,找了一下剛好有 PyPNG 可以使用。


Python PNG encoder/decoder


$ tar -xvf pypng-0.0.12.tar.gz
$ cd pypng-0.0.12
$ sudo python setup.py install


程式碼:


import png
import random


rawRow = []
rawColumn = ()
width = 1024
height = 1024
for i in range(256):
        if len(rawRow) >= height:
                break
        if i == 0:
                continue
        for j in range(256):
                if len(rawRow) >= height:
                        break
                if j == 0 :
                        continue
                for k in range(256):
                        if len(rawRow) >= height:
                                break
                        if k == 0:
                                continue
                        if len(rawColumn) < width*3:
                                rawColumn = rawColumn + (i,j,k,)
                                #rawColumn = rawColumn + (random.randint(1,255),random.randint(1,255),random.randint(1,255),)
                        else:
                                rawRow.append( rawColumn )
                                rawColumn = (i,j,k,)


f = open("test"+str(width)+"x"+str(height)+".png","wb")
w = png.Writer(width,height)
w.write( f, rawRow )
f.close()


程式碼有點醜,但堪用 XD 所以還是好好珍惜光陰吧!