2013年9月2日 星期一

PHP Extension (1) - 環境準備與Hello World

下列所有實作均以Ubuntu為範例,視不同distribution或版本可能指令與路徑均有不同

準備環境

$sudo apt-get install apache2 php5 php5-dev

Hello World

傳統PHP function要達到輸出hello world的方式
<?php
function hello_world() {  
  return 'Hello World';  
}
echo hello_world();
?>

若要使用PHP extension開發,要使用c語言實作出相同的function

test_hello_world.h
#ifndef PHP_TEST_HELLO_WORLD_H  
#define PHP_TEST_HELLO_WORLD_H  

extern zend_module_entry test_hello_world_module_entry;  
#define phpext_test_hello_world_ptr &test_hello_world_module_entry  

#ifdef PHP_WIN32  
#define PHP_TEST_HELLO_WORLD_API __declspec(dllexport)  
#else  
#define PHP_TEST_HELLO_WORLD_API  
#endif  

#ifdef ZTS  
#include "TSRM.h"  
#endif  

PHP_MINIT_FUNCTION(test_hello_world);  
PHP_MSHUTDOWN_FUNCTION(test_hello_world);  
PHP_MINFO_FUNCTION(test_hello_world);  

PHP_FUNCTION(hello_world);  

/*  
    Declare any global variables you may need between the BEGIN 
    and END macros here:      

    ZEND_BEGIN_MODULE_GLOBALS(test_hello_world) 
    long  global_value; 
    char *global_string; 
    ZEND_END_MODULE_GLOBALS(test_hello_world) 
 */  

#ifdef ZTS  
#define TEST_HELLO_WORLD_G(v) TSRMG(test_hello_world_globals_id, zend_test_hello_world_globals *, v)  
#else  
#define TEST_HELLO_WORLD_G(v) (test_hello_world_globals.v)  
#endif  

#endif  /* PHP_TEST_HELLO_WORLD_H */  

test_hello_world.cc
#ifdef HAVE_CONFIG_H  
#include "config.h"  
#endif  

#include "php.h"  
#include "php_ini.h"  
#include "ext/standard/info.h"  
#include "test_hello_world.h"  
#include "string"  

using namespace std;  

/* If you declare any globals in php_test_hello_world.h uncomment this: 
   ZEND_DECLARE_MODULE_GLOBALS(test_hello_world) 
 */  

function_entry test_hello_world_functions[] = {  
    PHP_FE(hello_world, NULL)  
    {NULL, NULL, NULL}  
};  

zend_module_entry test_hello_world_module_entry = {  
#if ZEND_MODULE_API_NO >= 20010901  
    STANDARD_MODULE_HEADER,  
#endif  
    "test_hello_world",  
    test_hello_world_functions,  
    PHP_MINIT(test_hello_world),  
    PHP_MSHUTDOWN(test_hello_world),  
    NULL, //RINIT  
    NULL, //RSHUTDOWN  
    PHP_MINFO(test_hello_world),  
#if ZEND_MODULE_API_NO >= 20010901  
    "$Revision: 1.5 $",  
#endif  
    STANDARD_MODULE_PROPERTIES  
};  

extern "C" {  
#ifdef COMPILE_DL_TEST_HELLO_WORLD  
    ZEND_GET_MODULE(test_hello_world)  
#endif  
}  

PHP_MINIT_FUNCTION(test_hello_world)  
{  
    return SUCCESS;  
}     

PHP_MSHUTDOWN_FUNCTION(test_hello_world)  
{  
    return SUCCESS;  
}     

PHP_MINFO_FUNCTION(test_hello_world)  
{  
    php_info_print_table_start();  
    php_info_print_table_header(2, "test_hello_world support", "enabled");  
    php_info_print_table_end();  
}     

PHP_FUNCTION(hello_world)  
{  
    string ret("hello world");  
    RETURN_STRING(const_cast(ret.c_str()), 1);  
}  

config.m4
PHP_ARG_ENABLE(test_hello_world, whether to enable test_hello_world support,  
Make sure that the comment is aligned:  
[  --enable-test_hello_world           Enable test_hello_world support])  

if test "$PHP_TEST_HELLO_WORLD" != "no"; then  
    PHP_SUBST(TEST_HELLO_WORLD_LIBADD)  
    PHP_NEW_EXTENSION(test_hello_world, test_hello_world.cc, $ext_shared)  
    PHP_REQUIRE_CXX  

    PHP_ADD_INCLUDE(/usr/include)  
    PHP_ADD_LIBRARY_WITH_PATH(stdc++, /usr/lib, TEST_HELLO_WORLD_LIBADD)  
    OS=`uname`;  
    if test $OS = "FreeBSD"; then  
        CPPFLAGS="$CPPFLAGS -Wno-error -Wall -g"
    else  
        CPPFLAGS="$CPPFLAGS -Wno-error -Wall -g -m32 -lstdc++"
    fi  
