發表文章

目前顯示的是有「PHP」標籤的文章

用更好的設定檔來處理不同的網站

圖片
這次要來介紹的是關於我自己在 處理多個網站,使用不同的設定檔 的處理方式。 優點 減少FTP上傳的時候不小心覆蓋線上設定檔的問題。 各網站參數統一,不會發生有各自自訂參數的問題,且一定有預設值。 共用的Config方法可以只寫一次, 不必一直複製與修改 。 先來看看一般網站的設定檔是怎麼處理的 這裡指的設定檔是甚麼? 設定檔通常是全域的,並且在程式中統一使用。 // 從Config設定檔中取得資料庫的物件,然後使用 $db = Config::GetConnection(); $db->Sql("SELECT * FROM `table_name`") 常見的設定檔用法 因為 不同網站的資料庫帳密、設定值是不同的 ,所以通常我們會寫Config1.php,Config2.php ..。 Config1.php class Config { //資料庫各項連線設定 public static $DbName = "1"; public static $DbHost = "1"; public static $DbPort = "1"; public static $DbUser = "1"; public static $DbPassword = "1"; public static $EnablePHPErrorReport = false; public static function GetConnection() { $host = \Config::$DbHost; $name = \Config::$DbName; $username = \Config::$DbUser; $password = \Config::$DbPassword; $db = new \Lib\MySqlDb($host, $username, $password, $n...

用更好的設定檔來處理不同的網站

圖片
這次要來介紹的是關於我自己在 處理多個網站,使用不同的設定檔 的處理方式。 優點 減少FTP上傳的時候不小心覆蓋線上設定檔的問題。 各網站參數統一,不會發生有各自自訂參數的問題,且一定有預設值。 共用的Config方法可以只寫一次,不必一直複製與修改。 先來看看一般網站的設定檔是怎麼處理的 這裡指的設定檔是甚麼? 設定檔通常是全域的,並且在程式中統一使用。 // 從Config設定檔中取得資料庫的物件,然後使用 $db = Config::GetConnection(); $db->Sql( "SELECT * FROM `table_name`" ) 常見的設定檔用法 因為 不同網站的資料庫帳密、設定值是不同的 ,所以通常我們會寫Config1.php,Config2.php ..。 Config1.php class Config { //資料庫各項連線設定 public static $DbName = "1" ; public static $DbHost = "1" ; public static $DbPort = "1" ; public static $DbUser = "1" ; public static $DbPassword = "1" ; public static $EnablePHPErrorReport = false ; public static function GetConnection () { $host = \Config::$DbHost; $name = \Config::$DbName; $username = \Config::$DbUser; $password = \Config::$DbPassword; $db = new \Lib\MySqlDb($host...

PHP 閉包,簡易記數工廠

閉包的使用 php5.3開始支援閉包 // 簡易的計數器工廠模式 function counterFactory() { $counter = 1; return function() use(&$counter) { return $counter++; }; } $counter1 = counterFactory(); $counter2 = counterFactory(); echo "counter1: " . $counter1() . "<br />"; echo "counter1: " . $counter1() . "<br />"; echo "counter1: " . $counter1() . "<br />"; echo "counter1: " . $counter1() . "<br />"; echo "counter2: " . $counter2() . "<br />"; echo "counter2: " . $counter2() . "<br />"; echo "counter2: " . $counter2() . "<br />"; // counter1: 1 // counter1: 2 // counter1: 3 // counter1: 4 // counter2: 1 // counter2: 2 // counter2: 3

目前使用的php-cs-fixer設定php_cs

