Apache + Ubuntu + Varnish 無痛升級

Varnish 是一個「反向」的代理 (reverse proxy)
用法是和你的 Apache 一起,所有的流量都先經過 Varnish 的緩存
緩存落空後才由 Varnish 向 Apache 拿資料
因為 Apache 的結構是沒有針對檔案類別的
例如 Apache 送出一張圖片一樣會將 mod_php 載入到 RAM 內
同例可用於 CSS, JS 等靜態的檔案
做成大量的 RAM 浪費
而Varnish 的緩存可大大幫助這類靜態檔案佔用的資源
從而提升整體的效能

這次我的目標是用最少的下線時間安裝和設置 Varnish
大家記得一定要先備份有關設定的檔案

安裝 Varnish

curl http://repo.varnish-cache.org/debian/GPG-key.txt | sudo apt-key add -
echo "deb http://repo.varnish-cache.org/ubuntu/ lucid varnish-3.0" | sudo tee -a /etc/apt/sources.list
sudo apt-get update
sudo apt-get install varnish

Varnish 預設會從 localhost 的 port 8080 連接 Apache
所以我們便設定一下 Apache 打開 8080:

sudo vim /etc/apache2/ports.conf

NameVirtualHost *:80
NameVirtualHost *:8080
Listen 80
Listen 8080

為了最少的下線時間,Apache 會暫時打開 80 和 8080 兩個 port
80 為一般的使用者
8080 為了測試和 Varnish 的連接
VirtualHost 的設定

sudo vim /etc/apache2/sites-avaiable/default

<VirtualHost *:80 *:8080>

重啟 Apache

sudo service apache2 restart

可以使用 http://localhost:8080/ 測試一下 Apache 的 port 8080

Varnish 預設會使用 256M RAM 我修改一下:

sudo vim /etc/default/varnish

DAEMON_OPTS="-a :6081 \
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s malloc,64m"

sudo /etc/init.d/varnish restart

看到 Varnish 是預設使用 port 6081 的
可以使用 http://localhost:6081/ 測試一下
使用 chrome 的 network inspector 可以看到 “Response Header" 有一段 "Via 1.1 varnish" 就表示成功了

成功之後便可以真正使用 Varnish 服務 port 80 了
修改 Apache:

sudo vim /etc/apache2/ports.conf

#NameVirtualHost *:80
NameVirtualHost *:8080
#Listen 80
Listen 8080

修改 Varnish:

DAEMON_OPTS="-a :80 \
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s malloc,64m"

一次過重啟 Apache, Varnish

sudo service apache2 restart;sudo /etc/init.d/varnish restart

成為 imagefield_crop 模組的維護者

因為我現在自己開展了自己的事業,公司
現在的工作有一段時間會非常忙碌,但也常會有空閒的時間

所以我便選了一個我自己常用的模組 imagefield_crop 申請成為維護者

已經開始了一個月左右的時間了,
作為一個日常已經使用 git 的開發者,
而 drupal.org 又為每一個模組提供一個非常好的 "version control" tab
維護的工作其實不是太難
提交其他人覆議過的 patch ,有多點時間的話覆議 patch,解答一下支援問題等...

希望除了寫 blog 和教學之外可以為 Drupal 社區貢獻一下

自定義 Drupal commerce 付款流程

Commerce 是 Drupal 7.x 電子商務的最新模組

背景資料

ubercart 一直為 Drupal 6.x 電子商務的指定模組
但它和其他的模組有一點點的不同,它的主站並不設在 Drupal.org (www.ubercart.org)
所以 Drupal 社區嘗試將它移回 Drupal.org 的時候就發生了一些磨擦
有一些開發者便決定為 Drupal 7.x 的電子商務重新出發
所以便誕生了 commerce 模組了

最近的更新

Commerce 模組已經開發了一年以上,而且各方面都越加成熟了

Variations

那 "display node" 的易用性的問題已經用一個全新的 "variations" 概念完美的解決了
你可以建立一個產品然後增加那個產品的 "Color variations","Size variations" 等等
它們會在同一個頁面顯示,而 variations 會化為一組 dropdown 給客人選擇
完美解決客人和管理者的易用性問題