fi  

編譯
$ phpize

$ ./configure

$ make
如果編譯成功,可以看到如下畫面



將設定檔放入下列路徑/etc/php5/conf.d/test_hello_world.ini,php才知道需要載入此模組
extension = test_hello_world.so

將編譯完成的.so放入php的library中
/usr/lib/php5/20090626+lfs/test_hello_world.so



重起apache服務
$ service apache2 restart

重新測試test.php
<?php
echo hello_world();
?>

若需要清除編譯結果,指令如下
$ make clean
$ phpize --clean











 
疑難排解
如果遇到錯誤訊息undefined symbol: _ZNSs4_Rep20_S_empty_rep_storageE

PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php5/20090626+lfs/yahoo_hello_world.so' - /usr/lib/php5/20090626+lfs/yahoo_hello_world.so: undefined symbol: _ZNSs4_Rep20_S_empty_rep_storageE in Unknown on line 0

解決方法
加上-lstdc++在CPPFLAGS中

參考: http://stackoverflow.com/questions/11939934/c-apache-module-fails-on-znss4-rep20-s-empty-rep-storagee



2013年8月23日 星期五

Ubuntu 13.04安裝筆記

SSD硬碟開啟TRIM功能

確認SSD硬碟是否支援TRIM
$ sudo hdparm -I /dev/sda | grep "TRIM supported"


編輯/etc/fstab

需要加上TRIM的磁區,於errors前加入noatime,nodiratime,discard,
並將log相關的設定放入tmpfs減少SSD存取

將SSD trimming放入daily job
編輯/etc/cron.daily/trim,寫入如下設定








更改權限
$ sudo chmod +x /etc/cron.daily/trim

參考資料:
http://yblog.org/archive/index.php/11734
http://www.webupd8.org/2013/01/enable-trim-on-ssd-solid-state-drives.html

gcin

加入repository
$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 835AB0E3




安裝
$ sudo apt-get update
$ sudo apt-get install gcin

到語言設定去設定輸入法,之後登出再登入

解決icon消失的問題,可啟動gcin-tools,進入"外觀設定"=>"面板狀態(tray)"=>"Unity indicator"叫出

參考資料:
http://hyperrate.com/thread.php?tid=28044


Gnome-do

安裝
$ sudo apt-get install gnome-do
手動啟動後,調整熱鍵跟開機自動啟動選項,登出再登入即可生效

Pidgin

安裝
$ sudo add-apt-repository ppa:pidgin-developers/ppa
$ sudo apt-get update
$ sudo apt-get install pidgin

支援右上角訊息
$ sudo apt-get install pidgin-libnotify

設定支援office communicator
需要使用SIPE
http://sipe.sourceforge.net/
$ sudo apt-get install libglib2.0-dev intltool build-essential libnss3-dev libxml2-dev libgtk2.0-dev libpurple-dev
$ tar -xzvf pidgin-sipe-1.6.2.tar.gz
$ cd pidgin-sipe-1.6.2
$ ./configure --prefix=/usr
$ make
$ sudo make install
重新啟動pidgin就會看到office communicator的選項
記得不需要特別設定server等等,只需要設定username跟login都用mail即可

Dropbox

安裝
$ sudo apt-key adv --keyserver pgp.mit.edu --recv-keys 5044912E
新增 deb http://linux.dropbox.com/ubuntu/ raring main
$ sudo apt-get update
$ sudo apt-get install dropbox

Font
複製到ttf檔案到/usr/share/fonts/truetype/裏面 fc-cache -f -v

PCman
$ sudo apt-get install pcmanx-gtk2

Perforce
下載後,將bin內檔案放入/usr/bin,lib內p4v目錄放入/usr/lib/ 設定p4v.desktop放入/usr/share/applications/

[Desktop Entry]
Type=Application
Name=P4V
Comment=Perforce Visual Client
Icon=/usr/lib/p4v/P4VResources/icons/p4v_48_high.png
Exec=/usr/bin/p4v
Terminal=false
Categories=Development

VMWare

安裝
$ chmod 755 VMware-Player-5.0.2-1031769.x86_64.bundle
$ sudo ./VMware-Player-5.0.2-1031769.x86_64.bundle

kernel升級完掛點,直接重裝最快
$ sudo vmware-installer --uninstall-product vmware-player


移除惱人的menu bar
$ sudo apt-get autoremove appmenu-gtk appmenu-gtk3 appmenu-qt

關閉按到alt會跳出command的設定法
到keyboard的shortcut設定,將key to show the HUD設定為Disabled (使用backspace按鈕)

