2011年3月31日 星期四
facebook api use on fb iframe canvas
2009年5月20日 星期三
學習 CakePHP
之前回絕掉一個cakePHP的案子, 實在是因為要寫報告和找資料太忙了...。
說到cakePHP, 最重要的就是 MVC(Model-View-Controller) 的設計模式, 以往由於php是比較近似於程序導向語言, 故大家都會把所有動作與畫面顯示寫在一隻程式上, 當然這樣是很方便的, 不過萬一遇到的不是網站而是大型的網路應用程式, 可能這個做法會讓你非常頭痛, 等到寫幾百隻php時回頭除錯真可形容為"欲哭無淚"。而 MVC 所指的是把 1.資料處裡 2.流程邏輯 3.畫面顯示 分開, 這樣針對不同的功能產生清晰的分類, 維護與除錯就不再是一件惱人的事。
傳統的寫法
MVC的寫法
此外 cakePHP 在資料層(Model)做了物件關連映射 ORM(Object-Relational Mapping) 的處理, 可以以物件導向的方式操作資料庫欄位(做了映射, 欄位變成物件屬性或方法), 對於不熟悉關連資料庫的朋友也是一大福音。
長久以來物件導向與程序導向都各擁有一派死忠者, 但我個人認為並沒有甚麼好擁護的, "適得其所"才是最重要, 一個小型程式不需要把它用大工程的方式進行, 而一項大工程基於良好的時效與後續維護, 也應該採用物件導向而非程序導向。
但說來說去還是沒有好好研究cakePHP, 或許等以後有案子碰到在說, 畢竟重點是觀念而不是技術。
2009年3月9日 星期一
PHPMailer utf-8郵件主旨亂碼問題
日前使用PHPMailer發送utf-8格式的中文郵件時, 發現收件夾內接收的郵件均為亂碼, 而且連帶影響到郵件的html內文, 原因在於E-Mail標準格式中表頭的部分不允許使用雙位元的文字(也就是中文等...), 所以必須使用mb_encode_mimeheader()函式將雙位元文字編碼為單位元字串。
但是因為mb_encode_mimeheader()預設的字串編碼為西方ISO-8859-1, 所以如果你的編碼中文字為UTF-8就必須使用mb_internal_encoding()將內部預設編碼改為UTF-8。
<?php mb_internal_encoding('UTF-8'); // 內部預設編碼改為UTF-8 $mail->Subject = mb_encode_mimeheader($_POST['title'], "UTF-8"); $mail->Body = $_POST['content']; ?>
2009年2月7日 星期六
一些php網頁驗證小技巧
一般而言坊間教學書上對於登入驗證這塊都沒有說明的很詳細, 但其實還有一些技巧需注意, 雖然這些技巧並不能讓你網站100%安全, 但是至少能夠防範"輕易"的被誤用或連結.
例如說處理表單的php來源照理來說應該要是表單的html等, 如果不判斷來源, 就能夠使用一些機器人隨意新增或修改資料, 下段程式判斷時否有來源網頁, 有的話是否是你設定的網頁.
<?php $referrer = $_SERVER['HTTP_REFERER']; if($referrer == '' || strpos($referrer, 'your_php.php') == false){ // 判斷來源網頁 die('來源網頁錯誤'); } ?>
至於登入很多人可能會忘記要驗證當初登入的瀏覽器與IP位址, 你可以在登入時註冊一個session為如下:
<?php $_SESSION['userAgent'] = $_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT']; ?>
如果要使用cookie記憶長時效, 為了不讓cookie被破解我們會做一些混淆動作, 但要還原卻又很困難, 所以我們把混淆後的cookie記錄在資料庫中, 並設定時效, 每次瀏覽需要驗證的頁面時都去比對, 直到cookie過期失效.
<?php $cookie = md5($date.$mail.$identify.rand(0, 1000000)); $cookieexpiry = (time() + 21600); setcookie('memberVerify', $cookie, $cookieexpiry); //時效驗證 ?>
如果有看過我之前破解一些網站的文章就知道上述方法還是能夠被手動取代, 但至少不會輕易讓門外漢利用!
2009年1月5日 星期一
php與MySQL連接類別
日前整理的一個類別, 特殊的地方在於使用了Array儲存查詢結果, 所以能夠依照查詢時給予的ID重新調用結果。
此外設定檔存放在db_mysql.inc中, 如果臨時需要調換資料庫則在建構子中填入即可。
db_mysql.inc :
<?php // or set date.timezone = Asia/Taipei in php.ini if(function_exists("date_default_timezone_set")) date_default_timezone_set('Asia/Taipei'); // database configure. define(DB_HOST, 'localhost'); define(DB_USER, 'root'); define(DB_PASSWD, 'root1234'); define(DB_DATABASE, 'PHP_MODULE_TEST'); define(DB_PERSISTENT, false); define(DB_UTF, true); ?>
database_mysql.php :
<?php require('db_mysql.inc'); class DataBase { // Connection parameters var $host = ''; var $user = ''; var $password = ''; var $database = ''; var $persistent = false; var $utf = true; // Database connection handle var $conn = null; var $connected = false; // Query result var $result = array(); var $insert_id = array(); // constructor. function DataBase($otherDatabase = null) { $this->host = DB_HOST; $this->user = DB_USER; $this->password = DB_PASSWD; if($otherDatabase == null) $this->database = DB_DATABASE; else $this->database = $otherDatabase; $this->persistent = DB_PERSISTENT; $this->utf = DB_UTF; } // open database connection. function connect() { // Choose the appropriate connect function if ($this->persistent){ $func = 'mysql_pconnect'; }else{ $func = 'mysql_connect'; } // Connect to the MySQL server $this->conn = $func($this->host, $this->user, $this->password) or die($this->error()); if($this->utf == true){ mysql_query("SET NAMES 'utf8'"); } // Select the requested database mysql_select_db($this->database, $this->conn) or die($this->error()); $this->connected = true; } // database query. function query($rs_id='RESULT_ID', $sql='', $debug=0) { if($this->connected == false) $this->connect(); if($debug!=0) $this->debug($sql, $debug); $this->result[$rs_id] = mysql_query($sql, $this->conn) or die($this->error()); $this->insert_id[$rs_id] = mysql_insert_id(); return ($this->result[$rs_id] != false); } // 取得先前操作MySQL所受到影響的列的數目 function affectedRows() { return (mysql_affected_rows($this->conn)); } // 取得結果中列的數目 function numRows($rs_id) { return (mysql_num_rows($this->result[$rs_id])); } // 取得查詢後的物件結果(使用$row->user_id查詢) function fetchObject($rs_id) { return (mysql_fetch_object($this->result[$rs_id])); } // 取得查詢後的陣列結果(使用$row['user_id']查詢) function fetchArray($rs_id) { return (mysql_fetch_array($this->result[$rs_id])); } // 回傳一個欄位的值(ex: select name from school where id=1, 傳回$rs['name']) function fetchAssoc($rs_id) { return (mysql_fetch_assoc($this->result[$rs_id])); } // 釋放�憶體 function freeResult($rs_id) { return (mysql_free_result($this->result[$rs_id])); } // 移動內部指標 function resetResult($rs_id) { return (mysql_data_seek($this->result[$rs_id], 0)); } // 取得先前insert操作的id主鍵(AUTO_INCREMENTED) function getInsertID($rs_id) { return $this->insert_id[$rs_id]; } // show database configure. function showDetail() { $str = ''; $str .= 'DB_HOST: '.DB_HOST.'<br>'; $str .= 'DB_USER: '.DB_USER.'<br>'; $str .= 'DB_PASSWD: '.DB_PASSWD.'<br>'; $str .= 'DB_DATABASE: '.DB_DATABASE.'<br>'; if(DB_PERSISTENT == true) $str .= 'DB_PERSISTENT: true<br>'; else $str .= 'DB_PERSISTENT: false<br>'; if(DB_UTF == true) $str .= 'DB_UTF: true<p>'; else $str .= 'DB_UTF: false<p>'; return $str; } // debug sql condition. function debug($sql,$debug) { if($debug==1)echo "<script>alert(\"".$sql."\");</script>"; else if($debug==2)echo '<p><b>'.$sql.'</b></p>'; else if($debug==3)exit; } // close connection. (無法關閉pconnect所開啟的連線) function close() { $this->connected = false; return mysql_close($this->conn); } function error() { return mysql_error(); } } ?>
2008年12月24日 星期三
用php做出類似Google的字詞驗證圖片
雖然日前Google字詞驗證與CAPTCHA都已經宣告被破解, 但還是用php來寫出一個類似的介面, php圖片要扭曲必須要用像素位移的方式, 所以出來的圖片會有一點沙沙的感覺。 其實也可以使用其他附加軟體進行扭曲的動作, 但那樣可攜性就相對降低了。
使用時請在這支php同資料夾加上font資料夾, 裡面放置要產生驗證碼的字型, 幾個都可以, 會隨機挑選, 驗證碼存在$_SESSION['vCode']中, 格式為 驗證碼|時間, 比對時要explode("|", $_SESSION['vCode'])。
也可以加上干擾線條與點數, 變的更難辨識。
<?php session_start(); // if header already send, change output_buffering = On at php.ini. otherwise save as UTF-8 without BOM. $vi = new vCodeImage(); $vi -> SetImage(2,7,130,60,120,1); class vCodeImage { var $mode; // 1.文字模式, 2.字母模式, 3.文字字母混合模式, 4.其他文字字母優化模式 var $v_num; // 驗證碼個數 var $img_w; // 圖像寬度 var $img_h; // 圖像�度 var $int_pixel_num; // 干擾像數個數 var $int_line_num; // 干擾線條數量 var $font_dir; // 字型文件路徑 var $border; // 圖像邊框 var $borderColor; // 圖像邊框顏色 function SetImage($mode, $v_num, $img_w, $img_h, $int_pixel_num, $int_line_num, $font_dir='font', $border=false, $borderColor='0,0,0') { if(!isset($_SESSION['vCode'])){ session_register('vCode'); } $_SESSION['vCode'] = ""; $this -> mode = $mode; $this -> v_num = $v_num; $this -> img_w = $img_w; $this -> img_h = $img_h; $this -> int_pixel_num = $int_pixel_num; $this -> int_line_num = $int_line_num; $this -> font_dir = $font_dir; $this -> border = $border; $this -> borderColor = $borderColor; $this -> GenerateImage(); } function GetChar($mode) { if($mode == "1"){ $ychar = "0,1,2,3,4,5,6,7,8,9"; }else if($mode == "2"){ $ychar = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z"; }else if($mode == "3"){ $ychar = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z"; }else{ $ychar = "3,4,5,6,7,8,9,a,b,c,d,h,k,p,r,s,t,w,x,y"; } return $ychar; } function RandColor($rs, $re, $gs, $ge, $bs, $be) { $r = mt_rand($rs, $re); $g = mt_rand($gs, $ge); $b = mt_rand($bs, $be); return array($r, $g, $b); } function GenerateImage() { $fonts = scandir($this -> font_dir); $ychar = $this -> GetChar($this -> mode); $list = explode(",", $ychar); $cmax = count($list) - 1; $fmax = count($fonts) - 2; $fontrand = mt_rand(2, $fmax); $font = $this -> font_dir."/".$fonts[$fontrand]; // 驗證碼 $v_code = ""; for($i = 0; $i < $this-> v_num; $i++){ $randnum = mt_rand(0, $cmax); $this_char = $list[$randnum]; $v_code .= $this_char; } // 扭曲圖形 $im = imagecreatetruecolor ($this -> img_w + 50, $this -> img_h); $color = imagecolorallocate($im, 32, 81, 183); $ranum = mt_rand(0, 2); if($ranum == 0){ $color = imagecolorallocate($im, 32, 81, 183); }else if($ranum == 1){ $color = imagecolorallocate($im, 17, 158, 20); }else{ $color = imagecolorallocate($im, 196, 31, 11); } imagefill($im, 0, 0, imagecolorallocate($im, 255, 255, 255) ); imagettftext ($im, 24, mt_rand(-6, 6), 10, $this -> img_h * 0.6, $color, $font, $v_code); // 干擾線條 for($i = 0; $i < $this -> int_line_num; $i++){ $rand_color_line = $color; imageline($im, mt_rand(2,intval($this -> img_w/3)), mt_rand(10,$this -> img_h - 10), mt_rand(intval($this -> img_w - ($this -> img_w/3) + 50),$this -> img_w), mt_rand(0,$this -> img_h), $rand_color_line); } $ranum = mt_rand(0, 1); $dis_range = mt_rand(8, 12); $distortion_im = imagecreatetruecolor ($this -> img_w * 1.5 ,$this -> img_h); imagefill($distortion_im, 0, 0, imagecolorallocate($distortion_im, 255, 255, 255)); for ($i = 0; $i < $this -> img_w + 50; $i++) { for ($j = 0; $j < $this -> img_h; $j++) { $rgb = imagecolorat($im, $i, $j); if($ranum == 0){ if( (int)($i+40+cos($j/$this -> img_h * 2 * M_PI) * 10) <= imagesx($distortion_im) && (int)($i+20+cos($j/$this -> img_h * 2 * M_PI) * 10) >=0 ) { imagesetpixel ($distortion_im, (int)($i+10+cos($j/$this -> img_h * 2 * M_PI - M_PI * 0.4) * $dis_range), $j, $rgb); } }else{ if( (int)($i+40+sin($j/$this -> img_h * 2 * M_PI) * 10) <= imagesx($distortion_im) && (int)($i+20+sin($j/$this -> img_h * 2 * M_PI) * 10) >=0 ) { imagesetpixel ($distortion_im, (int)($i+10+sin($j/$this -> img_h * 2 * M_PI - M_PI * 0.4) * $dis_range), $j, $rgb); } } } } // 干擾像素 for($i = 0; $i < $this -> int_pixel_num; $i++){ $rand_color_pixel = $color; imagesetpixel($distortion_im, mt_rand() % $this -> img_w + 20, mt_rand() % $this -> img_h, $rand_color_pixel); } // 繪製邊框 if($this -> border){ $border_color_line = $color; imageline($distortion_im, 0, 0, $this -> img_w, 0, $border_color_line); // 上橫 imageline($distortion_im, 0, 0, 0, $this -> img_h, $border_color_line); // 左豎 imageline($distortion_im, 0, $this -> img_h-1, $this -> img_w, $this -> img_h-1, $border_color_line); // 下橫 imageline($distortion_im, $this -> img_w-1, 0, $this -> img_w-1, $this -> img_h, $border_color_line); // 右豎 } imageantialias($distortion_im, true); // 消除鋸齒 $time = time(); $_SESSION['vCode'] = $v_code."|".$time; // 把驗證碼與時間賦與給 $_SESSION[vCode], 時間欄位可以驗證��否超時 // 生成圖像給瀏覽器 if (function_exists("imagegif")) { header ("Content-type: image/gif"); imagegif($distortion_im); }else if (function_exists("imagepng")) { header ("Content-type: image/png"); imagepng($distortion_im); }else if (function_exists("imagejpeg")) { header ("Content-type: image/jpeg"); imagejpeg($distortion_im, "", 80); }else if (function_exists("imagewbmp")) { header ("Content-type: image/vnd.wap.wbmp"); imagewbmp($distortion_im); }else{ die("No Image Support On This Server !"); } imagedestroy($im); imagedestroy($distortion_im); } } ?>