Commerce kickstart

Commerce kickstart 是一個包括了很多模組的 Drupal "Profile"
它安裝的時候有更多的預設的設定令你建立一個電子商務的網站更加容易
你還可以匯入一些商品範例,體驗一下真實的情況之下網站的設定和流程
令你可以在數分鐘之內開始評估網站對你的適用性
這絕對是學習曲線的一大進步

自定 Checkout 流程

checkout 流程可以在 "Checkout Settings" 中定義
拖曵去修改流程中的每一步的每一組表單
所以如果你知道修改/增加步驟的方法
便可以實現一個完全客製的流程了

代碼

最重要的兩個 functions 是 hook_commerce_checkout_page_info()hook_commerce_checkout_pane_info()
可以定義 "步" 和 "表單"

<?php
/**
 * hook_commerce_checkout_page_info()
 */
function custom_checkout_commerce_checkout_page_info() {
 
$checkout_pages = array();

 
$checkout_pages['custom_checkout'] = array(
   
'title' => t('Custom Step'),
   
'weight' => 6,
  );

  return
$checkout_pages;
}

/**
 * hook_commerce_checkout_pane_info()
 * @param  string $value [description]
 * @return [type]        [description]
 */
function custom_checkout_commerce_checkout_pane_info($value='')
{
 
$checkout_panes = array();

 
$checkout_panes['custom_checkout'] = array(
   
'title' => t('Custom Checkout'),
   
'page' => 'custom_checkout',
   
'weight' => 2,
   
'review' => TRUE,
   
'callbacks' => array(
     
'checkout_form' => 'custom_checkout_pane_checkout_form',
    ),
  );

  return
$checkout_panes;
}
?>

Easy easy!

自定義 Rules action 例子

