变量提升:先获取变量再执行
标签:label
可以用于跳出代码块
foo: {
console.log(1);
break foo;
console.log('本行不会输出');
}
console.log(2);
// 1
// 2
typeof 运算符 确定变量类型
typeof window
typeof {}
typeof []
typeof null
以上都是Object类型
null表示一个空对象,转为数值为0
undefined是一个表示 此处无定义的原始值 转为数值为NaN
undefined,null,false,0,NaN,""或''都为false, 其他为true
NaN的数据类型依然属于Number,NaN不等于任何值,包括它本身
Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN)
Infinity与NaN比较,总是返回false。
parselnt()用于将字符串转为整数
parseFloat()用于将一个字符串转为浮点数
isNaN()判断一个值是都为NaN
_SSL_VERIFYPEER = 64;
const CURLOPT_WRITEDATA = 10001;
const CURLOPT_WRITEFUNCTION = 20011;
$libcurl = FFI::scope("libcurl");
$write = FFI::scope("write");
$url = "https://www.laruence.com/2020/03/11/5475.html";
$data = $write->new("own_write_data");
$ch = $libcurl->curl_easy_init();
$libcurl->curl_easy_setopt($ch, CURLOPT_URL, $url);
$libcurl->curl_easy_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$libcurl->curl_easy_setopt($ch, CURLOPT_WRITEDATA, FFI::addr($data));
$libcurl->curl_easy_setopt($ch, CURLOPT_WRITEFUNCTION, $write->init());
$libcurl->curl_easy_perform($ch);
$libcurl->curl_easy_cleanup($ch);
ret = FFI::string($data->buf, $data->size);
也就是,我们现在使用
FFI :: scope
来代替
FFI :: load
,引用对应的函数。
static
?
function
?
scope(string $name): FFI;
然后还有另外一个问题,FFI虽然给了我们很大的规模,但是毕竟直接调用C库函数,还是非常具有风险性的,我们应该只允许用户调用我们确认过的函数,于是,
ffi.enable = preload
就该上场了,当我们设置
ffi.enable = preload
的话,那就只有在
opcache.preload
的脚本中的函数才能调用FFI,而用户写的函数是没有办法直接调用的。
我们稍微修改下
ffi_preload.inc
变成
ffi_safe_preload.inc
< php
class CURLOPT {
const URL = 10002;
const SSL_VERIFYHOST = 81;
const SSL_VERIFYPEER = 64;
const WRITEDATA = 10001;
const WRITEFUNCTION = 20011;
}
FFI::load("curl.h");
FFI::load("write.h");
function get_libcurl() : FFI {
return FFI::scope("libcurl");
}
function get_write_data($write) : FFICData {
return $write->new("own_write_data");
}
function get_write() : FFI {
return FFI::scope("write");
}
function get_data_addr($data) : FFICData {
return FFI::addr($data);
}
function paser_libcurl_ret($data) :string{
return FFI::string($data->buf, $data->size);
}
也就是,我们把所有会调用FFI API的函数都定义在
preload
脚本中,然后我们的示例会变成(
ffi_safe.php
):
< php
$libcurl = get_libcurl();
$write = get_write();
$data = get_write_data($write);
$url = "https://www.laruence.com/2020/03/11/5475.html";
$ch = $libcurl->curl_easy_init();
$libcurl->curl_easy_setopt($ch, CURLOPT::URL, $url);
$libcurl->curl_easy_setopt($ch, CURLOPT::SSL_VERIFYPEER, 0);
$libcurl->curl_easy_setopt($ch, CURLOPT::WRITEDATA, get_data_addr($data));
$libcurl->curl_easy_setopt($ch, CURLOPT::WRITEFUNCTION, $write->init());
$libcurl->curl_easy_perform($ch);
$libcurl->curl_easy_cleanup($ch);
$ret = paser_libcurl_ret($data);
这样一来通过
ffi.enable = preload
,我们就可以限制,所有的FFI API只能被我们可控制的
preload
脚本调用,用户不能直接调用。从而我们可以在这些函数内部做好适当的安全保证工作,从而保证一定的安全性。
好了,经历了这个例子,大家应该对FFI有一个比较深入的理解了,详细的PHP API说明,大家可以参考:PHP-FFI Manual,有兴趣的话,就去找一个C库,试试吧?
本文的例子,你可以在我的github上下载到:FFI example
最后还是多说一句,例子只是为了演示功能,所以省掉了很多错误分支的判断捕获,大家自己写的时候还是要加入。毕竟使用FFI的话,会让你会有1000种方式让PHP segfault crash,所以be careful