PHP面試複習知識點(超級全面,由淺入深)

本教程是本人基於 360大牛:全面解讀PHP面試的課程所作的筆記,加上我我的對一些其餘知識的補充,聚集了一些其餘教程聚集。衆人智慧結晶,我的總結所得
轉載請註明出處 PHP面試複習知識點(超級全面,由淺入深)

PHP基礎知識

false的七種狀況

  1. 整型0
  2. 浮點0.0
  3. 布爾false
  4. 空字符串'',""
  5. 字符串'0'
  6. 空數組[]
  7. NULL
字符串和數字用等於模糊判斷時,字符串會被先轉換成數字再進行對比

示例代碼eq.phpphp

<?php
$arr = [
    "'0e123' == ''" => '0e123' == '',
    "'0e123' == '0'" => '0e123' == '0',
    "'0e123' == 0" => '0e123' == 0,
    "'0e123' == 'e'" => '0e123' == 'e',
    "'0e123' == '000'" => '0e123' == '000',
    "'1e123' == '1'" => '1a000e123' == '1',
    "'1e123' == 1" => '1a000e123' == 1,
    "'000e123' == '0'" => '000e123' == '0',
    "'e123' == 0" => 'a123' == 0,
    "'e123' == '0'" => 'a123' == '0',
    "null == 0" => null == 0,
    "null == '0'" => null == '0',
    "null == false" => null == false,
    "[] == 0" => [] == 0,
    "[] == '0'" => [] == '0',
    "[] == false" => [] == false,
    "false == 0" => false == 0,
    "false == '0'" => false == '0',
];
foreach ($arr as $key => $value) {
    echo '( ' . $key . ' ) => ' . ($value === true ? 'true' : 'false') . PHP_EOL;
}

輸出結果css

( '0e123' == '' ) => false
( '0e123' == '0' ) => true
( '0e123' == 0 ) => true
( '0e123' == 'e' ) => false
( '0e123' == '000' ) => true
( '1e123' == '1' ) => false
( '1e123' == 1 ) => true
( '000e123' == '0' ) => true
( 'e123' == 0 ) => true
( 'e123' == '0' ) => false
( null == 0 ) => true
( null == '0' ) => false
( null == false ) => true
( [] == 0 ) => false
( [] == '0' ) => false
( [] == false ) => true
( false == 0 ) => true
( false == '0' ) => true

超全局數組

  1. $GLOBALS,包含下面8個超全局數組的值
  2. $_GET
  3. $_POST
  4. $_REQUERT,包含$_GET,$_POST,$_COOKIE
  5. $_SEESION
  6. $_COOKIE
  7. $_SERVER
$_SERVER['SERVER_ADDR'] //服務器地址
$_SERVER['SERVER_NAME'] //服務名稱
$_SERVER['REQUEST_TIME'] //請求時間
$_SERVER['QUERY_STRING'] //請求地址中問號後的內容
$_SERVER['HTTP_REFERER'] //上次請求地址
$_SERVER['HTTP_USER_AGENT'] //瀏覽器信息
$_SERVER['REMOTE_ARRR'] //客戶端請求ip
$_SERVER['REQUEST_URI'] // 請求中腳本名稱
$_SERVER['PATH_INFO'] // 請求中路徑
  1. $_FIELS
  2. $_ENV

null的三種狀況

  1. 直接賦值NULL
  2. 未定義變量
  3. unset銷燬後的變量

常量

必定定義,不可刪除和修改html

  1. const 更快,是語言結構,可定義類常量
  2. define 是函數

預約義常量

  1. FILE 文件所在路徑+文件名
  2. LINE 所在代碼行
  3. DIR 所在文件夾路徑
  4. FUNCTION 方法名
  5. CLASS 類名
  6. TRAIT TRAIT的名稱
  7. METHOD 類名+方法名
  8. NAMESPACE 命名空間名

引用變量

用不一樣名字訪問同一個變量內容,用『&』符號表示前端

抽象類和接口

抽象類(abstract):

  1. 定義爲抽象的類不能被實例化.
  2. 任何一個類,若是它裏面至少有一個方法是被聲明爲抽象的,那麼這個類就必須被聲明爲抽象的。
  3. 被定義爲抽象的方法只是聲明瞭其調用方式(參數),不能定義其具體的功能實現。
  4. 繼承一個抽象類的時候,子類必須定義父類中的全部抽象方法;另外,這些方法的訪問控制必須和父類中同樣(或者更爲寬鬆)。
  5. 例如某個抽象方法被聲明爲受保護的,那麼子類中實現的方法就應該聲明爲受保護的或者公有的,而不能定義爲私有的。此外方法的調用方式必須匹配,即類型和所需參數數量必須一致。例如,子類定義了一個可選參數,而父類抽象方法的聲明裏沒有,則二者的聲明並沒有衝突。
  6. 這也適用於 PHP 5.4 起的構造函數。在 PHP 5.4 以前的構造函數聲明能夠不同的.

示例代碼abstract_class.phpmysql

<?php
abstract class Animal {
    protected $name = 'animal';

    abstract public function call();

    abstract public function run();

    public function getName() {
        return $this->name;
    }
}

class Cat extends Animal {
    protected $name = 'cat';

    public function call() {
        echo $this->getName() . ': 喵喵叫~' . PHP_EOL;
    }

    public function run() {
        echo $this->getName() . '在跑~' . PHP_EOL;
    }
}

class Dog extends Animal {
    protected $name = 'dog';

    public function call() {
        echo $this->getName() . ': 汪汪叫~' . PHP_EOL;
    }

    public function run() {
        echo $this->getName() . '在跑~' . PHP_EOL;
    }
}

$cat = new Cat;
$cat->call();
$cat->run();

$dog = new Dog;
$dog->call();
$dog->run();

運行結果:react

cat: 喵喵叫~
cat在跑~
dog: 汪汪叫~
dog在跑~

接口(interface):

  1. 使用接口(interface),能夠指定某個類必須實現哪些方法,但不須要定義這些方法的具體內容。
  2. 接口是經過 interface 關鍵字來定義的,就像定義一個標準的類同樣,但其中定義全部的方法都是空的。
  3. 接口中定義的全部方法都必須是公有,這是接口的特性。
  4. 要實現一個接口,使用 implements 操做符。類中必須實現接口中定義的全部方法,不然會報一個致命錯誤。類能夠實現多個接口,用逗號來分隔多個接口的名稱。
  5. 實現多個接口時,接口中的方法不能有重名。
  6. 接口也能夠繼承,經過使用extends操做符.
  7. 類要實現接口,必須使用和接口中所定義的方法徹底一致的方式。不然會致使致命錯誤.

示例代碼interface_class.phpnginx

<?php
interface Animal {
    public function call();
    public function run();
}

class HasName {
    protected $name = 'name';

    public function getName() {
        return $this->name;
    }
}

class Cat extends HasName implements Animal {
    protected $name = 'cat';

    public function call() {
        echo $this->getName() . ': 喵喵叫~' . PHP_EOL;
    }

    public function run() {
        echo $this->getName() . '在跑~' . PHP_EOL;
    }
}

class Dog  extends HasName implements Animal {
    protected $name = 'dog';

    public function call() {
        echo $this->getName() . ': 汪汪叫~' . PHP_EOL;
    }

    public function run() {
        echo $this->getName() . '在跑~' . PHP_EOL;
    }
}

輸出結果laravel

cat: 喵喵叫~
cat在跑~
dog: 汪汪叫~
dog在跑~

區別:

  1. 對接口的繼承使用implements,抽象類使用extends
  2. 接口中不能夠聲明變量,但能夠聲明類常量.抽象類中能夠聲明各類變量
  3. 接口沒有構造函數,抽象類能夠有
  4. 接口中的方法默認爲public,抽象類中的方法能夠用public,protected,private修飾
  5. 一個類能夠繼承多個接口,但只能繼承一個抽象類
  6. 接口的定義用interface,抽象類定義用abstract

運算符優先級

優先級由高到低排序
  1. ==遞增/遞減==
  2. 非(!)
  3. ==算術運算符==
  4. ==大小比較==
  5. (不)相等比較
  6. 引用
  7. 位運算符(^)
  8. 位運算符(|)
  9. ==邏輯與==
  10. ==邏輯或==
  11. ==三目==
  12. ==賦值==
  13. and
  14. oxr
  15. or

浮點數值得精度丟失問題

緣由:由於計算機存儲是二進制,準換進制時會有精度丟失git

解決方案:先將浮點字符串化,再進行整數獲取,輸出可經過printgithub

$f = 0.57;
$f = $f * 100;
// 輸入可經過print
printf('%d', $f);

// 用於存儲或二次計算,先將浮點字符串化,再進行整數獲取
$f = strval($f);
var_dump($f);
echo floor($f);
echo intval($f);
echo (int)($f);

switch 只能判斷整型、浮點、字符

變量類型

  1. 普通變量
  2. 全局變量,經過global定義,能夠在局部域調用全局變量,可經過$GLOBAL['XXX']讀取變量的值
  3. 靜態變量,經過static定義,僅在局部域中存在,執行函數離開做用域,其值也不會消失

ip處理函數

  1. ip2long()
  2. long2ip()

示例代碼ip.php

<?php
$ip = '192.168.1.1';
echo $ip. ' => ' . ip2long($ip) . ' => ' . long2ip(ip2long($ip));

// 輸出
// 192.168.1.1 => 3232235777 => 192.168.1.1

