[TOC]
# 字符串 == 比較類型強轉隱患
~~~
// php 5
var_dump(md5('240610708') == md5('QNKCDZO'));//bool(true)
var_dump(md5('aabg7XSs') == md5('aabC9RqS'));//bool(true)
var_dump(sha1('aaroZmOk') == sha1('aaK1STfY'));//bool(true)
var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m'));//bool(true)
var_dump('0010e2' == '1e3');//10×10^2 = 1×10^3 bool(true)
var_dump('0x1234Ab' == '1193131');//bool(true)
var_dump('0xABCdef' == ' 0xABCdef');//bool(true)
var_dump("603E-4234" == "272E-3063");//bool(true)
var_dump('0e1' == '0e2'); //bool(true)
// php 7 含十六進制字符串不再被認為是數字 http://php.net/manual/zh/migration70.incompatible.php
var_dump('0x1234Ab' == '1193131');//bool(false)
var_dump('0xABCdef' == ' 0xABCdef');//bool(false)
var_dump("0x123" == "291");//bool(false)
var_dump(is_numeric("0x123"));//bool(false)
>>> md5('240610708')
=> "0e462097431906509019562988736854"
>>> md5('QNKCDZO')
=> "0e830400451993494058024219903391"
// php 是弱語言,會自動判斷數據類型,0eXXXXXXXXXX 轉成 0 了
//來自文檔:如果比較一個數字和字符串或者比較涉及到數字內容的字符串,則字符串會被轉換為數值并且比較按照數值來進行。此規則也適用于 switch 語句。當用 === 或 !== 進行比較時則不進行類型轉換,因為此時類型和數值都要比對。
>>> md5('QNKCDZO')==0
=> true
>>> md5('240610708')==0
=> true
// 使用 === 判斷 官方都建議直接用password_hash加密
var_dump(md5('240610708') === md5('QNKCDZO'));//bool(false)
//http://bayescafe.com/php/yuebaomei-ctf.html
var_dump("42"=="0x2A");//bool(true)
var_dump("1" == "01"); // 1 == 1 -> true
var_dump("10" == "1e1"); // 10 == 10 -> true
var_dump(100 == "1e2"); // 100 == 100 -> true
var_dump("\x34\x32\x2E"=="42");//bool(true)
var_dump("\001abc");//abc
var_dump('\001abc');//\001abc
$a = "1234567";
var_dump($a['test']);//1
var_dump(in_array(false, array('xxx')));//false
empty('0');//false
"133" == "0133";
133 == "0133";
133 == 0133; //因為0133是一個八進制數,轉成十進制是91
"0133" != 91; //字符串中的數字始終是十進制的,這個也可以理解
"0x10" == 16; //但是!,在十六進制中上面的說法又不成立了
"1e3" == 1000; //科學計數表示也一樣
#'string' == true,而且'string' == 0,但是,true != 0
null == 0;
null < -1;
$flag = "THIS IS FLAG";
if ("POST" == $_SERVER['REQUEST_METHOD'])
{
$password = $_POST['password'];//420.00000e-1
if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password))
{
echo 'Wrong Format';
exit;
}
while (TRUE)
{
$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr))
break;
$c = 0;
$ps = array('punct', 'digit', 'upper', 'lower');
foreach ($ps as $pt)
{
if (preg_match("/[[:$pt:]]+/", $password))
$c += 1;
}
if ($c < 3) break;
if ("42" == $password) echo $flag;
else echo 'Wrong password';
exit;
}
}
//https://segmentfault.com/q/1010000012046306
$red_money = 143.66;
$receive_money = 14.55;
$residue_money = $red_money > $receive_money ? $red_money - $receive_money : 0;
$receive_money = $residue_money * 100;
var_dump($receive_money);//12911
var_dump((int)$receive_money);/12910
var_dump(intval(12910.9));//int(12910)
var_dump($receive_money*10000);//12910000
var_dump((int)($receive_money*10000));//12910999
var_dump(decbin($receive_money));
var_dump(decbin(12911));
~~~
# PDO bindParam 要求第二個參數是一個引用變量
~~~
$dbh = new PDO('mysql:host=localhost;dbname=test', "test");
$query = <<<QUERY
INSERT INTO `user` (`username`, `password`) VALUES (:username, :password);
QUERY;
$statement = $dbh->prepare($query);
$bind_params = array(':username' => "laruence", ':password' => "weibo");
foreach( $bind_params as $key => $value ){
$statement->bindParam($key, $value);
}
$statement->execute();
//期望執行 sql
INSERT INTO `user` (`username`, `password`) VALUES ("laruence", "weibo");
// 實際執行 sql
INSERT INTO `user` (`username`, `password`) VALUES ("weibo", "weibo");
//第一次循環
$value = $bind_params[":username"];
$statement->bindParam(":username", &$value); //此時, :username是對$value變量的引用
//第二次循環
$value = $bind_params[":password"]; //oops! $value被覆蓋成了:password的值
$statement->bindParam(":password", &$value);
// 解決
foreach( $bind_params as $key => &$value ) { //注意這里
$statement->bindParam($key, $value);
}
return $statement->execute($params);
~~~
# php引用
~~~
$arr = range(1,3);
foreach($arr as &$v){
}
foreach($arr as $v){
}
print_r($arr);//[1,2,2]
// 解決一
$arr = range(1,3);
foreach($arr as &$v){
}
unset($v);
foreach($arr as $v){
}
print_r($arr);//[1,2,3]
// 解決二
$arr = range(1,3);
foreach($arr as &$v){
}
foreach($arr as $v2){
}
print_r($arr);//[1,2,3]
// 解決三
$arr = range(1,3);
foreach($arr as &$v){
}
foreach($arr as &$v){
}
print_r($arr);//[1,2,3]
~~~
# array_merge vs +
~~~
$arr1 = array(1 => "one", "2" => "two", 3 => "three");
$arr2 = array(2 => "new two", 3 => "new three");
print_r($arr1 + $arr2);
Array
(
[1] => one
[2] => two
[3] => three
)
print_r(array_merge($arr1, $arr2));
Array
(
[0] => one
[1] => two
[2] => three
[3] => new two
[4] => new three
)
~~~
# 浮點數精度問題
~~~
var_dump(15702>=(157.02*100));//bool(false)
var_dump(11111>=(111.11*100));//bool(true)
var_dump(bcsub(15702,(157.02*100)) >= 0);//bool(true)
if(abs(15702-(157.02*100)) < 0.001) {
echo "相等";
} else {
echo "不相等";
}
$f = 0.58;
var_dump(intval($f * 100)); //57 0.58 * 100 = 57.999999999...
~~~
# in_array switch/case 松散比較
~~~
$arr = ['a', 'pro' => 'php', 8, true];
var_dump(in_array(2, $arr)); // bool(true)
var_dump(in_array('b', $arr)); // bool(true)
var_dump(in_array(0, $arr)); // tbool(true)
var_dump(in_array(null, $arr)); // bool(false)
var_dump(in_array(2, $arr, true)); // bool(false)
var_dump(in_array(0, $arr, true)); // bool(false)
$name = 0;
switch ($name) {
case "a":
//...
break;
case "b":
//...
break;
}
switch (strval($name)) {
case "a":
//...
break;
case "b":
//...
break;
}
//http://php.net/manual/zh/types.comparisons.php#types.comparisions-loose
function test($var)
{
switch (true)
{
case 'apple' === $var:
echo 'apple', PHP_EOL;
break;
case 0 === $var:
echo '0', PHP_EOL;
break;
default:
echo 'default', PHP_EOL;
}
}
$arr = array('0', 0, 'apple');
foreach ($arr as $value)
{
test($value);
}
~~~
# strpos
~~~
function getReferer($link)
{
$refMap = [
'baidu' => '百度',
'sougou' => '搜狗',
'360' => '360',
'google' => '谷歌'
];
foreach ($refMap as $key => $value) {
if (strpos($link, $key) !== false) {
return $value;
}
}
return '其他';
}
// https://secure.php.net/manual/zh/function.strpos.php 如果 needle 不是一個字符串,那么它將被轉換為整型并被視為字符的順序值。
echo getReferer('https://www.google.com/search?workd=google');//360
// 解決
function getReferer($link)
{
$refMap = [
'baidu' => '百度',
'sougou' => '搜狗',
'360' => '360',
'google' => '谷歌'
];
foreach ($refMap as $key => $value) {
if (mb_strpos($link, $key) !== false) {
//if (strpos($link, strval($key)) !== false) {
return $value;
}
}
return '其他';
}
~~~
# PHP 不同版本 curl 文件上傳
~~~
//PHP的cURL支持通過給CURL_POSTFIELDS傳遞關聯數組(而不是字符串)來生成multipart/form-data的POST請求 https://blog.zsxsoft.com/post/5
if (class_exists('\CURLFile')) {
$field = array('fieldname' => new \CURLFile(realpath($filepath)));
} else {
$field = array('fieldname' => '@' . realpath($filepath));
}
~~~
# foreach 順序
~~~
$arr=[];
$arr[2] = 2;
$arr[1] = 1;
$arr[0] = 0;
foreach ($arr as $key => $val) {
echo $val;// 2 1 0
}
while (list($key, $v) = each($arr)) {
//獲取不到 foreach會自動reset,each之前, 先reset數組的內部指針
}
for($i=0,$l=count($arr); $i<$l; $i++) {
echo $arr[$i];// 0 1 2
}
~~~
# json_decode
~~~
>>> json_decode('php')
=> null
// 對非 json 字符串并非返回 null
>>> json_decode('0x123')
=> 291
echo json_encode(["name" => "php", "age" => "22"]) . "\n";// {"name":"php","age":"22"}
echo json_encode([]) . "\n";//[] 返回這個會讓 APP 崩潰
echo json_encode((object)[]) . "\n";//{}
>>> $a = 0.1 + 0.7
=> 0.8
>>> printf('%.20f', $a)
=> 0.79999999999999993339
>>> json_encode($a)
=> "0.7999999999999999"
>>> \YaJson::encode($a)//https://github.com/seekerliu/laravel-another-json
=> "0.8"
ini_set('serialize_precision', 14);
$a = 0.1 + 0.7;
echo json_encode($a);//0.8
echo json_decode(0.7999999999999999);//0.8
~~~
# strtotime('-x month')
~~~
date_default_timezone_set('Asia/Shanghai');
$t = strtotime('2017-08-31');
echo date('Ym',strtotime('- 1 month',$t));//201707
echo date('Ym',strtotime('- 2 month',$t));//201707 ?
//
$first_day_of_month = date('Y-m',strtotime('2017-08-31')) . '-01 00:00:01';
$t = strtotime($first_day_of_month);
echo date('Ym',strtotime('- 1 month',$t));//201707
echo date('Ym',strtotime('- 2 month',$t));//201706
echo date("Ym", strtotime("-2 month", strtotime("first day of 2017-08-31")));//201706
~~~
# BOM
~~~
//json 解析成 null 寫代碼時指定 utf-8 without bom
function remove_utf8_bom($text)
{
$bom = pack('H*','EFBBBF');
$text = preg_replace("/^$bom/", '', $text);
return $text;
}
// ps:PHP導出Excel 可能會亂碼,需要寫入 BOM頭
$content = pack('H*','EFBBBF');
fwrite($fp, $content);
~~~
# PHP解析大整數
~~~
$shopId = 17978812896666957068;
var_dump($shopId);//float(1.7978812896667E+19)
$shopId= number_format(17978812896666957068);
var_dump($shopId);//17978812896666957824
$shopId= strval(17978812896666957068);
var_dump($shopId);
$shopId = 17978812896666957068 . '';
var_dump($shopId);//float(1.7978812896667E+19)
$shopId = '17978812896666957068';
var_dump($shopId);
// 輸出
// string(20) "17978812896666957068"
超過PHP最大表示范圍的純整數,在MySQL中可以使用bigint/varchar保存,MySQL在查詢出來的時候會將其使用string類型保存的。 對于賦值,在PHP里,如果遇到有大整數需要賦值的話,不要嘗試用整型類型去賦值$var = '17978812896666957068';
#
~~~
# curl獲取網頁內容出現亂碼
~~~
curl_setopt($ch,CURLOPT_ENCODING,'gzip')//)如果抓取的網頁進行了gzip壓縮 加入gzip解析
$data = file_get_contents("compress.zlib://".$url); //???? Header 里 Accept-Encoding:gzip 是告訴對方服務器使用 Gzip 進行傳輸。 ????
~~~
# trim 中文亂碼
~~~
echo rawurlencode('河北省');//%E6%B2%B3%E5%8C%97%E7%9C%81
echo rawurlencode('廣東省');//%E5%B9%BF%E4%B8%9C%E7%9C%81
echo rtrim('河北省', '省');//河北
echo rtrim('廣東省', '省');//廣??
//省的十六制作表示是e7 9c 81,而東的十六進制表示是e4 b8 9c,都出現了9c,哦~正因為是rtrim,所以rtrim('廣東省', '省')的時候把“東”的十六進制表示的最后一位也被trim掉了。同理rtrim('河北省', '省')不存在此問題
echo trim_cn('廣東省','省');//廣東
function trim_cn($str, $trim, $charset = 'UTF-8') {
$len = mb_strlen($str, $charset);
if (!$len)
return;
$t1 = $t2 = false;$o=$l=0;
for($i=0;$i<$len;$i++)
{
$str1 = mb_substr($str, $i, 1, $charset);
$str2 = mb_substr($str, $len-$i-1, 1, $charset);
if($str1 == $trim && !$t1) $o++; else $t1 = true;
if($str2 == $trim && !$t2) $l++; else $t2 = true;
}
return mb_substr($str, $o, ($len-$l-$o), $charset);;
}
~~~
# __callStatic
~~~
//在對象中調用一個不可訪問方法時,__call() 會被調用
//在靜態上下文中調用一個不可訪問方法時,__callStatic() 會被調用 目標方法非 public 時__callStatic 才會起作用。
class A{
public static function __callStatic($name, $arguments)
{
echo $name.'靜態方法不存在!';
}
public function test()
{
echo 'test 方法';
}
}
A::test();//test 方法
~~~
# mb_substr字符編碼
~~~
$str = '北京市朝陽區';
var_dump(mb_substr($str,0,3));//預期輸出是:string(9) "北京市",但是輸出確是:string(3) "北"
//mb_substr這個函數在操作的時候如果沒有傳字符編碼,則按照默認的內部編碼操作字符串。PHP5.6之前的默認編碼都是ISO-8859-1,5.6之后的才是UTF8,UTF8模式下,一個中文字符占3個字節,而ISO-8859-1則是按照一個字節進行處理,所以自然取出來的是異常的字符串。
var_dump(mb_substr($str,0,3,'UTF-8'));//string(9) "北京市"
~~~
# url參數中的+替換為空格
~~~
$name=str_replace('%20','+',$_GET['name']);
//安全 base64
function urlsafeB64Decode($input)
{
$remainder = strlen($input) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= str_repeat('=', $padlen);
}
return base64_decode(strtr($input, '-_', '+/'));
}
function urlsafeB64Encode($input)
{
return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
}
~~~
# array Undefined offset
~~~
# php -a
php > $a=[];
php > echo $a[1];
PHP Notice: Undefined offset: 1 in php shell code on line 1
php > $a=null;
php > echo $a[1];
php > $a=4;
php > echo $a[1];
~~~
# 數組比較
~~~
array("foo", "bar") != array("bar", "foo"); //這個時候,array就是數組
array("foo" => 1, "bar" => 2) == array("bar" => 2, "foo" => 1); //這個時候,array又變成了無序hash表
$first = array("foo" => 123, "bar" => 456);
$second = array("foo" => 456, "bar" => 123);
var_dump(array_diff($first, $second));
==> array()
~~~
# 數組序列化
~~~
$arrA = array('a', 'b', 'c');
echo json_encode($arrA) . "\n";
$arrB = array('a' => 1, 'b' => 2, 'c' => 3);
echo json_encode($arrB) . "\n";
["a","b","c"]
{"a":1,"b":2,"c":3}
$arrA = array(1 => 'a', 2 => 'b', 3 => 'c');
echo json_encode($arrA) . "\n";
$arrA = array(0 => 'a', 2 => 'b', 3 => 'c');
echo json_encode($arrA) . "\n";
{"1":"a","2":"b","3":"c"}
{"0":"a","2":"b","3":"c"}
//僅當數組的key是從0開始的整數,并且key連續不間斷,對其序列化的結果才是JS中的數組,也就是通常認為的PHP索引數組。
~~~
- OAuth
- 簡介
- 步驟
- 單點登錄
- .user.ini
- 時間轉換為今天昨天前天幾天前
- 獲取ip接口
- 協程
- 概念
- yield-from && return-values
- 協程與阻塞的思考
- 中間件
- mysqli異步與php的協程
- 代碼片段
- pdo 執行的sql語句
- 二進制安全
- 捕捉異常中斷
- global
- 利用cookie模擬登陸
- 解析非正常json
- 簡單的對稱加密算法
- RSA 加密
- 過濾掉emoji表情
- 判斷遠程圖片是否存在
- 一分鐘限制請求100次
- 文件處理
- 多文件上傳
- 顯示所有文件
- 文件下載和上面顯示所有文件配合
- 文件的刪除,統計,存數組等
- 圖片處理
- 簡介
- 驗證碼
- 圖片等比縮放
- 批量添加水印
- beanstalkd
- 安裝
- 使用
- RabbitMQ
- 簡介
- debain安裝
- centos安裝
- 常用方法
- 入門
- 工作隊列
- 訂閱,發布
- 路由
- 主題
- 遠程調用RPC
- 消息中間件的選型
- .htaccess
- isset、empty、if區別以及0、‘’、null
- php各版本
- php7.2 不向后兼容的改動
- php中的各種坑
- php7改變
- php慢日志
- 郵件
- PHPMailer實現發郵件
- 驗證郵件地址真實性
- 文件下載
- FastCgi 與 PHP-fpm 之間的關系
- openssl 加解密
- 反射
- 鉤子方法
- 查找插件
- opcode
- opcache使用
- opcache優化
- 分布式一致性hash算法
- 概念
- 哈希算法好壞的四個定義
- php實現
- java實現
- 數組
- jwt
- jwt簡介
- 單點登錄
- phpize
- GeoIP擴展
- php無法獲得https網頁內容的解決方案
- homestead運行的腳本
- Unicode和Utf-8轉換
- php優化
- kafka
- fpm配置
- configure配置詳解