2014/11/26

MySQL Scripter

MySQL Script

最近常常需要在沒有 phpMyAdmin 的情形下進行 MySQL 的操作,索性把一些常用的指令寫成了一個 tool,就叫做 MySQL Scripter 吧。

2014/11/11

Laravel With Vagrant

一般 programmer 開發程式都是自己安裝自己的開發環境,不管在 Windows 或者是 Linux 都有所謂的懶人包,譬如說早期的 AppServXAMPP 以及 WampServer,Linux 的部分也有,但我通常都是用套件管理裝的所以就不舉例了,如果大家都是 Windows 並且強迫安裝同一套就還好,但如果 A 同事是 Windows 愛用者,B 同事用 Ubuntu,C 同事用 Mac,這樣就有點麻煩了,虛擬機器這個 solution 就可以確保所有的人開發環境都一樣,目前最佳解大概就是 Vagrant + VirtualBox 了。

Vagrant 可以說是 VirtualBox 的管理套件,以往我們要使用 VirtualBox,就是開一個環境,然後 download 某個 OS 的 ISO 檔案,掛載虛擬光碟,然後再進 VirtualBox 慢慢安裝,Vagrant 可以讓你把已經設定好的環境打包成一個 box,有點類似 ghost,所以你可以找人家包好的環境,例如說今天需要一個「真正」的 IE 6 的測試環境,你可以去 http://www.vagrantbox.es/ 或者是 https://vagrantcloud.com/ 搜尋 Windows XP,看到有人打包了 indows XP with IE6,我們就可以輕輕鬆鬆部屬這個環境,只要以下的指令即可。

vagrant add ie6_test http://aka.ms/vagrant-xp-ie6
vagrant ie6_test
vagrant up

甚至你可以自己把自己建置好的環境打包給別人使用,今天來示範一下怎麼快速建置一個 Laravel 環境,Laravel 有製作自己的 Vagrant Box 叫 Homestead,我來一步步操作怎麼在 Windows 建立官方的範例。

下載 laravel/homestead

vagrant box add laravel/homestead

當然你要在你的電腦先裝好 Vagrant 以及 VirtualBox,當他跑完安裝以後,可以執行 vagrant box list,如果有看到 laravel/homestead (virtualbox, 0.2.0) 代表你的 box 已經進來了,接下來我在 D:/ 建立一個叫 vm 的資料夾,進入 D:/vm,執行 git clone https://github.com/laravel/homestead.git Homestead,成功後看到 D:/vm/Homestead 資料夾,進去之後打開 Homestead.yaml 來修改,一般來說我們要 init 一個新的 box 都是修改 Vagrantfile 這個 config,而 Laravel 這個 yaml 就是他們獨立出來的客製化 config,預設如下:

---
ip: "192.168.10.10"
memory: 2048
cpus: 1

authorize: ~/.ssh/id_rsa.pub

keys:
    - ~/.ssh/id_rsa

folders:
    - map: ~/Code
      to: /home/vagrant/Code

sites:
    - map: homestead.app
      to: /home/vagrant/Code/Laravel/public

variables:
    - key: APP_ENV
      value: loca

ip 就是該虛擬機器的 ip,memory 就是你要給這台機器占用多少記憶體,authorize 以及 keys 是 Laravel 驗證 ssh 使用,folders 是指 folder sync,也就是說,假設我們在 D:/ 建立了一個資料夾,將他跟 vm 裡面的開發資料夾做 sync 的話,我們就不用整天都要 ssh 進去該 vm 來改程式,只要改我們 D:/ 的資料夾以後 vm 裡面的開發資料夾就會同步 sync 了,sites 就是將 domain name 指定到開發資料夾,如果你沒有要修改 hosts 的話,這個東西就沒有作用了,variables 就不用管,所以修改過後的內容如下:

---
ip: "192.168.10.14"
memory: 1024
cpus: 1

authorize: C:/Users/YOUR_USER_NAME/.ssh/id_rsa.pub

keys:
    - C:/Users/YOUR_USER_NAME/.ssh/id_rsa

folders:
    - map: 'D:/vm/laravel'
      to: /home/vagrant/www

sites:
    - map: laravel.app
      to: /home/vagrant/www/laravel/public

variables:
    - key: APP_ENV
      value: local