時間日期處理函數

  1. date()
  2. strtotime()
  3. mktime()
  4. time()
  5. microtime()
  6. date_default_timezone_set()

打印處理

  1. print() 僅輸出單個變量
  2. printf() 按格式輸出
  3. print_r() 格式化輸出
  4. echo 輸出多個變量
  5. sprintf() 按格式返回
  6. var_dump() 格式化輸出,並輸出變量類型
  7. var_export() 將格式化輸出,加true可返回,返回內容可直接作變量使用

示例代碼print.php

<?php
print('aaaaaa');
echo PHP_EOL;
printf("%s:%2.2f", 'sada', 111.222);
echo PHP_EOL;
print_r([1, 2]);
echo PHP_EOL;
echo 11;
echo PHP_EOL;
echo sprintf("%s:%2.2f", 'sada', 111.222);
echo PHP_EOL;
var_dump([1, 2]);
echo PHP_EOL;
var_export([1, 2]);
echo PHP_EOL;
echo var_export([1, 2], true);
echo PHP_EOL;

輸出結果

aaaaaa
sada:111.22
Array
(
    [0] => 1
    [1] => 2
)

11
sada:111.22
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}

array (
  0 => 1,
  1 => 2,
)
array (
  0 => 1,
  1 => 2,
)

序列化

  1. serialize()
  2. unserialize()

示例代碼serialize.php

<?php
$a = 'klinson';
echo $a . ' =>' . serialize($a) . ' => ' . unserialize(serialize($a));

輸出結果

klinson => s:7:"klinson"; => klinson

字符串處理

  1. implode(),join()
  2. explode()
  3. strrev() 反轉字符
  4. trim(),ltrim(),rtrim()
  5. strstr() 獲取第一次出現指定字符串的字符串
  6. number_format() 數字格式化爲金錢格式

示例代碼string.php

<?php
$str = 'klinson';
$array = explode('n', $str);
var_dump($array, join('n', $array), implode('n', $array));
echo 'strrev(\'klinson\') => ' . strrev($str) . PHP_EOL;
$str = ' klinson ';
var_dump(trim($str), ltrim($str), rtrim($str));
echo 'strstr(\'klinson\', \'n\') => '.strstr($str, 'n') . PHP_EOL;
echo 'number_format(100000000000) => ' . number_format(100000000000) . PHP_EOL;

輸出結果

array(3) {
  [0]=>
  string(3) "kli"
  [1]=>
  string(2) "so"
  [2]=>
  string(0) ""
}
string(7) "klinson"
string(7) "klinson"
strrev('klinson') => nosnilk
string(7) "klinson"
string(8) "klinson "
string(8) " klinson"
strstr('klinson', 'n') => nson 
number_format(100000000000) => 100,000,000,000

數組處理

  1. array_keys()
  2. array_values()
  3. array_diff()
  4. array_merge()
  5. array_shift()
  6. array_unshift()
  7. array_pop()
  8. array_push()
  9. sort(), rsort() 對數組升降序排序
  10. asort(),arsort() 對數組鍵值升降序排序,並保持索引關係
  11. ksort(),krsort() 對數組鍵名升降序排序

文件操做

fopen() 打開文件並指定模式

  1. r/r+ 只讀打開/讀寫打開,指針在文件開頭
  2. w/w+ 只寫打開/讀寫打開,文件存在會清空,不存在會建立
  3. a/a+ 寫入追加寫入/讀寫的追加寫入,指針在文件末尾
  4. x/x+ 寫入/讀寫打開,指針開頭,文件存在返回false,不存在就直接建立
  5. b 二進制打開

寫入

  1. fwrite()
  2. fputs()

讀取

  1. fread() 獲取指定長度字符
  2. fgets() 獲取一行字符
  3. fgetc() 獲取一個字符

關閉 fopen()

文件大小 filesize()

文件複製 copy()

文件刪除 unlink()

文件類型 filetype()

重命名或移動 rename()

文件屬性

  1. file_exist()
  2. is_readable()
  3. is_writable()
  4. is_executable()
  5. filectime() 建立時間
  6. fileatime() 訪問時間
  7. filemtime() 更新時間

其餘不須要fopen()打開的函數

  1. file_get_contents()
  2. file_put_contents()

其餘

  1. file()整個文件內容按行讀取到一個數組裏
  2. readfile()整個文件讀取出來,並輸出

遠程訪問

php.ini中打開allow_url_fopen配置,http協議只能使用只讀,ftp協議,只能只讀或只寫

目錄操做

名稱相關

  1. basename() 文件基礎名稱
  2. dirname() 文件夾名稱
  3. pathinfo() 文件信息數組

示例代碼fileinfo.php

<?php
$filepath = __FILE__;
echo '__FILE__ => ' . $filepath . PHP_EOL;
echo 'basename(__FILE__) => ' . basename($filepath) . PHP_EOL;
echo 'dirname(__FILE__) => ' . dirname($filepath) . PHP_EOL;
echo  'pathinfo(__FILE__) => ' . PHP_EOL;
var_dump(pathinfo($filepath));

輸出結果

__FILE__ => /home/wwwroot/default/public/index0.php
basename(__FILE__) => index0.php
dirname(__FILE__) => /home/wwwroot/default/public
pathinfo(__FILE__) => 
array(4) {
  ["dirname"]=>
  string(28) "/home/wwwroot/default/public"
  ["basename"]=>
  string(10) "index0.php"
  ["extension"]=>
  string(3) "php"
  ["filename"]=>
  string(6) "index0"
}

目錄讀取

  1. opendir()
  2. readdir()
  3. closedir()
  4. rewinddir() 重置句柄
  5. disk_free_space()
  6. disk_total_space()

目錄刪除 rmdir()

目錄必須爲空

目錄建立 mkdir()

重命名或移動 rename()

設計模式

  1. 工廠模式

    工廠模式能夠將對象的生產從直接new 一個對象,改爲經過調用一個工廠方法生產。這樣的封裝,代碼若需修改new的對象時,不需修改多處new語句,只需更改生產對象方法

    示例代碼factory.php

    <?php
    /*** Interface people 人類
     */
    interface  people
    {
        public function  say();
    }
    
    /*** Class man 繼承people的男人類
     */
    class man implements people
    {
        // 實現people的say方法
        function say()
        {
            echo '我是男人-hi' . PHP_EOL;
        }
    }
    
    /* Class women 繼承people的女人類
     */
    class women implements people
    {
        // 實現people的say方法
        function say()
        {
            echo '我是女人-hi' . PHP_EOL;
        }
    }
    
    /* Interface createPeople 建立人物類
     */
    interface  createPeople
    {
        public function create();
    
    }
    
    /* Class FactoryMan 繼承createPeople的工廠類-用於實例化男人類
     */
    class FactoryMan implements createPeople
    {
        // 建立男人對象(實例化男人類)
        public function create()
        {
            return new man();
        }
    }
    
    /* Class FactoryMan 繼承createPeople的工廠類-用於實例化女人類
     */
    class FactoryWomen implements createPeople
    {
        // 建立女人對象(實例化女人類)
        function create()
        {
            return new women();
        }
    }
    
    class  Client
    {
        // 具體生產對象並執行對象方法測試
        public function test() {
            $factory = new FactoryMan();
            $man = $factory->create();
            $man->say();
    
            $factory = new FactoryWomen();
            $man = $factory->create();
            $man->say();
        }
    }
    
    // 執行
    $demo = new Client;
    $demo->test();

    輸出結果

    我是男人-hi
    我是女人-hi

    參考PHP設計模式之工廠模式

  2. 單例模式

    用於爲一個類生成一個惟一的對象

    示例代碼singleton.php

    <?php
    class Db
    {
        protected static $instance;
    
        public static function getInstance($config = [])
        {
            if (is_null(self::$instance)) {
                self::$instance = new self($config);
            }
            return self::$instance;
        }
    
        public function __construct($config = [])
        {
            // TODO:: 數據庫鏈接操做
    
            echo '這裏已經完成數據庫的鏈接!' . PHP_EOL;
        }
    
        public function getData($table)
        {
            // TODO:: 數據庫讀取數據操做
    
            echo "這裏獲取了表 [ {$table} ] 的數據了!" . PHP_EOL;
        }
    }
    
    Db::getInstance()->getData('klinson0');
    Db::getInstance()->getData('klinson1');
    Db::getInstance()->getData('klinson2');

    輸出結果

    已經完成數據庫的鏈接!
    這裏獲取了表 [ klinson0 ] 的數據了!
    這裏獲取了表 [ klinson1 ] 的數據了!
    這裏獲取了表 [ klinson2 ] 的數據了!
  3. 適配器模式

    適配器模式將一個類的接口轉換成客戶但願的另一個接口,使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠在一塊兒工做

    示例代碼adapter.php

    <?php
    /* 微博提供的登陸類
*/
class Weibo {
    public function myLogin($username,$password){
        echo $username.' is logining weibo with password '. $password. PHP_EOL;
    }
}

/* 微信提供的登陸類
 */
class Weixin {

    public function login2($config){
        echo $config['username'].' is logining weixin with password '. $config['password']. PHP_EOL;
    }
}

/* 咱們設計的適配器接口
 */
interface Adapter {
    public function login($username, $password);
}

/* 微博的適配器
 */
class WeiboAdapter extends Weibo implements Adapter {

    public function login($username, $password) {
        $this->myLogin($username, $password);
    }
}

/* 微信的適配器類
 */
