- 引言
- 1 从一篇网络文章中爬取图片
- 2 获取当前客户端的 IP 地址
- 3 什么是 CSRF 攻击
- 4 什么是 XSS 攻击
- CSRF 和 XSS 的区别与联系
- 5 http 状态码及其含意
- 6 判断是否设置或为空
- 7 http 协议的 header 中有哪些 key 及含义
- 8 二叉树前中后遍历代码
- 9 接口,抽象类
- 10 引号问题
- 11 截取文件名后缀
- 12 访问网页经历过程
- 13 foreach &引用问题
- 14 IO异步模型
- 15 海量数据处理方法
- 16 进程模型
- 17 CAP 原理
- 18 怎么解决跨域
- 19 json 和 xml 区别
- 20 查找最长公共子串
- 21 进程间通信方式有哪些
- 22 缓存只留热数据
- 23 PHP 的协程以及用途
- 一般什么会导致服务器阻塞
- 防止SQL注入
- FPM与Swoole的访问速度比较
- 参考资料
引言
除了下面列出的点,还应该读一下最下面的参考资料的内容。
1 从一篇网络文章中爬取图片
写一个函数,获取一篇文章内容中的全部图片,并下载。
<?php
function download_images($article_url = '', $image_path = 'tmp') {
// 获取文章类容
$content = file_get_contents($article_url);
// 利用正则表达式得到图片链接
$reg_tag = '/<img.*?\"([^\"]*(jpg|bmp|jpeg|gif|png)).*?>/';
$ret = preg_match_all($reg_tag, $content, $match_result);
$pic_url_array = array_unique($match_result[1]);
// 创建路径
$dir = getcwd() . DIRECTORY_SEPARATOR .$image_path;
mkdir(iconv("UTF-8", "GBK", $dir), 0777, true);
foreach($pic_url_array as $pic_url){
// 获取文件信息
$ch = curl_init($pic_url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_NOBODY, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE );
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$fileInfo = curl_exec($ch);
$httpinfo = curl_getinfo($ch); // 获取一个cURL连接资源句柄的信息,https://www.php.net/manual/zh/function.curl-getinfo.php
curl_close($ch);
// 获取图片文件后缀
$ext = strrchr($pic_url, '.');
$filename = $dir . '/' . uniqid() . $ext;
// 保存图片信息到文件
$local_file = fopen($filename, 'w');
if (false !== $local_file) {
if ( false !== fwrite($local_file, $fileInfo) ) {
fclose($local_file);
}
}
}
}
2 获取当前客户端的 IP 地址
参阅 https://www.cnblogs.com/rendd/p/6183094.html
一、如果没有使用代理服务器,
REMOTE_ADDR = 客户端IP
HTTP_X_FORWARDED_FOR = 没数值或不显示
$ip = $_SERVER['REMOTE_ADDR'];
二、使用透明代理,
REMOTE_ADDR = 最后一个代理服务器 IP
HTTP_X_FORWARDED_FOR = 客户端真实 IP (经过多个代理服务器时,这个值类似:221.5.252.160, 203.98.182.163, 203.129.72.215)
这类代理还会将客户真实ip发送到请求对象,无法隐藏真实ip。
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
三、使用普通匿名代理服务器,
REMOTE_ADDR = 最后一个代理服务器 IP
HTTP_X_FORWARDED_FOR = 代理服务器 IP (经过多个代理服务器时,这个值类似:203.98.182.163, 203.98.182.163, 203.129.72.215)
这样就隐藏了客户端的真实ip,但服务器会知道客户端是通过代理服务器去访问的。
四、使用欺骗性代理服务器,
REMOTE_ADDR = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 随机的 IP(经过多个代理服务器时,这个值类似:220.4.251.159, 203.98.182.163, 203.129.72.215)
服务器可以识别到时通过代理服务器访问的,但发送给目标服务器的是虚假ip。
五、使用高匿名代理,
REMOTE_ADDR = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 没数值或不显示
使用这种代理时,不同浏览器不同设备会返回不同的ip头信息,因此PHP使用$_SERVER["REMOTE_ADDR"] 、
$_SERVER["HTTP_X_FORWARDED_FOR"] 获取的值可能是空值也可能是“unknown”值。
PHP获取ip代码如下:
<?php
function ip() {
//strcasecmp 比较两个字符,不区分大小写。返回0,>0,<0。
if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
$ip = getenv('HTTP_CLIENT_IP');
} elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
} elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
$ip = getenv('REMOTE_ADDR');
} elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
$ip = $_SERVER['REMOTE_ADDR'];
}
$res = preg_match ( '/[\d\.]{7,15}/', $ip, $matches ) ? $matches [0] : '';
echo $res;
//dump(phpinfo());//所有PHP配置信息
}
strcasecmp(string $string1, string $string2): int,二进制安全比较字符串(不区分大小写)。
比较不会注意区域;只有 ASCII 字母以不区分大小写的方式进行比较。
如果 string1 小于 string2 返回 -1;如果 string1 大于 string2 返回 1;如果两者相等,返回 0。
3 什么是 CSRF 攻击
CSRF:Cross-site request forgery,跨站请求伪造,可以通过通过判断来源和加 Token 的方式来防范。
CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding, 通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。 其原理是攻击者构造网站后台某个功能接口的请求地址,诱导用户去点击或者用特殊方法让该请求地址自动加载。 用户在登录状态下这个请求被服务端接收后会被误以为是用户合法的操作。对于 GET 形式的接口地址可轻易被攻击, 对于 POST 形式的接口地址也不是百分百安全,攻击者可诱导用户进入带 Form 表单可用POST方式提交参数的页面。
参阅 https://ibaiyang.github.io/blog/yii2/2017/12/03/Yii2-csrf综合.html 、 https://ibaiyang.github.io/blog/it技术/2023/07/07/网络应用安全实操要点.html
4 什么是 XSS 攻击
XSS:Cross Site Scripting,跨站脚本攻击,可以通过对内容转义(htmlspecialchars或者htmlentities)和过滤来防范,还有 CSP。
XSS(Cross Site Scripting)跨站脚本攻击,恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时, 嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。
这里可以看下 https://ibaiyang.github.io/blog/php/2022/04/02/PHP-The-Right-Way-学习.html#安全
CSRF 和 XSS 的区别与联系
CSRF(跨站请求伪造)和XSS(跨站脚本攻击)是两种常见的Web安全漏洞,它们各自有不同的特点和影响。 以下是关于这两种攻击方式的详细解释和比较:
CSRF(跨站请求伪造)
定义:
CSRF是一种攻击者利用受害者在被攻击网站已经获取的注册凭证,诱导受害者在第三方网站执行非法请求的攻击方式。 这种攻击利用了Web的跨站特性,使得攻击者可以在受害者不知情的情况下,伪造请求,从而达到攻击的目的。
特点:
- 利用受害者身份:攻击者利用受害者在被攻击网站已经获取的注册凭证(如Cookie),伪造请求。
- 诱导受害者:攻击者通常通过诱导受害者点击链接或访问第三方网站来触发攻击。
- 绕过验证:由于请求中包含了受害者的注册凭证,因此可以绕过被攻击网站的用户验证。
影响: CSRF攻击可能导致受害者在被攻击网站执行未经授权的操作,如转账、更改密码等。
XSS(跨站脚本攻击)
定义:
XSS是一种攻击者向目标网站注入恶意脚本代码,当其他用户浏览该网站时,这些脚本代码会被执行,从而达到攻击用户的目的。
特点:
- 注入恶意代码:攻击者通过向目标网站注入恶意脚本代码来实施攻击。
- 执行环境:这些恶意脚本代码会在用户的浏览器中执行,因此可以获取用户的敏感信息,如Cookie、浏览记录等。
- 传播性:一旦恶意脚本代码被注入到目标网站,它将影响所有访问该网站的用户。
影响:
XSS攻击可能导致用户信息泄露、会话劫持、钓鱼攻击等严重后果。
CSRF与XSS的比较
- 原理不同:CSRF是利用网站A本身的漏洞,去请求网站A的API;而XSS是向目标网站注入JS代码,然后执行JS里的代码。
- 触发条件:CSRF需要用户先登录目标网站获取Cookie,而XSS不需要登录。
- 攻击目标:CSRF的目标是用户,通过伪造请求来影响用户的行为;而XSS的目标是服务器, 通过执行恶意脚本代码来攻击服务器或窃取用户信息。
- 防御方法:针对CSRF,可以采取设置随机Token、验证请求来源等方式进行防御;而针对XSS, 可以采取对输入进行过滤、对输出进行编码、设置HttpOnly属性等方式进行防御。
5 http 状态码及其含意
- 200 请求已成功,请求所希望的响应头或数据体将随此响应返回。
- 301 被请求的资源已永久移动到新位置。
- 302 请求的资源现在临时从不同的 URI 响应请求。
- 400 1、语义有误,当前请求无法被服务器理解。2、请求参数有误。
- 401 当前请求需要用户验证。
- 403 服务器已经理解请求,但是拒绝执行它。
- 404 请求失败,请求所希望得到的资源未被在服务器上发现。
- 500 服务器遇到了一个未曾预料的状况,无法完成对请求的处理,会在程序码出错时出现。
- 501 服务器不支持当前请求所需要的某个功能。无法识别请求的方法。
- 502 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
- 503 由于临时的服务器维护或者过载,服务器当前无法处理请求。
6 判断是否设置或为空
isset(null), isset(false), empty(null), empty(false) 输出:
分别是 false, true, true, true
7 http 协议的 header 中有哪些 key 及含义
参阅 https://www.cnblogs.com/Joans/p/3956490.html
HTTP(HyperTextTransferProtocol) 即超文本传输协议,目前网页传输的的通用协议。HTTP协议采用了请求/响应模型, 浏览器或其他客户端发出请求,服务器给与响应。就整个网络资源传输而言,包括message-header和message-body两部分。 首先传递message-header,即http header消息 。http header 消息通常被分为4个部分: general header, request header, response header, entity header。但是这种分法就理解而言,感觉界限不太明确。 根据维基百科对http header内容的组织形式,大体分为Request和Response两部分。
Requests部分:
Header 解释 示例
Accept 指定客户端能够接收的内容类型 Accept: text/plain, text/html
Accept-Charset 浏览器可以接受的字符编码集。 Accept-Charset: iso-8859-5
Accept-Encoding 指定浏览器可以支持的web服务器返回内容压缩编码类型。 Accept-Encoding: compress, gzip
Accept-Language 浏览器可接受的语言 Accept-Language: en,zh
Accept-Ranges 可以请求网页实体的一个或者多个子范围字段 Accept-Ranges: bytes
Authorization HTTP授权的授权证书 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Cache-Control 指定请求和响应遵循的缓存机制 Cache-Control: no-cache
Connection 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) Connection: close
Cookie HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 Cookie: $Version=1; Skin=new;
Content-Length 请求的内容长度 Content-Length: 348
Content-Type 请求的与实体对应的MIME信息 Content-Type: application/x-www-form-urlencoded
Date 请求发送的日期和时间 Date: Tue, 15 Nov 2010 08:12:31 GMT
Expect 请求的特定的服务器行为 Expect: 100-continue
From 发出请求的用户的Email From: user@email.com
Host 指定请求的服务器的域名和端口号 Host: www.zcmhi.com
If-Match 只有请求内容与实体相匹配才有效 If-Match: “737060cd8c284d8af7ad3082f209582d”
If-Modified-Since 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT
If-None-Match 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 If-None-Match: “737060cd8c284d8af7ad3082f209582d”
If-Range 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag If-Range: “737060cd8c284d8af7ad3082f209582d”
If-Unmodified-Since 只在实体在指定时间之后未被修改才请求成功 If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT
Max-Forwards 限制信息通过代理和网关传送的时间 Max-Forwards: 10
Pragma 用来包含实现特定的指令 Pragma: no-cache
Proxy-Authorization 连接到代理的授权证书 Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Range 只请求实体的一部分,指定范围 Range: bytes=500-999
Referer 先前网页的地址,当前请求网页紧随其后,即来路 Referer: http://www.zcmhi.com/archives/71.html
TE 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 TE: trailers,deflate;q=0.5
Upgrade 向服务器指定某种传输协议以便服务器进行转换(如果支持) Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
User-Agent User-Agent的内容包含发出请求的用户信息 User-Agent: Mozilla/5.0 (Linux; X11)
Via 通知中间网关或代理服务器地址,通信协议 Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
Warning 关于消息实体的警告信息 Warn: 199 Miscellaneous warning
Responses 部分:
Header 解释 示例
Accept-Ranges 表明服务器是否支持指定范围请求及哪种类型的分段请求 Accept-Ranges: bytes
Age 从原始服务器到代理缓存形成的估算时间(以秒计,非负) Age: 12
Allow 对某网络资源的有效的请求行为,不允许则返回405 Allow: GET, HEAD
Cache-Control 告诉所有的缓存机制是否可以缓存及哪种类型 Cache-Control: no-cache
Content-Encoding web服务器支持的返回内容压缩编码类型。 Content-Encoding: gzip
Content-Language 响应体的语言 Content-Language: en,zh
Content-Length 响应体的长度 Content-Length: 348
Content-Location 请求资源可替代的备用的另一地址 Content-Location: /index.htm
Content-MD5 返回资源的MD5校验值 Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==
Content-Range 在整个返回体中本部分的字节位置 Content-Range: bytes 21010-47021/47022
Content-Type 返回内容的MIME类型 Content-Type: text/html; charset=utf-8
Date 原始服务器消息发出的时间 Date: Tue, 15 Nov 2010 08:12:31 GMT
ETag 请求变量的实体标签的当前值 ETag: “737060cd8c284d8af7ad3082f209582d”
Expires 响应过期的日期和时间 Expires: Thu, 01 Dec 2010 16:00:00 GMT
Last-Modified 请求资源的最后修改时间 Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT
Location 用来重定向接收方到非请求URL的位置来完成请求或标识新的资源 Location: http://www.zcmhi.com/archives/94.html
Pragma 包括实现特定的指令,它可应用到响应链上的任何接收方 Pragma: no-cache
Proxy-Authenticate 它指出认证方案和可应用到代理的该URL上的参数 Proxy-Authenticate: Basic
refresh 应用于重定向或一个新的资源被创造,在5秒之后重定向(由网景提出,被大部分浏览器支持) Refresh: 5; url=http://www.zcmhi.com/archives/94.html
Retry-After 如果实体暂时不可取,通知客户端在指定时间之后再次尝试 Retry-After: 120
Server web服务器软件名称 Server: Apache/1.3.27 (Unix) (Red-Hat/Linux)
Set-Cookie 设置Http Cookie Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1
Trailer 指出头域在分块传输编码的尾部存在 Trailer: Max-Forwards
Transfer-Encoding 文件传输编码 Transfer-Encoding:chunked
Vary 告诉下游代理是使用缓存响应还是从原始服务器请求 Vary: *
Via 告知代理客户端响应是通过哪里发送的 Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
Warning 警告实体可能存在的问题 Warning: 199 Miscellaneous warning
WWW-Authenticate 表明客户端请求实体应该使用的授权方案 WWW-Authenticate: Basic
8 二叉树前中后遍历代码
- 层序遍历
- 先序遍历
- 中序遍历
- 后序遍历
层序遍历 参阅 https://ibaiyang.github.io/blog/php/2019/07/30/PHP-算法-查找篇.html#广度优先搜索
先序、中序、后序遍历 参阅 https://ibaiyang.github.io/blog/php/2019/07/30/PHP-算法-查找篇.html#二叉搜索树
<?php
class BinarySearchTree
{
/**
* @var $root 根节点
*/
public $root = null;
/**
* 创建新节点
* @param $data 关键码
*/
protected function createNode($data)
{
$node = new stdClass();
$node->value = $data;
$node->left = null;
$node->right = null;
return $node;
}
/**
* 插入节点
* @param $node 根节点
* @param $value 关键值
*/
public function insert(&$node, $value)
{
// $value为 null、 '' 的情况
if (empty($value) && $value !== 0) {
return ;
}
if ($node == null) {
// 创建结点
$node = $this->createNode($value);
} else if ($value < $node->value) {
$this->insert($node->left, $value);
} else {
$this->insert($node->right, $value);
}
}
/**
* 先序遍历
* @param $node 根节点
*/
public function preOrder(&$node)
{
if ($node != null) {
echo $node->value . PHP_EOL ;
$this->preOrder($node->left);
$this->preOrder($node->right);
}
}
/**
* 中序遍历
* @param $node 根节点
*/
public function middleOrder(&$node)
{
if ($node != null) {
$this->middleOrder($node->left);
echo $node->value . PHP_EOL ;
$this->middleOrder($node->right);
}
}
/**
* 后序遍历
* @param $node 根节点
*/
public function afterOrder(&$node)
{
if ($node != null) {
$this->afterOrder($node->left);
$this->afterOrder($node->right);
echo $node->value . PHP_EOL;
}
}
}
$tree = new BinarySearchTree();
$tree->insert($tree->root, 3);
$tree->insert($tree->root, 9);
$tree->insert($tree->root, 2);
$tree->insert($tree->root, 20);
echo "先序遍历".PHP_EOL;
$tree->preOrder($tree->root);
echo "中序遍历" . PHP_EOL;
$tree->middleOrder($tree->root);
echo "后序遍历" . PHP_EOL;
$tree->afterOrder($tree->root);
输出:
先序遍历
3
2
9
20
中序遍历
2
3
9
20
后序遍历
2
20
9
3
9 接口,抽象类
参阅 https://www.cnblogs.com/kangxl/p/6347179.html
一、 抽象类abstract class
1、抽象类是指在 class 前加了 abstract 关键字且存在抽象方法(在类方法 function 关键字前加了 abstract 关键字)的类。
2、抽象类不能被直接实例化。抽象类中只定义(或部分实现)子类需要的方法。 子类可以通过继承抽象类并通过实现抽象类中的所有抽象方法,使抽象类具体化。
3、如果子类需要实例化,前提是它实现了抽象类中的所有抽象方法。如果子类没有全部实现抽象类中的所有抽象方法, 那么该子类也是一个抽象类,必须在 class 前面加上 abstract 关键字,并且不能被实例化。
二、 接口interface
1、抽象类提供了具体实现的标准,而接口则是纯粹的模版。接口只定义功能,而不包含实现的内容。接口用关键字 interface 来声明。
2、 interface 是完全抽象的,只能声明方法,而且只能声明 public 的方法,不能声明 private 及 protected 的方法, 不能定义方法体,也不能声明实例变量 。然而, interface 却可以声明常量变量 。 但将常量变量放在 interface 中违背了其作为接口的作用而存在的宗旨,也混淆了 interface 与类的不同价值。 如果的确需要,可以将其放在相应的 abstract class 或 Class 中。
三、 抽象类和接口的异同
- 相同点:
(1) 两者都是抽象类,都不能实例化。
(2) interface 实现类及 abstract class 的子类都必须要实现已经声明的抽象方法。
- 不同点:
(1) interface 需要实现,要用 implements ,而 abstract class 需要继承,要用 extends 。
(2) 一个类可以实现多个 interface ,但一个类只能继承一个 abstract class 。
(3) interface 强调特定功能的实现,而 abstract class 强调所属关系。
(4) 尽管 interface 实现类及 abstract class 的子类都必须要实现相应的抽象方法,但实现的形式不同。 interface 中的每一个方法都是抽象方法,都只是声明的 (declaration, 没有方法体 ) ,实现类必须要实现。 而 abstract class 的子类可以有选择地实现。这个选择有两点含义:
- a) abstract class 中并非所有的方法都是抽象的,只有那些冠有 abstract 的方法才是抽象的,子类必须实现。 那些没有 abstract 的方法,在 abstract class 中必须定义方法体;
- b) abstract class 的子类在继承它时,对非抽象方法既可以直接继承,也可以覆盖;而对抽象方法,可以选择实现, 也可以留给其子类来实现,但此类必须也声明为抽象类。既是抽象类,当然也不能实例化。
(5) abstract class 是 interface 与 class 的中介。 abstract class 在 interface 及 class 中起到了承上启下的作用。 一方面, abstract class 是抽象的,可以声明抽象方法,以规范子类必须实现的功能;另一方面,它又可以定义缺省的方法体, 供子类直接使用或覆盖。另外,它还可以定义自己的实例变量,以供子类通过继承来使用。
(6) 接口中的抽象方法前不用也不能加 abstract 关键字,默认隐式就是抽象方法,也不能加 final 关键字来防止抽象方法的继承。 而抽象类中抽象方法前则必须加上 abstract 表示显示声明为抽象方法。
(7) 接口中的抽象方法默认是 public 的,也只能是 public 的,不能用 private , protected 修饰符修饰。 而抽象类中的抽象方法则可以用 public ,protected 来修饰,但不能用 private 。
- interface 的应用场合
(1) 类与类之间需要特定的接口进行协调,而不在乎其如何实现。
(2) 作为能够实现特定功能的标识存在,也可以是什么接口方法都没有的纯粹标识。
(3) 需要将一组类视为单一的类,而调用者只通过接口来与这组类发生联系。
(4) 需要实现特定的多项功能,而这些功能之间可能完全没有任何联系。
- abstract class 的应用场合
一句话,在既需要统一的接口,又需要实例变量或缺省的方法的情况下,就可以使用它。最常见的有:
(1) 定义了一组接口,但又不想强迫每个实现类都必须实现所有的接口。可以用 abstract class 定义一组方法体, 甚至可以是空方法体,然后由子类选择自己所感兴趣的方法来覆盖。
(2) 某些场合下,只靠纯粹的接口不能满足类与类之间的协调,还必需类中表示状态的变量来区别不同的关系。 abstract 的中介作用可以很好地满足这一点。
(3) 规范了一组相互协调的方法,其中一些方法是共同的,与状态无关的,可以共享的,无需子类分别实现; 而另一些方法却需要各个子类根据自己特定的状态来实现特 定的功能 。
10 引号问题
‘$var’ 和 “$var” 的区别
双引号串中的内容可以被解释而且替换,而单引号串中的内容总被认为是普通字符。
在单引号串中甚至反斜杠也失去了他的扩展含义(除了插入反斜杠 \ 和插入单引号 ')。 所以,当你想在字串中进行变量代换和包含 \n(换行符)等转义序列时,你应该使用双引号。 单引号串可以用在其他任何地方,脚本中使用单引号串处理速度会更快些。
11 截取文件名后缀
截取文件名后缀的方法或函数。
<?php
echo substr(strrchr($file, '.'), 1);
echo substr($file, strrpos($file, '.')+1);
$arr=explode('.', $file);
echo $arr[count($arr)-1];
$arr=explode('.', $file);
echo end($arr);
echo strrev(explode('.', strrev($file))[0]);
echo pathinfo($file)['extension'];
echo pathinfo($file, PATHINFO_EXTENSION);
12 访问网页经历过程
从用户在浏览器中输入网址并回车,到看到完整的见面,中间都经历了哪些过程。
以 PHP 为例:通常最简单的回答,从用户的电脑找到最近的 DNS 服务,然后解析到对应的 IP 然后双方开始 HTTP 连接, 然后发送请求信息,服务器拿到请求信息就开始准备回应的信息,中间要经过 nginx 转发到 frstCGI (PHP-FPM), 然后 PHP 开始解析框架,解析请求头部,找到对应的 API,该查数据库查数据,该组装 HTML 组装 HTML, 完事了就重新返回给用户。用户拿到返回数据,浏览器开始渲染页面,JS 开始加载。
13 foreach &引用问题
<?php
$a=[1,2,3];
foreach ($a as &$v){}
foreach ($a as $v){}
var_dump($a);
输出什么?
输出:122
foreach 完之后,$index , $value 并不会消失保留最后一次赋值。 这里的第一次 foreach 之后,数组中最后一个元素变成引用,引用变量 $v 继续存在且指向数组的最后一个元素。 第二次遍历,因为遍历变量名是 $v , 所以等于说每次遍历都将此次遍历的值修改成最后元素的值, 直至到遍历最后一个元素(引用元素),因为此时数组的最后一个元素已被修改成上一个元素的值, 最后一次赋值就是 自己 == 自己。 故最后一个等于倒数第二个。
参阅 https://www.php.net/manual/zh/control-structures.foreach.php https://learnku.com/articles/7001/php-ray-foreach-and-references-thunder
14 IO异步模型
参阅 https://cloud.tencent.com/developer/article/1005481、 https://ibaiyang.github.io/blog/php/2023/09/28/PHP-IO多路复用.html
15 海量数据处理方法
参阅 https://blog.csdn.net/v_JULY_v/article/details/6279498
16 进程模型
参阅 https://www.jianshu.com/p/542935a3bfa8
17 CAP 原理
让你实现一个简单的架构,并保持高可用,两个接口,一个上传一条文本,一个获取上传的内容,你怎么来设计? 要避免单机房故障,同时要让代码层面无感。
参考:分布式架构设计必备 CAP 原理。
18 怎么解决跨域
- 服务代理模式
- 跨子域名的调用
- CORS跨源资源共享
- 使用JSONP协议
- 跨文档消息(Cross-document Messaging)
参见 https://ibaiyang.github.io/blog/网络协议/2021/02/23/CORS-跨域资源共享.html
参见 https://ibaiyang.github.io/blog/php/2018/08/11/PHP-跨域请求解决方法.html
19 json 和 xml 区别
json 和 xml 区别,各有什么优缺点
(1)可读性方面:基本相同,XML 的可读性比较好;
(2)可扩展性方面:都具有良好的扩展性;
(3)编码难度方面:相对而言,JSON 的编码比较容易;
(4)解码难度:JSON 的解码难度基本为零,XML 需要考虑子节点和父节点;
(5)数据体积方面:JSON 相对于 XML 来讲,数据体积小,传递的速度比较快;
(6)数据交互方面:JSON 与 javascript 的交互更加方便,更容易解析处理,更好的数据交互;
(7)数据描述方面:XML 对数据描述性比较好;
(8)传输速度方面:JSON 的速度远远快于 XML。
20 查找最长公共子串
参阅 https://www.jb51.net/article/128445.htm
PHP实现求两个字符串最长公共子串的方法。
LCS经典算法:
<?php
class LCS{
public static function main(){
//设置字符串长度
$substringLength1 = 20;
$substringLength2 = 20; //具体大小可自行设置
$opt=array_fill(0,21,array_fill(0,21,null));
// 随机生成字符串
$x = self::GetRandomStrings($substringLength1);
$y = self::GetRandomStrings($substringLength2);
$startTime = microtime(true);
// 动态规划计算所有子问题
for ($i = $substringLength1 - 1; $i >= 0; $i--){
for ($j = $substringLength2 - 1; $j >= 0; $j--){
if ($x[$i] == $y[$j])
$opt[$i][$j] = $opt[$i + 1][$j + 1] + 1;
else
$opt[$i][$j] = max($opt[$i + 1][$j], $opt[$i][$j + 1]);
}
}
echo "substring1:".$x."\r\n";
echo "substring2:".$y."\r\n";
echo "LCS:";
$i = 0;
$j = 0;
while ($i < $substringLength1 && $j < $substringLength2){
if ($x[$i] == $y[$j]){
echo $x[$i];
$i++;
$j++;
} else if ($opt[$i + 1][$j] >= $opt[$i][$j + 1])
$i++;
else
$j++;
}
$endTime = microtime(true);
echo "\r\n";
echo "Totle time is " . ($endTime - $startTime) . " s";
}
public static function GetRandomStrings($length){
$buffer = "abcdefghijklmnopqrstuvwxyz";
$str="";
for($i=0;$i<$length;$i++){
$random=rand(0,strlen($buffer)-1);
$str.=$buffer[$random];
}
return $str;
}
}
LCS::main();
运行结果:
substring1:cgqtdaacneftabsxvmlb
substring2:suwjwwakzzhghbsmnksg
LCS:absm
Totle time is 0.000648975372314 s
方法二:
<?php
$a = 'abceee12345309878';
$b = 'abceeew2345i09878fsfsfsfabceeewsfsdfsfsabceeew';
$c = array();
$lenht1 = strlen($a);
$lenth2 = strlen($b);
$startTime = microtime(true);
for ($i=0;$i<$lenht1;$i++) {
for ($j=0;$j<$lenth2;$j++) {
$n = ($i-1>=0 && $j-1>=0)?$c[$i-1][$j-1]:0;
$n = ($a[$i] == $b[$j]) ? $n+1:0;
$c[$i][$j] = $n;
}
}
foreach ($c as $key=>$val) {
$max = max($val);
foreach ($val as $key1 =>$val1) {
if ($val1 == $max && $max>0) {
$cdStr[$max] = substr($b,$key1-$max+1,$max);
}
}
}
ksort($cdStr);
$endTime = microtime(true);
echo "Totle time is " . ($endTime - $startTime) . " s"."<br/>";
print_r(end($cdStr));
exit;
运行结果:
Totle time is 0.0012800693512 s
abceee
21 进程间通信方式有哪些
1) 管道
管道分为有名管道和无名管道
无名管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。 进程的亲缘关系一般指的是父子关系。无名管道一般用于两个不同进程之间的通信。当一个进程创建了一个管道, 并调用 fork 创建自己的一个子进程后,父进程关闭读管道端,子进程关闭写管道端,这样提供了两个进程之间数据流动的一种方式。
有名管道也是一种半双工的通信方式,但是它允许无亲缘关系进程间的通信。
2) 信号量
信号量是一个计数器,可以用来控制多个线程对共享资源的访问., 它不是用于交换大批数据,而用于多线程之间的同步。 它常作为一种锁机制,防止某进程在访问资源时其它进程也访问该资源。因此,主要作为进程间以及同一个进程内不同线程之间的同步手段.
3) 信号
信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生.
4) 消息队列
消息队列是消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少, 管道只能承载无格式字节流以及缓冲区大小受限等特点。消息队列是 UNIX 下不同进程之间可实现共享资源的一种机制, UNIX 允许不同进程将格式化的数据流以消息队列形式发送给任意进程。 对消息队列具有操作权限的进程都可以使用 msget 完成对消息队列的操作控制。 通过使用消息类型,进程可以按任何顺序读信息,或为消息安排优先级顺序.
5) 共享内存
共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。 共享内存是最快的 IPC (进程间通信) 方式,它是针对其它进程间通信方式运行效率低而专门设计的。 它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步与通信.
6) 套接字:可用于不同及其间的进程通信
22 缓存只留热数据
设计一个缓存系统,可以定期或空间占满之后自动删除长期不用的数据,不能使用用遍历。
用链表来存,缓存命中就将该缓存移到链表头,然后链表尾就都是冷数据了。
23 PHP 的协程以及用途
参阅 https://www.laruence.com/2015/05/28/3038.html 、 https://blog.csdn.net/gavin_new/article/details/54603490
一. 什么是协程(Coroutine)?
在协程出现之前,要实现多任务并发,在无OS(操作系统)时代,可以使用状态机的思想对多任务进行拆解, 在单进程环境中运行多任务,但是这种模式下需要开发者对每个任务有清晰的了解,也要开发者自行开发与任务相关功能(如任务间的通讯)。
后来出现了OS(操作系统),咱们就开始使用OS提供的进程和线程功能来轻易实现多任务了。 在OS中,进程的上下文切换是OS内核控制。但是后来却出现了一个问题,频繁的进程上下文切换导致了OS性能的降低(主要是短时执行消耗小的任务进程)。
为了解决这个问题,开始提出新的概念,就是在同一进程或线程中运行多个任务, 这种问题就相当于回到了早期的无OS时代的多任务实现。而现在解决方案称为协程。其本质是,将将任务切换的部分工作从内核转移到应用层。
二. php中协程的基本工具以及基本使用
要实现协程,php给出了两个新东西:生成器和yield关键字。
生成器继承了实现了迭代器,在php代码中和函数的定义类似,不过内部使用了yield关键字,如:
<?php
function gen(){
echo "hello gen".PHP_EOL; //step1
$ret = (yield "gen1"); //step2
var_dump($ret);//step3
$ret = (yield "gen2)"); //step4
var_dump($ret); //step5
}
使用时,这样子:
<?php
$my_gen = gen();
var_dump($my_gen->current());
var_dump($my_gen->send("main send"));
好了,这样使用代表什么意思呢?
- (1)首先$my_gen = gen();这句代码只是实例化一个新的生成器,里面的代码并未执行;
- (2)$my_gen->current();这句代码就执行了生成器里面的step2中的yield “gen1”了,这时代码中断,并 且字符串“gen1”被传进了生成器$my_gen,并且作为current()函数的返回值;
- (3)send(“main send”)执行完之后,字符串”main send”被传递进了生成器$my_gen, 同时生成器作为step2中yield的返回值传递给ret;
- (4) 生成器step3执行完后,在step4时,遇到yield就会再次进入中断。
三. 协程的特点
(1)为应用层实现多任务提供了工具;
(2)协程不允许多任务同时执行,要执行其它协程,必须使用关键字yield主动放弃cpu控制权;
(3)协程需要自己写任务管理器,以及任务调度器;
(4)减轻了OS处理零散任务和轻量级任务的负担;
一般什么会导致服务器阻塞
file_get_contents
mysql_connect
session_start
忘记关闭连接
大量并发UPDATE +1
consumer执行复杂运算
防止SQL注入
PHP 防SQL注入技术的方法有哪些?
魔术引号
addslashes()
mysql_real_escape_string
mysqli_real_escape_string
PDO::quote
预处理语句
正则匹配替换
htmlspecialchars
FPM与Swoole的访问速度比较
在比较FPM(FastCGI Process Manager,通常指的是PHP-FPM)和Swoole的访问速度时,我们可以从以下几个方面进行分析:
- 同步与异步IO模型:
- FPM:采用同步IO模型,这意味着在处理一个请求时,PHP进程会阻塞等待直到该请求处理完成,然后才能处理下一个请求。这种模型在高并发场景下可能会导致资源利用不充分和性能瓶颈。
- Swoole:采用异步IO模型,允许PHP进程在处理一个请求时同时处理其他请求,不需要等待当前请求完成。这种模型可以显著提高PHP程序的响应速度和并发处理能力。
- 并发处理能力:
- FPM:通过进程管理器管理多个PHP进程,每个进程独立处理请求。虽然可以通过增加进程数量来提高并发处理能力,但受限于系统资源和进程切换的开销。
- Swoole:基于异步IO和协程技术,可以在单个PHP进程中实现多任务并发处理,避免了进程切换的开销。同时,Swoole支持多进程模型,可以进一步提高并发处理能力。
- 协议支持:
- FPM:主要支持HTTP协议,与Web服务器(如Nginx、Apache)进行通信。
- Swoole:除了支持HTTP协议外,还支持TCP、UDP和UnixSocket协议,适用于更多样化的应用场景。
- 缓存机制:
- FPM:可以结合PHP的缓存机制(如OPcache)来提高性能,减少编译时间。
- Swoole:同样可以利用PHP的缓存机制,但由于其异步IO和协程特性,可以更高效地利用缓存资源。
- 配置和优化:
- FPM:通过调整配置文件(如php-fpm.conf)中的参数,如进程池大小、闲置超时时间等,可以优化FPM的性能。
- Swoole:Swoole的性能优化更多地依赖于其异步IO和协程特性,以及适当的编程实践来避免阻塞和减少资源竞争。
- 总结:
- 在访问速度方面,Swoole由于其异步IO和协程特性,通常会比FPM具有更高的性能和更好的并发处理能力。 特别是在高并发、大流量访问下的应用场景中,Swoole的优势更加明显。
- 然而,FPM作为PHP的标准处理方式,具有广泛的兼容性和稳定性,适用于大多数Web应用场景。在选择使用FPM还是Swoole时,需要根据具体的应用需求和系统环境进行权衡。
参考资料
PHP 高级工程面试题汇总 https://learnku.com/articles/20714