[PHP] ウェブサイト

会員登録


会員登録の最初のページ読み込み時

1. [セキュリティ] ドメインチェック

if ($_SERVER['HTTP_HOST'] != 'domain'){
  exit('許可されていないドメインです。');
}

2. ログインセッションチェック (ログイン状態の場合はメインページへ強制移動)

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. 利用規約への同意

JavaScriptを利用して該当チェックボックスがチェックされているか確認後に進める。

ログイン

1. ログインデータの送信

: フォームタグを利用してID、パスワードを送信

2. [セキュリティ] ドメインチェック

if ($_SERVER['HTTP_HOST'] != 'domain'){
  exit('許可されていないドメインです。');
}

3. 外部から生成されたフォームデータの送信防止

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インジェクション防止

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

$backurl = trim( $_POST['backurl'] );
if (!$backurl) {
	$backurl = trim( $_GET['backurl'] ); // ログイン完了後に戻るURL
}
$backurl = xss_replace($backurl); // クロスサイトスクリプト防止関数による文字列処理

if (!$backurl) {
	$backurl = 'メインアドレス設定'; // 戻るURLがない場合はメインアドレスに設定
}

5. ハッシュ化

$encode_pw = sha1($pw);


6. セッションを利用した連続ログイン遅延処理

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チェック

クッキーを利用したIPチェック + ログイン回数制限(10回以下) > 10分間制限を設ける(クッキーにログイン時間を保存して処理)

8. ログインマクロチェック

総当たり攻撃(ブルートフォース)によるハッキング防止

9. 実際のユーザーチェック

ユーザーが存在するか、退会済みユーザーではないか、パスワードが合っているか。該当部分はクエリでチェックしても良いし、PHP内部でチェックしても良い。

10. 海外IP遮断ユーザーチェック

海外IP遮断による迂回ハッキング防止。

11. ログイン失敗回数累積5回以上でログイン不可 > パスワード検索へ誘導

ログイン失敗回数が5回以上の場合、パスワード検索ページへリダイレクト

12. ログイン開始

セッション生成。

13. ユーザー情報の最終ログイン情報更新

session_id、ログイン失敗回数、ログイン日付、ログインIP

14. ログイン履歴追加

ログイン履歴テーブルにログイン記録を残します。

15. かんたん会員、Facebook会員チェック

正会員転換メニューへ強制移動。

16. パスワード変更チェック

パスワード変更後、90日が経過したか確認します。

MySQL

1. Insertがエラーになった場合でもauto_increment値は増加している。

実際、MySQLiを利用してinsertクエリを投げた後、duplicateなどのエラーでレコードが追加されなくても、該当auto_incrementキー値は+1増加している。

次のarticleでは、これを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


3. globalとは何ですか?

globalは、関数内で使用する変数がグローバル変数と同じ名前の時に、グローバル変数を使えるようにしてくれるものです。

iOS側のコードにおけるself.変数名のような感覚だと考えると分かりやすいです。

参考資料


[SERVER]

$_SERVER['REQUEST_URI'] = 現在のページのURLからドメインを除外したもの = index.phpuser=&name=

$_SERVER['PHP_SELF'] = 現在のページのURLからドメインと送信値を除外したもの = 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ループのために最大の値を指定する時は、ループの中に入れないで

$max = count($array)をforループが始まる前に使用しよう。

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を一緒に使う ことを忘れないようにしよう。

locationが変わったにもかかわらず、スクリプトはそのまま進行してしまう。


変数は事前に初期化して使用しよう。そうしないと非常に遅い。


エラーを見えなくする@は非常に遅い

単純な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