如果你的驗證有問題的話,請執行 ssh-keygen -t rsa -C "you@homestead",如果順利起來的話,執行 vagrant ssh 就可以直接進入 server,如果你想用其他的 ssh 軟體,只要指定 ssh 127.0.0.1 2222 即可,帳號密碼都是 vagrant,我們進入剛指定的資料夾 /home/vagrant/www,開始建立我們的 Laravel 專案,執行 composer create-project laravel/laravel --prefer-dist,composer 會開始幫我們載入檔案,我們可以切換到 D:/vm/laravel 資料夾,應該多了一個 laravel 資料夾並且正在同步下載檔案,安裝完畢後在 browser 跑 192.168.10.14,如果看到 Laravel 歡迎畫面,表示打完收工。

Homestead 幫你打造了下列的環境:

  • Ubuntu 14.04
  • PHP 5.6
  • HHVM
  • Nginx
  • MySQL
  • Postgres
  • Node (With Bower, Grunt, and Gulp)
  • Redis
  • Memcached
  • Beanstalkd
  • Laravel Envoy
  • Fabric + HipChat Extension

實用的 vagrant 指令

vagrant box list # 列出現在所有的 box
vagrant box remove xxx # 移除某個 box
vagrant destroy # 將某個目錄下的 vm 銷毀
vagrant status # 查看目前 vm 的狀況
vagrant halt # 關閉目前的 vm
vagrant reload # 重啟 vm

2014/11/07

Transaction With Eloquent

今天研究 Database Transaction 的時候發現了一招可以 Eloquent 跟 Transaction 混用。

<?

$user = new User;
$user->name = 'Chan';

$member = new Member;
$member->age = 33;

DB::transaction(function() use ($user, $member) {
    try {
        $user->save();
        $member->save();
    } catch (Exception $e) {
        dd($e->getMessage());
    }
});

Abstract Interface Traits 差異

PHP 對於 class 的使用方式很多,在這邊做一下筆記整理。

Basic

<?php

class Main
{
    public function foo()
    {
        echo 'foo';
    }
}

class Sub extends Main
{
    public function bar()
    {
        echo 'bar';
    }
}

$sub = new Sub;
$sub->bar(); // bar
$sub->foo(); // foo

這是最基本的 class 應用,Sub extends 了 Main,因此可以在 Sub 拿到 protected 以及 public 的變數以及使用 function。

Interface

<?php

interface Main
{
    public function foo();
}

class Sub implements Main
{
    public function bar()
    {
        echo 'bar';
    }
}

$sub = new Sub;
$sub->bar(); // bar

interface 是規範 class 一定要有對應的 function 宣告,所以上面的例子退吐出下列的錯誤訊息。

Fatal error: Class Sub contains 1 abstract method and must therefore be declared abstract or implement the remaining methods

我們只要宣告一個同等名稱的 function 即可。

<?php

interface Main
{
    public function foo();
}

class Sub implements Main
{
    public function foo()
    {
    }

    public function bar()
    {
        echo 'bar';
    }
}

$sub = new Sub;
$sub->bar(); // bar

interface 本身是不可以下功能的,所以通常設計來當作一種使用規範。

abstract

<?php

abstract class Main
{
    abstract public function foobar();

    public function foo() {
        echo 'foo';
    }
}

class Sub extends Main
{
    public function bar()
    {
        echo 'bar';
    }
}

$sub = new Sub;
$sub->foo(); // foo
$sub->bar(); // bar

abstract 等於 basic 用法跟 interface 用法的集合,所以上述的內容會吐出錯誤訊息。

Fatal error: Class Sub contains 1 abstract method and must therefore be declared abstract or implement the remaining methods

此時我們要在 Sub 加上對應的 function name。

<?php

abstract class Main
{
    abstract public function foobar();

    public function foo() {
        echo 'foo';
    }
}

class Sub extends Main
{
    public function foobar()
    {
    }

    public function bar()
    {
        echo 'bar';
    }
}

$sub = new Sub;
$sub->foo(); // foo
$sub->bar(); // bar

traits

<?php

trait Main
{
    public function foo() {
        echo 'foo';
    }
}

class Sub
{
    use Main;

    public function bar()
    {
        echo 'bar';
    }
}

