2009-04-29

Web 文件類型壓縮及註解清除器

大部分的 Web 文件壓縮,都是將不要的空白文字或不必要的註解清除,以換取檔案的大小。

之前找尋不到合適的工具,索性就自己寫一個工具,這次將之前的HTML & Smarty、JavaScript、CSS 及 PHP 註解清除器做一個整合,並且做一些使用上的教學。

修改特點:
  • 整合之前的文件類型至一個工具上
  • 只針對 html , htm , css , js 及 php 副檔名的文件做處理
  • 增加參數選擇

web_clear 參數說明

web_clear [-hvc] (filename)
[-h | -?] : 顯示參數說明
[-v] : 顯示被執行的檔案列表
[-c] : 單純只清除註解
(filename) : 檔案路徑或目錄路徑


Windows 下的操作


可以透過拖移文件或資料夾的方式執行此工具。

也可以透過命令列或批次檔去執行

@ECHO off

web_clear.exe -v "Z:\Web" Z:\WebServer\1.html Z:\WebServer\1.css

PAUSE


Linux 下的操作

透過命令列或 Shell 去執行

#!/bin/bash

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

./web_clear -v /home/test/index.php

# 也可以配合 find 去執行
#./web_clear -v `find /home/test -name '*.css' -or -name '*.js'`

exit 0


檔案下載:

web_clear.tar.gz


