[PHP] 網站

會員註冊


會員註冊首頁載入時

1. [安全] 網域檢查

if ($_SERVER['HTTP_HOST'] != 'domain'){
  exit('不允許的網域。');
}

2. 登入 Session 檢查 (若為登入狀態,強制移動至首頁)

if($_SESSION['session_id']){
    header('Location: '.$url);
    exit;
}

3. SSL 相關處理

if(!isset($_SERVER["HTTPS"])){
    $url = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
header('Location: '.$url);
}


4. i-Pin 認證,本人認證(手機)

此部分使用 form 標籤建立相關請求,並處理回傳值。


5. 同意使用條款 </span>

使用 JavaScript 確認該核取方塊是否已勾選後再進行下一步。

登入

1. 傳送登入資料

:使用表單標籤傳送帳號、密碼。

2. [安全] 網域檢查

if ($_SERVER['HTTP_HOST'] != 'domain'){
  exit('不允許的網域。');
}

3. 防止外部產生的表單資料傳送 </span>

function referer(){

	$http_referer = str_replace('http://','',$_SERVER['HTTP_REFERER']);
	$http_referer = str_replace('https://','',$http_referer);

	$referer = explode('/',$http_referer);

	if ($referer[0] <> $_SERVER['HTTP_HOST']) {

		//使用警告視窗指令碼處理較方便 echo '....';
		exit;
	}

}

4. 確認傳入的值

$user_id = trim( $_POST['userid'] );

$user_id= $mysqli_accountdb_s1->real_escape_string( $userid );// 防止 SQL Injection

$pw = trim( $_POST['password'] );

$backurl = trim( $_POST['backurl'] );
if (!$backurl) {
	$backurl = trim( $_GET['backurl'] ); // 登入完成後返回的 URL
}
$backurl = xss_replace($backurl); // 透過防止跨站指令碼(XSS)函式處理字串

if (!$backurl) {
	$backurl = '設定主網址'; // 若無返回 URL,則設定為主網址
}

5.雜湊處理

$encode_pw = sha1($pw);


6. 使用 Session 處理連續登入延遲

if($_SESSION['ss_logintime'] != '') {
	$chk_time = mktime(date("H"),date("i"),date("s")-10,date("m"),date("d"),date("Y"));

	if ($chk_time < strtotime($_SESSION['ss_logintime'])) {
		$msg = "正在登入中,請稍候。";
		msg($msg); // 顯示通知
		ob_flush();
		flush();
		sleep(2);
	}
}

$_SESSION['ss_logintime'] = date('Y-m-d H:i:s');

7. IP 檢查

利用 Cookie 進行 IP 檢查 + 限制登入次數 (10次以下) > 限制 10 分鐘 (將登入時間寫入 Cookie 處理)

8. 登入機器人檢查

防止利用暴力破解法進行駭客攻擊。

9. 實際使用者檢查

確認使用者是否存在、是否為已註冊使用者、密碼是否正確。此部分可透過 Query 檢查,或在 PHP 內部檢查。

10. 海外 IP 封鎖檢查

透過封鎖海外 IP 防止繞道駭客攻擊。

11. 登入失敗次數累計 5 次以上禁止登入 > 引導至忘記密碼

若登入失敗次數超過 5 次,則重新導向至忘記密碼頁面。

12. 開始登入

建立 Session。

13. 更新使用者資訊與最終登入資訊

session_id、登入失敗次數、登入日期、登入 IP。

14. 新增登入紀錄

在登入歷史資料表中寫入登入紀錄。

15. 簡易會員、Facebook 會員檢查

強制移動至轉換為正式會員的選單。

16. 檢查密碼變更

確認密碼是否已超過 90 天未變更。

MySQL

1. 即使 Insert 發生錯誤,auto_increment 值仍會增加。

實際上,使用 MySQLi 執行 insert 查詢後,即使因為 duplicate 等錯誤導致紀錄未寫入,該 auto_increment 鍵值仍會 +1 增加。

在下一篇文章中稱此為 MySQL 臭蟲。

(http://desmart.com/blog/be-careful-with-mysqls-auto-increment-how-we-ended-up-losing-data)

QA

1. &#65279

若螢幕上顯示以下代碼,且未顯示預期的 echo 值。 &#65279;

這是「編碼問題」。

解決方法是使用 Notepad++ 將該檔案的編碼轉換為 UTF-8 (無 BOM) 即可解決。

2. 若要在 HTML 檔案中執行 PHP 程式碼

(1) 在 httpd.conf 檔案內輸入以下內容:

AddHandler application/x-httpd-php .html


(2) 在 .htaccess 檔案內輸入以下內容:


AddType application/x-httpd-php .html


global 是什麼?

global 是當函數中使用的變數名稱與全域變數相同時,用來存取全域變數的語法。

在 iOS 的程式碼中,可以想成類似 self.變數名稱 的感覺。

參考事項


[SERVER]

$_SERVER['REQUEST_URI'] = 當前頁面網址中扣除網域的部分 = index.phpuser=&name=

$_SERVER['PHP_SELF'] = 當前頁面網址中扣除網域與傳遞參數的部分 = index.php

[required or required_once, include or include_once]

原先使用 required、include,後來改用 required_once、include_once。

使用這些 API 的原因是為了避免重複定義函數。

不過,據說這些 API 會拖慢速度。

因此,據說採取以下方式較好:

if (!defined('MyIncludeName')) {
    require('MyIncludeName');
    define('MyIncludeName', 1);
}

以下是測試比較結果:



php                  hhvm


if



defined



0.18587779998779



0.046600103378296


require_once


1.2219581604004



3.2908599376678


[額外建議 (TIP)]


echo 比 print 快。


包覆字串時,單引號(') 比雙引號(") 快。

原因是 PHP 會在雙引號中尋找變數,而在單引號中則不會。

若字串中沒有變數,請使用單引號。


請使用預先計算好的值。在 for 迴圈中設定最大值時,請不要將計算放在迴圈內:

請在 for 迴圈開始前先使用 $max = count($array)

for($x=0;$x<count($array);$x++) ==> for($x=0;$x<$max;$x++)

為了釋放記憶體, 大型陣列必須使用 unset null 處理。

str_replace 比 preg_replace 快。 str_replace 通常是首選,但 strstr 在某些大型字串處理時有時更快。在 str_replace 中使用陣列通常比使用多次 str_replace 更快。


else if 語法比 switch 快。


使用完後請關閉資料庫連線。


$row['id'] 比 $row[id] 快 7 倍。 如果不使用單引號,系統必須猜測你指的是什麼索引。


宣告 PHP 時請使用 <?php ... ?>,其他樣式皆為不規範。



請使用嚴格的程式碼,避免隱藏 notice、warning 和 error。這樣能產生更乾淨的程式碼並降低負載。 考慮隨時開啟 error_reporting(E_ALL)。



使用 header('location:'.$url); 時,請記得同時使用 exit。 即使位置已切換,指令碼仍會繼續執行。


變數請先初始化再使用,否則會非常慢。


用來隱藏錯誤的 @ 符號非常慢。

執行單純 SELECT 功能時建議使用 GET 方法,而 UPDATE 功能則建議使用 POST。

因為 GET 會被快取,速度相對較快。(POST 不會被快取)

PHP 5.2.9 不支援將 array() 寫成 '[ ]',請注意。

若現有原始碼使用 '[ ]' 來定義陣列,在 5.2.9 版本中必須改為 array()。

Do not use preg_match()

if you only want to check if one string is contained in another string.

Use strpos() or strstr() instead as they will be faster.

</span>

AD