$sub = new Sub;
$sub->foo(); // foo
$sub->bar(); // bar

trait 是一個有趣的東西,他可以透過 use 的方式直接調用 class,彈性無比的大,但確切的使用時機目前我還不清楚。

大亂鬥

<?php

abstract class Cool
{
    abstract public function foo3();

    public function foo2()
    {
        echo 'foo2';
    }
}

interface Happy
{
    public function foo4();
}

interface Smile
{
    public function foo5();
}

trait Main
{
    public function foo() {
        echo 'foo';
    }
}

class Sub extends Cool implements Happy, Smile
{
    use Main;

    public function bar()
    {
        echo 'bar';
    }

    public function foo3()
    {
    }

    public function foo4()
    {
    }

    public function foo5()
    {
    }
}

$sub = new Sub;
$sub->foo(); // foo
$sub->bar(); // bar
$sub->foo2(); // foo2

2014/11/06

MongoDB 初探

NoSQL 紅一陣子了,比較有名的不外乎是 Redis 或者是 MongoDB,Redis 一般來說比較會運用在快取上(類似 memcached),MongoDB 比較會使用在 persistence database solution,來示範一下這兩天試用 Mongo 的心得。

安裝

http://www.mongodb.org/downloads

MongoDB 對各家 OS 支援度很高,今天測試的環境是 Windows,所以我們就下載 Windows 的版本,我是下載了 zip 版本,下載後將壓縮檔案內 bin 資料夾下的檔案全部複製到 c:\mongodb

PHP 預設是沒有支援 MongoDB 的,但安裝方式很簡單,首先我們去下載 dll 檔案,下載最新的版本 php_mongo-1.5.7.zip,解壓縮後選擇符合你 server 版本的 dll,將他複製到 PHP 的 ext 資料夾,並且更名為 php_mongo.dll,修改 php.ini,加入 extension=php_mongo.dll,重啟 Apache,接著看一下 phpinfo,如果你看到以下的畫面,表示你已經成功了。

啟用

基本的 MongoDB 啟用很簡單,首先我在 c:\mongodb 下多建了一個 db 資料夾,接著啟用他。

mongod --dbpath="c:\mongodb\db"

如果沒有任何的錯誤訊息,恭喜你成功啟用了

使用

http://us3.php.net/manual/en/book.mongo.php

PHP 官方有非常詳細的使用文件,我們來看幾個比較常用的例子。

Connection

$m = new MongoClient();
$db = $m->selectDB('db');

若預設值如 ip 以及 port 沒改變的話,這是最基本的連線方式,當然還有其他的連線方式,甚至可以做到 replica。

$m = new MongoClient();
$db = $m->selectDB('db');
$users = $db->users;
echo $users->count(); // 0

MongoDB 的資料是一種 collection 的概念要存取相當簡單,上面的例子指定了 users 這個 connection,但我們沒有任何的資料,所以 count 的結果當然是 0,接下來我們塞一些資料進去。

$m = new MongoClient();
$db = $m->selectDB('db');
$users = $db->users;
$data = array(
    'name' => 'Chan',
    'age'  => 34
);

$users->insert($data);
echo $users->count(); // 1

上面的例子我們使用了 insert 功能塞進了一筆資料,count 的結果就變成 1 了,如果 refresh 頁面的話數字就會變成 2,若要多重存取的話可以使用另一個 batchInsert function。

$m = new MongoClient();
$db = $m->selectDB('db');
$users = $db->users;
$users->drop();
$data = array(
    array(
        'name' => 'Chan',
        'age'  => 34
    ),
    array(
        'name' => 'Phoebe',
        'age'  => 35
    )
);

$users->batchInsert($data);
echo $users->count(); // 2

上面的範例為了避免資料重複的 insert,所以我多加了 $users->drop() 的 function,此時 count 的結果就為 2 了,接下來我們來抓取資料。

$m = new MongoClient();
$db = $m->selectDB('db');
$users = $db->users;
$users->drop();
$data = array(
    array(
        'name' => 'Chan',
        'age'  => 34
    ),
    array(
        'name' => 'Phoebe',
        'age'  => 35
    )
);

$users->batchInsert($data);

foreach ($users->find() as $id => $item) {
    echo 'id: ' . $id;
    var_dump($item);
}

我們會得到