目前使用的php-cs-fixer設定php_cs <?php return PhpCsFixer\Config::create() ->setRules(array( '@PSR2' => true, // 'array_indentation' => true, 'array_syntax' => array('syntax' => 'long'), 'combine_consecutive_unsets' => true, 'combine_consecutive_issets' => true, // 'method_separation' => true, // 'no_multiline_whitespace_before_semicolons' => true, // 'single_quote' => true, 'binary_operator_spaces' => array( 'align_double_arrow' => true, 'align_equals' => true, // 'default' => 'align_single_space_minimal', ), // 'blank_line_after_opening_tag' => true, // 'blank_line_before_return' => true, 'braces' => array( // 'allow_single_line_closure...

PHP debug用,印出各行之間執行時間

<?php $pm_time = microtime(true); echo "[pass time(".__LINE__.")]: ". number_format(microtime(true) - $pm_time, '4') ."<br>\n"; $pm_time = microtime(true); echo "[pass time(".__LINE__.")]: ". number_format(microtime(true) - $pm_time, '4') ."<br>\n"; $pm_time = microtime(true); echo "[pass time(".__LINE__.")]: ". number_format(microtime(true) - $pm_time, '4') ."<br>\n"; $pm_time = microtime(true); ... ...

PHP 去除陣列空元素

$params = array_filter($params); // 去除陣列空元素 (null, "", 0);

PHP RE 金額格式判斷

// 小數點支援到第四位 if (!preg_match("#^\d+(\.\d{1,4})?$#", $amount)) { die("金額格式不符!!") }

PHP 域名與子域名判斷

/** * nimo * 判斷域名是否在域名陣列裡面 * @.表示域名本身,*.表示所有子域名 * @param string $domain 被判斷的域名 * @param array $domain_list 域名陣列 * @param string $match_sub_domain 符合域名的的字域名 * @param string $match_domain 符合域名的母域名 * @return boolean true(在)/false(不在) */ function in_domain($domain, $domain_list, &amp;$match_sub_domain='', &amp;$match_domain='') { foreach ($domain_list as $judge_domain) { if (preg_match("#^(?:\*\.)(.*)$#", $judge_domain, $match)) { $tmp_domain = str_replace(".","\.",$match[1]); if (preg_match("#^(.+)\.({$tmp_domain})$#", $domain, $match2)) { $match_sub_domain = $match2[1]; $match_domain = $match2[2]; return true; } } else if (preg_match("#^(?:\@\.)(.*)$#", $judge_domain, $match)) { $tmp_domain = str_replace(".","\.",$match[1]); if (preg_match...

PHP snippet 每N個資料使用tag包起來

/** * 這是一個會用ul把輸出資料包起來並且是依照每$defaultLineRow個資料包一個ul **/ $count = 0; $defaultLineRow = 5; foreach ($List as $array) { if ($count !== 0 && $count % $defaultLineRow === 0) { echo "</ul>"; } echo $array['data'] ; if ($count % $defaultLineRow === 0){ echo "<ul>"; } $count++; } echo "</ul>";

PHP 修改網頁編碼

header("content-Type: text/html; charset=UTF-8");

PHP 讓json\_encode不要把東西轉成\uXXXX

<?php function json_encode_ex($value) { if (version_compare(PHP_VERSION, '5.4.0', '<')) { $str = json_encode($value); $str = preg_replace_callback("#\\\u([0-9a-f]{4})#i", "replace_unicode_escape_sequence", $str); $str = stripslashes($str); return $str; } else { return json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); } } function replace_unicode_escape_sequence($match) { return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE'); } echo json_encode_ex("中文字!@#$%^&*()"); echo "\n"; echo json_encode("中文字!@#$%^&*()");

PHP 檢查是否為關聯陣列

/** * 檢查陣列是否為關聯陣列 * @param array $arr 被檢查的陣列 * @return boolean */ function isAssoc(array $arr) { if (array() === $arr) { return false }; return array_keys($arr) !== range(0, count($arr) - 1); }

PHP parse_str 遇到的問題

問題 parse_str 在解析+時的問題會解析成 ,但依據RFC 3986規範不應該這樣,應解析為+。 狀況 解析 QueryString 後拿到的值去做加密驗證時一直失敗。 解決 此方法無法處理含有陣列的QueryString // 等我有哪天無聊再來弄吧!! 改進了一個function達成。 從PHP 官方的討論中找出程式片段並改進 function parseQueryString($str) { $op = array(); $pairs = explode('&', $str); foreach ($pairs as $pair) { list($k, $v) = array_map('rawurldecode', explode('=', $pair)); $op[$k] = $v; } return $op; } 因為rawurldecode不會將+換成 總結與心得 找查許久之後才發現parse_str在解析QueryString會對其值做urldecode(),而、PHP對+做urldecode()時會轉換成 ,但是依據RFC 3986規範應解析成+於是使用rawurldecode()代替。 下次再做加解密時若有用到 parse_str 或是 urlencode/urldecode 時要注意來源或目的的url加密格式(主要差別在於+是轉換成 還是 )。 補充 取代http_build_query // 也是用urlencode function buildQueryString(array $arr) { $op = array(); foreach ($arr as $key => $val) { list($k, $v) = array_map('rawurlencode', array($key, $val)); array_push($op, "{$k}={$v}"); } return implode('&', $op); }

PHP Curl 送Xml的方法

在curl參數header中加入傳送類型 curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: text/xml"));

PHP filter_input 驗証輸入,過濾輸入。

說明 當在做API或是一些需要接收表單資料的時候,總會需要確定發送端有沒有把值送過來,送過來的值有沒有正確。 這是一個php內建的函式,可以過濾或驗証輸入端變數的型態。 函式 mixed filter_input ( int $type , string $variable_name [, int $filter = FILTER_DEFAULT [, mixed $options ]] ) $type => 類型 INPUT_GET 從$_GET拿值 INPUT_POST 從$_POST拿值 更多請參考 $variable_name => 變數名 $filter => 過濾或驗証的方式 過濾類型 更多請參考 驗証類型 FILTER_VALIDATE_BOOLEAN 驗証是否為boolean值 ("1", "true", "on" and "yes" 為 true,其他為 false) 更多請參考 參考 php.net

PHP JS PHP輸出換行字元導致JS停止執行

說明 有時候我們會需要把從 PHP 取得的資料,放到 JS 的code中執行。 今天碰到了問題,所以記錄下來。 狀況 當PHP取得的字串echo到JS的字串時,換行字元會導致JS語法錯誤,進而使JS停止執行。 先來看看一般JS的物件宣告 // 一般JS正常的物件宣告 <script> var tmp = { 'key' : 'variable' } </script> 利用PHP輸出到JS物件的值 // 加入PHP值的JS物件宣告 <?php $php_string = "test123"; ?> <script> var tmp = { 'key' : '<?= $php_string ?>' } </script> 其輸出會長這樣 // 輸出(加入PHP值的JS物件宣告) <script> var tmp = { 'key' : 'test123' } </script> 今天碰到的狀況(遇到換行字元) // 加入PHP值(帶有換行字元)的JS物件宣告 <?php $php_string = "test\r\n123"; ?> <script> var tmp = { 'key' : '<?= $php_string ?>' } </script> 其輸出會長這樣 // 輸出(入PHP值(帶有換行字元)的JS物件宣告) <script> var tmp = { 'key' : 'test 123' } </script> 發現問題了嗎?? 在JS中字串是不允許換行的,所以程式報錯,瀏覽器中斷JS的執行。 然後這個世界就爆炸啦!! 解決 方法就是把換行字元替換掉 <?php $php_string = "test\r\n123"; preg_replace("/(?:\r\n|\r|\n)/", ...

PHP 2016/06/04 遇到的版本差異

狀況 本地測試正常,線上版本會出現500錯誤。 由於線上版本是不能顯錯誤訊息的,導至尋找錯誤的時間很長,實際解決問題時間很短。 歷經一個多小時的嚐試,終於找出問題。 $var = explode('-', '2016-04')[1]; echo $var; // 這裡應該要echo出'04',但是本地端正常,線上版本卻出現500 error。 解決 $var = explode('-', '2016-04'); $var = $var[1]; echo $var; 總結與心得 問題是由於5.4版本才支援這個語法( 參考 ,版本差異太可怕啦!! 下次遇到離奇事件的時候,要記的想想版本的問題。

PHP 可有可無的WHERE,自動判斷WHERE語句

說明 在寫程式時候,有時候會有_可有可無的WHERE_被下載 SQL 語句中的時候 什麼是_可有可無的WHERE_? 好比方在搜尋的時候,我有輸入"搜索時間範圍",才會搜索時間;有輸入"搜索地區",才會搜索地區。 所以在程式裡面WHERE有沒有出現,是看使用者代入的參數的! Code 這在這例子中,有設定姓名,才會搜尋姓名;有設定時間範圍,才會搜尋時間範圍,如果都沒有設定的話,就不會有WHERE語句出現。 // 不是重點的部份直接註解掉了:) // $db = new db(); $where = array(); ... .. . // if (isset($data->name)) { array_push($where, "tableName.name='{$data->}'"); // } // if (isset($data->minSearchTime) AND isset($data->maxSearchTime)) { array_push($where, "tableName.datetime BETWEEN '{$data->minSearchTime}' AND '{$data->maxSearchTime}'"); // } $where_string = empty($where) ? '' : ' WHERE '.join(' AND ', $where); $sql = "SELECT * FROM tableName {$where_string}"; //$rst = $db->Query($sql); return $rst;

PHP 檢查網域字串

/** * 檢查網域字串 * @param string $domain 輸入網域名 * @return bool */ function CheckDomainString($domain) { return preg_match("/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/", $domain); }

PHP for, foreach時 pass by reference 要注意的地方(超難找的問題)

// 先來看看狀況 $arr = array("a", "b", "c"); foreach ($arr as &$item) {} print_r($arr); foreach ($arr as $item) {} print_r($arr); // output /* Array ( [0] => a [1] => b [2] => c ) Array ( [0] => a [1] => b [2] => b ) */ // 第二次的陣列被改變了 // 原因是因為當這行執行完時 foreach ($arr as &$item) {} // $item 其實是指到$arr[2]的 // 在後來的回圈 foreach ($arr as $item) {} // 這邊的$item指的是$arr[2]的位址 // foreach的時候會不斷的把$arr的每一個值都放到$item中 // 而$item因為上一個傳址呼叫的原因被指定為$arr[2] // 所以第二個回圈只是不停的改變$arr[2] // 解決方法: unset(); $arr = array("a", "b", "c"); foreach ($arr as &$item) {} print_r($arr); unset($item); foreach ($arr as $item) {} print_r($arr); // 結論: 如果使用到 pass by reference(傳址呼叫) // 要記得把那個變數改unset掉, // 不然誤用到那個變數就不好了。