參考資料
http://askubuntu.com/questions/122209/how-do-i-modify-or-disable-the-huds-use-of-the-alt-key

Java
$ sudo add-apt-repository ppa:webupd8team/java
$ sudo apt-get update
$ sudo apt-get install oracle-java8-installer
$ sudo update-java-alternatives -s java-7-oracle

Chrome
$ wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - deb http://dl.google.com/linux/chrome/deb/ stable main
$ sudo apt-get update
$ sudo apt-get install google-chrome-stable

Gnome
$ sudo add-apt-repository ppa:webupd8team/gnome3
$ sudo apt-get update
$ sudo apt-get install gnome-shell-extensions-gpaste compiz
$ sudo apt-get install gnome-session-fallback

2013年7月9日 星期二

Mac使用老式USB掃瞄器(以Mustek 1200 UB為例)

安裝軟體

1. libusb
2. SANE backends
3. SANE Preference Pane
4. TWAIN SANE Interface

下載處: http://www.ellert.se/twain-sane/

下載驅動程式

下載相對應的驅動程式放入/usr/local/share/sane/gt68xx/目錄

下載處: http://www.meier-geinitz.de/sane/gt68xx-backend/

以Mustek 1200 UB為例,需要下載sbfw.usb
放置於/usr/local/share/sane/gt68xx/,並修改權限為777

$ sudo cp sbfw.usb /usr/local/share/sane/gt68xx/
$ sudo chmod 777 /usr/local/share/sane/gt68xx/sbfw.usb

確認掃瞄器是否有無抓到

使用下列兩個指令確認是否能正常抓到掃瞄器
1. scanimage --list-devices
2. sane-find-scanner

掃描

使用scanimage指令掃描

$ sudo scanimage --format=tiff --mode=Color --resolution=300 > result.tiff

若對scanimage指令有疑問可以man一下










$ man scanimage

參考文件

http://nepkertkft.hu/en/mustek-ub-plus-1200-scanner-under-mac-os-x

2013年6月3日 星期一

Shell Scripting常用範例說明

建議開頭
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
export LANG="en_US.UTF-8"
註解
#user comment
定義變數與列印變數
VAR="hello world"
echo $VAR

printf "\33[1;31m"
printf "Color Version: $VAR"
printf "\33[0m\n"
正常結束
exit 0
if-else判斷式
if [ "$INPUT" == "Yes" ]; then
  echo "result is Yes"
elif [ "$INPUT" == "No" ]; then
  echo "result is No"
else
  echo "wrong input"
fi
讀取argument
if [ ! -z "$1" ]; then
  ARGS=$1
fi
echo $ARGS
檢查執行者身份
whoami_ret="$(whoami)"
if [ "$whoami_ret" != "root" ]; then
  echo "This script must be run as root"
  exit
fi
使用者輸入
read -p "Please input (Y/N), default is N:" ANSWER
if [ "$ANSWER" == "Y" -o "$ANSWER" == "y" ]; then
  echo "result is Yes"
fi
執行指令的結果
pyOpenSSL_ret="$(rpm -q python-openssl | grep install | wc -l)"
if [ "$pyOpenSSL_ret" == "1" ]; then
  echo "python-openssl is not installed, please install python-openssl"
  exit
fi  
類似traverse陣列
SERVER_LIST=(192.168.0.1 192.168.0.2 192.168.0.3)
for IP in ${SERVER_LIST[@]}
do
  echo "IP address: $IP"
done
Switch case
case $CAR in
  AUDI | audi)
    echo "audi"
  ;;
  VOLVO | volvo)
    echo "volvo"
  ;;
  BENZ | benz)
    echo "benz"
  ;;
  *) 
    echo "wrong role type"
    exit
  ;;
esac
Loop
until [ "$ANSWER" == "yes" ]
do
  read -p "Please input \"yes\":" ANSWER
done

i=0
while [ "$i" != "10" ]
do
  i=$(($i+1))
  echo $i
done

for CAR in AUDI VOLVO BENZ
do
 echo ${CAR}
done

for i in $(seq 1 10)
do
  echo ${i}
done

for (( i=1; i<=10; i=i+1 ))
do
  echo $i
done
等候某個事件發生
FILE_EXISTED=0;
while [ $FILE_EXISTED -ne "1" ]; 
do
  if [ -z "/root/test_file" ];then
    FILE_EXISTED=1
  fi
  sleep 1;
done
Function
function PRINT_FUNCTION(){
  echo "args is $1"
}

PRINT_FUNCTION "first_args"
參考 http://tldp.org/LDP/abs/html/ http://linux.vbird.org/linux_basic/0340bashshell-scripts.php

2013年5月29日 星期三

screen基本指令教學