id: 545af6263ad521b819000031
array (size=3)
  '_id' => 
    object(MongoId)[9]
      public '$id' => string '545af6263ad521b819000031' (length=24)
  'name' => string 'Chan' (length=4)
  'age' => int 34
id: 545af6263ad521b819000032
array (size=3)
  '_id' => 
    object(MongoId)[10]
      public '$id' => string '545af6263ad521b819000032' (length=24)
  'name' => string 'Phoebe' (length=6)
  'age' => int 35

以上就是最基本的存跟取了,其他的條件式 PHP 官網有詳細的範例,SQL to Mongo Mapping Chart

SQL Statement Mongo Query Language Statement
CREATE TABLE USERS (a Number, b Number) Implicit or use MongoDB::createCollection().
INSERT INTO USERS VALUES(1,1) $db->users->insert(array("a" => 1, "b" => 1));
SELECT a,b FROM users $db->users->find(array(), array("a" => 1, "b" => 1));
SELECT * FROM users WHERE age=33 $db->users->find(array("age" => 33));
SELECT a,b FROM users WHERE age=33 $db->users->find(array("age" => 33), array("a" => 1, "b" => 1));
SELECT a,b FROM users WHERE age=33 ORDER BY name $db->users->find(array("age" => 33), array("a" => 1, "b" => 1))->sort(array("name" => 1));
SELECT * FROM users WHERE age>33 $db->users->find(array("age" => array('$gt' => 33)));
SELECT * FROM users WHERE age<33 $db->users->find(array("age" => array('$lt' => 33)));
SELECT * FROM users WHERE name LIKE "%Joe%" $db->users->find(array("name" => new MongoRegex("/Joe/")));
SELECT * FROM users WHERE name LIKE "Joe%" $db->users->find(array("name" => new MongoRegex("/^Joe/")));
SELECT * FROM users WHERE age>33 AND age<=40 $db->users->find(array("age" => array('$gt' => 33, '$lte' => 40)));
SELECT * FROM users ORDER BY name DESC $db->users->find()->sort(array("name" => -1));
CREATE INDEX myindexname ON users(name) $db->users->ensureIndex(array("name" => 1));
CREATE INDEX myindexname ON users(name,ts DESC) $db->users->ensureIndex(array("name" => 1, "ts" => -1));
SELECT * FROM users WHERE a=1 and b='q' $db->users->find(array("a" => 1, "b" => "q"));
SELECT * FROM users LIMIT 20, 10 $db->users->find()->limit(10)->skip(20);
SELECT * FROM users WHERE a=1 or b=2 $db->users->find(array('$or' => array(array("a" => 1), array("b" => 2))));
SELECT * FROM users LIMIT 1 $db->users->find()->limit(1);
EXPLAIN SELECT * FROM users WHERE z=3 $db->users->find(array("z" => 3))->explain()
SELECT DISTINCT last_name FROM users $db->command(array("distinct" => "users", "key" => "last_name"));
SELECT COUNT(*y) FROM users $db->users->count();
SELECT COUNT(*y) FROM users where AGE > 30 $db->users->find(array("age" => array('$gt' => 30)))->count();
SELECT COUNT(AGE) from users $db->users->find(array("age" => array('$exists' => true)))->count();
UPDATE users SET a=1 WHERE b='q' $db->users->update(array("b" => "q"), array('$set' => array("a" => 1)));
UPDATE users SET a=a+2 WHERE b='q' $db->users->update(array("b" => "q"), array('$inc' => array("a" => 2)));
DELETE FROM users WHERE z="abc" $db->users->remove(array("z" => "abc"));

管理工具

Robomongo

2014/10/31

我的婚禮攝影

結婚也快半年了,一直想找時間分享關於婚禮攝影這件事情,但忙碌愉快的婚姻生活讓我拖稿許久,先聲明一下,這是我自己長期下來的感受,或許每個人有每個人的看法,大家還是可以選擇自己舒適的方式進行,結婚一生一次,在這個重要的時刻,還是要尊重聽取雙方的意見,快快樂樂地進行婚禮才對。

相機發達的現代,人手一台單眼的朋友應該不在少數,所以常常會看到托自己朋友幫忙拍攝婚禮的情況,我自己之前就常常被找,所以感受是最深的,來說說我的經驗談。