web_clear
|-- linux
| |-- source
| | |-- web_clear.c
| | `-- web_clear.l
| |
| |-- clear_file.sh
| `-- web_clear
|
`-- windows
|-- source
| |-- web_clear.c
| `-- web_clear.l
|
|-- clear_file.bat
`-- web_clear.exe

4 directories, 8 files

[PHP] 線上編碼文件轉換器

這是利用 iconv 及 curl 去做線上文件編碼轉換,之前為了讓桌面行事曆能夠讀取 Google Calendar 而做的轉換器。


<?php
// 設定最長執行的秒數
ini_set ("expect.timeout", 30);
set_time_limit(30);

if($_GET['url']){
// 設定原始編碼及目標編碼
$source=($_GET['source'])? $_GET['source']: 'UTF-8';
$target=($_GET['target'])? $_GET['target']: 'BIG5';

// 取得 URL
$url=$_GET['url'];

// 初始化 CURL
$ch = curl_init();

// 設定 URL
curl_setopt($ch, CURLOPT_URL, $url);
// 讓 curl_exec() 獲取的信息以資料流的形式返回,而不是直接輸出。
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
// 在發起連接前等待的時間,如果設置為0,則不等待
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 0);
// 設定 CURL 最長執行的秒數
curl_setopt ($ch, CURLOPT_TIMEOUT, 30);

// 嘗試取得文件內容
$store = curl_exec ($ch);

// 檢查文件是否正確取得
if (!curl_errno($ch)){
// 編碼轉換
echo iconv($source,$target, $store);
exit;
}
}
?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>線上編碼文件轉換器</title>
</head>
<body style="width:28em;margin:5% auto;text-align:center;">
<form method="get" action="">
<fieldset>
<legend>線上編碼文件轉換器</legend>
<label>URL : <input type="text" name="url" size="48" /></label>
<p>
<input type="text" name="source" size="12" value="UTF-8" />
-&gt; 轉換至 -&gt;
<input type="text" name="target" size="12" value="BIG5" />
</p>
<p><input type="submit" value="開始轉換"/></p>
</fieldset>
</form>
</body>
</html>



參考文章:
PHP程式學習筆記本(PHP.Javascript.Mysql.cakephp.Jquery.Smarty): php.curl詳解

[PHP] 透過靜態成員函數建立物件

PHP5 對物件建立的架構還不是很完善
有些物件的操作方式是不允許的
  • 在新增物件時不能直接呼叫成員函數
  • 要透過函數才能建立匿名函數


<?php
class DataCheck {
// 成員變數
public $value=null;

// 建構子
public function __construct($value) {
$this->value=$value;
return $this;
}

// 成員函數
public function getValue() {
return $this->value;
}
}


// PHP 物件的使用方式
$a = new DataCheck("test");
$v = $a->getValue();


// 一般物件的使用方式
$v = new DataCheck("test")->getValue(); //Error
/* 但這樣做在 PHP5 中是不可行
* PHP5 對物件的架構還不是很完善
* 為了達到這樣的使用方式
* 建議使用物件中的靜態成員函數去達成
* 會比在 new 外加一個 () 要好多了
* 也可以在生成物件前做一些前置處理
* */


/**######################################################*/
class DataCheck {
// 靜態函數建立物件
public static function Value($value) {
return (new DataCheck($value));
}

// 成員變數
public $value=null;

// 建構子
public function __construct($value) {
$this->value=$value;
return $this;
}

// 成員函數
public function getValue() {
return $this->value;
}
}


// 利用靜態函數建立物件
$v = DataCheck::Value("test")->getValue();
/* 這樣就可以達成我們期望的方式
* 但最好還是希望 PHP 能夠對物件有更好的架構出現
* */

[PHP] 驗證碼2

根據之前寫的[PHP] 驗證碼做了一些修正
  • 增加圖片類型的選擇
  • 隨機文字色彩
  • 隨機底部線條
  • 根據文字大小產生相對應的圖片

<?php
/*定义header,声明图片文件,最好是png,无版权之扰; */
/*生成新的四位整数验证码 */
header('Content-type:image/png');
header('Content-Disposition:filename=image_code.png');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');


/* 字形檔的路徑 */
$TTF="/var/lib/defoma/fontconfig.d/D/DejaVu-Serif-Bold.ttf";

/* 開啟 SESSION */
if (!isset($_SESSION)) { session_start(); }

/* 設定亂數種子 */
mt_srand((double)microtime()*1000000);


/* 類型選擇 */
switch ($_GET['t']) {
case 'post':
//定義用來顯是在圖片上的文字
$codeBase='ABCDEFGHJKLMNPRSTUVWXYZ23456789';

$codeLength=5; //定義循環隨機抽取的位數
$codeName='checkPostCode'; // 認證碼名稱
$textSize=18; // 字體大小(點)
$proportion=0.2; //字寬加乘比例
break;

case 'min_post':
//定義用來顯是在圖片上的文字
$codeBase='ABCDEFGHJKLMNPRSTUVWXYZ23456789';

$codeLength=5; // 定義循環隨機抽取的位數
$codeName='checkMinPostCode'; // 認證碼名稱
$textSize=18; // 字體大小(點)
$proportion=0.2; // 字寬加乘比例
break;

case 'shoutbox':
//定義用來顯是在圖片上的文字
$codeBase='1234567890';

$codeLength=3; // 定義循環隨機抽取的位數
$codeName='checkShoutCode'; // 認證碼名稱
$imageX=60; $imageY=24; // 圖片的長寬
$textSize=18; // 字體大小(點)
$proportion=0.2; // 字寬加乘比例
break;

case 'comm':
default:
//定義用來顯是在圖片上的文字
$codeBase='1234567890';

$codeLength=3; // 定義循環隨機抽取的位數
$codeName='checkMsgCode'; // 認證碼名稱
$textSize=18; // 字體大小(點)
$proportion=0.2; // 字寬加乘比例
break;
}

// 圖片的高度
$imageY=intval($textSize*(1+$proportion));
// 圖片的寬度
$imageX=$imageY*$codeLength;


/*建立圖片物件 */
$im = @imagecreatetruecolor($imageX, $imageY) or die('Image Error');

/* 設定底色 */
imagefill($im,0,0,
imagecolorallocate($im, 255,255,255)
);


/* 建立筆刷 */
$s=intval($textSize/8);
$brush = imagecreate($s,$s);
imagesetbrush($im,$brush);

/*底色干擾線條 */
$l=$codeLength*7;
for($i=0;$i<$l;$i++){
imagefill($brush,0,0,imagecolorallocate(
$brush, rand(127,255),rand(127,255),rand(127,255)
));
imageline(
$im,
rand(0,$imageX),
rand(0,$imageY),
rand($imageY,$imageX),
rand(0,$imageY),
IMG_COLOR_BRUSHED
);
}


/*得到字串的長度;减1是因为截取字符是从0开始起算;*/
$l = strlen($codeBase)-1;
$widgetSize=$imageX/$codeLength;
$codeStr = '';

/*循環隨機抽取前面定義的文字*/
for($i=0;$i<$codeLength;$i++){
/*每次随机抽取一位数字;从第一个字到该字串最大长度, */
$num=rand(0,$l);
$codeStr.= $codeBase[$num];

/*利用true type字型來產生圖片 */
$Color = imagecolorallocate( // 文字顏色
$im,rand(0,60),rand(0,60),rand(0,60)
);
imagettftext(
$im,
$textSize,
rand(-25,25),
$widgetSize*($i+$proportion),
$textSize,
$Color,
$TTF,
$codeBase[$num]
);

/*
imagettftext (int im, int size, int angle,
int x, int y, int col,
string fontfile, string text)

im 圖片物件
size 文字大小
angle 0度將會由左到右讀取文字,而更高的值表示逆時鐘旋轉
x y 文字起始座標
col 顏色物件
fontfile 字形路徑,為主機實體目錄的絕對路徑,可自行設定想要的字型
text 寫入的文字字串
*/
}


/* 建立筆刷 */
$s=intval($textSize/9);
$brush = imagecreate($s,$s);
imagesetbrush($im,$brush);

/* 文字干擾像素 */
$l=$codeLength*13;
for($i=0;$i<$l;$i++){
imagefill($brush,0,0,imagecolorallocate(
$brush,rand(40,100),rand(40,100),rand(40,100)
));
imagesetpixel(
$im,
rand(0,$imageX),
rand(0,$imageY),
IMG_COLOR_BRUSHED
);
}


/*用session来做验证也不错;注册session,名称为checkMsgCode, */
/*其它页面只要包含了该图片 */
/*即可以通过$_SESSION['checkMsgCode']来调用 */
session_register($codeName);
$_SESSION[$codeName] = $codeStr;

imagepng($im);
imagedestroy($im);



輸出結果:

手動調整 ffdshow 中的影像解碼器

之前安裝 K-Lite Codec Pack 來作為我主要的播放器
可是有些影片的影像解碼上會有不正常的問題
在影像上會出現奇怪的線條跟殘影

最後找到問題的所在點
那就是解碼器的版本問題造成的

最簡單的方法就是關閉 ffdshow 中的預設解碼器


像我最常出現問題的就是 DivX
在 ffdshow 中將 "DivX 4/5/6" 的選項設成 disabled
按下 OK 後再重新播放影片就可以了

當然建議再安裝 K-Lite Codec Pack 時
最好選擇安裝全部的解碼格式
這樣在調整 ffdshow 時才有意義
2009-04-28

[PHP] Smarty 繼承改寫(範例)


<?php

// 繼承 Smarty
class SmartyTpl extends Smarty {
// 建構子
function __construct( $dir = '' ){
if( $dir ){ $dir .= '/'; }

$this->template_dir = $_SERVER['DOCUMENT_ROOT'].$dir."view/";
$this->compile_dir = $_SERVER['DOCUMENT_ROOT'].$dir."cache/tpl_c/";
$this->cache_dir = $_SERVER['DOCUMENT_ROOT'].$dir."cache/html/";

$this->left_delimiter='<%';
$this->right_delimiter='%>';
}

// 改寫 assign
function assign( $tpl_var, $value=null ){
// 呼叫父類別的方法
parent::assign( $tpl_var, $value );
// 回傳 this 讓方法可以疊加呼叫
return $this;
}

// 改寫 assign_by_ref
function assign_by_ref( $tpl_var, &$value ){
// 呼叫父類別的方法
parent::assign_by_ref( $tpl_var, $value );
// 回傳 this 讓方法可以疊加呼叫
return $this;
}

}



參考來源:
Smarty
Smarty中文手册,Smarty教程,Smarty模板的入门教材(PHP技术)

[C語言] 高斯消去法-特約化矩陣(RREF)


#include<stdio.h>
#include<stdlib.h>

/*高斯消去法 - 特約化矩陣*/
double **matrix_rref(double **matrix, int m, int n){
double zero=0.00000001;
double temp;

int x=0,y=0,j,i;
while(x<n && y<m){
// 如果列首為零,則找尋可以互換的列
while(x<n && matrix[y][x]<zero && matrix[y][x]>(-zero)){
j=y+1;
while(j<m && matrix[j][x]<zero && matrix[j][x]>(-zero)){j++;}

// 此行都為零,移至下一行
if(j >= m){ x++; continue; }

// 找到列首不為零的列,兩列互換
for(i=x; i<n; i++){
temp=matrix[j][i];
matrix[j][i]=matrix[y][i];
matrix[y][i]=temp;
}
// 互換結束跳出迴圈
break;
}
if(x>=n){ break; }

// 所有列值都除以列首,列首為(1)處理
for(i=n-1; i>x; i--){
matrix[y][i]/=matrix[y][x];
}
matrix[y][x]=1;

// 消去上下列
for(j=0; j<m; j++){
// 跳過選取的列
if(j == y){ continue; }

// 選取的列消去其他列
for(i=n-1; i>=x; i--){
matrix[j][i]-=matrix[y][i]*matrix[j][x];
}
}

x++; y++;
}
return matrix;
}



/*
input.txt
4 5
1 2 3 7 55
1 3 2 4 76
3 2 1 6 43
4 6 5 3 34
*/

/*主程式*/
int main(){
int m,n,i,j;
FILE *in;
// 開啟檔案
in=fopen("input.txt","r");

// 讀取 m,n 值
fscanf(in,"%d\n",&m);
fscanf(in,"%d\n",&n);

// 利用 malloc 配置二維空間 。
double **mar= (double**) malloc(m * sizeof(double*));
for (i=0; i<m; i++){
mar[i] = (double*) malloc(n * sizeof(double));
}

// 讀取矩陣
for(i=0;i<m;i++){
for(j=0;j<n;j++){
fscanf(in,"%lf",&mar[i][j]);
}
}

// 高斯消去法
mar=matrix_rref(mar,m,n);

// 列印結果
for(i=0;i<m;i++){
for(j=0;j<n;j++){
printf("%.2lf ",mar[i][j]);
}
printf("\n");
}

_getch();

return 0;
}

Eclipse 外部工具的設定方法

最近再使用 Eclipse 寫 Lex,原本為了執行 flex 的編譯有點不順手,後來發現可以使用外部工具去執行這個動作,讓整個編輯過程都很快樂。


點選外部工具,並建立一個新的外部工具。


在位址匡選擇上外部工具的位址。
工作目錄設成專案目錄:${project_loc}
引數設定是給予命令列上的參數:-FLi8 -o${project_name}.c ${project_name}.l


再重新整理的頁籤中勾選執行完後要如何重新整理,在這裡可以讓 C語言 的專案自動重新編譯。


Eclipse 提供的變數:
  • ${container_loc}
    傳回資源儲存器的絕對檔案系統路徑。當沒有指定引數或資源是由工作區相對路徑來識別時,目標資源就是所選的資源。
    value= E:\Program\file-test

  • ${container_name}
    傳回資源儲存器的名稱。當沒有指定引數或資源是由工作區相對路徑來識別時,目標資源就是所選的資源。
    value= file-test

  • ${container_path}
    傳回資源儲存器的工作區相對路徑。當沒有指定引數或資源是由工作區相對路徑來識別時,目標資源就是所選的資源。
    value= \file-test

  • ${eclipse_home}
    執行中平台的基本程式安裝位置
    value= /C:/Program Files/eclipse-gcc/

  • ${file_prompt:圖片檔案}
    傳回選取檔案的對話框所選擇之檔案的絕對檔案系統路徑。當提供一個引數時,它用來作為對話框標題的提示要點。當提供第二個引數時,它用來作為選取檔案的對話框的起始值。第一和第二個引數必須用 ':' 分開。


  • ${folder_prompt}
    傳回選取目錄的對話框所選擇之目錄的絕對檔案系統路徑。當提供一個引數時,它用來作為對話框標題的提示要點。當提供第二個引數時,它用來作為選取目錄的對話框的起始值。第一和第二個引數必須用 ':' 分開。


  • ${project_loc}
    傳回資源專案的絕對檔案系統路徑。當沒有指定引數或資源是由工作區相對路徑來識別時,目標資源就是所選的資源。
    value= E:\Program\file-test

  • ${project_name}
    傳回資源專案的名稱。當沒有指定引數或資源是由工作區相對路徑來識別時,目標資源就是所選的資源。
    value= file-test

  • ${project_path}
    傳回資源專案的工作區相對路徑。當沒有指定引數或資源是由工作區相對路徑來識別時,目標資源就是所選的資源。
    value= \file-test

  • ${resource_loc}
    傳回資源的絕對檔案系統路徑。當沒有指定引數或資源是由工作區相對路徑來識別時,目標資源就是所選的資源。
    value= E:\Program\file-test\file-test.c

  • ${resource_name}
    傳回資源的名稱。當沒有指定引數或資源是由工作區相對路徑來識別時,目標資源就是所選的資源。
    value= file-test.c

  • ${resource_path}
    傳回資源的工作區相對路徑。當沒有指定引數或資源是由工作區相對路徑來識別時,目標資源就是所選的資源。
    value= \file-test\file-test.c

  • ${selected_text}
    傳回作用中的編輯器目前選取的文字。
    value= for(i=0;i<length;i++)

  • ${string_prompt}
    傳回輸入提示對話框的文字值。當提供一個引數時,它用來作為輸入對話框中的提示要點。當提供第二個引數時,它用來作為輸入對話框中的起始值。第一和第二個引數必須用 ':' 分開。

  • ${workspace_loc}
    傳回工作區根目錄的絕對檔案系統路徑。當指定引數時,會傳回工作區相對路徑所識別的資源的絕對檔案系統路徑。
    value= E:\Program


參考來源:
Eclipse+CDT+MinGW 安裝手冊
2009-04-26

[PHP] PDO 資料庫操作方法(快速範例)


<?php

/*--[PDO::query]-----------------------------------*/
// 建立查詢連結
$stmt = $DB_Link->query(sprintf("
SELECT id, colour FROM test_table WHERE name=%s
",$name));

// 設定查詢結果的資料格式,之後可以省去 fetch 時的格式設定
$stmt->->setFetchMode(PDO::FETCH_ASSOC);

// 取得查詢結果的列數
$count = $stmt->rowCount ();
/* PDOStatement::rowCount()主要是用於 PDO::query()和PDO::prepare()進行DELETE、INSERT、UPDATE操作影響的結果集,對PDO::exec()方法 和SELECT操作無效。 */

// 取得一列的查詢結果
$row = $stmt->fetch(PDO::FETCH_ASSOC);

// 利用迴圈對每一列做處理
$dataArray = array(); // 結果儲存陣列
while ($row = $stmt->fetch(PDO::FETCH_ASSOC) {
// 資料處理
$row['colour'] = $row['colour']? $row['colour'] : '#000';
// 加儲存陣列
array_push($dataArray,$row);
}

// 取得一列單一欄位的查詢結果
$column = $stmt->fetchColumn(); // id
$column = $stmt->fetchColumn(1); // colour
/* 當查詢結果之有一個時很好用(SELECT COUNT(*) FROM test_table) */

// 取得所有的查詢結果列
$dataArray = $stmt->fetchAll (PDO::FETCH_ASSOC);


/* PDO::fetch , PDO::fetchAll 選項參數
PDO::FETCH_LAZY
將每一行結果作為一個對象返回

PDO::FETCH_ASSOC
僅返回以鍵值作為下標的查詢的結果集,名稱相同的數據只返回一個

PDO::FETCH_NAMED
僅返回以鍵值作為下標的查詢的結果集,名稱相同的數據以數組形式返回

PDO::FETCH_NUM
僅返回以數字作為下標的查詢的結果集

PDO::FETCH_BOTH
同時返回以鍵值和數字作為下標的查詢的結果集(預設)

PDO::FETCH_OBJ
按照對象的形式,類似於以前的 mysql_fetch_object()

PDO::FETCH_BOUND
將PDOStatement::bindParam()和PDOStatement::bindColumn()所綁定的值作為變量名賦值後返回

PDO::FETCH_COLUMN
將返回結果每一列全部集中在一個欄位

PDO::FETCH_CLASS
以 Class 的形式返回結果集

PDO::FETCH_INTO
將數據合併入一個存在的類中進行返回

PDO::FETCH_FUNC
PDO::FETCH_GROUP
PDO::FETCH_UNIQUE
PDO::FETCH_KEY_PAIR
以首個鍵值下表,後面數字下表的形式返回結果集

PDO::FETCH_CLASSTYPE
PDO::FETCH_SERIALIZE
表示將數據合併入一個存在的類中并序列化返回

PDO::FETCH_PROPS_LATE
Available since PHP 5.2.0
*/



/*--[PDO::exec]-----------------------------------*/
$colour="'red'";

// 建立新增請求
$count = $DB_Link->exec(sprintf("
INSERT INTO test_table(colour) VALUES(%s)
",$colour));
// 取得上次 Insert 時產生的 AUTO_INCREMENT Id
$id = $DB_Link->lastInsertId();

// 建立更新請求
$count = $DB_Link->exec(sprintf("
UPDATE test_table SET colour = %s WHERE id=1
",$colour));

// 建立刪除請求
$count = $DB_Link->exec(sprintf("
DELETE FROM test_table WHERE colour = %s LIMIT 10
",$colour));
/*
PDO::exec 會回傳所影響的列數
但如果 DELETE 到資料表為空時將回傳 0,而不是所刪除的列數
*/



參考來源:
PHP: PDO::lastInsertId - Manual
PHP: PDOStatement->fetchColumn - Manual
PHP: PDO::exec - Manual
PHP: PDO::query - Manual

PDO (PHP Data Object) 簡易教學 @ wEd2.5
PHP的PDO类教程_PHP技巧
pdo使用简例 - 板子博客

[PHP] PDO 資料庫連接設定(快速範例)


<?php
$hostname = "localhost";
$database = "test_db";
$username = "root";
$password = "0000";


/* DSN :
mysql:host=localhost;port=3307;dbname=testdb;unix_socket=/tmp/mysql.sock;

pgsql:host=localhost port=5432 dbname=testdb user=bruce password=mypass;

mssql:host=localhost;dbname=testdb
sybase:host=localhost;dbname=testdb
dblib:host=localhost;dbname=testdb

odbc:DRIVER={IBM DB2 ODBC DRIVER};HOSTNAME=localhost;PORT=50000;DATABASE=SAMPLE;PROTOCOL=TCPIP;UID=db2inst1;PWD=ibmdb2;
odbc:Driver={Microsoft Access Driver (*.mdb)};Dbq=C:\\db.mdb;Uid=Admin;

ibm:DRIVER={IBM DB2 ODBC DRIVER};DATABASE=testdb;HOSTNAME=11.22.33.444;PORT=56789;PROTOCOL=TCPIP;

oci:dbname=192.168.10.145/orcl;charset=CL8MSWIN1251

sqlite:/opt/databases/mydb.sq3
sqlite::memory:
sqlite2:/opt/databases/mydb.sq2
sqlite2::memory:
*/

$dsn="mysql:host=$hostname;dbname=$database";
try {
$DB_Link = new PDO($dsn, $username,$password
/*,array(
PDO::ATTR_PERSISTENT => true, // 開啟 DB 長連接
PDO::MYSQL_ATTR_INIT_COMMAND => // MySQL 前置設定
"SET NAMES 'utf8'; SET group_concat_max_len=65536;",
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY=>false // MySQL 查詢緩衝區
)*/
);
} catch (PDOException $e) {
// 資料庫連結失敗
$e->errorInfo ; // 錯誤明細
$e->getMessage(); // 返回異常資訊
$e->getPrevious(); // 返回前一個異常
$e->getCode(); // 返回異常程式碼
$e->getFile(); // 返回發生異常的檔案名
$e->getLine(); // 返回發生異常的程式碼行號
$e->getTrace(); // backtrace() 陣列
$e->getTraceAsString(); // 已格成化成字串的 getTrace() 資訊

// 錯誤處理...
}

/*
PDO::ATTR_CASE: 返回的資料欄位名稱設定
PDO::CASE_LOWER: 欄位名稱全部轉換成小寫
PDO::CASE_NATURAL: 使用原始欄位名稱(預設)
PDO:: CASE_UPPER: 欄位名稱全部轉換成大寫
*/
//$DB_Link->setAttribute(PDO::ATTR_CASE,PDO::CASE_NATURAL);


/*
PDO::ATTR_ERRMODE: 錯誤報告
PDO::ERRMODE_SILENT: 不顯示錯誤信息,只顯示錯誤碼。
PDO::ERRMODE_WARNING: 顯示警告跟錯誤。
PDO::ERRMODE_EXCEPTION: 拋出異常。
*/
$DB_Link->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING);


/*
PDO::ATTR_ORACLE_NULLS : 轉換無效的空字串
PDO::NULL_NATURAL: 不轉換(預設)。
PDO::NULL_EMPTY_STRING: 空字串轉換為 NULL。
PDO::NULL_TO_STRING: NULL 轉換為空字串。
*/
//$DB_Link->setAttribute(PDO::ATTR_ORACLE_NULLS,PDO::NULL_NATURAL);

/*
PDO::ATTR_STRINGIFY_FETCHES:
Convert numeric values to strings when fetching. Requires bool.
*/
//$DB_Link->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);


/*
PDO::ATTR_STATEMENT_CLASS: 變更預設 PDOStatement Class
*/
//class DBStatement extends PDOStatement {}
//$DB_Link->setAttribute(PDO::ATTR_STATEMENT_CLASS,
// array('DBStatement', array($DB_Link))
//);


/*
PDO::ATTR_AUTOCOMMIT: 自動啟動交易處理
在設置成true的時候,PDO會自動嘗試停止接受委託,開始執行
*/
//$DB_Link->setAttribute(PDO::ATTR_AUTOCOMMIT,true);



// 設定存取的編碼方式
$DB_Link->exec("SET NAMES 'utf8';");

// 設定 GROUP_CONCAT 的最大長度
$DB_Link->exec("SET group_concat_max_len=65536;");

// 關閉查詢快取
//$DB_Link->exec("SET SESSION query_cache_type=OFF;");





參考來源:
PHP: PDO Drivers - Manual
PHP: PDO::__construct - Manual
PHP: PDOException - Manual
PHP: PDO::setAttribute - Manual

牛刀小小試 PHP5中PDO的簡單使用
2009-04-25

[LEX] 使用命令列參數開啟檔案


/*[flex] 的指令參數
* ( flex -FLi8 %f )
* -l 最大兼容性法則
* -i 不區分大小寫
* -f 產生不壓縮的完整表格,效率快,所需空間大
* -F 最佳效率與空間優化
* -L 在產生的程式碼中不加入 #line
* -7 使用 7 bit 掃瞄文字(預設)
* -8 使用 8 bit 掃瞄文字
*
* -+ 產生 C++ 掃瞄 Class
*
* -oOutputName 指定輸出檔案名稱
*
* -h 參數說明
* -V 版本顯示
* -T 顯示追蹤記錄
* */


/* [定義段落] */
%{
#include <stdio.h>

%}

/* 告知沒有自訂的 unput() */
%option nounput

/* 初始狀態 */
%s START
/* 多行註解狀態 */
%s COMMENTS

/* 換行符號 */
EN [\r\n]
/* 換行符號及空白字元 */
SP [ \t\r\n] //
/* 單引號字串 */
//STR1 (\'([^\'\r\n]|"\\\'")*\')
/* 雙引號字串 */
//STR2 (\"([^\"\r\n]|"\\\"")*\")


%% /* [規則段落] */

/* 多行註解模式 */
<COMMENTS>"*/"{SP}* { BEGIN START; }
<COMMENTS>.|{SP} ;

/* 初始模式 */
<START>"/*" { BEGIN COMMENTS; }
<START>"//".*{EN}+ ;
<START>. {fprintf(yyout,"%s",yytext);}


%% /* [自訂函數段落] */

/* 程式執行方式與檔案參數
* 程式.exe 文件1.txt 文件2.txt 文件3.txt
* 或使用文件拖放至程式上
* */
char **fileList;
unsigned currentFile = 0;
unsigned nFiles;

int main(int argc,char **argv){
// 沒有檔案
if(argc<2){
printf("沒有給予檔案參數");return 0;

}else{
// 取得檔案參數
fileList = argv+1;
nFiles = argc-1;

// 嘗試開啟第一個檔案
yywrap();
}

// 執行文字解析器
yylex();
/* 文字解析器會在檔案結束時
* 自動呼叫 yywrap() 開啟下一個檔案
* */

return 0;
}

/* 當沒自訂的 yywrap() 時
* 記得在前加上 "%option noyywrap"
* */
int yywrap(){
// 關閉上次開啟的檔案
if ((currentFile > 0) && (nFiles >= 1) && (currentFile <= nFiles)) {
// 關閉輸入與輸出的文件
fclose(yyin); fclose(yyout);

// 將暫存檔覆蓋原始輸入文件
remove(fileList[currentFile-1]);
rename("temp",fileList[currentFile-1]);
}

FILE *fileIn = NULL;
while ((currentFile < nFiles)) {
// 檢查副檔名
if(strstr(fileList[currentFile],".txt")!= NULL){
// 設定初始狀態
BEGIN START;
}else{
// 跳過不符合的檔案
continue;
}


// 嘗試開啟檔案
fileIn = fopen(fileList[currentFile++], "r");
if (fileIn != NULL) {
// 指定輸入與輸出的文件指標
yyin = fileIn;
yyout = fopen("temp","w");

// 成功開啟檔案跳出迴圈
break;
}
printf("無法開啟檔案: %s\n",fileList[currentFile-1]);
}
// 回傳狀態 ( 0:成功開啟 , 1:開啟失敗 )
return (fileIn ? 0 : 1);
}


相關連結:Yacc 与 Lex 快速入门

[C語言] 快速排序法(quick sort)


#include<stdio.h>

/** quick_sort [快速排序法]
* @param {array} array
* @param {int} low
* @param {int} high
*/
int quick_sort(int *array,int low,int high) {
int pivot_point,pivot_item,i,j,temp;
// 指標交界結束排序
if(high<=low){return 1;}

// 紀錄樞紐值
pivot_item = array[low];
j=low;

// 尋找比樞紐小的數
for(i=low+1; i<=high; i++) {
// 跳過等於或大於的數
if(array[i]>=pivot_item){continue;}

j++;
// 交換 array[i] , array[j]
temp = array[i];
array[i] = array[j];
array[j] = temp;
}

// 將樞紐位址移到中間
pivot_point=j;
// 交換 array[low] , array[pivot_point]
temp = array[low];
array[low] = array[pivot_point];
array[pivot_point] = temp;

// 遞迴處理左側區段
quick_sort(array,low,pivot_point-1);
// 遞迴處理右側區段
quick_sort(array,pivot_point+1,high);

return 1;
}


/*主程式*/
int main(){
int a[]={12,42,54,3,5,32,61,24,31};

quick_sort(a,0,8);

int i;
for(i=0; i<=8; i++) {
printf("%d\n",a[i]);
}

_getch();
return 0;
}

[C語言] 連結串列(link list)


/* link list (連結串列) */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

/* 定義結構型態 */
typedef struct link_node{
int data;
struct link_node *link;
} LINK_NODE;



/* 產生新節點 */
LINK_NODE *new_node(int data){
LINK_NODE *node;
node=(LINK_NODE *) malloc(sizeof(LINK_NODE));/*<stdlib.h>*/

// 記憶體不足
if(node == NULL){ return NULL;}

node->data=data;
node->link=NULL;
return node;
}


/* 加入新的資料於最後 */
LINK_NODE *push_node(LINK_NODE *list, int data){
/*產生新節點*/
LINK_NODE *node=new_node(data);

// 加入第一個新節點
if(list==NULL){
list=node;
}else{
LINK_NODE *p=list;
// 取得最後一個節點
while(p->link!=NULL){p=p->link;}
p->link=node;
}
return list;
}


/* 排序插入新節點 */
LINK_NODE *sort_insert(LINK_NODE *list,int data){
// 加入第一筆資料

// 產生新節點
LINK_NODE *node=new_node(data);
if(list==NULL){ list=node; return list; }

// 尋找大於資料(data)的位址
LINK_NODE *r=list,*q=list;
while(r!=NULL && r->data<data){ q=r; r=r->link; }

if(r==list){ // 首節點
node->link=list; list=node;
}else{ // 加入新節點於中間
node->link=q->link;
q->link=node;
}
return list;
}


/* 計算串列長度 */
int get_length(LINK_NODE *list){
LINK_NODE *p=list;
int count=0;
while(p!=NULL){
count++;
p=p->link;
}

return count;
}


/* 搜尋資料(data)的節點位子 */
LINK_NODE *search_node(LINK_NODE *list, int data){
LINK_NODE *p=list;
while(p!=NULL && p->data!=data){ p=p->link; }
return p ;
}


/* 印出所有串列的所有資料 */
int display(LINK_NODE *list){
LINK_NODE *p=list;
while(p!=NULL){
printf("%d\n",p->data);/*<stdio.h>*/
p=p->link;
}
return 1;
}




/*主程式*/
int main(){
LINK_NODE *list=NULL;

list=sort_insert(list,4);
list=sort_insert(list,2);
list=sort_insert(list,7);
list=sort_insert(list,9);
list=sort_insert(list,14);
display(list);

printf("--------------------------\n");

list=push_node(list,4);
list=push_node(list,2);
list=push_node(list,7);
list=push_node(list,9);
list=push_node(list,14);
display(list);

_getch();
return 0;
}

[C語言] 字串取代(str_replace)

strlen , strcpy , strstr , strcat , malloc

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* str_replace [字串取代]
* @param {char*} source 原始的文字
* @param {char*} find 搜尋的文字
* @param {char*} rep 替換的文字
* */
char *str_replace (char *source, char *find, char *rep){
// 搜尋文字的長度
int find_L=strlen(find);
// 替換文字的長度
int rep_L=strlen(rep);
// 結果文字的長度
int length=strlen(source)+1;
// 定位偏移量
int gap=0;

// 建立結果文字,並複製文字
char *result = (char*)malloc(sizeof(char) * length);
strcpy(result, source);

// 尚未被取代的字串
char *former=source;
// 搜尋文字出現的起始位址指標
char *location= strstr(former, find);

// 漸進搜尋欲替換的文字
while(location!=NULL){
// 增加定位偏移量
gap+=(location - former);
// 將結束符號定在搜尋到的位址上
result[gap]='\0';

// 計算新的長度
length+=(rep_L-find_L);
// 變更記憶體空間
result = (char*)realloc(result, length * sizeof(char));
// 替換的文字串接在結果後面
strcat(result, rep);
// 更新定位偏移量
gap+=rep_L;

// 更新尚未被取代的字串的位址
former=location+find_L;
// 將尚未被取代的文字串接在結果後面
strcat(result, former);

// 搜尋文字出現的起始位址指標
location= strstr(former, find);
}

return result;

}


int main(){
char* str1 = "this is a string of characters";
char* str2 = str_replace(str1, "is","FFF");

printf( "str1: '%s'\n", str1 );
printf( "str2: '%s'\n", str2 );

_getch();
return 0;
}



參考來源:
Standard C String and Character [C++ Reference]
2009-04-24

[C語言] 取得目錄名稱路徑(dirname)

dirname

#include <libgen.h>

int main(){
char W_path1[] = "E:\\test" ;
char W_path2[] = "E:\\Program\\clear\\ape-06\\Debug" ;
char W_path3[] = "E:\\Program\\clear\\.metadata\\.plugins\\org" ;

dirname(W_path1);
printf("%s\n",W_path1);
// E:\

dirname(W_path2);
printf("%s\n",W_path2);
// E:\Program\clear\ape-06

dirname(W_path3);
printf("%s\n",W_path3);
// E:\Program\clear\.metadata\.plugins

char L_path1[] = "/test" ;
char L_path2[] = "/Program/clear/ape-06/Debug" ;
char L_path3[] = "/Program/clear/.metadata/.plugins/org" ;

dirname(L_path1);
printf("%s\n",L_path1);
// /

dirname(L_path2);
printf("%s\n",L_path2);
// /Program/clear/ape-06

dirname(L_path3);
printf("%s\n",L_path3);
// /Program/clear/.metadata/.plugins


_getch();
return 0;
}



參考來源:
<libgen.h>

[C語言] 遞迴掃瞄目錄下所有文件(dir_recursive)

opendir , readdir , closedir

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <dirent.h>


/* dir_recursive [遞迴掃瞄目錄下所有文件]
* 掃瞄 path 下所有的文件,並輸出至 output 的文件中
* output 必須為可寫入的文件
* */
int dir_recursive(char *path, FILE *output){
char glue='\\'; // Windows 的分隔符號
//char glue='/'; // Linux 的分隔符號

// 嘗試開啟目錄
DIR * dp = opendir(path);

if (!dp){
// 不是目錄,輸出至檔案
fprintf(output,"%s\n",path);
return 1;
}

struct dirent *filename;
while((filename=readdir(dp))){
// 跳過當前及母目錄
if(!strcmp(filename->d_name,"..") || !strcmp(filename->d_name,".")){
continue;
}

// 計算新的路徑字串所需的長度
int pathLength=strlen(path)+strlen(filename->d_name)+2;
// 產生新的陣列空間
char *pathStr = (char*)malloc(sizeof(char) * pathLength);
// 複製當前目錄路徑至新的陣列空間
strcpy(pathStr, path);

// 檢查目錄分隔符號
int i=strlen(pathStr);
if(pathStr[i-1]!=glue){
pathStr[i]=glue;
pathStr[i+1]='\0';
}

// 串接次目錄名稱或檔案名稱至新的陣列空間
strcat(pathStr, filename->d_name);

// 遞迴呼叫目錄掃瞄
dir_recursive(pathStr,output);

}

// 關閉目錄
closedir(dp);

return 1;
}



int main(){
// 建立輸出的文件檔
FILE *fileOut = fopen("output.txt", "w");

// 掃瞄 E:\test 下所有的文件
dir_recursive("E:\\test",fileOut);

return 0;
}



參考來源:
[原创]LINUX下用C语言历遍目录 C语言列出目录_小徐博客 学无止境 minix and linux

[C語言] 字串相加(string_concat)

strlen , strcpy , strcat

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* string_concat [字串相加]
* 將 str1 與 str2 相加,並返回新的字串
* */
char *string_concat(char *str1, char *str2) {
// 計算所需的陣列長度
int length=strlen(str1)+strlen(str2)+1;

// 產生新的陣列空間
char *result = (char*)malloc(sizeof(char) * length);

// 複製第一個字串至新的陣列空間
strcpy(result, str1);
// 串接第二個字串至新的陣列空間
strcat(result, str2);

return result;
}


int main(){
char *a="123456";
char *b="abcde";
char *c=string_concat(a,b);
printf("%s\n",c);

_getch();
return 0;
}



參考來源:
Standard C String and Character [C++ Reference]

[C語言] 檔案讀寫

fclose , feof , fopen , fprintf , fscanf , printf , remove , rename , rewind , scanf , ftell , fseek
#include <stdio.h>

int main(){
    FILE *fileIn;
    FILE *fileOut;

    fileIn = fopen("input.txt", "r");
    if(fileIn == NULL){printf("檔案不存在\n"); return 0;}

    fileOut = fopen("output.txt", "w");
    /* Mod:
    * "r" : 開啟檔案,以純文字方式[讀取]。
    * "w" : 開啟或建立檔案,以純文字方式[寫入],會複寫原先的資料。
    * "a" : 開啟或建立檔案,以純文字方式[寫入],並將檔案指標移到最後。
    * "rb" : 同 "r" 但以二進位(binary)方式[讀取]。
    * "wb" : 同 "w" 但以二進位(binary)方式[寫入]。
    * "ab" : 同 "a" 但以二進位(binary)方式[寫入]。
    * "r+" : 同 "r" 但同時具有[讀取/寫入]的權力
    * "w+" : 同 "w" 但同時具有[讀取/寫入]的權力
    * "a+" : 同 "a" 但同時具有[讀取/寫入]的權力
    * "rb+" : 同 "rb" 但同時具有[讀取/寫入]的權力
    * "wb+" : 同 "wb" 但同時具有[讀取/寫入]的權力
    * "ab+" : 同 "ab" 但同時具有[讀取/寫入]的權力。
    */


    int    a1;
    float  a2;
    char   a3;
    char   a4[100];

    while(!feof(fileIn)){// 當讀取結束時會回傳 true
        // 依格式讀取一列文字,所有的變數都要取址,除了字元陣列
        fscanf(fileIn,"%d %f %c %s",&a1,&a2,&a3,a4);

        // 依格式將資料輸出至螢幕上
        printf("%d %f %c %s\n",a1,a2,a3,a4);

        // 依格式寫入一列文字
        fprintf(fileOut,"%d %f %c %s\n",a1,a2,a3,a4);

        /* %c : 一個字元(char)格式
        * %s : 一個字串格式
        *
        * %i : 一個整數(int)格式
        * %d : 一個十進位整數(int)格式
        * %u : 一個十進位無符號整數(unsigned)格式
        *
        * %e, %f, %g : 一個浮點數(float)格式
        * %lf: 一個浮點數(double)格式
        *
        * %o : 八進位(02732)格式
        * %x : 十六進位(0x27fa)格式
        * %% : 跳脫成 %
        * */

    }

    // 輸出當前的檔案指標位址
    printf("offset = %ld\n", ftell(fileIn) );

    // 將檔案指標返回至最上面,失敗則回傳 0
    // 會清除錯誤並將 EOF 標示清除
    // 當需要重新讀取時可利用此函數
    rewind(fileIn);

    // 將移動檔案指標從開始處偏移 5 個字元,成功則回傳 0
    // 會將 EOF 標示清除
    fseek(fileIn,5,SEEK_SET);
    /* int fseek( FILE *stream, long offset, int origin );
    * stream : 檔案指標
    * offset : 偏移量,可為正負數
    * origin : 偏移的依據位址
    *   SEEK_SET 0  檔案起始位址
    *   SEEK_CUR  1  當前位址
    *   SEEK_END  2  檔案結束位址
    * */


    // 關閉檔案指標
    fclose(fileIn);
    fclose(fileOut);

    // 將檔案 "input.txt" 移除
    remove("input.txt");

    // 將 "output.txt" 的檔案名稱變更為 "input.txt"
    rename("output.txt","input.txt");


    // 按任意鍵結束
    _getch();
    return 0;
}



參考來源:
Standard C I/O [C++ Reference]
printf() 與 scanf()

[C語言] 動態記憶體配置(malloc)

malloc , calloc , realloc , free

#include <stdlib.h>

int main(){

/*一維陣列*/
int size1=1000;
int *array1;

// 利用 malloc 配置空間 。
array1 = (int*) malloc(size1 * sizeof(int));

// 利用 calloc 配置空間,會初始為 0 。
array1 = (int*) calloc(size1 , sizeof(int));

// 利用 realloc 將原本的空間調整成兩倍,並且複製原本的內容,
// 但不保證是原本的空間位址。
array1 = (int*) realloc(array1, 2 * size1 * sizeof(int));


// 釋放記憶體空間。
free(array1);


/*二維陣列*/
int i;
int size_x=100;
int size_y=100;
int **array2;

// 利用 malloc 配置二維空間 。
array2 = (int**) malloc(size_x * sizeof(int*));
for (i=0; i<size_x; i++){
array2[i] = (int*) malloc(size_y * sizeof(int));
}


// 釋放記憶體空間
for (i=0; i<size_x; i++){
free(array2[i]);
}
free(array2);

return 0;
}


參考來源:
Standard C Memory [C++ Reference]

Dos 下的目錄顯示(DIR)

顯示檔案清單以列出目錄中的檔案及子目錄。

DIR [drive:][path][filename] [/A[[:]attributes]] [/B] [/C] [/D] [/L] [/N]
[/O[[:]sortorder]] [/P] [/Q] [/S] [/T[[:]timefield]] [/W] [/X] [/4]

[drive:][path][filename]
 指定要顯示的磁碟機、目錄或檔案。

/?顯示參數說明。

/A依照指定的檔案屬性來顯示檔案。
attributesD 目錄
R 唯讀檔
H 隱藏檔
A 保存檔
S 系統檔案
- 無意義

/B使用單純格式 (沒有標頭資訊或摘要)。

/C顯示檔案大小千位數分隔符號。這是預設值。 使用 /-C 來停用分隔符號的顯示。

/D與寬的列表格式相同,但是依照欄來排序。

/L使用小寫顯示。

/N使用新的長列表格式,檔名會顯示在最右方。

/O依照指定的排序順序來列出檔案。
sortorderN 依名稱 (英文字母)
S 依大小 (最小的在前)
E 依副檔名 (英文字母)
D 依照日期與時間 (日期較早的在前)
G 先列出子目錄 - 表示相反的順序

/P當資料填滿整個螢幕時暫停顯示。

/Q顯示檔案擁有者。

/S顯示指定目錄及所有子目錄中的檔案。

/T指定用來顯示或排序的時間欄位
timefieldC 建立
A 上次檔案存取時間
W 上次寫入檔案時間

/W使用寬的列表格式。

/X顯示對非 8.3 格式的檔案產生的短檔名。這個格式和 /N 相同,但是短檔名會插入在長檔名之前。 如果沒有長檔名存在,該處會顯示空白。

/4顯示四位數的年份

參數可能會在 DIRCMD 環境變數預先設定。您可以在任何參數使用連字號字首(-)來覆蓋預先的設定--例如: /-W。


操作範例:

# 列出所有 D:\test 下的檔案與目錄
DIR D:\test /S /B
# print:
# D:\test\001.jpg
# D:\test\002.jpg
# D:\test\003.jpg
# D:\test\pics
# D:\test\pics\001.jpg
# D:\test\pics\002.jpg


# 列出當前目錄下的檔案與目錄,並將結果輸出至 D:\test\dir.txt
DIR /S /B >D:\test\dir.txt

# 將列出的結果加入至 D:\test\dir.txt 檔案後面
DIR /S /B >>D:\test\dir.txt


# 找出 D:\test 下的副檔名為 jpg 的檔案
DIR D:\test /S /B |FIND /I ".jpg"
# print:
# D:\test\001.jpg
# D:\test\002.jpg
# D:\test\003.jpg
# D:\test\pics\001.jpg
# D:\test\pics\002.jpg
2009-04-23

PhotoShop 實用教學-動作與批次處理

在 PhotoShop 中有個很實用的功能,那就是動作紀錄與批次處理,可能你對這個軟體不是很熟悉,但這個功能可以方便你在處理大量圖片,我最喜歡的就是這個功能完全的客製化,只要你會的功能通通都可以錄製個人的批次處理,好處就是只要這套軟體就可以處理很多事。


PhotoShop 實用教學-動作與批次處理
廢話那麼多,我用一個為圖片加上個人標註的範例來說明好了。


PhotoShop 實用教學-動作與批次處理
首先開啟一個圖檔,並點選動作視窗。


PhotoShop 實用教學-動作與批次處理
按下動作視窗中的建立新增動作


PhotoShop 實用教學-動作與批次處理
取一個適合的名稱,以免以後忘記當初做的事。
這裡還可以為此動作設立快捷鍵,在平時編輯圖片上也是蠻方便的。


PhotoShop 實用教學-動作與批次處理
這裡要注意錄製的按鈕是否按下,在一開始都會預設啟動,為了保險起見來是注意一下,以免等一下都白做了。


PhotoShop 實用教學-動作與批次處理
一開始先選取影像尺寸調整圖片的解析度,這也是最重要的事。
因為在不同的解析度下,編輯單位會大大的受影響,免得最後做出來的動作不通用,為了方便通用性,建議先規定圖片的大小跟解析度。


PhotoShop 實用教學-動作與批次處理
這裡建議固定寬度與高度,只調整圖片的解析度至網頁用的 72 dpi


PhotoShop 實用教學-動作與批次處理
為產生上下所需要的高度,選擇調整版面尺寸


PhotoShop 實用教學-動作與批次處理
以相對方式為上下各增加 30 px,這裡的高度就依個人需要而定了,沒有特別限制,最後會為寬高都增加至 40 px。


PhotoShop 實用教學-動作與批次處理
選擇文字工具。


PhotoShop 實用教學-動作與批次處理
這裡要特別注意,文字定位是採用 % 來計算的,盡可能讓文字的 X Y 值壓在最邊界上,為了通用性的考量,我想沒有人願意接受非預期的效果,所以這裡要特別注意。


PhotoShop 實用教學-動作與批次處理
你可以在動作紀錄中發現文字處理上所記錄的事項,這裡很明顯的看到文字的定位單位(%)


PhotoShop 實用教學-動作與批次處理
再來選取版面尺寸增加剩下的高度與寬度。


PhotoShop 實用教學-動作與批次處理
為寬度增加 40 px 及高度 10 px。


PhotoShop 實用教學-動作與批次處理
最後做一的影像平面化


PhotoShop 實用教學-動作與批次處理
最後點選停止紀錄
到這裡動作的錄製就算完成了,你可以嘗試的按下旁邊的播放扭,就可以發覺剛剛錄製的效果了。


PhotoShop 實用教學-動作與批次處理
接下就要將錄製好的動作轉存批次處理的程序檔
在上一個選項批次處理可以快速的將錄製的動作直接使用,但為了讓批次處理可以更方便,也為了讓這個動作可以好好的保存,我建議製作成程序檔,雖然程序檔不可以再改寫及察看。


PhotoShop 實用教學-動作與批次處理
選擇程序檔(.exe)要存放的位置,當然最好還是取一個好一點的名稱,要不然到時候又忘記是做什麼用的,那今天的努力又白費了。


PhotoShop 實用教學-動作與批次處理
選擇剛剛錄製好的動作,當然你也可以選擇其他預設的動作。


PhotoShop 實用教學-動作與批次處理
選擇儲存的方式,這裡我選擇直接覆蓋原始圖片的方式,當然也可以另存至其他目錄。
這裡要記得勾選上面兩個選項,『包括全部的次當案夾』可以讓選取目錄下所有的圖檔,都套用此批次處理,這樣在批次套用上會很方便,『抑制色彩描述警告』如果你不想再批次處理的過程中,一直點選討厭的對話匡的話,最好勾選此選項。


PhotoShop 實用教學-動作與批次處理
你可以利用文件管理,將圖檔或目錄拖放至程序上,接下來就會套用批次處理中動作記錄。


當然也可以使用命令列去執行套用的動作,建議使用目錄當作參數,在處理大量圖片的時候會比較簡短。

E:\>著作權標示.exe E:\photo-test\001.jpg E:\photo-test\002.jpg

E:\>著作權標示.exe E:\photo-test\ss
2009-04-17

利用 switch 該善程式碼的閱讀性

一個簡單的網頁 Script 架構,不外乎一個進入點及一個輸出點,由上到下一個很單純的流程。

在資料驗證上也是一個接一個,但卻數量多的時候,卻會讓整體流程看起來很複雜,很不直覺。

一個基本 switch 的撰寫方法,用在代替有結構的 IF 時還蠻放便的。

<?php
switch ($_GET['type']) {
// 當 $_GET['type']=="apple" 時進入程式片段
case "apple":
//程式片段...
break;

// 當 $_GET['type']=="bar" 時進入程式片段
case "bar":
//程式片段...
break;

// 當以上都不符合,預設進入程式片段
default :
//程式片段...
break;
}
?>


這個例子,將判斷式移到 case 上,讓原本的 switch 更加彈性,但這不是主要目的,在 switch 裡主要的好處是可以利用 break 跳出流程,這樣的用法跟 function 很像,利用跳出的方式結束剩下的程序,在區塊中檢查到錯誤的數入參數時,直接丟出訊息並讓輸出程序去處理顯示的問題。

<?php
switch (true){
case ($_GET['type']=='view'):
//其他判斷或動作...
break;

case ($_GET['action']=='delete'):
//其他判斷或動作...
break;

case ($_GET['action']=='add'):
//標題檢查
$title=trim($_GET['title']);/*去除頭尾空白*/
$title=htmlspecialchars($title,ENT_QUOTES);/*HTML 跳脫*/
$title=mb_substr($title, 0, 100);/*100字剪裁*/
if(!$title){ //利用 if 判斷,錯誤則跳出 switch
// 列出錯誤訊息
break;
}

//訊息檢查
$msg=trim($_GET['msg']);/*去除頭尾空白*/
$msg=htmlspecialchars($msg,ENT_QUOTES);/*HTML 跳脫*/
$msg=mb_substr($msg, 0, 1000);/*1000字剪裁*/
if(!$msg)){ //利用 if 判斷,錯誤則跳出 switch
// 列出錯誤訊息
break;
}

//其他判斷或動作...
break;

default :
// 列出錯誤訊息
break;
}
?>


再看看如果用 IF 去處理輸入驗證時,必須將所有資料先做處理,後面再一個一個去判斷,在閱讀上很不直覺,如果中間有大量的輸入參數要處理時,會讓人找很久。

<?php
if($_GET['type']=='view'){
//其他判斷或動作...

}elseif($_GET['action']=='delete'){
//其他判斷或動作...

}elseif($_GET['action']=='add'){
//標題檢查
$title=trim($_GET['title']);/*去除頭尾空白*/
$title=htmlspecialchars($title,ENT_QUOTES);/*HTML 跳脫*/
$title = mb_substr($title, 0, 100);/*100字剪裁*/

//訊息檢查
$msg=trim($_GET['msg']);/*去除頭尾空白*/
$msg=htmlspecialchars($msg,ENT_QUOTES);/*HTML 跳脫*/
$msg = mb_substr($msg, 0, 1000);/*1000字剪裁*/

if(!$title){
// 列出錯誤訊息
}elseif(!$msg){
// 列出錯誤訊息
}else{
//其他判斷或動作...
}

break;
}else{
// 列出錯誤訊息
}
?>


參考來源:
PHP: switch - Manual
2009-04-16

[Web] Cookie 小觀念的補述

今天看到網站製作學習誌中提到 COOKIE 的問題
引用來源:[Web] Cookie 小觀念

setcookie('test', 'abc');
var_dump($_COOKIE);

如果你回答的是空陣列的話,那就表示你瞭解 Cookie 的作用了。


除了這個問題之外
其實在 COOKIE 簡單的操作上
有一些問題也常常被忽視

在過去的文章中也有提到我遇到的問題
cookie 路徑問題
apache 301 Redirect 永久重新導向

例如:

http://domain.com/
http://www.domain.com/
http://www.domain.com/dir


這三種都是 COOKIE 有可能的儲存路徑
這常常讓 COOKIE 的存取上造成問題
上層路徑的程式無法取得下層路徑的 COOKIE
而下層路徑在 COOKIE 寫入上卻會不小心造成雙份的問題
2009-04-15

寬度(width)不要與其他屬性同時設定[CSS]

這是一個很基礎的 CSS 設計觀念,在設有寬度(width)的 Box 上,別加入 border , padding 及 margin 這三個屬性,這對於維護及變更上有相當的好處。

這下面就是全部都設在同一個 Box 上的例子,雖然所需要的語法很少,但在固定寬度的情況下,當要變更其他一個屬性時,勢必要重新設定寬度的大小,是非常不明智的作法,有嘗到苦果的朋友,想必就會瞭解。
.widget{
    width:200px;
    border:2px solid #000;
    padding:3px;
    margin:5px;
}
<div class="widget">text text</div>


最好的方式就是將寬度的屬性獨立成單一的 Box,其他屬性則設定在內層 Box 上,雖然需要較多的語法,但在未來的修改變動上會比較直覺,除了排版上的設定,其他 Box 盡可能使用相對寬度(%)的設定,在對整體欄寬做調整時會比較快樂。
.widget{
    width:200px;
}
.widget div{
    border:2px solid #000;
    padding:3px;
    margin:5px;
}
<div class="widget">
    <div>text text</div>
</div>
2009-04-14

改寫 dp.SyntaxHighlighter 中 CSS 的 Highlighter 方式

最近掙扎了很久,考慮要不要用 dp.SyntaxHighlighter 來處理 Blog 中程式碼的 Highlighter,因為之前用的 Iris Syntax Highlighter 已經收起來了,而且在文章撰寫上十分不方便也不直覺,所以花了一點心思改成 dp.SyntaxHighlighter 的模式,但 1.5.1 版還蠻陽春的,花了一點時間做語法增強及檔案瘦身,希望這個套件可以用久一點。

原本 dp.SyntaxHighlighter 中 CSS 的 Highlighter 是用 keyword 的方式去處理的,未定義的 keyword 將不會有 Highlighter,為了得到更好的效果,又必須增加更多的 keyword,實在是很不划算。

所以我改用解析 Syntax 結構的方式去處理 Highlighter 的動作,雖然還不是很完整,但整體的效果比原生好多了。


/**=[ CSS ]===========================================*/
dp.sh.Brushes.CSS = function(){
// 樣式定義
this.CssClass = 'dp-css';
this.Style = '.dp-css .value{color:blue;}' +
'.dp-css .important{color:red;font-weight:bold;}'+
'.dp-css .keyword{color:#7F0055;font-weight:bold;}'+
'.dp-css .func{color:#F55;font-weight:normal;}';
};

dp.sh.Brushes.CSS.prototype = new dp.sh.Highlighter();
dp.sh.Brushes.CSS.Aliases = ['css'];

dp.sh.Brushes.CSS.prototype.ProcessRegexList = function(){
function push(array, value){
array[array.length] = value;
}
var match1,match2,regex1,regex2;

/* 加入註解解析 */
this.GetMatches(dp.sh.RegexLib.MultiLineCComments, 'comments');
/* 加入 !important 解析 */
this.GetMatches(new RegExp('!important', 'g'),'important');

/* 解析屬性區塊 */
// 匹配 '{' 至 '}' 之間的文字
regex1 = new RegExp('\{[^}]+\}', 'gm');
// 匹配 'xxx:xxx[;\n\(!]' 格式的文字
regex2 = new RegExp('([:\\w-\.]+)\\s*:\\s*([^;\n\(!]+)[;\n\(!]', 'gm');
while((match1 = regex1.exec(this.code))){
while((match2 = regex2.exec(match1[0]))){
if(!match2[1]){continue;}
// 匹配屬性名稱
push(this.matches, new dp.sh.Match(
match2[1],
match1.index+match2.index,
'func'
));

// 匹配屬性值
if(match2[2]){
push(this.matches,new dp.sh.Match(
match2[2],
match1.index+match2.index+match2[0].indexOf(match2[2]),
'value'
));
}
}
}

/* 解析選擇器區塊 */
// 匹配 'xxx[,\{\n]' 格式的文字
regex1 = new RegExp('^([\\s\\w\.#*:+-]+)[,\{\n]', 'gm');
while((match1 = regex1.exec(this.code))){
if(!match1[1]){continue;}
push(this.matches, new dp.sh.Match(
match1[1],
match1.index,
'keyword'
));
}
};


效果可察看之前的文章:
IE6 對 visibility 負荷過大的問題[CSS]
IE6 中的最大最小寬度和高度
CSS fixed 定位( FF / IE6 )
利用 !important 修正 IE 與 Firefox 的差異
2009-04-13

網頁常用編碼轉換 (iGoogle)小工具

將一些 JavaScript 中常用的 escape, unescapek, encodeURI, decodeURI, encodeURIComponent, decodeURIComponent 及 HTML 跳脫與反跳脫製作成小工具。

IE6 對 visibility 負荷過大的問題[CSS]

IE6 在對大量元件做 visibility 顯示及隱藏
會有負荷量過大的問題出現讓整個瀏覽器變慢
解決的辦法就是用 filter 去代替相同的效果
就會得到很明顯的改善

.Action{
visibility:hidden;
_visibility:visible;/* for IE6 */
_filter:alpha(opacity=0);/* for IE6 */
}

.Action:hover{
visibility:visible;
_filter:alpha(opacity=100);/* for IE6 */
}
2009-04-10

IE6 在負邊界( margin )上的異常問題[CSS]

當負邊界( margin )加上 float 屬性時
在 IE6 上會出現詭異的邏輯問題
設定的數值會乘於二
也就是 margin:-100px; 會變成 margin:-200px;
解決這個問題只好做特別做修正設定


HTML 與 CSS 設定:

.widget{
padding-left:35px;
}
.widget .image{
width:30px;
float:left;
margin-left:-30px;
_margin-left:-15px;/*for IE6*/
}

<div class="widget">
<div class="image"><img /></div>
<div>text text</div>
</div>
2009-04-09

[PHP] 解析 URL 字串 parse_url , parse_str

parse_url 會解析一個標準的 URL 字串


<?php
$urlStr="http://user:passwd@host:80/path?a1=v1&a2=v2#anchor";
$url=parse_url($urlStr);
print_r($url);
/* output:
Array
(
[scheme] => http
[host] => host
[port] => 80
[user] => user
[pass] => passwd
[path] => /path
[query] => a1=v1&a2=v2
[fragment] => anchor
)
*/

echo parse_url($url, PHP_URL_SCHEME);
// prints: http

echo parse_url($url, PHP_URL_HOST);
// prints: host

echo parse_url($url, PHP_URL_PORT);
// prints: 80

echo parse_url($url, PHP_URL_USER);
// prints: user

echo parse_url($url, PHP_URL_PASS);
// prints: passwd

echo parse_url($url, PHP_URL_PATH);
// prints: /path

echo parse_url($url, PHP_URL_QUERY);
// prints: a1=v1&a2=v2

echo parse_url($url, PHP_URL_FRAGMENT);
// prints: anchor

?>



parse_str 會解析 URL Query 格式的字串
這裡特別注意,別使用下面的第一種方式直接解析 URL 上的 query
這會造成資安上的漏洞,這會讓外部可以直接修改裡面的變數值

<?php
$url_query = "city=new+york&id=3456&paid%5Bcurrency%5D=euro&paid%5Bamount%5D=345&paid%5Breceipt%5D=fgf"
parse_str($url_query);

echo $city;
// prints: new york

echo $id;
// prints: 3456

print_r($paid);
/* output:
Array
(
[currency] => euro
[amount] => 345
[receipt] => fgf
)
*/

/* 不建議上面的作法,因為會複寫原本的變數
* 造成資安上的漏洞
* */

parse_str($url_query, $query);
print_r($query);
/* output :
Array
(
[city] => new york
[id] => 3456
[paid] => Array
(
[currency] => euro
[amount] => 345
[receipt] => fgf
)

)*/
?>


參考來源:
Easy way to build GET query strings in php
2009-04-08

HTML 中 Flash 遮蓋問題的解決方法

flash 在頁面中會顯示在最上層
想要用其他元素覆蓋在上面時
必須做以一下參數設定
但不管有沒有元素覆蓋
最好還是加入這個參數
避免意料之外的版面問題
<object ... >
    <param name="wmode" value="transparent"/>
    <!-- ... -->
    <embed wmode="transparent" ... />
</object>


wmode 的參數值:
  • Window
  • Opaque
  • Transparent


參考來源:
【求助】关于下拉菜单被FLASH遮盖,怎样解决
wmode 三選一