Rules 內的 action 原來和 trigger 使用的,Drupal 原生的 action 是不相同的
大家可以參考 rules/modules/*.rules.inc 便會看到很多 core - optional 的 module 的 rules

我寫一個 rules action 的 example module:

<?php
/**
 * hook_rules_action_info
 * @return
 *   An array of information about the module's provided rules actions.
 *   The array contains a sub-array for each action, with the action name as
 *   the key. Actions names may only contain lowercase alpha-numeric characters
 *   and underscores and should be prefixed with the providing module name.
 *   Possible attributes for each sub-array are:
 *   - label: The label of the action. Start capitalized. Required.
 *   - group: A group for this element, used for grouping the actions in the
 *     interface. Should start with a capital letter and be translated.
 *     Required.
 *   - parameter: (optional) An array describing all parameter of the action
 *     with the parameter's name as key. Each parameter has to be
 *     described by a sub-array with possible attributes as described
 *     afterwards, whereas the name of a parameter needs to be a lowercase,
 *     valid PHP variable name.
 *   - provides: (optional) An array describing the variables the action
 *     provides to the evaluation state with the variable name as key. Each
 *     variable has to be described by a sub-array with possible attributes as
 *     described afterwards, whereas the name of a parameter needs to be a
 *     lowercase, valid PHP variable name.
 *   - 'named parameter': (optional) If set to TRUE, the arguments will be
 *     passed as a single array with the parameter names as keys. This emulates
 *     named parameters in PHP and is in particular useful if the number of
 *     parameters can vary. Defaults to FALSE.
 *   - base: (optional) The base for action implementation callbacks to use
 *     instead of the action's name. Defaults to the action name.
 *   - callbacks: (optional) An array which allows to set specific function
 *     callbacks for the action. The default for each callback is the actions
 *     base appended by '_' and the callback name.
 *   - 'access callback': (optional) A callback which has to return whether the
 *     currently logged in user is allowed to configure this action. See
 *     rules_node_integration_access() for an example callback.
 *  Each 'parameter' array may contain the following properties:
 *   - label: The label of the parameter. Start capitalized. Required.
 *   - type: The rules data type of the parameter, which is to be passed to the
 *     action. All types declared in hook_rules_data_info() may be specified, as
 *     well as an array of possible types. Also lists and lists of a given type
 *     can be specified by using the notating list<integer> as introduced by
 *     the entity metadata module, see hook_entity_property_info(). The special
 *     keyword '*' can be used when all types should be allowed. Required.
 *   - bundles: (optional) An array of bundle names. When the specified type is
 *     set to a single entity type, this may be used to restrict the allowed
 *     bundles.
 *   - description: (optional) If necessary, a further description of the
 *     parameter.
 *   - options list: (optional) A callback that returns an array of possible
 *     values for this parameter. The callback has to return an array as used
 *     by hook_options_list(). For an example implementation see
 *     rules_data_action_type_options().
 *   - save: (optional) If this is set to TRUE, the parameter will be saved by
 *     rules when the rules evaluation ends. This is only supported for savable
 *     data types. If the action returns FALSE, saving is skipped.
 *   - optional: (optional) May be set to TRUE, when the parameter isn't
 *     required.
 *   - 'default value': (optional) The value to pass to the action, in case the
 *     parameter is optional and there is no specified value.
 *   - 'allow null': (optional) Usually Rules will not pass any NULL values as
 *     argument, but abort the evaluation if a NULL value is present. If set to
 *     TRUE, Rules will not abort and pass the NULL value through. Defaults to
 *     FALSE.
 *   - restriction: (optional) Restrict how the argument for this parameter may
 *     be provided. Supported values are 'selector' and 'input'.
 *   - default mode: (optional) Customize the default mode for providing the
 *     argument value for a parameter. Supported values are 'selector' and
 *     'input'. The default depends on the required data type.
 *   - sanitize: (optional) Allows parameters of type 'text' to demand an
 *     already sanitized argument. If enabled, any user specified value won't be
 *     sanitized itself, but replacements applied by input evaluators are as
 *     well as values retrieved from selected data sources.
 *   - translatable: (optional) If set to TRUE, the provided argument value
 *     of the parameter is translatable via i18n String translation. This is
 *     applicable for textual parameters only, i.e. parameters of type 'text',
 *     'token', 'list<text>' and 'list<token>'. Defaults to FALSE.
 *   - ui class: (optional) Allows overriding the UI class, which is used to
 *     generate the configuration UI of a parameter. Defaults to the UI class of
 *     the specified data type.
 *   - cleaning callback: (optional) A callback that input evaluators may use
 *     to clean inserted replacements; e.g. this is used by the token evaluator.
 *   - wrapped: (optional) Set this to TRUE in case the data should be passed
 *     wrapped. This only applies to wrapped data types, e.g. entities.
 *  Each 'provides' array may contain the following properties:
 *   - label: The label of the variable. Start capitalized. Required.
 *   - type: The rules data type of the variable. All types declared in
 *     hook_rules_data_info() may be specified. Types may be parametrized e.g.
 *     the types node<page> or list<integer> are valid.
 *   - save: (optional) If this is set to TRUE, the provided variable is saved
 *     by rules when the rules evaluation ends. Only possible for savable data
 *     types. Defaults to FALSE.
 */
function rules_example_rules_action_info(){
  return array(
   
'rules_example_extra_node_title' => array(
     
'group' => t('Example'),
     
'label' => t('Add prefix to node title'),
     
'parameter' => array(
       
//pass in parameters
       
'node' => array(
         
'type' => 'node',
         
'label' => t('Node'),
         
'description' => t('The node to add the prefix.'),
         
'save' => TRUE,
        ),
      ),
    ),
  );
}

/**
 * Rules action implementation
 * Key defined in hook_rules_action_info
 * @param  Object $node node being editted
 */
function rules_example_extra_node_title($node) {
 
$node->title .= '[Rules action example prefix] ';
 
node_save($node);
}
?>

要全部明白 hook_rules_action_info() 的確要花點時間
或者從 rules modules 內參考一個類似的比較容易吧

Pages

Google