寫一下目前查資料之後的結果
當然實際的驗證及比較要先等一段時間後,有空再去把這些都學完
目前較常拿來做比較的跨資料庫抽象層應用大致上有MDB2、ADOdb、PDO三種
MDB2的優點在於pear的套件取得上較為容易,開發較不會有客戶端缺少開發環境的問題
當然套件的相依性會是比較麻煩的議題
資料庫處理速度不錯,算是各方面都有中上表現的選擇
詳情可以看MDB2筆記
ADOdb以微軟的ADO為基底所製作,很多習慣使用ASP的使用者會比較喜歡ADOdb
它有蠻多強大的功能,卻也因為過於龐大讓資料庫處理速度慢的缺點浮現
官方網站有提供Lite版本,大小大約是原本的1/6
不過因為缺少許多強大的ADOdb功能,如果原先有使用那些功能的話還要改變程式的寫法
官方網站:http://adodb.sourceforge.net/
熱心人士翻譯的手冊:http://www.php5.idv.tw/documents/ADODB/
PDO是PHP5以後新增加的功能,也會是以後PHP6預設的資料庫處理方式
資料庫處理的速度會是目前PHP選擇中最快的
因為PHP5.3後物件導向方面的變化不小,學習及使用上要更加注意
2010年7月10日 星期六
2010年7月8日 星期四
MDB2使用筆記(2)
上篇介紹了如何建立資料庫的連線
接著來說說MDB2的query部分,總共有query()和exec()兩種
成功會回傳結果,失敗則都會回 傳MDB2_Error訊息
差別在於query()是執行sql指令並取得值
exec()則是單純的執行指令,適用於 INSERT、UPDATE或DELETE
query()範例:
// Proceed with a query
$res = $mdb2->query('SELECT * FROM clients');
// Always check that result is not an error
if (PEAR::isError($res)) {
die($res->getMessage());
}
exec() 範例:
$sql = "INSERT INTO clients (name, address) VALUES ($name, $address)";
$affected = $mdb2->exec($sql);
// Always check that result is not an error
if (PEAR::isError($affected)) {
die($affected->getMessage());
}
另 外在查詢時一樣可以設定查詢的範圍及起點
$sql = "SELECT * FROM clients";
$mdb2->setLimit(20, 10); //回傳20筆資料,從第10筆資料後開始算起
$affected =& $mdb2->exec($sql);
$sql = "DELETE FROM clients";
if ($mdb2->supports('limit_queries') === 'emulated') {
echo 'offset will likely be ignored'
}
// only delete 10 rows
$mdb2->setLimit(10);
$affected =& $mdb2->exec($sql);
查詢時可以使用quote()提高資料存取的安全性, 例如:
$query = 'INSERT INTO sometable (textfield1, boolfield2, datefield3) VALUES ('
.$mdb2->quote($val1, "text", true).', '
.$mdb2->quote($val2, "boolean", false).', '
.$mdb2->quote($val3, "date", true).')';
quote() 函式只有第一個參數-值是需要的,後面的三個參數則是視需求使用
第二個參數是值的類別,可以排除設定類別外的值
允許使用的有text, boolean, integer, decimal, float, time stamp, date, time, clob, blob
第三個參數是是否使用quote(),即用引號包住值,false的話則只是單純的將值輸出
第四個參數則是使否要脫離萬用字元
善用quote()可以增加安全性
針對query出來的結果也可以調整表現的方式,例如:
$mdb2->setFetchMode(MDB2_FETCHMODE_ASSOC);
setFetchMode() 有三種屬性
MDB2_FETCHMODE_ORDERED(例:$result[0])
MDB2_FETCHMODE_ASSOC(例:$result['name'])
MDB2_FETCHMODE_OBJECT(例:$result->name)
取得結果之後,接著就是要用函式來取出值
fetchOne(), fetchRow(), fetchCol() and fetchAll()這四個函式看起來就很容易懂
分別是取一個,取一行,取一列,取所有
此外 numRows(), numCols(), rowCount()等函式也可以獲取結果的其他資訊
除了以上處理過程外,也有函式可以幫助簡化撰寫,直接取得結果
就是queryOne(), queryRow(), queryCol() and queryAll()這四個對應的函式
以範例作比較,使用query():
$res = $mdb2->query("select ID,name,birthday from member");
while ($data = $res->fetchRow()) {
echo $data['ID'].','.$data['name'].','.$data['birthday'];
}
queryOne():
$res = $mdb2->queryOne("select count(*) from member");
if (!is_null($res)) echo $res;
queryRow():
$res = $mdb2->queryRow("select name,birthday from member where ID = 1");
if (!is_null($res)) echo $res['name'].','.$dbquery['birthday'];
依此類推,依需求選擇使用的函式
MDB2尚有預編譯及批量處理Prepare & Execute、moudle等好用功能沒提到
等之後有用到再去查技術手冊了
接著來說說MDB2的query部分,總共有query()和exec()兩種
成功會回傳結果,失敗則都會回 傳MDB2_Error訊息
差別在於query()是執行sql指令並取得值
exec()則是單純的執行指令,適用於 INSERT、UPDATE或DELETE
query()範例:
// Proceed with a query
$res = $mdb2->query('SELECT * FROM clients');
// Always check that result is not an error
if (PEAR::isError($res)) {
die($res->getMessage());
}
exec() 範例:
$sql = "INSERT INTO clients (name, address) VALUES ($name, $address)";
$affected = $mdb2->exec($sql);
// Always check that result is not an error
if (PEAR::isError($affected)) {
die($affected->getMessage());
}
另 外在查詢時一樣可以設定查詢的範圍及起點
$sql = "SELECT * FROM clients";
$mdb2->setLimit(20, 10); //回傳20筆資料,從第10筆資料後開始算起
$affected =& $mdb2->exec($sql);
$sql = "DELETE FROM clients";
if ($mdb2->supports('limit_queries') === 'emulated') {
echo 'offset will likely be ignored'
}
// only delete 10 rows
$mdb2->setLimit(10);
$affected =& $mdb2->exec($sql);
查詢時可以使用quote()提高資料存取的安全性, 例如:
$query = 'INSERT INTO sometable (textfield1, boolfield2, datefield3) VALUES ('
.$mdb2->quote($val1, "text", true).', '
.$mdb2->quote($val2, "boolean", false).', '
.$mdb2->quote($val3, "date", true).')';
quote() 函式只有第一個參數-值是需要的,後面的三個參數則是視需求使用
第二個參數是值的類別,可以排除設定類別外的值
允許使用的有text, boolean, integer, decimal, float, time stamp, date, time, clob, blob
第三個參數是是否使用quote(),即用引號包住值,false的話則只是單純的將值輸出
第四個參數則是使否要脫離萬用字元
善用quote()可以增加安全性
針對query出來的結果也可以調整表現的方式,例如:
$mdb2->setFetchMode(MDB2_FETCHMODE_ASSOC);
setFetchMode() 有三種屬性
MDB2_FETCHMODE_ORDERED(例:$result[0])
MDB2_FETCHMODE_ASSOC(例:$result['name'])
MDB2_FETCHMODE_OBJECT(例:$result->name)
取得結果之後,接著就是要用函式來取出值
fetchOne(), fetchRow(), fetchCol() and fetchAll()這四個函式看起來就很容易懂
分別是取一個,取一行,取一列,取所有
此外 numRows(), numCols(), rowCount()等函式也可以獲取結果的其他資訊
除了以上處理過程外,也有函式可以幫助簡化撰寫,直接取得結果
就是queryOne(), queryRow(), queryCol() and queryAll()這四個對應的函式
以範例作比較,使用query():
$res = $mdb2->query("select ID,name,birthday from member");
while ($data = $res->fetchRow()) {
echo $data['ID'].','.$data['name'].','.$data['birthday'];
}
queryOne():
$res = $mdb2->queryOne("select count(*) from member");
if (!is_null($res)) echo $res;
queryRow():
$res = $mdb2->queryRow("select name,birthday from member where ID = 1");
if (!is_null($res)) echo $res['name'].','.$dbquery['birthday'];
依此類推,依需求選擇使用的函式
MDB2尚有預編譯及批量處理Prepare & Execute、moudle等好用功能沒提到
等之後有用到再去查技術手冊了
MDB2使用筆記(1)
來自官方的說明:
PEAR MDB2 is a merge of the PEAR DB and Metabase php database abstraction layers.
It provides a common API for all supported RDBMS. The main difference to most other DB abstraction packages is that MDB2 goes much further to ensure portability.
MDB2整合了過去的 PEAR:db函式的新類別庫,為目前PEAR官方所支持
其有許多選擇性的功能,可以增加對各種資料庫系統間資料的可攜性
很適合作為跨資料庫的選擇
MDB2的安裝可以使用套件管理員來進行,詳情可以參考PEAR安裝教學那篇
或者是到PEAR套件官網下載,下載時要連同所連結的資料庫的驅動一起下載
以下簡介使用方式,詳細解說可以到官方說明手冊看
首先來個修改自官網的範例:
<?php
require_once 'MDB2.php';
$dsn = array(
'phptype' => 'mysqli', //輸入所要連結的資料庫類別
'username' => 'user',
'password' => 'pw',
'hostspec' => 'localhost',
'database' => 'DBname',
'charset' => 'utf8',
);
$options = array(
'debug' => 2, //numeric debug level
'portability' => MDB2_PORTABILITY_ALL,
);
$mdb2 =& MDB2::connect($dsn, $options);
if (PEAR::isError($mdb2)) {
die($mdb2->getMessage(). ', ' . $mdb2->getDebugInfo() );
}
$mdb2->disconnect();
?>
首先要使用PEAR的套件都必須先將使用的檔案include
dsn是Data Source Name,用來記錄資料庫資訊
另外,也可以寫成 $dsn = 'mysqli://user:pw@localhost/DBname';
options當然就是額外的附屬要求
需要一提的是portability選項
除非設置成了MDB2_PORTABILITY_NONE,否則query出來的結果都是小寫
例如結果不可能會有 echo $array['A'];
官方的預設是小寫,目的是要達到各種資料庫的相容性,當然這也是MDB2的原則
資料庫的連結方式有三種
&MDB2::connect 建立MDB2物件並連線資料庫
&MDB2::factory 建立MDB2物件,但等到要進行資料庫操作時才連線
&MDB2::singleton 同factory,但它保證只有一個MDB2物件連線到資料庫
想用哪個就用哪個,一般使用下應是factory效率較高
最後用disconnect()來結束連線
連線與結束連線可以以global variable的方式寫成function來增加使用的方便性
可以參考這篇文章
官網那邊尚有使用SSL來建立連線的範例,如下:
<?php
require_once 'MDB2.php';
$dsn = array(
'phptype' => 'mysqli',
'username' => 'someuser',
'password' => 'apasswd',
'hostspec' => 'localhost',
'database' => 'thedb',
'key' => 'client-key.pem',
'cert' => 'client-cert.pem',
'ca' => 'cacert.pem',
'capath' => '/path/to/ca/dir',
'cipher' => 'AES',
);
$options = array(
'ssl' => true,
);
// gets an existing instance with the same DSN
// otherwise create a new instance using MDB2::factory()
$mdb2 =& MDB2::singleton($dsn, $options);
if (PEAR::isError($mdb2)) {
die($mdb2->getMessage());
}
?>
PEAR MDB2 is a merge of the PEAR DB and Metabase php database abstraction layers.
It provides a common API for all supported RDBMS. The main difference to most other DB abstraction packages is that MDB2 goes much further to ensure portability.
MDB2整合了過去的 PEAR:db函式的新類別庫,為目前PEAR官方所支持
其有許多選擇性的功能,可以增加對各種資料庫系統間資料的可攜性
很適合作為跨資料庫的選擇
MDB2的安裝可以使用套件管理員來進行,詳情可以參考PEAR安裝教學那篇
或者是到PEAR套件官網下載,下載時要連同所連結的資料庫的驅動一起下載
以下簡介使用方式,詳細解說可以到官方說明手冊看
首先來個修改自官網的範例:
<?php
require_once 'MDB2.php';
$dsn = array(
'phptype' => 'mysqli', //輸入所要連結的資料庫類別
'username' => 'user',
'password' => 'pw',
'hostspec' => 'localhost',
'database' => 'DBname',
'charset' => 'utf8',
);
$options = array(
'debug' => 2, //numeric debug level
'portability' => MDB2_PORTABILITY_ALL,
);
$mdb2 =& MDB2::connect($dsn, $options);
if (PEAR::isError($mdb2)) {
die($mdb2->getMessage(). ', ' . $mdb2->getDebugInfo() );
}
$mdb2->disconnect();
?>
首先要使用PEAR的套件都必須先將使用的檔案include
dsn是Data Source Name,用來記錄資料庫資訊
另外,也可以寫成 $dsn = 'mysqli://user:pw@localhost/DBname';
options當然就是額外的附屬要求
需要一提的是portability選項
除非設置成了MDB2_PORTABILITY_NONE,否則query出來的結果都是小寫
例如結果不可能會有 echo $array['A'];
官方的預設是小寫,目的是要達到各種資料庫的相容性,當然這也是MDB2的原則
資料庫的連結方式有三種
&MDB2::connect 建立MDB2物件並連線資料庫
&MDB2::factory 建立MDB2物件,但等到要進行資料庫操作時才連線
&MDB2::singleton 同factory,但它保證只有一個MDB2物件連線到資料庫
想用哪個就用哪個,一般使用下應是factory效率較高
最後用disconnect()來結束連線
連線與結束連線可以以global variable的方式寫成function來增加使用的方便性
可以參考這篇文章
官網那邊尚有使用SSL來建立連線的範例,如下:
<?php
require_once 'MDB2.php';
$dsn = array(
'phptype' => 'mysqli',
'username' => 'someuser',
'password' => 'apasswd',
'hostspec' => 'localhost',
'database' => 'thedb',
'key' => 'client-key.pem',
'cert' => 'client-cert.pem',
'ca' => 'cacert.pem',
'capath' => '/path/to/ca/dir',
'cipher' => 'AES',
);
$options = array(
'ssl' => true,
);
// gets an existing instance with the same DSN
// otherwise create a new instance using MDB2::factory()
$mdb2 =& MDB2::singleton($dsn, $options);
if (PEAR::isError($mdb2)) {
die($mdb2->getMessage());
}
?>
PHP特殊符號
PHP除了一般運算時常見的符號以外,另外還有些符號較特殊
$ 變數宣告符號
& 變數指標(加在變數前)
@ 不顯示錯誤訊息(加在函數前)
-> 物件的方法或者屬性
=> 陣列的元素值
? : 三元運算子
$ 變數宣告符號
& 變數指標(加在變數前)
@ 不顯示錯誤訊息(加在函數前)
-> 物件的方法或者屬性
=> 陣列的元素值
? : 三元運算子
2010年6月12日 星期六
PEAR安裝
PEAR(PHP Extension and Application Repository)是PHP延伸及應用程式容器
裡面有許多PHP類別,可以提供SOAP服務
PHP4.3.0以後的版本會預設安裝PEAR套件管理工具
它有兩種安裝方式,以下分別說明
1.透過套件管理工具來執行安裝
這個感覺上也是最簡單的方式 ,不用調什麼設定
需要注意的是這個模式的安裝大多需要系統管理者的權限來執行
安裝完PHP後可以在資料夾下找到go-pear.bat檔案
點擊它然後一直按Enter就可以了
當然也可以在cmd模式下執行這個檔案安裝
接著打開CMD 視窗,一些關於PEAR的指令可以輸入
輸入"pear"可以列出所有指令的清單
執行"pear list"可以檢視所安裝的套件
想安裝套件可以執行"pear install" 套件名稱
例如輸入"pear install MDB2",這樣就會安裝 PEAR::MDB2 了
順帶一提的是使用MDB2還要以"pear install pear/MDB2#"安裝對主機上的資料庫的driver
例如現在主機上的資料庫系統是MySQL
則需執行"pear install pear/MDB2#mysql"、"pear install pear/MDB2#mysqli"
其他可以考慮安裝的套件有
"HTTP"、"Mail"、"Mail_mime"、"Net_SMTP"、"XML_Parser"、"XML_RPC2"等
有些套件會一併安裝或是需要其他的套件先安裝才能使用
假使有回傳Dependencies failed,install指令要加入"-a"旗標
例如"pear install -a XML_Beautifier"
這樣就能夠一併安裝所需要的套件
套件安裝完後得重新啟動Apache才能使用
如果要使用圖形介面來管理pear
有個套件PEAR_Frontend_Web可以使用
安裝之前還要先裝好"Net_UserAgent_Detect"、"Pager"兩個套件
不過在這份備忘錄撰寫的時候只有beta版
所以安裝的指令會是"pear install PEAR_Frontend_Web-beta"
安裝完後到PEAR資料夾底下(預設是php目錄下)找到 pearfrontendweb.php
複製到想放置的Apache目錄下並改成想用的名稱,之後就可以用這個圖形頁面作pear管理了
這篇文章的後半段有對這個套件做更詳細的說明
安裝完後記得執行"pear upgrade-all"
它可以對目前的套件進行自動更新
想要移除套件時執行"pear uninstall 套件名稱"
若套件之間有相互依賴性時會在移除時回報錯誤訊息
在uninstall指令後加入"-n"旗標可以強制移除
2.到 http://pear.php.net/go-pear 網頁進行安裝
進入網頁後,將頁面上所有內容複製另存為go-pear.php,放在Apache網頁目錄裡
接著以網頁方式開啟他,例如 http://localhost/go-pear.php
點選NEXT>>後調整參數安裝
Installation prefix
安裝PEAR的根目錄,有些選項裡的$prefix就是指這個位置
其他選項我不敢亂動太多
記得要在php.ini裡加入你選擇安裝pear的位置
例如:
;***** Added by go-pear
include_path=".;C:\AppServ\php5\pear"
;*****
安裝完成後注意頁面下方會出現 Start Web Frontend of the PEAR Installer >>
點擊它會會連到 PEAR_Frontend_Web 所建立的管理頁面
雖然測試時產生的連結會多一個 "\" 符號,刪除後繼續連結即可
推薦的方法還是第一種較好
go-pear在目錄設定時容易產生紊亂
假使需要圖形介面作管理再同介紹裡一般下載套件使用即可
補充一下,登入PEAR_Frontend_Web的頁面時會出現一個警告,訊息如下:
This package management website is not protected with a password, ...
必須要建立.htaccess檔案增加安全性,才會解除警告
在Linux底下要建立.htaccess似乎沒什麼限制
不過在windows底下要建立檔案則必須使用一點手法
首先到Apache資料夾下的conf打開httpd.conf
找到 AllowOverride None 這行後改成 AllowOverride All
接著我們要增加兩個檔案來做到保護效果
首先在放置PEAR_Frontend_Web管理頁面的資料夾底下新增文字檔案
命名為.htaccess,存檔類型改成所有檔案
內容打上
AuthUserFile XXX/.htpasswd #.htpasswd存放路徑
AuthType Basic
AuthName "Web-based PEAR Frontend"
Require valid-user
設定完成之後在讀取此目錄時會要求輸入帳號、密碼
接著來製作.htpasswd
可以的選擇的做法有二
一是到http://www.htaccesstools.com/htpasswd-generator/ 進行製作
將做出來的文字貼到.htpasswd即可
另一種做法是用cmd開啟Apache/bin底下的htpasswd,輸入指令:
C:\...>cd \AppServ\Apache2.2\bin
htpasswd -c -m .htpasswd admin
-c是建檔 -m是以md5去加密 下一個參數是檔名 接著是帳號
設定完之後會在bin資料夾底下找到一個.htpasswd檔案
.htpasswd放置的位置放在安全的位置即可
如此就完成了
另外,如果要在虛擬主機上使用pear則有別的處理方式
1.到官網下載pear程式
2.解壓縮後將上傳PEAR目錄到想放的目錄下
3.再上傳PEAR.php & PEAR5.php到相同的目錄下
4.要使用套件時一樣式下載套件後直接上傳到任意位置,使用時依照範例使用相對路徑
5..在撰寫php程式時加入宣告
範例:
<?php
//設定PEAR安裝的絕對路徑
ini_set("include_path", "路徑".
PATH_SEPARATOR.ini_get("include_path"));
//設定要使用的pear函式及相對路徑
require_once "Text/Password.php";
//輸出範例,產生10碼隨機亂數英文
echo Text_Password::create(10,'Pronounceable');
?>
裡面有許多PHP類別,可以提供SOAP服務
PHP4.3.0以後的版本會預設安裝PEAR套件管理工具
它有兩種安裝方式,以下分別說明
1.透過套件管理工具來執行安裝
這個感覺上也是最簡單的方式 ,不用調什麼設定
需要注意的是這個模式的安裝大多需要系統管理者的權限來執行
安裝完PHP後可以在資料夾下找到go-pear.bat檔案
點擊它然後一直按Enter就可以了
當然也可以在cmd模式下執行這個檔案安裝
裝好PEAR後,會在PHP安裝目錄底下會看到 pear.bat
把PHP安裝目錄加到 PATH 系統變數裡,例如:C:\AppServ\php5; 接著打開CMD 視窗,一些關於PEAR的指令可以輸入
輸入"pear"可以列出所有指令的清單
執行"pear list"可以檢視所安裝的套件
想安裝套件可以執行"pear install" 套件名稱
例如輸入"pear install MDB2",這樣就會安裝 PEAR::MDB2 了
順帶一提的是使用MDB2還要以"pear install pear/MDB2#"安裝對主機上的資料庫的driver
例如現在主機上的資料庫系統是MySQL
則需執行"pear install pear/MDB2#mysql"、"pear install pear/MDB2#mysqli"
其他可以考慮安裝的套件有
"HTTP"、"Mail"、"Mail_mime"、"Net_SMTP"、"XML_Parser"、"XML_RPC2"等
有些套件會一併安裝或是需要其他的套件先安裝才能使用
假使有回傳Dependencies failed,install指令要加入"-a"旗標
例如"pear install -a XML_Beautifier"
這樣就能夠一併安裝所需要的套件
套件安裝完後得重新啟動Apache才能使用
如果要使用圖形介面來管理pear
有個套件PEAR_Frontend_Web可以使用
安裝之前還要先裝好"Net_UserAgent_Detect"、"Pager"兩個套件
不過在這份備忘錄撰寫的時候只有beta版
所以安裝的指令會是"pear install PEAR_Frontend_Web-beta"
安裝完後到PEAR資料夾底下(預設是php目錄下)找到 pearfrontendweb.php
複製到想放置的Apache目錄下並改成想用的名稱,之後就可以用這個圖形頁面作pear管理了
這篇文章的後半段有對這個套件做更詳細的說明
安裝完後記得執行"pear upgrade-all"
它可以對目前的套件進行自動更新
想要移除套件時執行"pear uninstall 套件名稱"
若套件之間有相互依賴性時會在移除時回報錯誤訊息
在uninstall指令後加入"-n"旗標可以強制移除
2.到 http://pear.php.net/go-pear 網頁進行安裝
進入網頁後,將頁面上所有內容複製另存為go-pear.php,放在Apache網頁目錄裡
接著以網頁方式開啟他,例如 http://localhost/go-pear.php
點選NEXT>>後調整參數安裝
Installation prefix
安裝PEAR的根目錄,有些選項裡的$prefix就是指這個位置
其他選項我不敢亂動太多
記得要在php.ini裡加入你選擇安裝pear的位置
例如:
;***** Added by go-pear
include_path=".;C:\AppServ\php5\pear"
;*****
安裝完成後注意頁面下方會出現 Start Web Frontend of the PEAR Installer >>
點擊它會會連到 PEAR_Frontend_Web 所建立的管理頁面
雖然測試時產生的連結會多一個 "\" 符號,刪除後繼續連結即可
推薦的方法還是第一種較好
go-pear在目錄設定時容易產生紊亂
假使需要圖形介面作管理再同介紹裡一般下載套件使用即可
補充一下,登入PEAR_Frontend_Web的頁面時會出現一個警告,訊息如下:
This package management website is not protected with a password, ...
必須要建立.htaccess檔案增加安全性,才會解除警告
在Linux底下要建立.htaccess似乎沒什麼限制
不過在windows底下要建立檔案則必須使用一點手法
首先到Apache資料夾下的conf打開httpd.conf
找到 AllowOverride None 這行後改成 AllowOverride All
接著我們要增加兩個檔案來做到保護效果
首先在放置PEAR_Frontend_Web管理頁面的資料夾底下新增文字檔案
命名為.htaccess,存檔類型改成所有檔案
內容打上
AuthUserFile XXX/.htpasswd #.htpasswd存放路徑
AuthType Basic
AuthName "Web-based PEAR Frontend"
Require valid-user
設定完成之後在讀取此目錄時會要求輸入帳號、密碼
接著來製作.htpasswd
可以的選擇的做法有二
一是到http://www.htaccesstools.com/htpasswd-generator/ 進行製作
將做出來的文字貼到.htpasswd即可
另一種做法是用cmd開啟Apache/bin底下的htpasswd,輸入指令:
C:\...>cd \AppServ\Apache2.2\bin
htpasswd -c -m .htpasswd admin
-c是建檔 -m是以md5去加密 下一個參數是檔名 接著是帳號
設定完之後會在bin資料夾底下找到一個.htpasswd檔案
.htpasswd放置的位置放在安全的位置即可
如此就完成了
另外,如果要在虛擬主機上使用pear則有別的處理方式
1.到官網下載pear程式
2.解壓縮後將上傳PEAR目錄到想放的目錄下
3.再上傳PEAR.php & PEAR5.php到相同的目錄下
4.要使用套件時一樣式下載套件後直接上傳到任意位置,使用時依照範例使用相對路徑
5..在撰寫php程式時加入宣告
範例:
<?php
//設定PEAR安裝的絕對路徑
ini_set("include_path", "路徑".
PATH_SEPARATOR.ini_get("include_path"));
//設定要使用的pear函式及相對路徑
require_once "Text/Password.php";
//輸出範例,產生10碼隨機亂數英文
echo Text_Password::create(10,'Pronounceable');
?>
2010年6月11日 星期五
出現找不到php_mbstring.dll的處理方式
因為很多模組套件的安裝或是調整都會牽扯到這個dll檔
記錄一下處理方式
1.開啟php.ini
2.將裡面的 extension=php_exif.dll 剪貼在 php_mbstring.dll 之後
完成
記錄一下處理方式
1.開啟php.ini
2.將裡面的 extension=php_exif.dll 剪貼在 php_mbstring.dll 之後
完成
2010年6月3日 星期四
phpMyAdmin裡設定foreign key
在phpMyAdmin裡面也是可以用foreign key的
1.先對MySQL設定作調整 ,my.ini裡的skip-innodb用#註解掉,這樣phpMyAdmin就可以使用InnoDB引擎了。註解完後要重新開啟MySQL。
2.進入資料表裡,選取管理選項,會在左下的資料表選項裡找到儲存引擎,改為InnoDB
3.使用關聯選項時要先記得替想參考的key設定index值,這樣才可以連到其他的key
4.選取資料表的結構選項,這時候會發現一個原本沒有的關聯檢視選項,點選它吧
5.修改想調整的key,選項設成CASCADE就調整完了
有設定foreign key的部分在修改刪除時會有影響,謹記並慎用
1.先對MySQL設定作調整 ,my.ini裡的skip-innodb用#註解掉,這樣phpMyAdmin就可以使用InnoDB引擎了。註解完後要重新開啟MySQL。
2.進入資料表裡,選取管理選項,會在左下的資料表選項裡找到儲存引擎,改為InnoDB
3.使用關聯選項時要先記得替想參考的key設定index值,這樣才可以連到其他的key
4.選取資料表的結構選項,這時候會發現一個原本沒有的關聯檢視選項,點選它吧
5.修改想調整的key,選項設成CASCADE就調整完了
有設定foreign key的部分在修改刪除時會有影響,謹記並慎用
2010年5月31日 星期一
PHP實作安全機制(3)
php.ini裡儲存了關於php設定的資訊
有些設定可以考慮做些改變
另外這篇文章也會提到避免網站受到script攻擊
用文字編輯器打開php.ini
safe_mode
假如設定成on,會使得php網頁不能夠被相同伺服器上其他使用者的php網頁呼叫
open_basedir = directory[:...]
限制了PHP對目錄的存取能力,也影響了他能夠執行的檔案
display_errors
假如網站錯誤而不想讓網站參觀者知道,把這選項設定成off
log_errors
將錯誤送到錯誤記錄,是個檢查錯誤的好地方
如果display_errors設定成off,這個選項設定成on
可以讓自己知道問題原因而不會洩露給網站參觀者
error_log
這裡會儲存錯誤記錄的存放位置, log_errors設定成on時可以關注這個選項
script攻擊是應用injection attack
將script碼輸入到沒有防範的填寫格中
可以做到重新導引瀏覽器到別的網站,例如類似的假網站來盜取資料
又或者是盜取cookie等手法
防範的手法包括盡量做驗證或者是使用PHP函式
PHP函式中的strip_tags()可以幫助去除script攻擊
另外,以正規表示法防範不該出現的字元或符號也是一種方法
有些設定可以考慮做些改變
另外這篇文章也會提到避免網站受到script攻擊
用文字編輯器打開php.ini
safe_mode
假如設定成on,會使得php網頁不能夠被相同伺服器上其他使用者的php網頁呼叫
open_basedir = directory[:...]
限制了PHP對目錄的存取能力,也影響了他能夠執行的檔案
display_errors
假如網站錯誤而不想讓網站參觀者知道,把這選項設定成off
log_errors
將錯誤送到錯誤記錄,是個檢查錯誤的好地方
如果display_errors設定成off,這個選項設定成on
可以讓自己知道問題原因而不會洩露給網站參觀者
error_log
這裡會儲存錯誤記錄的存放位置, log_errors設定成on時可以關注這個選項
script攻擊是應用injection attack
將script碼輸入到沒有防範的填寫格中
可以做到重新導引瀏覽器到別的網站,例如類似的假網站來盜取資料
又或者是盜取cookie等手法
防範的手法包括盡量做驗證或者是使用PHP函式
PHP函式中的strip_tags()可以幫助去除script攻擊
另外,以正規表示法防範不該出現的字元或符號也是一種方法
PHP筆記(4)
這篇會提到
1.xml相關處理
2.錯誤與例外處理
3.善用print_r()函式
1.xml相關處理
範例:
$xml = simplexml_load_file($URL);
$entry = $xml->entry;
$attrs = $xml->entry->video->duration->attributes();
$media = $entry->children($URL);
使用simplexml_load_file()可以簡單取得XML的資訊
使用時加入XML提供方的link當參數即可
存取XML資料時會以階層性質來使用,指定標籤名稱可存取階層資訊
->符號以物件形式來看,會是從xml物件裡面取得子元素
然後利用 attributes()取得資訊
第三個程式碼擷取duration標籤,並用attributes()以陣列形式取得值
children這個方法可以回傳一個內含特定名稱空間內所有子元素的陣列
也可以跟 attributes()做很好的搭配
2.錯誤與例外處理
分別從MySQL與PHP來看錯誤處理
通常SQL碼的處理方式是
mysqli_connect(localhost, $account, $pw) or die('Couldn't connect !');
die()這個函式會在錯誤發生時被呼叫
但假如想知道詳細發生的訊息可用 or die(mysqli_error($db_link)) 來得知
PHP部分的例外處理則類似Java的例外處理,如下範例
function checkBalance($balance){
if($balance < 1000) {
throw new Exception("Balance is less than 1000");
}
return true;
}
try{
checkBalance(1);
echo 'Balance is above 1000';
}catch(Exception $e){
echo 'Error:'.$e->getMessage();
}
執行結果是Balance is less than 1000
3.善用print_r()函式
print_r()函式可以用來輸出變數的值或是字串
debug時最需要的就是確認變數的值有沒有如想像中的傳入或改變
善用這點就可以確認變數的狀態
1.xml相關處理
2.錯誤與例外處理
3.善用print_r()函式
1.xml相關處理
範例:
$xml = simplexml_load_file($URL);
$entry = $xml->entry;
$attrs = $xml->entry->video->duration->attributes();
$media = $entry->children($URL);
使用simplexml_load_file()可以簡單取得XML的資訊
使用時加入XML提供方的link當參數即可
存取XML資料時會以階層性質來使用,指定標籤名稱可存取階層資訊
->符號以物件形式來看,會是從xml物件裡面取得子元素
然後利用 attributes()取得資訊
第三個程式碼擷取duration標籤,並用attributes()以陣列形式取得值
children這個方法可以回傳一個內含特定名稱空間內所有子元素的陣列
也可以跟 attributes()做很好的搭配
2.錯誤與例外處理
分別從MySQL與PHP來看錯誤處理
通常SQL碼的處理方式是
mysqli_connect(localhost, $account, $pw) or die('Couldn't connect !');
die()這個函式會在錯誤發生時被呼叫
但假如想知道詳細發生的訊息可用 or die(mysqli_error($db_link)) 來得知
PHP部分的例外處理則類似Java的例外處理,如下範例
function checkBalance($balance){
if($balance < 1000) {
throw new Exception("Balance is less than 1000");
}
return true;
}
try{
checkBalance(1);
echo 'Balance is above 1000';
}catch(Exception $e){
echo 'Error:'.$e->getMessage();
}
執行結果是Balance is less than 1000
3.善用print_r()函式
print_r()函式可以用來輸出變數的值或是字串
debug時最需要的就是確認變數的值有沒有如想像中的傳入或改變
善用這點就可以確認變數的狀態
2010年5月30日 星期日
PHP繪圖處理
這篇會寫到PHP實作圖像的部分
會寫一個 CAPTCHA的範例
提到的函式還有轉換數字到ASCII字元的chr()函式、rand()函式等
CAPTCHA是指確認使用者端是否為人類使用,而非機器人程式的測試
一般常見的圖像認證碼即是一例
CAPTCHA範例:
首先實作一個隨機產生文字字串的程式
define('CAPTCHA_NUMBER', 5);
//generate the random pass-phrase
$pass_phrase = "";
for($i = 0; $i < CAPTCHA_NUMBER; i++){
$pass_phrase .= chr(rand(97, 122));
}
chr()函式將數字轉換成相對應的ASCII字元,數字97會被轉換成'a'
rand()函式當然就是回傳隨機整數
回傳範圍可以設定在指定範圍,或者是o與內建常數RAND_MAX(server設定)內
接著就是要產生圖像
define('CAPTCHA_WIDTH', 100);
define('CAPTCHA_HEIGHT', 25);
//create the image, make black background
$img = imagecreatetruecolor(CAPTCHA_WIDTH, CAPTCHA_HEIGHT);
//set a white background with black text and gray graphics
$bg_color = imagecolorallocate($img, 255, 255, 255); //white
$text_color = imagecolorallocate($img, 0, 0, 0); //black
$graphic_color = imagecolorallocate($img, 64, 64, 64); //dark gray
//fill the background
imagefilledrectangle($img, 0, 0, CAPTCHA_WIDTH, CAPTCHA_HEIGHT, $bg_color);
//draw some random lines
for($i = 0, $i < 5, $i++){
imageline($img, 0, rand() % CAPTCHA_HEIGHT, CAPTCHA_WIDTH,
rand() % CAPTCHA_HEIGHT, $graphic_color);
}
//sprinkle in some random dots
for($i = 0, $i < 50, $i++){
imagesetpixel($img, rand() % CAPTCHA_WIDTH, rand() % CAPTCHA_HEIGHT, $graphic_color);
}
//draw the pass-phrase string
imagettftext($img, 18, 0, 5,CAPTCHA_HEIGHT - 5, $text_color,
'Courier New Bold.ttf', $pass_phrase);
//output the image as a PNG using a header
header("Content-type: image/phg");
imagepng($img);
//release the image from memory
imagedestroy($img);
imagecreatetruecolor()函式在記憶體裡準備繪製用的空白圖像
imagefilledrectangle()可用來填滿它的顏色
回傳值是一個image identifier,通常是大多數GD繪圖函式需要的第一個參數
imagecolorallocate()是用來配色用的
第一個參數是image identifier,後面三個參數是RGB數值
imageline()函式的第2、3參數是線段起點
imagerectangle()會填滿顏色在參數裡所涵蓋的範圍
imagegettftext()可以用特定字體來繪製文字
使用時必須先將字體放置於伺服器上
字體檔通常具有.ttf副檔名
函式的座標位置是第一個字元的左下角
第2個參數是大小,第3個參數是字體角度,以逆時針方向計算
第4、5參數則是作標位置
imagepng()函式會將圖像輸出到client端的browser上
假如選擇直接創造圖象到記憶體中,而不是採取賦予檔名的方式
要呼叫header()函式幫助傳送到瀏覽器
如果要儲存圖像則在imagepng()函式裡面多加入參數
imagepng($img, $filename, 5);
$filename要輸入完整的路徑名稱,參數5代表壓縮程度中等
這樣就能夠寫入檔案到png檔
imagedestroy() 函式可以釋放記憶體空間
使用完畢之後就用imagedestroy($img);
成功清除會回傳true
沒提到的函式還有
imageellipse()是在這例子裡面沒有的畫圓函式
他的參數是中心點位置和寬度、高度,顏色用最後一個參數填入
imagefilledellipse()可以用來填滿它,接受的參數和圓函式相同
imagestring()函式則是用PHP的內建字體來繪製字串圖像
使用範例為 imagestring($img, 3, 75, 75, 'Sample', $color);
第2個參數是字體大小,範圍是1~5
第3、4函數是座標
imagestringup()類似imagestring(),參數也一樣
但顯示效果則是逆時針旋轉90度的直立輸出
接著寫一段html碼
<label for="verify">Verification:</label>
<input type="text" id="verify" name="verify" value="Enter the phrase" />
<img src="source.php" alt="Verification pass-phrase" />
圖片來源就修改下本篇的程式碼來接上即可
會寫一個 CAPTCHA的範例
提到的函式還有轉換數字到ASCII字元的chr()函式、rand()函式等
CAPTCHA是指確認使用者端是否為人類使用,而非機器人程式的測試
一般常見的圖像認證碼即是一例
CAPTCHA範例:
首先實作一個隨機產生文字字串的程式
define('CAPTCHA_NUMBER', 5);
//generate the random pass-phrase
$pass_phrase = "";
for($i = 0; $i < CAPTCHA_NUMBER; i++){
$pass_phrase .= chr(rand(97, 122));
}
chr()函式將數字轉換成相對應的ASCII字元,數字97會被轉換成'a'
rand()函式當然就是回傳隨機整數
回傳範圍可以設定在指定範圍,或者是o與內建常數RAND_MAX(server設定)內
接著就是要產生圖像
define('CAPTCHA_WIDTH', 100);
define('CAPTCHA_HEIGHT', 25);
//create the image, make black background
$img = imagecreatetruecolor(CAPTCHA_WIDTH, CAPTCHA_HEIGHT);
//set a white background with black text and gray graphics
$bg_color = imagecolorallocate($img, 255, 255, 255); //white
$text_color = imagecolorallocate($img, 0, 0, 0); //black
$graphic_color = imagecolorallocate($img, 64, 64, 64); //dark gray
//fill the background
imagefilledrectangle($img, 0, 0, CAPTCHA_WIDTH, CAPTCHA_HEIGHT, $bg_color);
//draw some random lines
for($i = 0, $i < 5, $i++){
imageline($img, 0, rand() % CAPTCHA_HEIGHT, CAPTCHA_WIDTH,
rand() % CAPTCHA_HEIGHT, $graphic_color);
}
//sprinkle in some random dots
for($i = 0, $i < 50, $i++){
imagesetpixel($img, rand() % CAPTCHA_WIDTH, rand() % CAPTCHA_HEIGHT, $graphic_color);
}
//draw the pass-phrase string
imagettftext($img, 18, 0, 5,CAPTCHA_HEIGHT - 5, $text_color,
'Courier New Bold.ttf', $pass_phrase);
//output the image as a PNG using a header
header("Content-type: image/phg");
imagepng($img);
//release the image from memory
imagedestroy($img);
imagecreatetruecolor()函式在記憶體裡準備繪製用的空白圖像
imagefilledrectangle()可用來填滿它的顏色
回傳值是一個image identifier,通常是大多數GD繪圖函式需要的第一個參數
imagecolorallocate()是用來配色用的
第一個參數是image identifier,後面三個參數是RGB數值
imageline()函式的第2、3參數是線段起點
imagerectangle()會填滿顏色在參數裡所涵蓋的範圍
imagegettftext()可以用特定字體來繪製文字
使用時必須先將字體放置於伺服器上
字體檔通常具有.ttf副檔名
函式的座標位置是第一個字元的左下角
第2個參數是大小,第3個參數是字體角度,以逆時針方向計算
第4、5參數則是作標位置
imagepng()函式會將圖像輸出到client端的browser上
假如選擇直接創造圖象到記憶體中,而不是採取賦予檔名的方式
要呼叫header()函式幫助傳送到瀏覽器
如果要儲存圖像則在imagepng()函式裡面多加入參數
imagepng($img, $filename, 5);
$filename要輸入完整的路徑名稱,參數5代表壓縮程度中等
這樣就能夠寫入檔案到png檔
imagedestroy() 函式可以釋放記憶體空間
使用完畢之後就用imagedestroy($img);
成功清除會回傳true
沒提到的函式還有
imageellipse()是在這例子裡面沒有的畫圓函式
他的參數是中心點位置和寬度、高度,顏色用最後一個參數填入
imagefilledellipse()可以用來填滿它,接受的參數和圓函式相同
imagestring()函式則是用PHP的內建字體來繪製字串圖像
使用範例為 imagestring($img, 3, 75, 75, 'Sample', $color);
第2個參數是字體大小,範圍是1~5
第3、4函數是座標
imagestringup()類似imagestring(),參數也一樣
但顯示效果則是逆時針旋轉90度的直立輸出
接著寫一段html碼
<label for="verify">Verification:</label>
<input type="text" id="verify" name="verify" value="Enter the phrase" />
<img src="source.php" alt="Verification pass-phrase" />
圖片來源就修改下本篇的程式碼來接上即可
PHP與正規表示法
正規表示法是用來比對使用者所輸入的字串規格
例如今天需要使用者輸入一筆電話號碼
要求的格式假如是 000 - 11111111
使用者假如輸入00 - 11111111,就會被事先設定的正規表示法排除
本篇介紹PHP使用正規表示法的方式
ps.提醒:正規表示法在不同語言裡有些微不同
正規表示法範例:
/^\(?[2-9]\d{2}\)?[-\s]\d{3}-\d{4}$/
每一段正規表示法都必需要包含在 / / 裡面
若要比對確實的數字如1234,那就用/1234/
^ 代表以所要的字串規則開頭,ex. ^abc = 比對abc開頭的字串
$則代表以所要的字串規則結束
如果不加$的話,^abc 的比對也會判定abcd是對的
所以如果要做嚴格的判斷一定要加上頭尾的符號
\d 比對 0 - 9的數字的一個字元
\w 比對 a - z & A -Z & 0 - 9的一個字元
\s可以比對一個空白字元,包含Tab的跳格字元或是換行字元等
. 比對出換行字元以外的任何字元
{ }裡面可以放進最多兩個參數,作用是設定前面字元或中介符號應有的數目
例如\d{2, 4} ,表示可比對出連續2到4個數字的資料,00、111、1234都對
[]可對比出設定範圍的字元,[0-2]對比出0、1、2,[A-C]對比出A、B、C
在[]中使用^的意思表示不要符合,[^3-9]可比對出0、1、2
+表示前面的字元或中介符號應該出現一次或多次
*表示前面的字元或中介符號應該出現一次或多次或是都不要出現
?表示前面的字元或中介符號應該出現一次或是都不要出現
注意若只是想使用這類符號就必須脫逸,例如\?就可比對出?
至於PHP裡面用來做比對的函式有preg_match()
它的使用方式是preg_match($regex, $my_string)
第一個參數是正規表示法,第二個參數是要比對的目標字串
因為傳進來的類別都必須是字串,正規表示法要記得加上引號
成功就回傳true
另外一個跟正規表示法有關的函式是preg_replace()
它的使用方法是preg_replace($pattern, $replacement, $my_string)
他的功用是找出不想要的字元並將他替換成我們需要的字元
例如:
$test = preg_replace('/100[0-9]/', '100', 'I have 1000 dollars');
修正後的結果會存到$test裡,成為I have 100 dollars
PHP裡提供一個checkdnsrr()函式
他可以檢查網域名稱的正確性
在裡面以字串的方式輸入@以後的網址,例如'yahoo.com.tw'
假使網域存在時會回傳1,否則就回傳0
注意一點是這個函式在Linux上沒有問題
在windows若發生問題的話則使用以下程式碼
function win_checkdnsrr($domain, $recType = ''){
if(!empty($domain)){
if($recType == '') $recType = "MX";
exec(nslookup -type=$recType $domain", $output);
//exe呼叫執行在伺服器上的外部程式
foreach($output as $line){
if(preg_match("/^$domain/", $line)){
return true;
}
}
return false;
}
return false;
}
結合起來的驗證用戶e-mail網址的程式如下
if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9\._\-&!?=#]*@/', $email)) {
// $email is invalid because LocalName is bad
echo '<p class="error">Your email address is invalid.</p>';
$output_form = 'yes';
}
else {
// Strip out everything but the domain from the email
$domain = preg_replace('/^[a-zA-Z0-9][a-zA-Z0-9\._\-&!?=#]*@/', '', $email);
// Now check if $domain is registered
if (!checkdnsrr($domain)) {
echo '<p class="error">Your email address is invalid.</p>';
$output_form = 'yes';
}
}
例如今天需要使用者輸入一筆電話號碼
要求的格式假如是 000 - 11111111
使用者假如輸入00 - 11111111,就會被事先設定的正規表示法排除
本篇介紹PHP使用正規表示法的方式
ps.提醒:正規表示法在不同語言裡有些微不同
正規表示法範例:
/^\(?[2-9]\d{2}\)?[-\s]\d{3}-\d{4}$/
每一段正規表示法都必需要包含在 / / 裡面
若要比對確實的數字如1234,那就用/1234/
^ 代表以所要的字串規則開頭,ex. ^abc = 比對abc開頭的字串
$則代表以所要的字串規則結束
如果不加$的話,^abc 的比對也會判定abcd是對的
所以如果要做嚴格的判斷一定要加上頭尾的符號
\d 比對 0 - 9的數字的一個字元
\w 比對 a - z & A -Z & 0 - 9的一個字元
\s可以比對一個空白字元,包含Tab的跳格字元或是換行字元等
. 比對出換行字元以外的任何字元
{ }裡面可以放進最多兩個參數,作用是設定前面字元或中介符號應有的數目
例如\d{2, 4} ,表示可比對出連續2到4個數字的資料,00、111、1234都對
[]可對比出設定範圍的字元,[0-2]對比出0、1、2,[A-C]對比出A、B、C
在[]中使用^的意思表示不要符合,[^3-9]可比對出0、1、2
+表示前面的字元或中介符號應該出現一次或多次
*表示前面的字元或中介符號應該出現一次或多次或是都不要出現
?表示前面的字元或中介符號應該出現一次或是都不要出現
注意若只是想使用這類符號就必須脫逸,例如\?就可比對出?
至於PHP裡面用來做比對的函式有preg_match()
它的使用方式是preg_match($regex, $my_string)
第一個參數是正規表示法,第二個參數是要比對的目標字串
因為傳進來的類別都必須是字串,正規表示法要記得加上引號
成功就回傳true
另外一個跟正規表示法有關的函式是preg_replace()
它的使用方法是preg_replace($pattern, $replacement, $my_string)
他的功用是找出不想要的字元並將他替換成我們需要的字元
例如:
$test = preg_replace('/100[0-9]/', '100', 'I have 1000 dollars');
修正後的結果會存到$test裡,成為I have 100 dollars
PHP裡提供一個checkdnsrr()函式
他可以檢查網域名稱的正確性
在裡面以字串的方式輸入@以後的網址,例如'yahoo.com.tw'
假使網域存在時會回傳1,否則就回傳0
注意一點是這個函式在Linux上沒有問題
在windows若發生問題的話則使用以下程式碼
function win_checkdnsrr($domain, $recType = ''){
if(!empty($domain)){
if($recType == '') $recType = "MX";
exec(nslookup -type=$recType $domain", $output);
//exe呼叫執行在伺服器上的外部程式
foreach($output as $line){
if(preg_match("/^$domain/", $line)){
return true;
}
}
return false;
}
return false;
}
結合起來的驗證用戶e-mail網址的程式如下
if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9\._\-&!?=#]*@/', $email)) {
// $email is invalid because LocalName is bad
echo '<p class="error">Your email address is invalid.</p>';
$output_form = 'yes';
}
else {
// Strip out everything but the domain from the email
$domain = preg_replace('/^[a-zA-Z0-9][a-zA-Z0-9\._\-&!?=#]*@/', '', $email);
// Now check if $domain is registered
if (!checkdnsrr($domain)) {
echo '<p class="error">Your email address is invalid.</p>';
$output_form = 'yes';
}
}
2010年5月29日 星期六
PHP筆記(3)
這篇提到
1.SQL碼整理
2.拆解字串函式 explode() 與結合字串函式 implode()
3.字元替換函式str_replace()
4.擷取字元函式 substr()
5.自訂函式寫法
1.SQL碼整理
$query = "SELECT mr.response_id, mr.topic_id, mr.response, mt.name AS topic_name " .
"FROM mismatch_response AS mr " .
"INNER JOIN mismatch_topic AS mt USING (topic_id) " .
"WHERE mr.user_id = '" . $_SESSION['user_id'] . "'";
SQL的AS關鍵字建立別名,如例子中的mismatch_topic被命名為mt
INNER JOIN是內聯結的陳述,會從FROM與JOIN提到的表作查詢
只有都符合條件的查詢才回被回傳
USING是簡化SQL碼的陳述
例子中可改成ON( mismatch_topic.topic_id = mismatch_response.topic_id)
兩張表裡都有相同的欄位名稱才可以這樣使用
SELECT xx FROM table WHERE xx LIKE '%world%'
Like的關鍵字可以尋找跟引號裡的字眼不完全相同的模糊比對
萬用字元%可以替代單字前後的任何字元
MySQL預設的搜尋是不分大小
所以可以找到 HelloWorld、 hello world 、wOrld這些資料
SELECT xx FROM table WHERE xx LIKE '____world%'
搜尋到的資料就必須是任意四字元後接world的資料,例如aaaaworldd
前面的字元數端視 _ 符號的數量
SELECT * FROM table ORDER BY title LIMIT 5
ORDER BY這個關鍵詞用在句尾,可以針對查詢做排列
針對title作降冪排列
當然排列的依據是數值或字元的大小順位
LIMIT 5 讓不管查詢到多少資料都只回傳前五筆
如果是 LIMIT 10, 5
第一個引數是要跳過多少筆資料,第二個引數是要擷取多少資料
善用的話可以做出將查詢結果分頁的效果
搭配PHP函式使用時有一些地方要注意
使用mysqli_query()時,若查詢的變數型別並不符合該欄位的型別
會回傳一個false值
而若查詢到的是空值(null)
則必須要進一步使用mysqli_fetch_array()函式
這函式會在查詢到空值時回傳false
2.拆解字串函式 explode() 與結合字串函式 implode()
explode()使用範例
$sarray = explode(' ', 'Tyler Clippard is awsome !');
第二個參數是想分解的字串,依照第一個參數代表的分隔符號來分割
之後在將分割後的字串重送到字串陣列裡面
$sarray[0] = Tyler
implode()使用範例
$clause = implode(' ', $sarray);
第二個參數是要結合的字串陣列,第一個參數是分隔符號
3.字元替換函式str_replace()
使用範例
$replace_string = str_replace('thousands', 'hundreds', 'It worths two thousands ');
第一個參數是要被替換的字元,第二個參數是取代前者的自元,第三個參數是是目標字串
4.擷取字元函式 substr()
使用範例
substr('Yes, we can !', 5, 2)
上式可取得字串 - we
第一個參數是原始字串,第二個參數是擷取位置
字元在原始字串中被給予從0開始的編號,在5這個位置上的字元就是w
第三個參數是截取的字元數
如果在第二個參數輸入負數表是從字串尾巴開始取字元
第三個參數假如不輸入則代表要擷取剩下所有的字元
假如要取得的字元數比剩下字元數還多也是如此,不會在字串尾補上空值
假如要做出常見的"繼續閱讀"之類的功能可以考慮用這個做
5.自訂函式寫法
function funcname($param){
...........
return $var;
}
寫自訂函式時的寫法很寬鬆,宣告不用宣告函式回傳型態
缺點是若有疏忽會比較難以察覺
1.SQL碼整理
2.拆解字串函式 explode() 與結合字串函式 implode()
3.字元替換函式str_replace()
4.擷取字元函式 substr()
5.自訂函式寫法
1.SQL碼整理
$query = "SELECT mr.response_id, mr.topic_id, mr.response, mt.name AS topic_name " .
"FROM mismatch_response AS mr " .
"INNER JOIN mismatch_topic AS mt USING (topic_id) " .
"WHERE mr.user_id = '" . $_SESSION['user_id'] . "'";
SQL的AS關鍵字建立別名,如例子中的mismatch_topic被命名為mt
INNER JOIN是內聯結的陳述,會從FROM與JOIN提到的表作查詢
只有都符合條件的查詢才回被回傳
USING是簡化SQL碼的陳述
例子中可改成ON( mismatch_topic.topic_id = mismatch_response.topic_id)
兩張表裡都有相同的欄位名稱才可以這樣使用
SELECT xx FROM table WHERE xx LIKE '%world%'
Like的關鍵字可以尋找跟引號裡的字眼不完全相同的模糊比對
萬用字元%可以替代單字前後的任何字元
MySQL預設的搜尋是不分大小
所以可以找到 HelloWorld、 hello world 、wOrld這些資料
SELECT xx FROM table WHERE xx LIKE '____world%'
搜尋到的資料就必須是任意四字元後接world的資料,例如aaaaworldd
前面的字元數端視 _ 符號的數量
SELECT * FROM table ORDER BY title LIMIT 5
ORDER BY這個關鍵詞用在句尾,可以針對查詢做排列
針對title作降冪排列
當然排列的依據是數值或字元的大小順位
LIMIT 5 讓不管查詢到多少資料都只回傳前五筆
如果是 LIMIT 10, 5
第一個引數是要跳過多少筆資料,第二個引數是要擷取多少資料
善用的話可以做出將查詢結果分頁的效果
搭配PHP函式使用時有一些地方要注意
使用mysqli_query()時,若查詢的變數型別並不符合該欄位的型別
會回傳一個false值
而若查詢到的是空值(null)
則必須要進一步使用mysqli_fetch_array()函式
這函式會在查詢到空值時回傳false
2.拆解字串函式 explode() 與結合字串函式 implode()
explode()使用範例
$sarray = explode(' ', 'Tyler Clippard is awsome !');
第二個參數是想分解的字串,依照第一個參數代表的分隔符號來分割
之後在將分割後的字串重送到字串陣列裡面
$sarray[0] = Tyler
implode()使用範例
$clause = implode(' ', $sarray);
第二個參數是要結合的字串陣列,第一個參數是分隔符號
3.字元替換函式str_replace()
使用範例
$replace_string = str_replace('thousands', 'hundreds', 'It worths two thousands ');
第一個參數是要被替換的字元,第二個參數是取代前者的自元,第三個參數是是目標字串
4.擷取字元函式 substr()
使用範例
substr('Yes, we can !', 5, 2)
上式可取得字串 - we
第一個參數是原始字串,第二個參數是擷取位置
字元在原始字串中被給予從0開始的編號,在5這個位置上的字元就是w
第三個參數是截取的字元數
如果在第二個參數輸入負數表是從字串尾巴開始取字元
第三個參數假如不輸入則代表要擷取剩下所有的字元
假如要取得的字元數比剩下字元數還多也是如此,不會在字串尾補上空值
假如要做出常見的"繼續閱讀"之類的功能可以考慮用這個做
5.自訂函式寫法
function funcname($param){
...........
return $var;
}
寫自訂函式時的寫法很寬鬆,宣告不用宣告函式回傳型態
缺點是若有疏忽會比較難以察覺
2010年5月26日 星期三
PHP樣板概念
程式碼的重複利用相當重要
它可以幫助減少程式碼的量以及撰寫時花的力氣
最大的好處是提供了維護的方便性
樣板就是將程式分成功能性元件
以下將提供範例:
原件成員:
startsession.php==========
<?php
session_start();
// If the session vars aren't set, try to set them with a cookie
if (!isset($_SESSION['user_id'])) {
if (isset($_COOKIE['user_id']) && isset($_COOKIE['username'])) {
$_SESSION['user_id'] = $_COOKIE['user_id'];
$_SESSION['username'] = $_COOKIE['username'];
}
}
?>
header.php======
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php
echo '<title>Mismatch - ' . $page_title . '</title>';
?>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<?php
echo '<h3>Mismatch - ' . $page_title . '</h3>';
?>
navmenu.php==========
<?php
// Generate the navigation menu
echo '<hr />';
if (isset($_SESSION['username'])) {
echo '<a href="index.php">Home</a> ❤ ';
echo '<a href="viewprofile.php">View Profile</a> ❤ ';
echo '<a href="editprofile.php">Edit Profile</a> ❤ ';
echo '<a href="logout.php">Log Out (' . $_SESSION['username'] . ')</a>';
}
else {
echo '<a href="login.php">Log In</a> ❤ ';
echo '<a href="signup.php">Sign Up</a>';
}
echo '<hr />';
?>
footer.php==========
<hr />
<p class="footer">Copyright ©2008 Mismatch Enterprises, Inc.</p>
</body>
</html>
完成品:
index.php============
<?php
// Start the session
require_once('startsession.php');
// Insert the page header
$page_title = 'Where opposites attract!';
require_once('header.php');
require_once('appvars.php');
require_once('connectvars.php');
// Show the navigation menu
require_once('navmenu.php');
// Connect to the database
$dbc = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// Retrieve the user data from MySQL
$query = "SELECT user_id, first_name, picture FROM mismatch_user WHERE first_name IS NOT NULL ORDER BY join_date DESC LIMIT 5";
$data = mysqli_query($dbc, $query);
// Loop through the array of user data, formatting it as HTML
echo '<h4>Latest members:</h4>';
echo '<table>';
while ($row = mysqli_fetch_array($data)) {
if (is_file(MM_UPLOADPATH . $row['picture']) && filesize(MM_UPLOADPATH . $row['picture']) > 0) {
echo '<tr><td><img src="' . MM_UPLOADPATH . $row['picture'] . '" alt="' . $row['first_name'] . '" /></td>';
}
else {
echo '<tr><td><img src="' . MM_UPLOADPATH . 'nopic.jpg' . '" alt="' . $row['first_name'] . '" /></td>';
}
if (isset($_SESSION['user_id'])) {
echo '<td><a href="viewprofile.php?user_id=' . $row['user_id'] . '">' . $row['first_name'] . '</a></td></tr>';
}
else {
echo '<td>' . $row['first_name'] . '</td></tr>';
}
}
echo '</table>';
mysqli_close($dbc);
?>
<?php
// Insert the page footer
require_once('footer.php');
?>
它可以幫助減少程式碼的量以及撰寫時花的力氣
最大的好處是提供了維護的方便性
樣板就是將程式分成功能性元件
以下將提供範例:
原件成員:
startsession.php==========
<?php
session_start();
// If the session vars aren't set, try to set them with a cookie
if (!isset($_SESSION['user_id'])) {
if (isset($_COOKIE['user_id']) && isset($_COOKIE['username'])) {
$_SESSION['user_id'] = $_COOKIE['user_id'];
$_SESSION['username'] = $_COOKIE['username'];
}
}
?>
header.php======
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php
echo '<title>Mismatch - ' . $page_title . '</title>';
?>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<?php
echo '<h3>Mismatch - ' . $page_title . '</h3>';
?>
navmenu.php==========
<?php
// Generate the navigation menu
echo '<hr />';
if (isset($_SESSION['username'])) {
echo '<a href="index.php">Home</a> ❤ ';
echo '<a href="viewprofile.php">View Profile</a> ❤ ';
echo '<a href="editprofile.php">Edit Profile</a> ❤ ';
echo '<a href="logout.php">Log Out (' . $_SESSION['username'] . ')</a>';
}
else {
echo '<a href="login.php">Log In</a> ❤ ';
echo '<a href="signup.php">Sign Up</a>';
}
echo '<hr />';
?>
footer.php==========
<hr />
<p class="footer">Copyright ©2008 Mismatch Enterprises, Inc.</p>
</body>
</html>
完成品:
index.php============
<?php
// Start the session
require_once('startsession.php');
// Insert the page header
$page_title = 'Where opposites attract!';
require_once('header.php');
require_once('appvars.php');
require_once('connectvars.php');
// Show the navigation menu
require_once('navmenu.php');
// Connect to the database
$dbc = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// Retrieve the user data from MySQL
$query = "SELECT user_id, first_name, picture FROM mismatch_user WHERE first_name IS NOT NULL ORDER BY join_date DESC LIMIT 5";
$data = mysqli_query($dbc, $query);
// Loop through the array of user data, formatting it as HTML
echo '<h4>Latest members:</h4>';
echo '<table>';
while ($row = mysqli_fetch_array($data)) {
if (is_file(MM_UPLOADPATH . $row['picture']) && filesize(MM_UPLOADPATH . $row['picture']) > 0) {
echo '<tr><td><img src="' . MM_UPLOADPATH . $row['picture'] . '" alt="' . $row['first_name'] . '" /></td>';
}
else {
echo '<tr><td><img src="' . MM_UPLOADPATH . 'nopic.jpg' . '" alt="' . $row['first_name'] . '" /></td>';
}
if (isset($_SESSION['user_id'])) {
echo '<td><a href="viewprofile.php?user_id=' . $row['user_id'] . '">' . $row['first_name'] . '</a></td></tr>';
}
else {
echo '<td>' . $row['first_name'] . '</td></tr>';
}
}
echo '</table>';
mysqli_close($dbc);
?>
<?php
// Insert the page footer
require_once('footer.php');
?>
PHP筆記(2)
這篇寫比較多關於註冊、登入相關的項目
1.使用MySQL函式做密碼加密
2.Cookie使用方法
3.session設置
1.使用MySQL函式做密碼加密
當在寫註冊、登入功能時
密碼的加密是一個要點
他可以在即使資料庫不幸被盜取後,損失也能降低
駭客即使取得加密之後的密碼也無能為力
加密的方法是使用資料庫的SHA()函式,例如:
INSERT INTO table (account, pw) VALUES ('John', SHA('password'))
上式使用的SHA()函式會將password這個字轉換成40個字元的16進位制字串
注意一點是SHA()函式是不可逆的過程,這是它防止被盜取的機制
假如要進行密碼驗證
只要再輸入一樣的字串,經過SHA()函式變換之後能得到相同的字串,例如:
SELECT * FROM table WHERE pw = SHA('password')
上式的password是使用者輸入的密碼
這樣一來就可以做好驗證的工作了
當然還有非常重要的一點一定要提醒
因為轉換的字串長度問題
一開始在建造密碼欄位時要改成40個字元長度
其他類似的函式有
MySQL的MD5() //安全性較差
PHP的sha1()及md5()
2.Cookie使用方法
當有必要持續記錄使用者登入狀態時,Cookie是一個選擇
他會將資料記錄並儲存在使用者端電腦裡
使用方法例如:
setcookie('index', 'value', time() + (60 * 60 * 1));
第三個變數會是cookie的存活時間值,沒有設置就是關掉瀏覽器即失效
範例中的例子是存活時間點會是現在過後的一個小時(3600s)內
讀取時使用$_COOKIE['index']來存取變數
假如要登出的話只要使存活時間成為過去時間即可
例如改成:
setcookie('index', 'value', time() - (60 * 60 * 1));
需要注意一點是Cookie設置仰賴瀏覽器協助
假使使用者關掉Cookie功能的話也不能成功
3.session設置
session可以視作另一種的Cookie
只不過資料儲存的地點是伺服器端,另外只要瀏覽器關閉即失效
這樣也可以避免瀏覽器關閉Cookie功能帶來的影響
假使cookie真的被停用時
server上的php.ini裡的session.use_trans_id 設定成1
這樣就可以克服問題了
使用session的範例:
logout.php======
<?php
//if the user is logged in, delete the session vars to log them out
session_start();
if(isset($_SESSION['id'])){
//delete the session vars by clearing the $_SESSION array
$_SESSION = array();
//delete the session cookie by setting its expiration to an hour ago
if(isset($_COOKIE[session_name()])){
setcookie(session_name(), "", time()-3600);
}
//Destroy the session
session_destroy();
}
?>
session_start()函式會啟動session功能,然後伺服器會發一組辨識ID
即使在登出也要使用這個函式才能存取session
尾部的session_destroy()結束session,瀏覽器關閉時也會自動呼叫這個函式
使用session的方法一樣是用全域函數 ,如$_SESSION['id'] = 'john'
要清除session的方法除了關掉瀏覽器外
$_SESSION = array()這樣,指定session為空陣列也可以
實際在運作時,session也很有可能在私底下會用到cookie
畢竟cookie是最佳化的資料儲存方式
session_name()可以幫助我們找到該cookie,這樣一來就可以握到完整的清除
1.使用MySQL函式做密碼加密
2.Cookie使用方法
3.session設置
1.使用MySQL函式做密碼加密
當在寫註冊、登入功能時
密碼的加密是一個要點
他可以在即使資料庫不幸被盜取後,損失也能降低
駭客即使取得加密之後的密碼也無能為力
加密的方法是使用資料庫的SHA()函式,例如:
INSERT INTO table (account, pw) VALUES ('John', SHA('password'))
上式使用的SHA()函式會將password這個字轉換成40個字元的16進位制字串
注意一點是SHA()函式是不可逆的過程,這是它防止被盜取的機制
假如要進行密碼驗證
只要再輸入一樣的字串,經過SHA()函式變換之後能得到相同的字串,例如:
SELECT * FROM table WHERE pw = SHA('password')
上式的password是使用者輸入的密碼
這樣一來就可以做好驗證的工作了
當然還有非常重要的一點一定要提醒
因為轉換的字串長度問題
一開始在建造密碼欄位時要改成40個字元長度
其他類似的函式有
MySQL的MD5() //安全性較差
PHP的sha1()及md5()
2.Cookie使用方法
當有必要持續記錄使用者登入狀態時,Cookie是一個選擇
他會將資料記錄並儲存在使用者端電腦裡
使用方法例如:
setcookie('index', 'value', time() + (60 * 60 * 1));
第三個變數會是cookie的存活時間值,沒有設置就是關掉瀏覽器即失效
範例中的例子是存活時間點會是現在過後的一個小時(3600s)內
讀取時使用$_COOKIE['index']來存取變數
假如要登出的話只要使存活時間成為過去時間即可
例如改成:
setcookie('index', 'value', time() - (60 * 60 * 1));
需要注意一點是Cookie設置仰賴瀏覽器協助
假使使用者關掉Cookie功能的話也不能成功
3.session設置
session可以視作另一種的Cookie
只不過資料儲存的地點是伺服器端,另外只要瀏覽器關閉即失效
這樣也可以避免瀏覽器關閉Cookie功能帶來的影響
假使cookie真的被停用時
server上的php.ini裡的session.use_trans_id 設定成1
這樣就可以克服問題了
使用session的範例:
logout.php======
<?php
//if the user is logged in, delete the session vars to log them out
session_start();
if(isset($_SESSION['id'])){
//delete the session vars by clearing the $_SESSION array
$_SESSION = array();
//delete the session cookie by setting its expiration to an hour ago
if(isset($_COOKIE[session_name()])){
setcookie(session_name(), "", time()-3600);
}
//Destroy the session
session_destroy();
}
?>
session_start()函式會啟動session功能,然後伺服器會發一組辨識ID
即使在登出也要使用這個函式才能存取session
尾部的session_destroy()結束session,瀏覽器關閉時也會自動呼叫這個函式
使用session的方法一樣是用全域函數 ,如$_SESSION['id'] = 'john'
要清除session的方法除了關掉瀏覽器外
$_SESSION = array()這樣,指定session為空陣列也可以
實際在運作時,session也很有可能在私底下會用到cookie
畢竟cookie是最佳化的資料儲存方式
session_name()可以幫助我們找到該cookie,這樣一來就可以握到完整的清除
2010年5月23日 星期日
PHP實作安全機制(2)
Injection attack是一種常見的網路攻擊型態
表單欄位是Web應用程式安全上的弱點
它提供了使用者輸入資料的空間卻又難以預料使用者的行為
攻擊作法的舉例:
假設有個欄位輸入的資料會以以下SQL指令存入到SQL資料庫裡
INSERT INTO table1 VALUES(0, $name, $score, 0)
假如在欄位裡面故意輸入10000', 1) --
注意--後面有一格空格, 這會讓資料庫儲存的資料被更改
被更改的原因是因為SQL的註解方式是( -- )
存入之後便會讓後方的資料被忽略,而存進他填進來的資料
這種注入攻擊是極端麻煩的一件事,而且SQL的註解方式不只這一種
即使對於資料竄改沒有湊效,填進的特殊字元也可能讓資料庫產生錯誤
所以一定要設法避免這種情形發生
解決方法:
利用PHP的 trim()、mysqli_real_escape_string()兩個函式來處理
trim($_POST['XXX']),這個函式可以去除資料表單頭尾處的空白
mysqli_real_escape_string($dbc, trim($_POST['XXX']))
函式的第一個參數是資料庫連結變數
它可以將有危險性字元脫逸掉,使他們可以出現在表單裡,但卻不會影響正常查詢
另外有幾個作法可以幫助資料輸入的安全性
INSERT查詢寫成明確指出要將哪個值插入哪個欄位
有自動產生值或是預設值的欄位就不提供輸入的機會
減少注入攻擊的方法還有進行表單驗證、
檢查檔案類型或是尺寸是否在規範內、
檢查欄位是否有填入資料、
預期只會填入數字的欄位也可以用 is_numeric()函式來做驗證
這些方法都能將安全性再提高些。
表單欄位是Web應用程式安全上的弱點
它提供了使用者輸入資料的空間卻又難以預料使用者的行為
攻擊作法的舉例:
假設有個欄位輸入的資料會以以下SQL指令存入到SQL資料庫裡
INSERT INTO table1 VALUES(0, $name, $score, 0)
假如在欄位裡面故意輸入10000', 1) --
注意--後面有一格空格, 這會讓資料庫儲存的資料被更改
被更改的原因是因為SQL的註解方式是( -- )
存入之後便會讓後方的資料被忽略,而存進他填進來的資料
這種注入攻擊是極端麻煩的一件事,而且SQL的註解方式不只這一種
即使對於資料竄改沒有湊效,填進的特殊字元也可能讓資料庫產生錯誤
所以一定要設法避免這種情形發生
解決方法:
利用PHP的 trim()、mysqli_real_escape_string()兩個函式來處理
trim($_POST['XXX']),這個函式可以去除資料表單頭尾處的空白
mysqli_real_escape_string($dbc, trim($_POST['XXX']))
函式的第一個參數是資料庫連結變數
它可以將有危險性字元脫逸掉,使他們可以出現在表單裡,但卻不會影響正常查詢
另外有幾個作法可以幫助資料輸入的安全性
INSERT查詢寫成明確指出要將哪個值插入哪個欄位
有自動產生值或是預設值的欄位就不提供輸入的機會
減少注入攻擊的方法還有進行表單驗證、
檢查檔案類型或是尺寸是否在規範內、
檢查欄位是否有填入資料、
預期只會填入數字的欄位也可以用 is_numeric()函式來做驗證
這些方法都能將安全性再提高些。
PHP實作安全機制(1)
使用PHP有幾種方法來保護安全:
這邊介紹用Http認證來防護
也會提到header()函式的用法
Http認證
Http認證的方式是透過伺服器與瀏覽器之間的header溝通來運作
header在每個瀏覽器請求或是伺服器回應裡頭傳送
這使得我們可以用它來中斷從伺服器到瀏覽器的頁面傳送
要求使用者輸入正確的帳號與密碼後才能繼續讀取頁面
實作程式碼如下:
auth.php===========
<?php
//user name and password for authentication
$username = 'admin';
$password = "pw";
if(!isset($_SERVER['PHP_AUTH_USER']) ||
!isset($_SERVER['PHP_AUTH_PW']) ||
$_SERVER['PHP_AUTH_USER'] != $username ||
$_SERVER['PHP_AUTH_PW'] != $password
){
//The user name/password are incorrect to send the authentication headers
header('HTTP?1.1 401 Unauthorized');
header('WWW-Authenticate:Basic realm = "test"');
exit('<h2>Fail Login!!!</h2>');
}else{
header('Location:http://www.google.com');
}
?>
這段程式碼要求使用者輸入帳密
如果帳密輸入錯誤,則會跳出Fail Login的字眼
成功則轉送到Google的頁面
程式碼裡用了兩個PHP超全域變數
$_SERVER['PHP_AUTH_USER'] 這個變數存放使用者輸入認證視窗的名稱
$_SERVER['PHP_AUTH_PW']則存入輸入認證視窗的密碼
header()函式控制伺服器傳送給瀏覽器的資訊
但是這個在使用上有一個限制,標頭必須在任何html內容之前被傳送
即使前面有個空白字元也不行
header('HTTP?1.1 401 Unauthorized')讓瀏覽器知道使用者尚未通過認證,無法觀看頁面
下一行的裡的WWW-Authenticate要求瀏覽器提示使用者輸入帳號密碼進行認證
Basic realm則是用來辨識這個特別認證的用語
它的值會出現在認證視窗中,一旦使用者正確輸入帳密,在同樣realm的面即可通行無阻
exit()當然就是提供了離開認證之後出現的畫面
這段程式碼設定了當前兩個header執行結束(認證失敗)時才會被執行到
header的使用上相當有彈性,不只是這例子裡面的認證。
header('Location:http://.....')能轉移網頁到別的頁面
header('Refresh: 5; url = http://......')這個則是重新整理header,每一段時間就重整一次
header('Content-Type:text/plain')這樣的header則可以控制伺服器遞送的資料形態
當然這段程式碼有需要的話能夠寫成單獨頁面,其他有需要使用的頁面用include方式引入即可
這邊介紹用Http認證來防護
也會提到header()函式的用法
Http認證
Http認證的方式是透過伺服器與瀏覽器之間的header溝通來運作
header在每個瀏覽器請求或是伺服器回應裡頭傳送
這使得我們可以用它來中斷從伺服器到瀏覽器的頁面傳送
要求使用者輸入正確的帳號與密碼後才能繼續讀取頁面
實作程式碼如下:
auth.php===========
<?php
//user name and password for authentication
$username = 'admin';
$password = "pw";
if(!isset($_SERVER['PHP_AUTH_USER']) ||
!isset($_SERVER['PHP_AUTH_PW']) ||
$_SERVER['PHP_AUTH_USER'] != $username ||
$_SERVER['PHP_AUTH_PW'] != $password
){
//The user name/password are incorrect to send the authentication headers
header('HTTP?1.1 401 Unauthorized');
header('WWW-Authenticate:Basic realm = "test"');
exit('<h2>Fail Login!!!</h2>');
}else{
header('Location:http://www.google.com');
}
?>
這段程式碼要求使用者輸入帳密
如果帳密輸入錯誤,則會跳出Fail Login的字眼
成功則轉送到Google的頁面
程式碼裡用了兩個PHP超全域變數
$_SERVER['PHP_AUTH_USER'] 這個變數存放使用者輸入認證視窗的名稱
$_SERVER['PHP_AUTH_PW']則存入輸入認證視窗的密碼
header()函式控制伺服器傳送給瀏覽器的資訊
但是這個在使用上有一個限制,標頭必須在任何html內容之前被傳送
即使前面有個空白字元也不行
header('HTTP?1.1 401 Unauthorized')讓瀏覽器知道使用者尚未通過認證,無法觀看頁面
下一行的裡的WWW-Authenticate要求瀏覽器提示使用者輸入帳號密碼進行認證
Basic realm則是用來辨識這個特別認證的用語
它的值會出現在認證視窗中,一旦使用者正確輸入帳密,在同樣realm的面即可通行無阻
exit()當然就是提供了離開認證之後出現的畫面
這段程式碼設定了當前兩個header執行結束(認證失敗)時才會被執行到
header的使用上相當有彈性,不只是這例子裡面的認證。
header('Location:http://.....')能轉移網頁到別的頁面
header('Refresh: 5; url = http://......')這個則是重新整理header,每一段時間就重整一次
header('Content-Type:text/plain')這樣的header則可以控制伺服器遞送的資料形態
當然這段程式碼有需要的話能夠寫成單獨頁面,其他有需要使用的頁面用include方式引入即可
2010年5月22日 星期六
上傳圖片到資料庫使用PHP
搭配MyySQL來建造一個上傳圖片的功能,但這篇不說明SQL部分的處理
首先先建立html表單如下:
<form enctype="multipart/form-data" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
//enctype 這個表單屬性讓表單使用特殊的編碼類別進行檔案上傳,影響POST時的打包及傳送
<input type="hidden" name="MAX_FILE_SIZE" value="32768" />
//建立檔案上傳容量限制(32KB)
<label for="name">Name:</label>
<input type="text" id="name" value="<?php if(!empty($name)) echo $name; ?>" />
<br />
<label for="score">Score:</label>
<input type="text" id="score" value="<?php if(!empty($score)) echo $score; ?>" />
<br />
<label for="screenshot">Screen shot:</label>
<input type="file" id="screenshot" name="screenshot" />
<hr />
<input type="submit" value="add" name="submit" />
接下來是獲得上傳檔案的名稱
這邊使用PHP的$_FILES超全域變數
他有以下幾個常用的用法
$_FILES['screenshot']['name'] //上傳檔案的名稱
$_FILES['screenshot']['type'] //上傳檔案的類別
$_FILES['screenshot']['size'] //上傳檔案的大小
$_FILES['screenshot']['tmp_name'] //伺服器上暫時性的檔案儲存位置
$_FILES['screenshot']['error'] //檔案上傳的錯誤碼;0表示成功,其他表示失敗
使用['name']建立在資料庫的欄位
儲存在外部檔案的資料比較好的應用方式是在資料庫裡儲存指向參考
假使儲存在資料庫中,則會面臨資料形態的轉換(2進制 -> 10進制)
讀取時又會面臨另外一次的資料形態轉換
注意一點,檔案上傳到伺服器後,會被儲存在暫時性的目錄
所以接下來要做的動作就是將檔案從暫時性的目錄搬到你想要放的位置
使用 move_upload_file($_FILES['screenshot']['temp_name'], $target) 函式
第一個參數前面說明過了,第二個參數放目標位置,包含路徑與檔案名稱
目標路徑的部分可以設置成常數,例如:
define('PIC_PATH','images/');
$target = PIC_PATH.time().$_FILES['screenshot']['name'];
//time()是用來增加獨特性,避免同檔名的檔案覆蓋
這樣一來萬一路徑有變就只需要改寫定義路徑(define)即可
當然在不同的頁面要使用共享的指令,例如這個路徑位置定義
使用include方法來處理
appvars.php============
<?php
//Define application constants
define('PIC_PATH','images/');
?>
在其他要使用的php頁面加上require_once('appvars.php'); 這行即可
require與include的差別在於發生錯誤時require會產生錯誤訊息,include則不會
視情況挑選自己想用的函式
PHP頁面中的DB部分設置如user、pw等常數也能這樣處理。
最後 is_file() 與 filesize() 這兩個函式也能幫助辨識檔案的存在與大小
以避免檔案不存在或建立0位元的空資料,可以好好利用
假使有檔案想刪除的話可以使用 @unlink() 函式
函式前面的@在檔案上傳實際上並不成功時可以抑制錯誤
首先先建立html表單如下:
<form enctype="multipart/form-data" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
//enctype 這個表單屬性讓表單使用特殊的編碼類別進行檔案上傳,影響POST時的打包及傳送
<input type="hidden" name="MAX_FILE_SIZE" value="32768" />
//建立檔案上傳容量限制(32KB)
<label for="name">Name:</label>
<input type="text" id="name" value="<?php if(!empty($name)) echo $name; ?>" />
<br />
<label for="score">Score:</label>
<input type="text" id="score" value="<?php if(!empty($score)) echo $score; ?>" />
<br />
<label for="screenshot">Screen shot:</label>
<input type="file" id="screenshot" name="screenshot" />
<hr />
<input type="submit" value="add" name="submit" />
接下來是獲得上傳檔案的名稱
這邊使用PHP的$_FILES超全域變數
他有以下幾個常用的用法
$_FILES['screenshot']['name'] //上傳檔案的名稱
$_FILES['screenshot']['type'] //上傳檔案的類別
$_FILES['screenshot']['size'] //上傳檔案的大小
$_FILES['screenshot']['tmp_name'] //伺服器上暫時性的檔案儲存位置
$_FILES['screenshot']['error'] //檔案上傳的錯誤碼;0表示成功,其他表示失敗
使用['name']建立在資料庫的欄位
儲存在外部檔案的資料比較好的應用方式是在資料庫裡儲存指向參考
假使儲存在資料庫中,則會面臨資料形態的轉換(2進制 -> 10進制)
讀取時又會面臨另外一次的資料形態轉換
注意一點,檔案上傳到伺服器後,會被儲存在暫時性的目錄
所以接下來要做的動作就是將檔案從暫時性的目錄搬到你想要放的位置
使用 move_upload_file($_FILES['screenshot']['temp_name'], $target) 函式
第一個參數前面說明過了,第二個參數放目標位置,包含路徑與檔案名稱
目標路徑的部分可以設置成常數,例如:
define('PIC_PATH','images/');
$target = PIC_PATH.time().$_FILES['screenshot']['name'];
//time()是用來增加獨特性,避免同檔名的檔案覆蓋
這樣一來萬一路徑有變就只需要改寫定義路徑(define)即可
當然在不同的頁面要使用共享的指令,例如這個路徑位置定義
使用include方法來處理
appvars.php============
<?php
//Define application constants
define('PIC_PATH','images/');
?>
在其他要使用的php頁面加上require_once('appvars.php'); 這行即可
require與include的差別在於發生錯誤時require會產生錯誤訊息,include則不會
視情況挑選自己想用的函式
PHP頁面中的DB部分設置如user、pw等常數也能這樣處理。
最後 is_file() 與 filesize() 這兩個函式也能幫助辨識檔案的存在與大小
以避免檔案不存在或建立0位元的空資料,可以好好利用
假使有檔案想刪除的話可以使用 @unlink() 函式
函式前面的@在檔案上傳實際上並不成功時可以抑制錯誤
2010年5月21日 星期五
PHP筆記(1)
最近回頭唸了些PHP的東西
回溫一點記憶跟想一些以前沒有體會的想法
把零零碎碎的部分寫成記事
寫PHP時先要準備撰寫環境
需要的有Apache、PHP(以上必備)、MySQL(或其他資料庫軟體)
單獨抓或者 是用套裝軟體都可以
常見的有AppServ、Xampp
套裝軟體管理上比較方便,而且整合比較好
管理資料庫上 通常也使用整合好的phpmyadmin圖形介面
算是方便的選擇
安裝完記得把WWW資料夾下除了phpMyAdmin以外的全砍了以保持安全
php.ini 裡的 extension=php_mysqli.dll extension=php_gd2.dll
這兩行如果前面有;要先去掉
這篇談的有:
1."和'的差別
2.連結資料庫使用的語法
3.SQL陳述式分號
4. mysqli_query()函式結果輸出
5.PHP寄送mail的方法
6.使用驗證變數的php函式
7.超全域變數$_SERVER['PHP_SELF'] 的使用方法
1."和'的差別
PHP裡對字串的處理方式有兩種,以單引號或雙引號括起來
不同的地方是單引號表達未經處理的字串
變數在裡面不會特別轉換出來
雙引號則是會將句子裡的變數自動替換成變數裡的值
當然如果有需要,是可以兩種引號混合使用
另外 . 這個符號也可以拿來分隔字串
例如 $a = "I eat ".$lunch." for lunch"怎樣處理都可以
維持易讀易修改的文章風格即可
下面有一個稍微特殊的例子
for($i = 1; $i <=3; $i++){
if(!empty($_POST["p$i"])){
$var = "p$i";
$$var = mysqli_real_escape_string($dbc, strip_tags(trim($_POST["p$i"])));
$query = 'SELECT `state` FROM `commodity_state` WHERE `serial number` ='.$$var;
.........
上面這個例子要做到動態物件配置
$$var可以先視作 以$var的值,再做一次變數宣告,但是在雙引號中只能變換一次
所以query那行只能用此寫法,否則字串的值會變成 "$$var" = $p1
2.連結資料庫使用的語法
$dbc = mysqli_connect('localhost','root','pw','db') or die("can't link to database");
//mysqli_connect第四個參數可以不輸入,而改用加上mysqli_select_db()進行
$query = "INSERT INTO xxx (firstname, lastname, tel) VALUES ('Salty','Jobs', 'kkkk')";
//result僅儲存是否執行成功,回傳一個query物件
$result = mysqli_query($dbc, $query) or die('Error ocurr');
mysqli_close($dbc); //只能在已經確實呼叫資料庫時才能夠呼叫此函數
//SELECT * form dbname WHERE xxx = 'yes'; 這串是查詢用的展示碼
mysqli是舊有的mysql函式的改良(improved)
3.SQL陳述式分號
只有在MySQL的終端執行SQL碼時需要加上分號,使用PHP的mysqli_query則不需要
4. mysqli_query()函式結果輸出
這個函式需要搭配mysqli_fetch_array()函式
否則只會看到伺服器所給定的資源編號
使用上為mysqli_fetch_array(query結果),每做一次擷取一筆資料
傳回結果當然是陣列,要讀取值的話就要用 $Array名稱[' column名稱 ']
搭配while迴圈更可以寫成如下範例:
while($row = mysqli_fetch_array($result)){
echo $row['name'].' '.$row['email'].'<br />';
}
當沒有傳回資料,這個就會被判定成false
而PHP判定true的條件很寬鬆,只要不為0都可以,所以可以這樣寫
另外有一個跟mysqli_fetch_array()相似的mysqli_fetch_field()函式
它的用途是取得傳回資料的相關資訊
例如:
while($row = mysqli_fetch_field($result)) {
$column = $row->name;
...
在每一次查詢的迴圈裡都會回傳一個欄位名稱
上述的範例可以求得該張資料表的所有欄位
5.PHP寄送mail的方法
mail($To, $subject, $msg, $from ); //msg就使用跳脫符號 \n 打成長長的字串吧
6.使用驗證變數的php函式
isset()與empty()這兩個函式可以幫助辨識變數的值
isset() 會確認變數是否存在,而empty則可以進一步辨識函數是否為空值
$v1 = 'a'; $v2 = '';
以這兩個變數來說,即使v2是空值,但是isset還是會判定成true
這個函式最常被使用的方法是確認表單的資訊是否有傳過來
接著再用empty判 斷變數值
每個表單裡一定也會有submit按鈕
if(isset($_POST['submit']))可以讓我們知道表單是不是有被遞送,這也是使 用上的一個方法
7.超全域變數$_SERVER['PHP_SELF'] 的使用方法
當 有個頁面需要傳送資料給自己
例如:<form action="index.php" method="post">
改 成<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
這項改變當然不是那麼誇張,但他是使頁面更易於維護的小方法之一
回溫一點記憶跟想一些以前沒有體會的想法
把零零碎碎的部分寫成記事
寫PHP時先要準備撰寫環境
需要的有Apache、PHP(以上必備)、MySQL(或其他資料庫軟體)
單獨抓或者 是用套裝軟體都可以
常見的有AppServ、Xampp
套裝軟體管理上比較方便,而且整合比較好
管理資料庫上 通常也使用整合好的phpmyadmin圖形介面
算是方便的選擇
安裝完記得把WWW資料夾下除了phpMyAdmin以外的全砍了以保持安全
php.ini 裡的 extension=php_mysqli.dll extension=php_gd2.dll
這兩行如果前面有;要先去掉
這篇談的有:
1."和'的差別
2.連結資料庫使用的語法
3.SQL陳述式分號
4. mysqli_query()函式結果輸出
5.PHP寄送mail的方法
6.使用驗證變數的php函式
7.超全域變數$_SERVER['PHP_SELF'] 的使用方法
1."和'的差別
PHP裡對字串的處理方式有兩種,以單引號或雙引號括起來
不同的地方是單引號表達未經處理的字串
變數在裡面不會特別轉換出來
雙引號則是會將句子裡的變數自動替換成變數裡的值
當然如果有需要,是可以兩種引號混合使用
另外 . 這個符號也可以拿來分隔字串
例如 $a = "I eat ".$lunch." for lunch"怎樣處理都可以
維持易讀易修改的文章風格即可
下面有一個稍微特殊的例子
for($i = 1; $i <=3; $i++){
if(!empty($_POST["p$i"])){
$var = "p$i";
$$var = mysqli_real_escape_string($dbc, strip_tags(trim($_POST["p$i"])));
$query = 'SELECT `state` FROM `commodity_state` WHERE `serial number` ='.$$var;
.........
上面這個例子要做到動態物件配置
$$var可以先視作 以$var的值,再做一次變數宣告,但是在雙引號中只能變換一次
所以query那行只能用此寫法,否則字串的值會變成 "$$var" = $p1
2.連結資料庫使用的語法
$dbc = mysqli_connect('localhost','root','pw','db') or die("can't link to database");
//mysqli_connect第四個參數可以不輸入,而改用加上mysqli_select_db()進行
$query = "INSERT INTO xxx (firstname, lastname, tel) VALUES ('Salty','Jobs', 'kkkk')";
//result僅儲存是否執行成功,回傳一個query物件
$result = mysqli_query($dbc, $query) or die('Error ocurr');
mysqli_close($dbc); //只能在已經確實呼叫資料庫時才能夠呼叫此函數
//SELECT * form dbname WHERE xxx = 'yes'; 這串是查詢用的展示碼
mysqli是舊有的mysql函式的改良(improved)
3.SQL陳述式分號
只有在MySQL的終端執行SQL碼時需要加上分號,使用PHP的mysqli_query則不需要
4. mysqli_query()函式結果輸出
這個函式需要搭配mysqli_fetch_array()函式
否則只會看到伺服器所給定的資源編號
使用上為mysqli_fetch_array(query結果),每做一次擷取一筆資料
傳回結果當然是陣列,要讀取值的話就要用 $Array名稱[' column名稱 ']
搭配while迴圈更可以寫成如下範例:
while($row = mysqli_fetch_array($result)){
echo $row['name'].' '.$row['email'].'<br />';
}
當沒有傳回資料,這個就會被判定成false
而PHP判定true的條件很寬鬆,只要不為0都可以,所以可以這樣寫
另外有一個跟mysqli_fetch_array()相似的mysqli_fetch_field()函式
它的用途是取得傳回資料的相關資訊
例如:
while($row = mysqli_fetch_field($result)) {
$column = $row->name;
...
在每一次查詢的迴圈裡都會回傳一個欄位名稱
上述的範例可以求得該張資料表的所有欄位
5.PHP寄送mail的方法
mail($To, $subject, $msg, $from ); //msg就使用跳脫符號 \n 打成長長的字串吧
6.使用驗證變數的php函式
isset()與empty()這兩個函式可以幫助辨識變數的值
isset() 會確認變數是否存在,而empty則可以進一步辨識函數是否為空值
$v1 = 'a'; $v2 = '';
以這兩個變數來說,即使v2是空值,但是isset還是會判定成true
這個函式最常被使用的方法是確認表單的資訊是否有傳過來
接著再用empty判 斷變數值
每個表單裡一定也會有submit按鈕
if(isset($_POST['submit']))可以讓我們知道表單是不是有被遞送,這也是使 用上的一個方法
7.超全域變數$_SERVER['PHP_SELF'] 的使用方法
當 有個頁面需要傳送資料給自己
例如:<form action="index.php" method="post">
改 成<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
這項改變當然不是那麼誇張,但他是使頁面更易於維護的小方法之一
訂閱:
文章 (Atom)