動作

MyDevop

出自 Itsmw

簡介

 此頁是筆者從事網頁開發的心得筆記區,內容大致是 PHP, MySQL, CSS, HTML5...等技術的一些應用片段。



HTML&PHP

響應式網頁Reponsive Design Web




手動建立響應式網頁原則

  • 綜合上面文章所述,筆者試著不靠任何 FrameWork ,手動建立簡單的響應式網頁,心得如下:
  • 依下述原則建立的網頁範本:http://myip.tw/download/web43.zip


  • 不同寬度要用不同的 CSS 設定,可以用 @media screen 來完成此一目的,本例是額外建立一個獨立的 CSS 檔案,請先看原始碼:
    #main {
      margin: 8px auto;
      width: 1200px;
      border:2px solid;
      border-radius:12px;
      background-color: #F6FFE9;
    }

    #header {
      width: 100%;
      background: url(headbk_1.png);
      background-repeat: repeat-x;
      height: 30px;
      text-align: center;
      border-top-left-radius: 12px;
      border-top-right-radius: 12px;
      padding-top: 4px;
    }
     
    @media screen and (min-width: 480px) and (max-width: 1200px) {
    	/* 如果使用者之視窗寬度介於 480px ~ 1024px,將會再載入這裡的 CSS。*/
    	#main {
    		margin: 8px auto;
    		width: 96%;
    		border:2px solid;
    		border-radius:6px;
    	}
    	#header {
    		background: url(headbk_1.png);
    		background-repeat: repeat-x;
    		height: 30px;
    		width: 100%;
    		text-align: center;
    		border-top-left-radius: 6px;
    		border-top-right-radius: 6px;
    		padding-top: 4px;
    	}
    }

    @media screen and (max-width: 480px) {
    	/* 如果使用者之視窗寬度 <= 480px,將會再載入這裡的 CSS。*/
    	#main {
    	  margin: 3px auto;
    	  width: 99%;
    	  border:2px solid;
    	  border-radius:3px;
    	}
    	#header {
    		background: url(headbk_2.png);
    		background-repeat: repeat-x;
    		height: 50px;
    		width: 100%;
    	}
    }
  • 說明:「@media screen 是指螢幕寬度在指定範圍,可以設定不同的「值」,依本例:一開始就給 main 及 header 參數,但在小於 1200 及 480 時予以變更,以符合不同寬度時之視覺需求。


  • 當網頁的寬度值被切成數段分別設定時,裡面所含的全區「區塊」寬度,最好是以「%」為單位。若是左右兩欄,就要用 float 等技術, 令其寬度不足時會自動往下跳。


  • 網頁的 <head> 區要為手機及平版平台額外加一組 meta 標籤 「 <meta name='viewport' content='width=device-width, initial-scale=1.0'>」, 它可以把網頁在小而高解析度的手機螢幕時,以較低的解析度呈現,例如:720x1280 的手機,會以 480px 來處理本網頁。重點是,在 PC 上卻又正常無誤。


  • 若 Header 會有一張大的風景照,style 寫法:「style='height: auto; max-width: 100%;'」, 目的是可以讓圖片,隨著視窗大小,自動縮放圖片。

Bootstrap

 Bootstrap 是一套多用途的網頁架構(Framework),已內建各種CSS樣式,並可兼容傳統固定寬度或可變環境的響應式網頁,如果再塔配 bootstrap watch 佈景,仍可呈現出多種面貌。基本上他的使用方式如下:



CSS

使用 position: relative 時如何置中

left:10%;
right:10%



優良的播放器projekktor

  • 官網:http://www.projekktor.com/
  • 簡介
    這一套播放器,是基於 html5 及 jquery 技術開發而成,可以讓 IE7 ~ IE10, Firefox, Chrome, 手機, 平板等裝置,都得到最佳化的影片串流播放功能。



PHP CLI 交談式介面設計

  • 範例:
#!/usr/bin/php
<?php
$exetime = trim(shell_exec("read -p '每幾分鐘要執行監控一次(建議10): ' exetime;echo \$exetime"));
echo  "將會把每 ".$exetime." 分鐘執行一次 chksrv.php 寫入 crontab 內。 \n";
?>
  • 說明
    • read -p ‘xxxx' exetime ;echo $exetime...
      這一行是 bash 指令,意思是指把使用者輸入的字串,存入 BASH exetime 變數,再 echo 出來。
    • echo 出來的值,會透過 PHP 的 shell_exec 傳給 PHP 變數



PHP 程式設計-防止攻擊之注意事項

強化 Apache2 設定

header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');
header('X-Content-Type-Options: nosniff'); 
  • 說明:X-Frame-Options 有三個值
    • DENY:網頁中一律無法使用 frame
    • SAMEORIGIN:自已可以,別的表單或 HTML 無法顯示
    • ALLOW-FROM uri :允許顯示特定 url 的網頁 frame