我想好好的參加

基本上,被找去幫朋友拍攝結婚過程當然開心,不過這也代表了你準備裡裡外外東奔西跑,全神貫注在攝影上面,其實這樣很累,也沒有辦法好好享受朋友重要的人生過程,時常得觀察現場狀況作出臨場反應,畢竟你不是拿這個當職業,很少人能夠每個場地拍超過三次,也就是說,可能每一次的拍攝對你來說都是「挑戰」,而這個挑戰,是你好哥們或好姊妹人生最重要的時刻,壓力可想而知。

我不能出包

我想很少有業餘的朋友身上會背兩台相機的,我自己就沒有,所以每一次的「挑戰」基本上都有一定的風險存在,相機要故障可以掛點的零件太多了,如果沒有萬全的準備,每一次的幫忙根本都是個賭注,求神拜佛我的機器不要出事,不然我該怎麼交代,專業的攝影師每次出機會準備兩台甚至三台的相機以備不時之需,這是一般人不可能做的事情。

我的東西真的行嗎

拍照這件事感覺好像都一樣,不就按下快門然後記錄當下嗎,其實不然,各種題材都有其精專的地方,你商攝拍的好人像不一定,人像拍的好風景不一定,風景拍得好的食物不一定,婚禮攝影尤其困難,因為你要面對的是人,人變化的排列組合根本是無窮大,有沒有經驗差很多,沒有拍出當下人與人的自然感情跟現場的氣氛,控光、構圖、顏色那些就不重要了,攝影眼是很難培養的,而通常被找的朋友可能只屬於男方或女方的朋友,假設是男方的朋友可能跟男方熟,所以一些親朋好友還可以做些微引導,女方那邊在不熟的狀態下你可能從頭到尾只會聽到「看這邊」,「一、二、三」,「在一張」,這三句話。

我的工具足以面對這一切嗎

攝影環境的光線其實很難掌控,尤其是遇到那種有各種投射燈的餐廳,控光、色偏都可能是一大麻煩,雖然單眼人人有,但你確保自己有足夠的設備(閃光燈、鏡頭)來應付這一切嗎?

基於以上幾點我長年下來的經驗,我自己的婚禮決定好好找一個專業的婚禮攝影,因為我想要我的好兄弟好朋友好好的 enjoy that moment,而且我希望他們全部都出現在照片裡面,被你找去當攝影師的好朋友,好兄弟,往往都消失在你的照片中,這點非常可惜,而且對我來說,我認為婚禮的照片可能是結婚過程第二重要的事情,僅次於婚紗照片。

我跟老婆網路上找了很久很久,一比再比,老婆基本上比較尊重我想法,而我個人偏好日式風格,照片輕鬆有韻味那種感覺,於是我們找上了自然捲

自然捲位於板橋,是幾個朋友自己出來創業的自助婚紗公司,少了大公司的束縛跟規範,他們可以盡情做自己想做的事情,跟我的主攝影師 Evan 聊天當中,我發現他視幫客人拍攝這件事情為一種玩樂的過程,一種開心的態度,當你真正喜歡自己的工作時,你是不會看輕他的,當你把新人當作同樂的朋友時,你是不會辜負他的,我們來看圖說故事吧。

專業的攝影師是會創造畫面的

專業的攝影師是很會利用所有空間的

專業攝影師會在對的時間做對的事情

專業攝影師不會錯過重要的時刻

所以如果可以的話,讓這一生中少數幾次你可能會願意花錢在照相,並且可以男的帥女的美的機會上,聘請個專業攝影師吧,我推薦自然捲,你會滿意的 :)

自然捲-攝影軽美学
22064 臺北市新北市板橋區實踐路93巷3號
週二 - 週日: 13:00 - 21:00
02 8961 2090 (採預約制)

2014/10/20

Xdebug Setting

軟體網址

WinCacheGrind

php.ini

[xdebug]
xdebug.remote_enable = off
xdebug.auto_trace = off
xdebug.auto_profile = off
xdebug.profiler_enable = off
xdebug.profiler_enable_trigger = on
xdebug.profiler_output_name = cachegrind.out.%u.%H_%R
xdebug.profiler_output_dir = "c:/wamp/xdebug_log"

參數帶上 XDEBUG_PROFILE 就可以產生檔案。