PHP 那些“坑”
本文持续更新,欢迎关注
字符串 == 比较类型强转隐患
// 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) $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; } }
ps: php 7 优化和不兼容
PDO bindParam 要求第二个参数是一个引用变量
$dbh = new PDO('mysql:host=localhost;dbname=test', "test"); $query = <<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
$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; }
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请求 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);
更多
https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/#operators
http://bayescafe.com/php/the-associativity-of-ternary-operator-in-php.html
http://bayescafe.com/php/yuebaomei-ctf.html
https://www.unphp.net/api/
原文链接:https://segmentfault.com/a/1190000010748235#articleHeader7