所有回傳的變數都要檢查

  • 無論是用 GET, POST, 或是 REQUEST 接到變數時,必須要先轉成合理的值,舉例如下:
    若此變數只用於整數,那在接到時強制轉成整數:$payment = intval($_POST["Payment"];
  • 去除不必要的斷行,空白:$subtitle = trim($_POST["SubTitle"];
  • 如果此欄位有限定長度,要塔配使用 substr, trim 整理字串:$userid = substr(trim($_POST["UserID"],0,8);
  • 時間欄位,先刻意轉成 unix 秒再轉回,以避免使用者亂塞東西。


用 session 控制登入之 PHP 程式碼注意事項

簡介

 Session是身分狀態的管理機制,我們可以用 PHP $_SESSION[ ] 陣列來建立各種 SESSION 值存放於伺服器端。只留 session id 放至瀏覽器的 cookie ,以確認正在登入中的是那個瀏覽器。而攻擊者會想辦法取得使用者的Session id(即PHPSESSID),取得了 user 的 id,即可冒充使用者對網站進行存取。防止的方法,可以參考以下文件說明,在此筆者只是依網路文章整理取出適合自己的幾點做個筆記:



原始碼示例

<?php
//在程式碼的開頭,變動 php.ini 設定,並立即產生新的 session id
ini_set('session.cookie_httponly',1);
ini_set('session.use_only_cookies',1);
ini_set("session.use_trans_sid", 0);
session_start();
session_regenerate_id();
ob_start();
date_default_timezone_set("Asia/Taipei");

error_reporting(E_ALL);
include_once('functions.php');

$p_hsn = "";
$strMain = "";
$strAdm = "";
$strErr = "";
$sqlerr = "";

//......
require("config/config.inc.php");
$conn = new mysqli($mysql_host, $mysql_user, $mysql_pwd, $mysql_db);
$conn -> query("SET NAMES 'utf8'");
if($conn->connect_errno) $sqlerr.="MySQL Connect Failed:(".$conn->connect_errno.") ".$conn->connect_error;
//......

/***** 防止跨站表單攻擊(Cross-Site Request Forgeries) ************
 *    以下程式碼用於防止 XSS 攻擊,因為做了許多檢查,程式碼有點長。     *
 *********************************************************/
// 記錄隨著請求發送的header所夾帶的User-Agent, User-Agent 是指瀏覽器名稱及版本, 例: IE9, Firefox 18...等
// 如果同一 SESSION_ID(應來自相同的某一次登入),User-Agent 不同時,可是某種攻擊行為
if (isset($_SESSION['HTTP_USER_AGENT'])) {
	if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT'])) {
		//來自別台 AGENT ,所以 reload 程式碼,不接受任何表單值
		session_destroy();
		header("Location: login.php?prog=admin");
	}
}else{
	$_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);
}


//  設 seeion["xsstoken"]的目的有二: 
// 1. 在啟用session時設定一 random 的 Token 值,並在下一次進來時檢查是否存在,如果在 $_SESSION 
//     裡有這個值的話,即代表我們有建立此 session,因為攻擊表單搞不清楚我們會有多少 session 值,當
//     惡意程式,複製我們的表單,再送回惡意表單時,很難猜到 SERVER 端會有這個 session 值。
// 2. 就算因為攻擊者知道有這個 session ,但我們每次進行便隨機動態改一次。
$isXsstoken = false;
if( isset($_SESSION['xsstoken']) ){
	if( $_POST["xsstoken"] ){
		if( $_POST["xsstoken"] == $_SESSION["xsstoken"] ) {
			$xsstoken = md5 (uniqid (rand()));
			$_SESSION["xsstoken"] = $xsstoken;
			$isXsstoken = true;
		}else{
			$isXsstoken = false;
			session_destroy();
		}
	}else{
		$xsstoken = md5 (uniqid (rand()));
		$_SESSION["xsstoken"] = $xsstoken;
		$isXsstoken = true;
	}
}else{
	$xsstoken = md5 (uniqid (rand()));
	$_SESSION["xsstoken"] = $xsstoken;
	$isXsstoken = true;
}
// 為配合此檢查,要在表單加一個 hidden 欄位
// <input name='xsstoken' type='hidden' value='$xsstoken' >
if( !$isXsstoken ) header("Location: login.php?prog=hosts");


// 下面程式碼是為更進一步的檢查 session ,如果攻擊者知道我們會在 session 製造 uid 值,那麼只檢查這個 
// session 值存不存在,是不夠的。還要把 uid 及 pwd 傳入資料庫檢查是否有此使用者,以避免攻擊程式(表
// 單)隨便假造這兩個 session 值。
$numValidChk = 0;
if( !isset( $_SESSION["uid"] ) ){
	header("Location: login.php?prog=hosts");
}else{
	$isValidUser = false;
	// use session uid, 及 passwd 再次到資料庫驗證,若不對到 login 去
	$uid = mysqli_real_escape_string( $conn, $_SESSION["uid"]);
	$pwd = mysqli_real_escape_string( $conn, $_SESSION["pwd"]);
	$sqlValidChk = "SELECT * FROM `users` WHERE uid='".$uid."' AND passwd='".$pwd."' ";
	if($rsValidChk = $conn->query( $sqlValidChk )){
		$numValidChk = $rsValidChk->num_rows;
		if( $numValidChk == 0 ) {
			$isValidUser = false;
		}else{
			$isValidUser = true;
		}
	}else{
		$isValidUser = false;
	}
}
if( !$isValidUser ) exit;
//------- End of XSS Check -----------------------------------------------------


重點說明

  • 一開始的 ini_set 是動態改變 php.ini 上的設定值,以增強安全性。
  • 再來 Random 的 xssToken 變數
    因為來自不同的 session id 不一定會有 token Session,所以我們在啟用 session 時設定一個變數「 random 的 xssToken」,再來檢查如果在 $_SESSION 裡有這個值的話,即代表我們有建立此 SESSION。
  • 每次都進行使用者身份檢查
    當使用者已經登入,在登入程式也給予 $_SESSION["uid"] 及 $_SESSION["pwd"]時,必須依此 session 值回資料庫檢查一下,避免被暴力破解。
  • 由最上的 ini_set 直到上面為止,都檢查通過,才可進入主程式



MySQL

MySQL 伺服器



PHP+MySQL 防止 SQL Injection設計


  • PHP mysqli 連結
require("config/config.inc.php");
$conn = new mysqli($mysql_host, $mysql_user, $mysql_pwd, $mysql_db);
$rs = $conn -> query("SET NAMES 'utf8'");
if ($conn->connect_errno) {
	$sqlerr = "Failed to connect to MySQL: (" . $conn->connect_errno . ") " . $conn->connect_error;
}


  • 特殊字元加跳脫符號「\」
    在 SELECT 時,變數必須先用 mysqli_real_escape_string() 函式,把會造成 SQL Injection 的特定字元加上「\」符號,再送至 SQL 語法,舉例如下:
$uid = mysqli_real_escape_string( $conn, $_SESSION["uid"]);
$pwd = mysqli_real_escape_string( $conn, $_SESSION["pwd"]);
$sqlValidChk = "SELECT * FROM `users` WHERE uid='".$uid."' AND passwd='".$pwd."' ";
$rsValidChk = $conn->query( $sqlValidChk );


......
  • 注意:mysqli_real_escape_string 必須塔配 mysql connect 使用,無法單獨取用。換句話說,不可以在開始時以 mysql 的函式庫連結資料庫,但卻使用本函式做特定字元過濾。



XOOPS筆記

Xoops2.5.x會員列表時顯示中文姓名

  • 資料表 users 結構-只列常用部分
    • uid: 序號
    • uname: 帳號
    • name: 中文姓名


  • 問題:
    預設 xoops 後台的會員列表,只有帳號、email、註冊日期...等,但為了解該帳號的使用人,還是得列一下中文姓名才方便。


  • 解法:修改 xoops/modules/system/templates/admin/system_users.html ,大約在第 20 幾行加入下列兩行,如下所示:
        ......
        <tr>
            <th class="txtcenter width3"><input name='allbox' id='allbox' onclick='xoopsCheckAll("memberslist", "allbox");'  type='checkbox' value='Check All' /></th>
            <th class="txtcenter width5"><{$smarty.const._AM_SYSTEM_USERS_STATUS}></th>
            // -----------加入下面這一行------------
            <th class="txtcenter"><{$smarty.const._AM_SYSTEM_USERS_NAME}></th>
            // --------------------------------------------
            <th class="txtcenter"><{$smarty.const._AM_SYSTEM_USERS_UNAME}></th>
            <th class="txtcenter"><{$smarty.const._AM_SYSTEM_USERS_EMAIL}></th>
            <th class="txtcenter"><{$smarty.const._AM_SYSTEM_USERS_REG_DATE}></th>
            <th class="txtcenter"><{$smarty.const._AM_SYSTEM_USERS_LAST_LOGIN}></th>
            <th class="txtcenter"><{$smarty.const._AM_SYSTEM_USERS_POSTS}></th>
            <th class="txtcenter" width='11%'><{$smarty.const._AM_SYSTEM_USERS_ACTION}></th>
        </tr>
        </thead>
        <!--Display data-->
        <{if $users_count == true}>
        <form name='memberslist' id='memberslist' action='<{$php_selft}>' method='POST'>
        <tbody>
        <{foreach item=users from=$users}>
        <tr class="<{cycle values='even,odd'}> alignmiddle">
            <td class="txtcenter"><{if $users.checkbox_user}><input type='checkbox' name='memberslist_id[]' id='memberslist_id[]' value='<{$users.uid}>' /><{/if}></td>
            <td class="txtcenter"><img class="xo-imgmini" src="<{$users.group}>" alt="" /></td>
            // -----------加入下面這一行------------
            <td class="txtcenter"><{$users.name}></td>
            // --------------------------------------------
            <td class="txtcenter"><{$users.uname}></td>
            <td class="txtcenter"><{$users.email}></td>
            <td class="txtcenter"><{$users.reg_date}></td>
            <td class="txtcenter"><{$users.last_login}></td>
            ......