class WeixinAdapter extends WeiXin implements Adapter {

    public function login($username, $password) {
        $this->login2(['username'=>$username, 'password'=> $password]);
    }
}

/* 主業務類
 */

class User {
    private $adapter;

    public function setAdapter(Adapter $adapter) {
        $this->adapter = $adapter;
    }

    public function login($username, $password){
        $this->adapter->login($username, $password);
    }
}

$weiboUser = new User();
// 實例化微博適配器
$adapter = new WeiboAdapter();
// 設置適配器
$weiboUser->setAdapter($adapter);
$weiboUser->login('klinson', '123456');

$Wxuser = new User();
// 實例化微博適配器
$adapter = new WeixinAdapter();
// 設置適配器
$Wxuser->setAdapter($adapter);
$Wxuser->login('klinson', '123456');
```

輸出結果
```
klinson is logining weibo with password 123456
klinson is logining weixin with password 123456
```
  1. 觀察者模式

    觀察者模式有時也被稱做發佈/訂閱模式,該模式用於爲對象實現發佈/訂閱功能:一旦主體對象狀態發生改變,與之關聯的觀察者對象會收到通知,並進行相應操做。

    將一個系統分割成一個一些類相互協做的類有一個很差的反作用,那就是須要維護相關對象間的一致性。咱們不但願爲了維持一致性而使各種緊密耦合,這樣會給維護、擴展和重用都帶來不便。觀察者就是解決這類的耦合關係的。

    消息隊列系統、事件都使用了觀察者模式。

    PHP 爲觀察者模式定義了兩個接口:SplSubject 和 SplObserver。SplSubject 能夠看作主體對象的抽象,SplObserver 能夠看作觀察者對象的抽象,要實現觀察者模式,只需讓主體對象實現 SplSubject ,觀察者對象實現 SplObserver,並實現相應方法便可。

    參考PHP 設計模式系列 —— 觀察者模式(Observer)

  2. 策略模式

    定義一系列算法,將每個算法封裝起來,並讓它們能夠相互替換。策略模式讓算法獨立於使用它的客戶而變化,也稱爲政策模式(Policy)

    參考PHP設計模式(十二)—策略模式 ( Strategy Pattern ) PHP設計模式之策略模式

  3. 註冊樹模式
    註冊模式(Registry)也叫作註冊樹模式,註冊器模式。註冊模式爲應用中常用的對象建立一箇中央存儲器來存放這些對象 —— 一般經過一個只包含靜態方法的抽象類來實現(或者經過單例模式)。參考laravel框架的app()定義

    示例代碼register.php

    <?php
    class Register
    {
        // 樹的枝幹-用於儲存樹上的果實(實例)
        public static $objects;
    
        /** 將實例插入註冊樹中
         *
         ** @param $alias 對象別名-註冊樹中的名稱
         ** @param $object 對象實例
         */
        public static function set($alias, $object)
        {
            self::$objects[$alias] = $object;
        }
    
        /**
         ** 從註冊樹中讀取實例
         *
         ** @param $alias 對象別名-註冊樹中的名稱
         *
         ** @return mixed 返回的對象實例
         */
        public static function get($alias)
        {
            if (isset(self::$objects[$alias])) {
                return self::$objects[$alias];
            } else {
                echo '您要找的對象實例不存在哦' . PHP_EOL;
                return false;
            }
    
        }
    
        /**
         ** 銷燬註冊樹中的實例
         *
         ** @param $alias 對象別名-註冊樹中的名稱
         */
        public static function unset($alias)
        {
            unset(self::$objects[$alias]);
        }
    }
    
    /**
     ** Class demo 演示類
     */
    class demo
    {
        /*
         ** 測試方法
         */
        public function test()
        {
            echo '看這裏看這裏' . PHP_EOL;
        }
    }
    
    // 實例化測試類,獲取對象實例
    $demo = new demo();
    // 註冊到樹上
    $tree = Register::set('demo', $demo);
    // 取出來
    $de_true = Register::get('demo');
    // 測試
    $de_true->test();
    // 銷燬
    Register::unset('demo');
    // 嘗試再次取出來
    $de_true_two = Register::get('de');
    // 嘗試再次測試
    var_dump($de_true_two);

    輸出結果

    看這裏看這裏
    您要找的對象實例不存在哦
    bool(false)

    參考PHP設計模式之註冊樹模式

魔術方法

  1. __construct()
  2. __destruct()
  3. __call()
  4. __callStatic()
  5. __get()
  6. __set()
  7. __isset()
  8. __unset()
  9. __sleep()
  10. __wakeup()
  11. __toString()
  12. __close()

加密

對稱加密

對稱加密又叫作私鑰加密,即信息的發送方和接收方使用同一個密鑰去加密和解密數據

對稱加密的特色是算法公開、加密和解密速度快,適合於對大數據量進行加密

常見的對稱加密算法有DES、3DES、TDEA、Blowfish、RC5和IDEA。

其加密過程以下:明文 + 加密算法 + 私鑰 => 密文

解密過程以下:密文 + 解密算法 + 私鑰 => 明文

對稱加密中用到的密鑰叫作私鑰,私鑰表示我的私有的密鑰,即該密鑰不能被泄露。

其加密過程當中的私鑰與解密過程當中用到的私鑰是同一個密鑰,這也是稱加密之因此稱之爲「對稱」的緣由。因爲對稱加密的算法是公開的,因此一旦私鑰被泄露,那麼密文就很容易被破解,因此對稱加密的缺點是密鑰安全管理困難。

非對稱加密

非對稱加密也叫作公鑰加密。

非對稱加密與對稱加密相比,其安全性更好。對稱加密的通訊雙方使用相同的密鑰,若是一方的密鑰遭泄露,那麼整個通訊就會被破解。而非對稱加密使用一對密鑰,即公鑰和私鑰,且兩者成對出現。私鑰被本身保存,不能對外泄露。

公鑰指的是公共的密鑰,任何人均可以得到該密鑰。用公鑰或私鑰中的任何一個進行加密,用另外一個進行解密。

被公鑰加密過的密文只能被私鑰解密,過程以下:

明文 + 加密算法 + 公鑰 => 密文, 密文 + 解密算法 + 私鑰 => 明文

被私鑰加密過的密文只能被公鑰解密,過程以下:(私鑰加密,公鑰解密通常被用於數字簽名。數字簽名是用於防篡改和防止假冒的,由於只有一人擁有私鑰。甲方經過私鑰對數據進行簽名,乙方經過甲方的公鑰驗證簽名,若是成功,說明確實是甲方發來的,而且數據沒有被修改。一旦相反,公鑰是公開的,你們都能作簽名,就沒意義了)

明文 + 加密算法 + 私鑰 => 密文, 密文 + 解密算法 + 公鑰 => 明文

因爲加密和解密使用了兩個不一樣的密鑰,這就是非對稱加密「非對稱」的緣由。

非對稱加密的缺點是加密和解密花費時間長、速度慢,只適合對少許數據進行加密。

在非對稱加密中使用的主要算法有:RSA、Elgamal、Rabin、D-H、ECC(橢圓曲線加密算法)等。

hash算法(非加密算法)

  1. md5
  2. sha1

數據編碼方式

  1. base64
  2. 二進制

網絡協議

http狀態碼

  1. 200 請求成功
  2. 204 not content
  3. 206 reset content
  4. 301 永久重定向
  5. 302 臨時重定向
  6. 307 臨時重定向
  7. 400 錯誤請求
  8. 401 缺乏認證信息
  9. 403 拒絕
  10. 404 不存在
  11. 500 服務器異常
  12. 502 Bad Gateway
  13. 503 服務器超負載或停機維護

OSI七層協議

  1. 物理層 創建、維護、斷開物理鏈接
  2. 數據鏈路層 創建邏輯鏈接,進行硬件地址尋址,差錯校驗等功能
  3. 網絡層 進行邏輯地址尋址,實現不一樣網絡之間的路徑選擇
  4. 傳輸層 定義傳輸數據的協議端口號,一級流控和差錯校驗。協議有TCP/UDP,數據包一旦離開網卡即進入網絡傳輸層
  5. 會話層 創建、管理、終止會話
  6. 表示層 數據的表示、安全、壓縮
  7. 應用層 網絡服務與最終用戶的一個藉口,協議有:http(80),ftp(21),tftp,smtp(25),snmp,dns(53),telnet(23),https(443),pop3(110),dhcp

參考HTTP、TCP、UDP、Socket解讀

HTTP協議的工做特色和工做原理

工做特色:

  1. 基於B/S模式
  2. 通訊開銷小,簡單快速,傳輸成本低
  3. 使用靈活,可以使用超文本傳輸協議
  4. 節省傳輸時間
  5. 無狀態

工做原理:

客戶端發送請求給服務器,創建一個TCP鏈接,指定端口號,默認80,鏈接到服務器,服務器監聽到瀏覽器的請求,一旦監聽到客戶端的請求,分析請求類型後,服務器會向客戶端發送狀態信息和數據內容

HTTP協議常見請求頭/響應頭

  1. Content-Type 指定數據內容類型
  2. Accept 指定客戶端能接受數據內容類型
  3. Origin 最初請求來源(POST)
  4. Cookie
  5. Cache-Control 指定請求的緩存機制
  6. User-Agent 用戶瀏覽器信息
  7. Referrer 上級請求路徑
  8. X-Forwarded-For 請求端真實ip
  9. Access-Control-Allow-Origin 容許其餘請求域名,用於跨域
  10. Last-Modified 最後響應時間

HTTPS的工做原理

HTTPS是一種基於SSL/TLS的HTTP協議,全部的HTTP數據都是SSL/TLS協議封裝之上傳輸的

HTTPS是在HTTP協議的基礎上,添加了SSL/TLS握手一級數據加密傳輸,也屬於應用層協議

HTTPS爲了兼顧安全與效率,同時使用了對稱加密(快)和非對稱加密(慢)。數據是被對稱加密傳輸的,對稱加密過程須要客戶端的一個密鑰,爲了確保能把該密鑰安全傳輸到服務器端,採用非對稱加密對該密鑰進行加密傳輸,總的來講,對數據進行對稱加密,對稱加密所要使用的密鑰經過非對稱加密傳輸。

完整流程

如下圖片來源 圖解HTTPS

Image text

HTTPS在傳輸的過程當中會涉及到三個密鑰:

服務器端的公鑰和私鑰,用來進行非對稱加密

客戶端生成的隨機密鑰,用來進行對稱加密

一個HTTPS請求實際上包含了兩次HTTP傳輸,能夠細分爲8步。

  1. 客戶端向服務器發起HTTPS請求,鏈接到服務器的443端口
  2. 服務器端有一個密鑰對,即公鑰和私鑰,是用來進行非對稱加密使用的,服務器端保存着私鑰,不能將其泄露,公鑰能夠發送給任何人。
  3. 服務器將本身的公鑰發送給客戶端。
  4. 客戶端收到服務器端的公鑰以後,會對公鑰進行檢查,驗證其合法性,若是發現發現公鑰有問題,那麼HTTPS傳輸就沒法繼續。嚴格的說,這裏應該是驗證服務器發送的數字證書的合法性,關於客戶端如何驗證數字證書的合法性,下文會進行說明。若是公鑰合格,那麼客戶端會生成一個隨機值,這個隨機值就是用於進行對稱加密的密鑰,咱們將該密鑰稱之爲client key,即客戶端密鑰,這樣在概念上和服務器端的密鑰容易進行區分。而後用服務器的公鑰對客戶端密鑰進行非對稱加密,這樣客戶端密鑰就變成密文了,至此,HTTPS中的第一次HTTP請求結束。
  5. 客戶端會發起HTTPS中的第二個HTTP請求,將加密以後的客戶端密鑰發送給服務器。
  6. 服務器接收到客戶端發來的密文以後,會用本身的私鑰對其進行非對稱解密,解密以後的明文就是客戶端密鑰,而後用客戶端密鑰對數據進行對稱加密,這樣數據就變成了密文。
  7. 而後服務器將加密後的密文發送給客戶端。

8.客戶端收到服務器發送來的密文,用客戶端密鑰對其進行對稱解密,獲得服務器發送的數據。這樣HTTPS中的第二個HTTP請求結束,整個HTTPS傳輸完成。

mysql相關知識

數據表引擎

  1. innodb引擎

默認事務型引擎,最重要最普遍的存儲引擎,性能很是優秀

數據存儲在共享表空間,可經過配置分開

對主鍵查詢的性能高於其餘類型的存儲引擎

內部作了不少優化,從磁盤讀取數據時自動在內存構建hash索引,插入數據時自動構建插入緩衝區

經過一些機制和工具支持真正的熱備份

支持崩潰後的安全恢復

支持行級鎖

支持外鍵

  1. MyISAM引擎

5.1版本前是默認引擎

擁有全文索引、壓縮、空間函數

不支持事務和行級鎖,不支持奔潰後安全恢復

表存儲在兩個文件,MYD和MYI

設計簡單,某些場景下性能很好

  1. 其餘引擎:

Archive、Blackhole、CSV、Memory

MySQL鎖機制

當多個查詢同一時刻進行數據修改時,會產生併發控制的問題

  1. 共享鎖(讀鎖)
  2. 排他鎖(寫鎖)

鎖粒度

  1. 表鎖

系統性能開銷最小,會鎖定整張表,myisam使用表鎖

  1. 行鎖

最大程度的支持併發處理,可是也帶來了最大的鎖開銷,innodb實現行級鎖

char與varchar

  1. char
char是定長的,根據定義的字符串長度分配足量空間
char會根據須要採用空格進行填充以方便比較
char適合存儲很短的字符串,或者全部值都接近同一個長度
char長度超過設定的長度,會被截斷
  1. varchar
varchar用於存儲可變長字符串,比定長類型更加節省空間
varchar使用1或2個額外字節記錄字符串的長度,列長度小於255字節用1個字節表示,不然用2個
varchar長度超過設定的長度,會被截斷
  1. 比較
對於常常變動的數據,char比varchar更好,char不容易產生碎片
對於很是短的列,char比varchar在存儲空間上更有效率
只分配真正須要的空間,更長的列會消耗更多的內存

索引

  1. 大大減小服務器須要掃描的數據量
  2. 幫助服務器避免排序和臨時表
  3. 將隨機I/O變順序I/O
  4. 大大提升查詢速度,下降寫的速度,佔用磁盤空間

索引類型

  1. 普通索引
  2. 主鍵索引
  3. 惟一索引
  4. 組合索引
  5. 外鍵索引
  6. 全文索引

索引建立原則

  1. 最適合索引的列是出如今where子句的列,或鏈接子句中的列,而不是出如今select的關鍵字後的列
  2. 索引列的基數越大,索引效果越好
  3. 對字符串進行索引,應指定一個前綴長度,能夠節省大量的索引空間
  4. 根據狀況建立複合索引,複合索引能夠提升查詢效率
  5. 避免建立過多索引,索引會額外佔用磁盤空間,減低寫操做效率
  6. 主鍵儘量選擇較短的數據類型,能夠有效減小索引的磁盤佔用,提升效率

索引的注意事項

  1. 複合索引遵循前綴原則
  2. like查詢,%不能在前,可使用全文索引
  3. column is null 可使用索引
  4. 若是MySQL估計使用索引比全表掃描更慢,會放棄使用索引

mysql優化

查詢速度慢的緣由

  1. 打開慢查詢日誌,經過pt-query-dugest分析
  2. show profile,經過set profiling=1;開啓,服務器上執行的全部語句消耗時間都會記錄到臨時表。show profile for query QUERY_ID查詢指定查詢
  3. show status,查詢一些計數器,猜出哪些代價高或消耗時間多
  4. show processlist,查詢線程狀態進行分析
  5. explain,分析單個SQL語句查詢

優化查詢過程當中的數據訪問

  1. 訪問數據太多致使性能降低
  2. 肯定應用程序是否檢索大量超過須要的數據,多是太多列或者行
  3. 肯定mysql是否分析大量沒必要要的數據行
  4. 查詢不須要的記錄,使用limit限制
  5. 奪標關聯返回所有列指定A.id,A.name
  6. 總數取出所有列,select * 會讓優化器沒法完成全部覆蓋掃碼的優化
  7. 重複查詢相同的數據,能夠緩存數據
  8. 改變數據庫和表的結構,修改數據表範式
  9. 重寫SQL語句,讓優化器能夠更優的執行

優化長可貴查詢語句

  1. MySQL內部每秒能掃描內存中上百萬行數據,相比之下,響應數據給客戶端就要慢得多
  2. 使用盡量少的查詢是好的,可是有時將一個大的查詢分解爲多個小的查詢是頗有必要的
  3. 分解關聯查詢,將一個關聯查詢分解爲多個sql來執行,讓緩存效率更高,執行單個查詢能夠減小鎖的競爭,在應用層作關聯能夠更容易對數據庫進行拆分,查詢效率會有大幅提高,較少冗餘記錄的查詢

優化特定類型的查詢語句

  1. 優化count()查詢,count(*)會忽略全部列,直接統計全部列數,所以不要用count(列名)
  2. 優化關聯查詢,肯定ON或者USING子句的列上有索引;確保GROUP BYORDER BY中只有一個表的列,這樣MySQL纔有可能使用索引
  3. 優化子查詢 建議使用關聯查詢替代
  4. 優化GROUP BYDISTINCT,創建索引進行優化
  5. 優化LIMIT分頁,能夠經過記錄上次查詢的最大ID,若是根據id排序時,下次查詢根據該ID來查詢(如:ID > maxID)
  6. 優化UNION查詢,UNION ALL性能比UNION

MySQL提高(高可擴展和高可用)

分區表

工做原理

對用戶而言,分區表是一個獨立的邏輯表,可是底層MySQL將其分紅了多個物理子表,對於用戶來講是透明的,每個分區表都會使用一個獨立的表文件。

建立表的時候使用partition by子句定義每一個分區存放的數據,執行查詢時,優化器會根據分區定義過濾那些沒有咱們須要數據的分區,這樣查詢只須要查詢所需數據在的分區便可

分區的主要目的是將數據按照一個較粗的粒度分在不一樣的表中,這樣能夠將相關的數據存放在一塊兒,並且若是想一次性刪除整個分區的數據也很方便

適用場景

  1. 表很是大,沒法所有存在內容,或者只有表的最後有熱點數據,其餘都是歷史數據
  2. 分區表的數據更易維護,能夠對獨立的分區進行獨立操做
  3. 分區表的數據能夠分佈在不一樣機器上,從而高效使用資源
  4. 可使用分區表來避免某些特殊瓶頸
  5. 能夠備份和恢復獨立分區

限制

  1. 一個表最多隻能有1024個分區
  2. 5.1版本中,分區表表達式必須是整數,5.5可使用列分區
  3. 分區字段中若是有主見和惟一索引列,那麼主鍵和惟一列都必須包含進來
  4. 分區表中沒法使用外鍵約束
  5. 須要對現有表的結構進行改變
  6. 全部分區都必須使用相同的存儲引擎
  7. 分區函數中可使用的函數和表達式會有一些限制
  8. 某些存儲引擎不支持分區
  9. 對於MyISAM的分區表,不能使用load index into cache
  10. 對於MyISAM表,使用分區表時須要打開更多的文件描述符

分庫分表

工做原理:

經過一些HASH算法或者工具實現將一張數據表垂直或者水平物理切分

適用場景

  1. 單表記錄條數達到百萬到千萬級別時
  2. 解決表鎖的問題

分別方式

  1. 水平切分:表很大,分割後能夠減低在查詢時須要讀的數據和索引的頁數,同時也減低了索引的層數,提升查詢速度
使用場景:
1. 表中數據自己就有獨立性,例如表中分別記錄各個地區的數據或者不一樣時期的數據,特別是有些數據經常使用,有些不經常使用
2. 須要把數據存放在多個介質

缺點:
1. 給應用增長複雜度,一般查詢時須要多個表名,查詢全部數據都須要UNION操做
2. 在許多數據庫應用中,這種複雜性會超過他帶來的優勢,查詢時會增長讀一個索引層的磁盤次數
  1. 垂直分表:把主鍵和一些列放在一個表,而後把主鍵和另外的列放在另外一張表中
使用場景:
1. 若是一個表中某些列經常使用,而另一些列不經常使用
2. 可使數據行變小,一個數據頁能存儲更多數據,查詢時減小I/O次數

缺點:
1. 管理冗餘列,查詢全部數據須要JOIN操做
2. 有些分表的策略基於應用層的邏輯算法,一旦邏輯算法改變,整個分表邏輯都會改變,擴展性較差
3. 對於應用層來講,邏輯算法無疑增長開發成本

主從複製

工做原理

  1. 在主庫上把數據更改記錄到二進制日誌
  2. 從庫將主庫的日誌複製到本身的中繼日誌
  3. 從庫讀取中繼日誌中的事件,將其重放到從庫數據中

解決問題

  1. 數據分佈:隨意中止或開始複製,並在不一樣地理位置分佈數據備份
  2. 負載均衡:減低單個服務器壓力
  3. 高可用和故障切換:幫助應用程序避免單點失敗
  4. 升級測試:可使用更高版本的MySQL做爲從庫

MySQL安全

安全操做

  1. 使用預處理語句防SQL這幾日
  2. 寫入數據庫的數據要進行特殊字符轉移
  3. 查詢錯誤信息不要返回給用戶,將錯誤記錄到日誌

安全設置

  1. 按期作數據備份
  2. 不給查詢用戶root權限,合理分配權限
  3. 關閉遠程訪問數據庫權限
  4. 修改root口令,不用默認口令,使用較複雜的口令
  5. 刪除多餘的用戶
  6. 改變root用戶的名稱
  7. 限制通常用戶瀏覽其餘庫
  8. 限制用戶對數據文件的訪問權限

MVC

MVC工做原理

  1. model 數據模型操做層,是應用程序中用於處理應用程序數據邏輯的部分
  2. view 視圖層,是應用程序中處理數據顯示的部分。
  3. controller 業務處理層,是應用程序中處理用戶交互的部分。

單一入口

工做原理

用一個處理程序文件處理全部的HTTP請求,根據請求時的參數的不一樣區分不一樣的模塊和操做請求

優點

  1. 能夠進行統一的安全性檢查
  2. 集中處理程序

劣勢

  1. URL不美觀(解決方法:URL重寫)
  2. 處理效率會下降(可忽略)

模板引擎

PHP是一種HTML內嵌式在服務端執行的腳本語言,可是PHP又不少可使PHP代碼和HTML代碼分開的模板引擎,例如:smarty

工做原理

模板引擎就是龐大的完善的正則表達式替換庫

算法

排序算法

示例代碼sort.php

冒泡排序

原理:兩兩相鄰的數進行比較,若是反序就交換,不然不交換

時間複雜度:最壞(O(n^2)), 平均(O(n^2))

空間複雜度:O(1)

function bubbling_sort($arr)
{
    $len = count($arr);
    if ($len <= 1) return $arr;

    for ($i = 0; $i < $len - 1; $i++) {
        for ($j = 0; $j < $len - $i -1; $j++) {
            if ($arr[$j] > $arr[$j+1]) {
                $tmp = $arr[$j+1];
                $arr[$j+1] = $arr[$j];
                $arr[$j] = $tmp;
            }
        }
    }

    return $arr;
}

快速排序

原理:經過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的全部數據和另外一部分的全部數據都要笑,而後按照此方法對這兩部分數據分別進行快速排序,整個排序過程能夠遞歸完成

時間複雜度:最壞(O(n^2)), 平均(O(nlog2n))

空間複雜度:最差(O(n)),平均(O(log2n))

function quick_sort($arr)
{
    $len = count($arr);
    if ($len <= 1) return $arr;

    $base = $arr[0];
    $left = [];
    $right = [];

    for ($i = 1; $i < $len; $i++) {
        if ($arr[$i] > $base) $right[] = $arr[$i];
        else $left[] = $arr[$i];
    }

    $left = quick_sort($left);
    $right = quick_sort($right);

    return array_merge($left, [$base], $right);
}

選擇排序

原理:每次從待排序的數據元素中選出最小(或最大)的一個元素,存放在序列的起始位置,知道所有待排序的數據元素排外

時間複雜度:最壞(O(n^2)), 平均(O(n^2))

空間複雜度:O(1)

function select_sort($arr)
{
    $len = count($arr);
    if ($len <= 1) return $arr;

    for ($i = 0; $i < $len - 1; $i++) {
        $min = $i;

        for ($j = $i+1; $j < $len; $j ++) {
            if ($arr[$min] > $arr[$j]) {
                $min = $j;
            }
        }

        if ($min !== $i) {
            $tmp = $arr[$i];
            $arr[$i] = $arr[$min];
            $arr[$min] = $tmp;
        }
    }

    return $arr;
}

直接插入排序

原理:每次從無序表中取出第一個元素,把他插入到有序表的合適位置,使有序表仍然有序

時間複雜度:最壞(O(n^2)), 平均(O(n^2))

空間複雜度:O(1)

希爾排序

原理:把待排序的數據根據增量分紅幾個子序列,對子序列進行插入排序,知道增量爲1,直接插入進行插入排序;增量的排序,通常是數組的長度的一半,再變爲原來增量的一半,直到增量爲1

時間複雜度:最壞(O(n^2)), 平均(O(nlog2n))

空間複雜度:O(1)

堆排序

原理:把待排序的元素按照大小在二叉樹位置上排序,排序好的元素要知足:父節點的元素要大於子節點;這個過程叫作堆化過程,若是根節點存放的最大的數,則叫作大根堆,若是是最小,就叫小跟堆,能夠把根節點拿出來,而後再堆化,循環到最後一個節點

時間複雜度:最壞(O(nlog2n)), 平均(O(nlog2n))

空間複雜度:O(1)

歸併排序

原理:將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分爲若干個有序的子序列,再把有序的子序列合併爲總體有序序列

時間複雜度:最壞(O(nlog2n)), 平均(O(nlog2n))

空間複雜度:O(n)

查找算法

二分查找

原理:從數組的中間元素開始,若是中間元素正好是要查找的元素,搜索結果,若是某一個特定元素大於或者小於中間元素的那一半中查找,並且跟開始同樣從中間開始比較,若是某一步驟數組爲空,表明找不到

時間複雜度:最壞(O(nlog2n)), 平均(O(nlog2n))

空間複雜度:迭代(O(1)), 遞歸(O(log2n))

順序查找

原理:按必定的順序檢查數組中每個元素,直到要找到鎖要尋找的特定指爲止

時間複雜度:最壞(O(n)), 平均(O(n))

空間複雜度:O(1)

b-tree

B-Tree是爲磁盤等外存儲設備設計的一種平衡查找樹

一棵m階的B-Tree有以下特性:

  1. 每一個節點最多有m個孩子。
  2. 除了根節點和葉子節點外,其它每一個節點至少有Ceil(m/2)個孩子。
  3. 若根節點不是葉子節點,則至少有2個孩子
  4. 全部葉子節點都在同一層,且不包含其它關鍵字信息
  5. 每一個非終端節點包含n個關鍵字信息(P0,P1,…Pn, k1,…kn)
  6. 關鍵字的個數n知足:ceil(m/2)-1 <= n <= m-1
  7. ki(i=1,…n)爲關鍵字,且關鍵字升序排序。
  8. Pi(i=1,…n)爲指向子樹根節點的指針。P(i-1)指向的子樹的全部節點關鍵字均小於ki,但都大於k(i-1)

image

b+tree

B+Tree是在B-Tree基礎上的一種優化,使其更適合實現外存儲索引結構,InnoDB存儲引擎就是用B+Tree實現其索引結構。

B+Tree相對於B-Tree有幾點不一樣:

  1. 非葉子節點只存儲鍵值信息。
  2. 全部葉子節點之間都有一個鏈指針。
  3. 數據記錄都存放在葉子節點中。
  4. 將B-Tree優化,因爲B+Tree的非葉子節點只存儲鍵值信息,假設每一個磁盤塊能存儲4個鍵值及指針信息

image

優化

高併發和大流量解決方案

高併發的問題,應關注

  1. QPS:每秒鐘請求或查詢數量,在互聯網領域指每秒響應的請求數(指HTTP請求)
  2. 吞吐量:單位時間內處理的請求數量(一般由QPS和併發數決定)
  3. 響應時間:從請求發出到收到響應花費時間
  4. PV:綜合瀏覽量(Page View),即頁面瀏覽量或者點擊量,一個訪客在24小時內訪問的頁面數量。同一我的瀏覽你的網站同一個頁面,只記做一次PV
  5. UV:獨立訪客(UniQue Visitor),即必定時間範圍內相同訪客屢次訪問網站,只能計算爲1個獨立訪客
  6. 帶寬:計算帶寬大小需關注兩個指標,峯值流量和頁面的平均大小
  7. 日網站帶寬=PV/統計時間(秒)平均頁面大小(KB)8
  8. 峯值通常是平均值的倍數
  9. QPS不等於併發併發鏈接數。QPS是每秒HTTP請求數量,併發鏈接數是系統同時處理的請求數量
  10. 二八定律(80%的訪問量集中在20%的時間):(總PV數80%)/(6小時秒速20%)=峯值每秒請求數(QPS)
  11. 壓力測試:能承受最大的併發數和最大承受的QPS值

經常使用性能測試工具

ab,wrk,Apache JMeter, http_load, Web Bench, Siege

ab

使用方法:
# 模擬併發請求100次,總請求5000次
ab -c 100 -n 5000 http://example.com
注意事項:
  1. 測試機器與被測機器分開
  2. 不要對線上服務作壓力測試
  3. 觀察測試工具所在機器,以及被測試的前端機的CPU、內存、網絡等都不超過最高限度的75%

QPS指標

  1. QPS達到50,能夠稱之爲小型網站,通常服務器均可以應付
  2. QPS達到100;瓶頸:MySQL查詢達到瓶頸;優化方案:數據庫緩存層,數據庫負載均衡
  3. QPS達到800;瓶頸:帶寬速度達到瓶頸;優化方案:CDN加速,負載均衡
  4. QPS達到1000;瓶頸:緩存服務器的帶寬達到瓶頸;優化方案:靜態HTML緩存
  5. QPS達到2000;瓶頸:文件系統訪問鎖成爲災難;優化方案:作業務分離,分佈式存儲

高併發優化方案

流量優化

  1. 防盜鏈處理

前端優化

  1. 減小HTTP請求
  2. 添加異步請求
  3. 啓用瀏覽器緩存和文件壓縮
  4. CDN加速
  5. 創建獨立的圖片服務器

服務端優化

  1. 頁面靜態化
  2. 併發處理

數據庫優化

  1. 數據庫緩存
  2. 分庫分表、分區操做
  3. 讀寫分離
  4. 負載均衡

web服務器優化

  1. 負載均衡

web資源防盜鏈

盜鏈定義

  1. 倒鏈是指在本身的頁面上展現一些並不在服務器上的內容
  2. 得到他人服務器上的資源地址,繞過別人的資源展現頁面,直接在本身的頁面上向最終用戶提供此內容
  3. 常見的是小站盜用大站的圖片、音樂、視頻、軟件等資源
  4. 倒鏈能夠減輕本身的服務器負擔

防盜鏈定義

防止別人經過一些技術手段繞過本站的資源展現頁面,盜用本站的資源,讓繞開本站資源展現頁面的資源連接失效,能夠大大減輕服務器及帶寬的壓力

防盜鏈的工做原理

  1. 經過Referer或者計算簽名,網站能夠檢測目標網頁訪問的來源網頁,若是是資源文件,則能夠跟蹤到顯示他的網頁地址
  2. 一旦檢測到來源不是本站即進行阻止或返回指定的頁面

防盜鏈實現方法

Referer

  1. NGINX模塊ngx_http_referer_module用來阻擋來源非法的域名請求
  2. NGINX指令valid_referers,全局變量$invalid_referer
配置:
valid_referers none|blocked|server_names|string...;
  1. none: Referer來源頭部爲空的狀況,好比直接打開
  2. blocked: Referer來源頭部不爲空,可是裏面的值被代理或者防火牆刪除了,這些值都不以http://或者https://開頭
  3. server_names: Referer來源頭部包含當前的server_names

配置例子:

location ~.*\.(gif|jpg|png|flv|swf|rar}zip)$
{
    valid_referers none blocked imooc.com *.imooc.com;
    if ($invalid_referer)
    {
        #return 403;
        rewrite ^/ http://www.imooc.com/403.jpg;
    }
}

減小HTTP請求

HTTP鏈接產生的開銷

  1. 域名解析
  2. TCP鏈接
  3. 發送請求
  4. 等待
  5. 下載資源
  6. 解析

解決方案

  1. 減小組件的數量,並由此減小HTTP請求的數量
  2. 圖片地圖:圖片地圖容許你在一個圖片上關聯多個URL。目標URL的選擇取決於用戶蛋雞了圖片上的哪一個位置
  3. CSS Sprites:css 精靈,經過使用合併圖片,經過指定css的background-image和background-position來顯示元素
  4. 合併腳本和樣式表適
  5. 圖片使用base64編碼減小頁面請求數

瀏覽器緩存和數據壓縮

HTTP緩存機制分類

  1. 200 from cache:直接從本地緩存中獲取響應,最快速,最省流量,由於根本沒有向服務器發送請求
  2. 304 Not Modified:協商緩存,瀏覽器在本地沒有命中的狀況下,請求頭中發送必定的校驗數據到服務端,若是服務端的數據沒有改變,瀏覽器從本地緩存響應,返回304。特色:快速,發送的數據不多,只返回一些基本的響應頭信息,數據量很小,不發送實際響應體
  3. 200 OK:以上兩種緩存所有失敗,服務器返回完整響應。沒有用到緩存,相對最慢

header設置HTTP緩存機制

  1. pragma:HTTP1.0時代的遺留產物,該字段被設置爲no-cache時,會告知瀏覽器禁用本地緩存,即每次都向服務器發送請求
  2. Expires:HTTP1.0時代用來啓用本地緩存的字段,設置值如‘Thu, 31 Dec 2037 23:55:55 GMT’的格林威治的時間。但瀏覽器與服務器的時間沒法保持一致,若是差距大就會影響緩存結果
  3. Cache-Control:HTTP1.1針對Expires時間不一致的解決方案,運用Cache-Control告知瀏覽器緩存過時的時間間隔而不是時刻,即便具體時間不一致,也不影響緩存的管理

優先級:Pragma > Cache-Control > Expires

Cache-Control配置
  1. no-store:禁止瀏覽器緩存響應
  2. no-cache:不容許直接使用本地緩存,先發起請求和服務器協商
  3. max-age=delta-seconds:告知瀏覽器該響應本緩存的有效的最長期限,以秒爲單位

協商緩存

  1. 當瀏覽器沒有命中本地緩存,如本地緩存過時或者響應中聲名不容許直接使用本地緩存,那麼瀏覽器確定會發起服務端請求
  2. 服務端會驗證數據是否修改,若是沒有就通知瀏覽器使用本地緩存

header設置協商緩存

  1. Last-Modified:通知瀏覽器資源的最後修改時間,設置值如‘Thu, 31 Dec 2037 23:55:55 GMT’的格林威治的時間
  2. If-Modified-Since:獲得資源的最後修改時間後,會將這個信息經過If-Modified-Since提交到服務器作檢查,若是沒有修改,返回304狀態碼,設置值如‘Thu, 31 Dec 2037 23:55:55 GMT’的格林威治的時間
  3. ETag:HTTP1.1推出,文件的指紋標識符,若是文件內容修改,指紋也會改變,設置值如‘5a643fc7-38a3’
  4. If-None-Match:本地緩存失效,會攜帶此值去請求服務端,服務端判斷該資源是否改變,若是沒有改變,直接使用本地緩存,返回304

緩存策略的選擇

適合緩存的內容

  1. 不變的圖像,如logo,圖標等
  2. js、css靜態文件
  3. 可下載的內容,媒體文件

適合協商緩存

  1. HTML文件
  2. 常常替換的圖片
  3. 常常修改的js、css文件,js、css文件的加載能夠加入文件的簽名來拒絕緩存,如‘index.css?簽名’,‘index.簽名.js’

不建議緩存的內容

  1. 用戶隱私等敏感數據
  2. 常常改變的API數據接口

NGINX配置緩存策略

本地緩存配置

  1. add_header指令:添加狀態碼爲2XX和3XX的響應頭信息,設置代碼add_header name value [always];,能夠設置Pragma、Expires、Cache-Control,能夠繼承
  2. expires指令:通知瀏覽器過時時長,設置代碼expires time;
  3. Etag指令:指定簽名,設置代碼etag on|off,默認on

前端代碼和資源壓縮

優點

  1. 讓資源文件更小,加快文件在網絡中的傳輸,讓網頁更快的展示,下降帶寬和流量的開銷

壓縮方式

  1. js、css、圖片、html代碼的壓縮
  2. gzip壓縮

gzip配置

gzip on|off; #是否開啓gzip
gzip_buffers 32 4K|16 8K; #緩衝(在內存中緩存幾塊?每塊多大)
gzip_comp_level [1-9] #推薦6,壓縮級別(級別越高,壓得越小,越浪費CPU計算資源)
gzip_disable #正則匹配UA,什麼樣的Uri不進行gzip
gzip_min_length 200 #開始壓縮的最小長度
gzip_http_version 1.0|1.1 #開始壓縮的http協議版本
gzip_proxied #設置請求者代理服務器,該如何緩存內容
gzip_types text/plain application/xml image/png #對哪些類型的文件壓縮,如txt、xml、css
gzip_vary on|off #是否傳輸gzip壓縮標誌

CDN加速

定義

  1. CDN的全稱content delivery network,內容分發網絡
  2. 儘量避開互聯網上有可能影響數據傳輸速度和穩定性的瓶頸和環節,使內容傳輸的更快、更穩定
  3. 在網絡各處放置節點服務器所構成的有的互聯網基礎之上的一層智能虛擬網絡
  4. CDN系統可以實現地根據網絡流量和各節點的鏈接、負載情況以及到用戶距離和響應時間等綜合信息將用戶的請求從新導向離用戶最近的服務節點上

優點

  1. 本地cache加速,提升了企業站點(尤爲含有大量圖片和靜態頁面站點)的訪問速度
  2. 跨運營商的網絡加速,保證不一樣網絡的用戶都能獲得良好的訪問質量
  3. 遠程訪問用戶根據DNS負載均衡技術只能選擇cache服務器
  4. 自動生成服務器的遠程Mirror(鏡像)cache服務器,遠程用戶訪問時從cache服務器上讀取數據,減小遠程訪問的帶寬、分擔網絡流量、減輕原站點web服務器負載等功能
  5. 普遍分佈的cdn節點加上節點之間的智能冗餘機制,能夠有效地預防黑客入侵

工做原理

  1. 用戶發起請求
  2. 智能DNS的解析(根據IP判斷地理位置、接入網類型、選擇路由最短和負載最輕的服務器)
  3. 取得緩存服務器ip
  4. 把內容返回給用戶(若是緩存中有,沒有就執行五、六、7)
  5. 向源站發起請求
  6. 將結果返回給用戶
  7. 將結果存入緩存服務器

適用場景

  1. 站點或者應用中大量靜態資源的加速分發,例如css、js、圖片和HTML
  2. 大文件下載
  3. 直播網站

獨立圖片服務器

必要性

  1. 分擔web服務器的I/O負載,將耗費資源的圖片服務器分離出來,提升服務器的性能和穩定性
  2. 可以專門對圖片服務器進行優化,爲圖片服務器設置針對性的緩存方案,減小帶寬成本,提升訪問速度
  3. 提升網站的可擴展性,經過增長圖片服務器,提升圖片吞吐能力

採用獨立域名

緣由:

  1. 同一域名下瀏覽器的併發鏈接數有限制,突破瀏覽器鏈接數的限制
  2. 因爲cookie的緣由,對緩存不利,大部分web cache都只緩存不帶cookie的請求,致使每次的圖片請求都不能命中cache

如何圖片上傳和同步

  1. NFS共享方式
  2. 利用FTP同步

動態語言靜態化

將現有的PHP等動態語言的邏輯代碼生成爲靜態的HTML文件,用戶訪問動態腳本重定向到靜態HTML文件的過程。對實時性要求不高

緣由:

  1. 動態腳本經過會作邏輯計算和數據查詢,訪問量越大,服務器壓力越大
  2. 訪問量大時可能會形成CPU負載太高,數據庫服務器壓力過大
  3. 靜態化能夠減低邏輯處理壓力,下降數據庫服務器查詢壓力

實現方法

  1. 使用模板引擎
  2. 利用ob系列函數
ob_start();//打開輸出控制緩衝
ob_get_content();//返回輸出緩衝區內容
ob_clean();//清空輸出緩衝區
ob_end_flush();//沖刷出(送出)輸出緩衝區內容並關閉緩衝

併發處理

進程(Process)

是計算機中程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單元,是操做系統結構的基礎。進程是一個執行中的程序

進程的三態模型:運行、就緒、阻塞

進程的五態模型:新建態、活躍就緒/靜止就緒、運行、活躍阻塞/靜止阻塞、終止態

  1. 新建態:對應於進程剛剛被建立時沒有被提交的狀態,並等待系統完成建立進程的全部必要信息
  2. 終止態:進程已結束運行,回收除進程控制塊以外的其餘資源,並讓其餘進程從進程控制塊中收集有關信息。
  3. 活躍就緒:是指進程在主存而且可被調度的狀態。
  4. 靜止就緒(掛起就緒):是指進程被對換到輔存時的就緒狀態,是不能被直接調度的狀態,只有當主存中沒有活躍就緒態進程,或者是掛起就緒態進程具備更高的優先級,系統將把掛起就緒態進程調回主存並轉換爲活躍就緒。
  5. 活躍阻塞:是指進程已在主存,一旦等待的事件產生便進入活躍就緒狀態。
  6. 靜止阻塞:進程對換到輔存時的阻塞狀態,一旦等待的事件產生便進入靜止就緒狀態。

線程

線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程本身不擁有系統資源,只擁有一點兒在運行中必不可少的資源但它可與同屬一個進程的其它線程共享進程所擁有的所有資源。

一個線程能夠建立和撤消另外一個線程,同一進程中的多個線程之間能夠併發執行。

線程是程序中一個單一的順序控制流程。進程內一個相對獨立的、可調度的執行單元,是系統獨立調度和分派CPU的基本單位指運行中的程序的調度單位。

在單個程序中同時運行多個線程完成不一樣的工做,稱爲多線程。

協程

協程是一種用戶態的輕量級線程,協程的調度徹底由用戶控制。協程擁有本身的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其餘地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操做棧則基本沒有內核切換的開銷,能夠不加鎖的訪問全局變量,因此上下文的切換很是快。

區別

線程與進程

  1. 線程是進程內的一個執行單元,進程內至少有一個線程,它們共享進程的地址空間,而進程有本身獨立的地址空間
  2. 進程是資源分配和擁有的單位,同一個進程內的線程共享進程的資源
  3. 線程是處理器調度的基本單位但進程不是
  4. 兩者都可併發執行
  5. 每一個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口,可是線程不可以獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制

協程和線程

  1. 一個線程能夠多個協程,一個進程也能夠單獨擁有多個協程
  2. 線程進程都是同步機制,而協程則是異步
  3. 協程能保留上一次調用時的狀態,每次過程重入時,就至關於進入上一次調用的狀態

例子

  1. 單進程單線程:一我的在一個桌子上吃菜
  2. 單進程多線程:多我的在同一個桌子上一塊兒吃菜
  3. 多進程單線程:多我的每一個人在本身的桌子上吃菜

同步阻塞

多進程模式

  1. 建立一個 socket
  2. 進入 while循環,阻塞在進程accept操做上,等待客戶端鏈接進入主進程在多進程模型下經過fork刨建子進程
  3. 收到數據後服務器程序進行處理而後使用send向客戶端發送響應
  4. 當客戶端鏈接關閉時,子進程/線程退出並銷燬全部資源。主進程/線程會回收掉此子進程/線程。

多線程模式

  1. 多線程模型下能夠建立子線程
  2. 子進程/線程建立成功後進入while循環,阻塞在recv調用上,等待客戶端向服務器發送數據
  3. 收到數據後服務器程序進行處理而後使用send向客戶端發送響應
  4. 當客戶端鏈接關閉時,子進程/線程退出並銷燬全部資源。主進程/線程會回收掉此子進程/線程。

缺點

  1. 這種模型嚴重依賴進程的數量解決併發問題
  2. 啓動大量進程會帶來額外的進程調度消耗

異步非阻塞

如今各類高併發異步IO的服務器程序都是基於epoll實現的

IO複用異步非阻塞程序使用經典的Reactor模型,Reactor顧名思義就是反應堆的意思,它自己不處理任何數據收發。只是能夠監視一個 socket句柄的事件變化

reactor模型

  • Add:添加一個 SOCKET到 Reactor
  • Set:修改 SOCKET對應的事件,如可讀可寫
  • Del:從 Reactor中移除
  • Callback:事件發生後回調指定的函數

常見reactor模型

  1. Nginx:多線程 Reactor
  2. Swoole:多線程 Reactor+多進程Worker

數據庫緩存

mysql查詢緩存

查詢緩存能夠看作是SQL文本和查詢結果的映射,第二次查詢的SQL和第一次查詢的SQL全相同,則會使用緩存

表的結構或數據發生改變時,查詢緩存中的數據再也不有效

配置:

query_cache_type

查詢緩存類型,有0、一、2三個取值。0則不使用查詢緩存。1表示始終使用查詢緩存。2表示按需使用查詢緩存。

query_cache_size

默認狀況下 query_cache_size爲0,表示爲查詢緩存預留的內存爲0,則沒法使用查詢緩存

SET GLOBAL query_cache_size= 134217728

使用

querycache_type爲1時,亦可關閉查詢緩存

SELECT SQL_NO_CACHE FROM my_table WHERE condition;

query_cache_type爲2時,可按需使用查詢緩存

SELECT SQL_CACHE FROM my_table WHERE condition;

其餘

查看命中次數

SHOW STATUS LIKE'Qcache_hits';

清理緩存

FLUSH QUERY CACHE∥清理查詢緩存內存碎片
RESET QUERY CACHE∥從查詢緩存中移出全部查詢
FLUSH TABLES;//關閉全部打開的表,同時該操做將會清空查詢
緩存中的內容

redis/memcache 緩存

  • Redis,依賴客戶端來實現分佈式讀寫
  • Memcache自己沒有數據冗餘機制
  • Redis支持(RDB快照、AOF),依賴快照進行持久化,aof加強了可靠性的同時,對性能有所影響
  • Memcache不支持持久化,一般作緩存,提高性能;
  • Memcache在併發場景下,用cas保證一致性, redis事務支持比較弱,只能保證事務中的每一個操做連續執行
  • Redis支持多種類的數據類型
  • Redis用於數據量較小的高性能操做和運算上
  • Memcache用於在動態系統中減小數據庫負載,提高性能;適合作緩存,提升性能

區別

  1. 數據結構:Memcache只支持key value存儲方式,Redis支持更多的數據類型,好比Key value、hash、list、set、zset;
  2. 多線程:Memcache支持多線程,Redis支持單線程;CPU利用方面Memcache優於Redis;
  3. 持久化:Memcache不支持持久化,Redis支持持久化;
  4. 內存利用率:Memcache高,Redis低(採用壓縮的狀況下比Memcache高);
  5. 過時策略:Memcache過時後,不刪除緩存,會致使下次取數據數據的問題,Redis有專門線程,清除緩存數據;

緩存可能問題

  1. 緩存穿透 : DB 承受了沒有必要的查詢流量,意思就是查到空值的時候沒有作緩存處理,再次查詢的時候繼續讀庫了
  2. 緩存擊穿:熱點 Key,大量併發讀請求引發的小雪崩, 就是緩存在某個時間點過時的時候,剛好在這個時間點對這個 Key 有大量的併發請求過來,這些請求發現緩存過時通常都會從後端 DB 加載數據並回設到緩存,這個時候大併發的請求可能會瞬間把後端 DB 壓垮
  3. 緩存雪崩:緩存設置同一過時時間,引起的大量的讀取數據庫操做

redis的持久化策略

  1. RDB(快照持久化)
  2. AOF(只追加文件持久化)

redis數據結構

  1. string(key=>value)
  2. 哈希(hash)
  3. 列表(list)
  4. 集合(set)
  5. 有序集合(zset)

redis瓶頸

參考資料[關於Redis的一些思考和總結
](https://www.jianshu.com/p/b88...

對cpu會成爲Redis的性能瓶頸的擔心是能夠理解的,可是在實際使用過程當中cpu或許不是制約Redis的關鍵因素,網絡io可能纔是最大的瓶頸。

由於CPU並非Redis的瓶頸,Redis的瓶頸最有多是機器內存或者網絡帶寬。既然單線程容易實現,並且CPU不會成爲瓶頸,那麼久瓜熟蒂落的採用了單線程的方案。

redis阻塞緣由

內因
  1. 不合理使用API和數據結構
  2. CPU飽和的問題
  3. 持久化相關的阻塞
外因
  1. CPU競爭
  2. 內存交換
  3. 網絡問題

Redis的數據過時策略

  1. Redis配置項hz定義了serverCron任務的執行週期,默認爲10,即cpu空閒時每秒執行10次。
  2. 每次過時key清理的視覺不超過cpu時間的25%,即若hz=1,則一次清理時間最大爲250ms,若hz=10,則一次清理時間最大爲25ms。
  3. 清理時依次遍歷全部的db。
  4. 從db中隨機取20個key,判斷是否過時,若過時則清理。
  5. 如有5個以上key過時,則重複步驟4,不然遍歷下一個db。
  6. 在清理過程當中,若達到了25%cpu時間,則退出清理過程。

Redis的數據淘汰策略

  1. volatile-lru:從已設置過時時間的數據集(server.db[i].expires)中挑選最近最少使用 的數據淘汰
  2. volatile-ttl:從已設置過時時間的數據集(server.db[i].expires)中挑選將要過時的數 據淘汰
  3. volatile-random:從已設置過時時間的數據集(server.db[i].expires)中任意選擇數據 淘汰
  4. allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰
  5. allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰

no-enviction(驅逐):禁止驅逐數據

mysql 優化

數據表數據類型優化

  • tinyint、 smallint、 bigint 考慮空間的問題,考慮範圍的問題
  • char、varchar
  • enum 特定、固定的分類可使用enum存儲,效率更快
  • ip地址 ip2long() 轉成長整型存儲

索引優化

索引建立原則

  • 索引不是越多越好,在合適的字段上建立合適的索引
  • 複合索引的前綴原則

索引注意事項

  • 複合索引的前綴原則
  • like查詢%的問題
  • 全表掃描優化
  • or條件索引使用狀況
  • 字符串類型索引失效的問題

SQL語句的優化

優化查詢過程當中的數據訪問

  • 使用 Limit
  • 返回列不用*

優化長難句的查詢語句

  • 變複雜爲簡單
  • 切分查詢
  • 分解關聯查詢

優化特定類型的查詢語句

  • 優化 count()
  • 優化關聯查詢
  • 優化子查詢
  • 優化 Group by和 distinct
  • 優化 limit和 union

存儲引擎的優化

儘可能使用 Inno DB存儲引擎

數據表結構設計的優化

分區操做

  • 經過特定的策略對數據表進行物理拆分
  • 對用戶透明
  • partition by

分庫分表

  • 水平拆分
  • 垂直拆分

數據庫服務器架構的優化

  • 主從複製
  • 讀寫分離
  • 雙主熱備
  • 負載均衡

負載均衡

  • 經過LVS的三種基本模式實現負載均衡
  • MyCat數據庫中間件實現負載均衡

web服務器的負載均衡、請求分發

七層負載均衡實現

基於URL等應用層信息的負載均衡

Nginx的 proxy是它一個很強大的功能,實現了7層負載均衡

nginx負載均衡

優勢

功能強大,性能卓越,運行穩定
配置簡單靈活
可以自動剔除工做不正常的後端服務器
上傳文件使用異步模式
支持多種分配策略,能夠分配權重,分配方式靈活

Nginx負載均衡策略

內置策略: IP Hash、加權輪詢
擴展策略:fair策略、通用hash、一致性hash

加權輪詢策略

首先將請求都分給高權重的機器,直到該機器的權值降到了比其餘機器低,纔開始將請求分給下一個高權重的機器

當全部後端機器都down掉時,Ngnx會當即將全部機器的標誌位清成初始狀態,以免形成全部的機器都處在 timeout的狀態

IP Hash策略

Nginx內置的另外一個負載均衡的策略,流程和輪詢很相似,只是其中的算法和具體的策略有些變化
IP Hash算法是一種變相的輪詢算法

fair策略

根據後端服務器的響應時間判斷負載狀況,從中選出負載最輕的機器進行分流

通用Hash、一致性Hash策略

通用hash比較簡單,能夠以 Nginx內置的變量爲key進行hash,

一致性hash採用 Nginx了內置的一致性hash環,支持 memcache

配置

http {
    upstream cluster {
        server srvl;
        server srv2;
        server srv3;
    }
    server {
        listen 80;
        location /
        proxy_pass http: //cluster;
    }
}

四層負載均衡實現

經過報文中的目標地址和端口,再加上負載均衡設備設置的服務器選擇方式,決定最終選擇的內部服務器

LvS實現服務器集羣負載均衡有三種方式,NAT,DR和TUN

攻擊與安全

hash 碰撞

參考資料

原理

通過特殊構造的鍵值, 使得PHP每一次插入都會形成Hash衝突, 從而使得PHP中array的底層Hash表退化成鏈表

哈希表是經過特定的哈希算法將索引轉換成特定的index而後映射到對應的槽中,而後採用拉鍊法,在一個槽中使用鏈表將數據進行存儲,鏈表的時間複雜度爲O(n)。

image

這樣在每次插入的時候須要遍歷一遍這個鏈表, 你們能夠想象, 第一次插入, 須要遍歷0個元素, 第二次是1個, 第三次是3個, 第65536個是65535個, 那麼總共就須要65534*65535/2=2147385345次遍歷….

PHP的Hash算法是開源的, 已知的, 因此有心人也能夠作到

示例攻擊數據

{
    "format": "json",
    "list": {
          "v1" : 1,
          "攻擊數據":{
              "0":0,
              "65536":0,
              "131072":0,
                …………
              "234553344":0
          }
     }
}

php示例代碼hash.php

<?php
$size = pow(2, 16);

$startTime = microtime(true);
$array = array();
for ($key = 0, $maxKey = ($size - 1) * $size; $key <= $maxKey; $key += $size) {
    $array[$key] = 0;
}
$endTime = microtime(true);
echo '插入 ', $size, ' 個惡意的元素須要 ', $endTime - $startTime, ' 秒', "\n";

$startTime = microtime(true);
$array = array();
for ($key = 0, $maxKey = $size - 1; $key <= $maxKey; ++$key) {
    $array[$key] = 0;
}
$endTime = microtime(true);
echo '插入 ', $size, ' 個普通元素須要 ', $endTime - $startTime, ' 秒', "\n";

輸出結果

插入 65536 個惡意的元素須要 5.0739450454712 秒
插入 65536 個普通元素須要 0.0010519027709961 秒

解決方法

  1. 打補丁,修改hash算法。
  2. 限制POST的參數個數,限制POST的請求長度。
  3. 使用防火牆檢測異常請求
  4. 增長權限驗證,最大可能的在jsonDecode()以前把非法用戶拒絕
  5. 重寫jsonDecode()方法
  6. 在php5.3以上的版本中,post參數的數量存在最大的限制max_input_vars => 1000
相關文章
相關標籤/搜索