screen是個簡單方便的terminal console管理工具,大概有幾個主要的優點:
  • 在一個terminal軟體中開啟許多子console視窗
  • 可以dettach出來、之後又reattach回去
  • 有scrollback的功能
  • console視窗間複製貼上
  • 切割console視窗

安裝

在Ubuntu上直接 $ sudo apt-get install screen就可以了

Command-line指令

$ screen
  • 直接開啟新的session
$ screen -list
  • 列出目前有哪些已經存在的session可以attach進去
$ screen -R
  • reattach回session。如果目前沒有session存在,直接就地開啟一個新的session。如果有好幾個不同的session,使用screen -R
$ screen -U
  • 以utf-8 mode執行
$ screen -d
  • 強制將某個正在被attach中的session給detach掉
$ screen -wipe
  • 將廢棄的screen清除

Key-Binding指令

screen預設是以Ctrl-a(同時按住鍵盤Ctrl跟a兩個按鈕,如果您能理解控制字元,這就是等同於"^A")來啟動console視窗管理,接著同時鬆開Ctrl與a鍵,按下另一按鍵或下達指令來進行操作。

Ctrl+a c
  • 開啟一個新的console視窗
Ctrl+a Ctrl+a
  • 連續兩次,回到上一個console視窗
Ctrl+a [1~9]
  • 切換到1號至9號的某個console視窗
Ctrl+a "
  • 列出目前所有視窗,可用上下方向鍵選擇要進入的console視窗,按下enter進入
Ctrl+a k
  • 刪除目前的console視窗
Ctrl+a d
  • 將目前session給detach掉
Ctrl+a Esc
  • 進入copy mode,可用上下左右操控或進行scrollback。/或?用來搜尋(類似vim)。空白鍵可進行選取,決定範圍後按下第二次空白鍵就會複製入buffer中。之後使用Ctrl+]就可以將剛剛screen放入buffer中的內容貼上
Ctrl+a :sessionname [name]
  • 設定session的名稱,之後在comman-line模式執行screen -list方便檢視
Ctrl+a v
  • [Ctrl+a] 輸入控制字元Ctrl+a(因為Ctrl+)
Ctrl+a S
  • 將目前所在區域,水平分割成另外兩個區域
Ctrl+a Q
  • 關閉分割區域
Ctrl+a Tab
  • 切換分割區域

進階議題

  • 在screen的vim中輸入控制字元^A,需要在vim中進入insert模式,然後按下Ctrl+A,再按下a,就可以了
  • 因為screen畫面有些單調,有時無法辨別目前console視窗的狀態與session的狀態。如果需要像bash一樣有客製化的畫面,可以透過設定編輯~/.screenrc這個檔案來得到自己想要的效果。只要上Google搜尋screenrc就有許多範本可以下載,有空我再來寫篇screenrc教學。
  • 垂直分割screen區域(需要拿git版screen重make自己build)
    • $ git clone git://git.savannah.gnu.org/screen.git
    • $ cd screen/src
    • $ ./autogen.sh
    • $ ./configure
    • $ make
    • $ make install
    • 使用Ctrl+a | 來垂直分割區域
    • 參考 http://savannah.gnu.org/projects/screen/

2013年5月28日 星期二

Ubuntu Distribution版本

通常要得知Linux核心的版本,使用uname -a指令就可以了。

不過要得知Distribution版本,這個指令還不太夠。這時候只要檢視/etc/os-release或/etc/issue就可以了。


2013年4月29日 星期一

在Ubuntu環境設定ctags

  • 安裝ctags
    • $ sudo apt-get install exuberant-ctags
  • 設定~/.ctags (支援python)
    •  --python-kinds=-i
    • 如果有需要放入過濾清單, 加入--exclude=
      • ex. --exclude=*/build/*
  • 設定~/.vimrc
    • 加入:set tags=~/.myctags
  • 手動執行ctags
    •  $ ctags -R -o ~/.myctags ~/src
  • 自動執行ctags (每分鐘執行一次)
    • $ sudo /etc/crontab
    • */1 * * * * account /usr/bin/ctags -R -o /home/howard/.myctags ~/src
    • $ service cron restart
  • vim中指令
    • ctrl+] 跳入該function
    • ctrl+t 跳出該function
    • :tselect 或 :stselect 選擇同名的其他function
    • :tnext 或 :tprev 往前或往後跳往同名的其他function
    • :help tags 得到更多訊息

2013年1月11日 星期五

在terminal中MySQL欄位太多時呈現資料的另一方式

當我們在terminal中連入MySQL時,有時會因為欄位過多,導致select出來的結果亂七八糟。


有個很簡單的方法就可以讓顯示的結果改成以一筆一筆資料秀出為主,就是在select的query最後加上\G即可。