在看这函数之前我验证邮箱或IP地址及url都是使用正则表达式来处理,今天发现filter函数可以替换正则哦并且方法简单好用,下面我用实例介绍这函数的用法吧。
早年使用php的时候还不知道有filter这玩意,那时候判断邮箱、url和ip地址格式是否符合都是用正则表达式。后来随着使用的逐渐深入,才知道在php中也可以使用内置的函数库filter来完成这些功能。
1、验证邮箱
先来看原始的正则验证
代码如下 |
复制代码 |
<?php
function isEmail($email){
if(preg_match("/^[0-9a-zA-Z]+@(([0-9a-zA-Z]+)[.])+[a-z]{2,4}$/i",$email )) {
return '邮箱验证OK';
} else {
return '验证不是邮箱';
}
}
?>
|
再看filter这玩意
代码如下 |
复制代码 |
$email = 'sjlinyu@qq.com';
$result = filter_var($email, FILTER_VALIDATE_EMAIL);
var_dump($result); //string(14) "sjlinyu@qq.com"
|
对于filter_var这个函数,如果验证通过则会返回验证对象,否则返回false。
感觉后者更简单一些哦
2、验证url地址
正则验证
代码如下 |
复制代码 |
<?php
$url = 'www.111cn.net';
$search = '/---正则N---/';
if(preg_match($search,$url)){
echo '匹配';
}else {
echo '不匹配';
}
?>
|
filter_var函数
代码如下 |
复制代码 |
$url = "http://www.111cn.net";
$result = filter_var($url, FILTER_VALIDATE_URL);
var_dump($result); //string(22) "http://www.111cn.net"
|
3、验证ip地址
正则验证函数
代码如下 |
复制代码 |
/**
* 检查IP地址是否正确。
*/
function checkipaddres ($ipaddres) {
$preg="/A((([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5])).){3}(([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))Z/";
if(preg_match($preg,$ipaddres))return true;
return false;
}
|
此函数验证
代码如下 |
复制代码 |
$url = "192.168.1.110";
$result = filter_var($url, FILTER_VALIDATE_IP);
var_dump($result); //string(13) "192.168.1.110"
|
值的一提的是,这方法也可以用来验证ipv6。
代码如下 |
复制代码 |
$url = "2001:DB8:2de::e13";
$result = filter_var($url, FILTER_VALIDATE_IP);
var_dump($result); //string(17) "2001:DB8:2de::e13"
|
验证数值是否为整数,并且在一个整数区间内
代码如下 |
复制代码 |
$i = '010';
$result = filter_var(
$i,
FILTER_VALIDATE_INT,
//设定校验的数值范围
array(
'options' => array('min_range' => 1, 'max_range' => 100)
)
);
var_dump($result);//bool(false)
|
php的变量是弱类型,如果不用过滤器,直接使用大于小于符号判断的话会是真的。
代码如下 |
复制代码 |
$i = '010';
$result = $i >= 1 && $i <= 100;
var_dump($result);//bool(true)
|
5、验证浮点数
代码如下 |
复制代码 |
$float = 12.312;
$result = filter_var($float, FILTER_VALIDATE_FLOAT);
var_dump($result); //float(12.312)
|
在做一些金额方面的验证时,经常需要验证金额是否为浮点数。
总结
php中的filter过滤器虽然比较冷门,但是功能还是蛮强大的。除了上述这些功能外,还有一些过滤输入的功能,可查阅php手册。
在php中过滤html字符串的方法有很多,如果我们使用系统自带的可能不适合于提交表单类数据了,如果用自定的相对会好处理一些,下面我介绍了一些方法大家可参考参考。
自定义的一个函数
代码如下 |
复制代码 |
function StripHTML($string){
$pattern=array ("'<script[^>]*?>.*?</script>'si", "'<style[^>]*?>.*?</style>'si", "'<[/!]*?[^<>]*?>'si", "'([rn])[s]+'", "'&(quot|#34);'i", "'&(amp|#38);'i", "'&(lt|#60);'i", "'&(gt|#62);'i", "'&(nbsp|#160);'i", "'&(iexcl|#161);'i", "'&(cent|#162);'i", "'&(pound|#163);'i", "'&(copy|#169);'i", "'&#(d+);'e");
$replace=array ('', '', "\1", '', "&", "<", ">", ' ', chr(161), chr(162), chr(163), chr(169), "chr(\1)");
return preg_replace ($pattern, $replace, $str);
}
|
除了上面自定的函数之外还有一个php自带的过滤html的函数:strip_tags(string) 这样就可以过滤掉所有的html标签了。
如果想过滤掉除了<img" width=100% src="">之外的所有html标签,则可以这样写:
代码如下 |
复制代码 |
strip_tags(string,"<img>");
|
过滤除了<img" width=100% src=""><p>xxx</p><b></b>之外的所有html标签,则可以这样写:
代码如下 |
复制代码 |
strip_tags(string,"<img><p><b>");
|
网上找到一个防sql注入函数
代码如下 |
复制代码 |
//php 批量过滤post,get敏感数据
if (get_magic_quotes_gpc()) {
$_GET = stripslashes_array($_GET);
$_POST = stripslashes_array($_POST);
}
function stripslashes_array(&$array) {
while(list($key,$var) = each($array)) {
if ($key != 'argc' && $key != 'argv' && (strtoupper($key) != $key || ''.intval($key) == "$key")) {
if (is_string($var)) {
$array[$key] = stripslashes($var);
}
if (is_array($var)) {
$array[$key] = stripslashes_array($var);
}
}
}
return $array;
}
//--------------------------
// 替换HTML尾标签,为过滤服务 www.111cn.net
//--------------------------
function lib_replace_end_tag($str)
{
if (empty($str)) return false;
$str = htmlspecialchars($str);
$str = str_replace( '/', "", $str);
$str = str_replace("\", "", $str);
$str = str_replace(">", "", $str);
$str = str_replace("<", "", $str);
$str = str_replace("<SCRIPT>", "", $str);
$str = str_replace("</SCRIPT>", "", $str);
$str = str_replace("<script>", "", $str);
$str = str_replace("</script>", "", $str);
$str=str_replace("select","select",$str);
$str=str_replace("join","join",$str);
$str=str_replace("union","union",$str);
$str=str_replace("where","where",$str);
$str=str_replace("insert","insert",$str);
$str=str_replace("delete","delete",$str);
$str=str_replace("update","update",$str);
$str=str_replace("like","like",$str);
$str=str_replace("drop","drop",$str);
$str=str_replace("create","create",$str);
$str=str_replace("modify","modify",$str);
$str=str_replace("rename","rename",$str);
$str=str_replace("alter","alter",$str);
$str=str_replace("cas","cast",$str);
$str=str_replace("&","&",$str);
$str=str_replace(">",">",$str);
$str=str_replace("<","<",$str);
$str=str_replace(" ",chr(32),$str);
$str=str_replace(" ",chr(9),$str);
$str=str_replace(" ",chr(9),$str);
$str=str_replace("&",chr(34),$str);
$str=str_replace("'",chr(39),$str);
$str=str_replace("<br />",chr(13),$str);
$str=str_replace("''","'",$str);
$str=str_replace("css","'",$str);
$str=str_replace("CSS","'",$str);
return $str;
}
|
使用方法
代码如下 |
复制代码 |
引用是直接这样:
$xxx = htmlspecialchars($_POST['xxx']);
或者
$xxx = htmlspecialchars($_GET['xxx']);
|
如果你直接使用PHP CURL函数来抓取http内容可能没有任何问题了,但是如果你要正抓取的是https文件才会发现本文章帮你解决了一个大难题了,下面我们来看看具体操作过程。
三年前写过一篇《一个简陋的支持HTTPS的PHP CURL封装函数》,当时只是知其然不知其所以然,今天来详细梳理一下。
https服务器post数据
代码如下 |
复制代码 |
function curlPost($url, $data, $timeout = 30)
{
$ssl = substr($url, 0, 8) == "https://" ? TRUE : FALSE;
$ch = curl_init();
$opt = array(
CURLOPT_URL => $url,
CURLOPT_POST => 1,
CURLOPT_HEADER => 0,
CURLOPT_POSTFIELDS => (array)$data,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_TIMEOUT => $timeout,
);
if ($ssl)
{
$opt[CURLOPT_SSL_VERIFYHOST] = 1;
$opt[CURLOPT_SSL_VERIFYPEER] = FALSE;
}
curl_setopt_array($ch, $opt);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
$data = curlPost('https://www.111cn.net', array('p'=>'hello'));
echo ($data);
|
-----------------------------我是分割线--------------------------------
其实这是告诉服务器不进行SSL认证,并不是真的走HTTPS
如果要真正使用HTTPS,那么需要提供CA证书
上面关于SSL部分按照如下设置:
代码如下 |
复制代码 |
01.CURLOPT_SSL_VERIFYPEER 设置为 true ,说明进行SSL证书认证
02.CURLOPT_SSL_VERIFYHOST 设置为 2, 说明进行严格认证
03.CURLOPT_CAINFO 设置为证书的路径
|
为方便说明,先上代码吧~ 这是今天重新封装的一个函数
代码如下 |
复制代码 |
/**
* curl POST
*
* @param string url
* @param array 数据
* @param int 请求超时时间
* @param bool HTTPS时是否进行严格认证
* @return string
*/
function curlPost($url, $data = array(), $timeout = 30, $CA = true){
$cacert = getcwd() . '/cacert.pem'; //CA根证书
$SSL = substr($url, 0, 8) == "https://" ? true : false;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout-2);
if ($SSL && $CA) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // 只信任CA颁布的证书
curl_setopt($ch, CURLOPT_CAINFO, $cacert); // CA根证书(用来验证的网站证书是否是CA颁布)
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 检查证书中是否设置域名,并且是否与提供的主机名匹配
} else if ($SSL && !$CA) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); // 检查证书中是否设置域名
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); //避免data数据过长问题
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
//curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); //data with URLEncode
$ret = curl_exec($ch);
//var_dump(curl_error($ch)); //查看报错信息
curl_close($ch);
return $ret;
}
|
如果URL地址是https打头,那就走SSL,否则就走普通的HTTP协议。
是否走HTTPS的话就安全了吗?其实SSL也有不同的验证程度。
例如需不需要验证证书中的公用名呢?(BTW:公用名(Common Name)一般来讲就是填写你将要申请SSL证书的域名 (domain)或子域名(sub domain)。)
需要验证主机名吗?
是任何证书都信任呢还是只信任CA颁布的呢?
(我擦嘞,电池快没点了,只捡关键地儿说了 - -|||)
如果网站SSL证书买的是CA的(通常比较贵),那么访问时可以使用比较严格的认证,即:
代码如下 |
复制代码 |
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // 只信任CA颁布的证书
curl_setopt($ch, CURLOPT_CAINFO, $cacert); // CA根证书(用来验证的网站证书是否是CA颁布)
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 检查证书中是否设置域名,并且是否与提供的主机名匹配
|
如果网站的证书是自己生成的,或者是网上的小机构申请的,那么访问时如果使用严格认证则不会通过,直接返回false。(对了,返回false时可以打印curl_error($ch)查看具体错误信息。)此时可以根据情况通过降低验证程度来保证正常访问,例如:
代码如下 |
复制代码 |
2 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
|
// 检查证书中是否设置域名(为0也可以,就是连域名存在与否都不验证了)
平时我们使用浏览器访问各个https网站时,有时会遇到证书不受信的提示,其实就是因为这些网站的证书不是正规CA机构颁布的。
市面上各种浏览器中都内置了CA根证书列表信息,访问有CA颁布证书的网站时,会根据根证书验证这些网站的证书,所以就不会有这个提示了。
关于CA根证书文件,其实就是包含了各个主要CA机构的公钥证书,用来验证网站的证书是否是这些机构颁发的
最近在研究discuz,发现后台很多设置项,都用textarea填写,然后每行一项,感觉很有意思,嘿嘿,主要是很简单,免得在设置的时候为控件的问题浪费太多时间。
不多说了,上代码:
代码如下 |
复制代码 |
$names = preg_split('/rn/',$_POST['textarea']);
foreach($names as $name){
// todo something eg: echo $name;
}
|
取值很简单,那么赋值呢,在textarea中输出换行符可没那么简单
代码如下 |
复制代码 |
$vals = get_from_mydb();
$tmp = '';
foreach($vals as $val){
$tmp .= $val.' ';
}
|
“ ”和” ”是什么意思,因为时间为题我就不说了,自己去百度 GG一下吧!
代码如下 |
复制代码 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.111cn.net ">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>PHP获取表单area数据中的换行问题</title>
</head>
<body>
<?php
$content=empty($_POST['content'])?null:trim($_POST['content']);
if(!empty($content))echo str_replace("r",'rl',nl2br($content));
echo "r".'<br/>----------分割线----------------------'."r";
if(!empty($content))echo str_replace("n",'nl',nl2br($content));
echo "n".'<br/>----------分割线----------------------'."n";
if(!empty($content))echo str_replace("r",'rl',str_replace("n",'nl',nl2br($content)));
echo "r".'<br/>----------分割线----------------------<br/>'."n";
echo 'hello'."n".'boys!';
echo 'hello'."r".'boys!';
?>
<form action="textareanl.php" method="post" enctype="multipart/form-data">
<textarea name="content" cols="20" rows="6"></textarea>
<br />
<input type="submit" value="提交" />
</form>
</body>
</html>
|
在浏览器中打开后,在表单中输入
:
按提交后,浏览器中显示结果如下:
在记事本可可看到如下结果:
从以上结果可见:
1.PHP函数nl2br()是在字符串中的每个新行(rn)之前插入HTML换行符:<br/>;
2.Windows下的换行是(rn);
3.在记事本中,r或n均有换行的功能;
文章截断使用主要是在列表页面时我没有写描述这样只能在文章中截取字符串了,但使用php 自带函数会导致div未结束,从而页面混乱了,那么要如何解决此问题呢?
博主写好一篇文章,博客后台一般会在搜索页面或者列表页面给出文章标题和截断了的的文章部分作为进一步阅读的入口。
Function: mb_substr( $str, $start, $length, $encoding )
$str,需要截断的字符串
$start,截断开始处
$length,长度(注意,这个跟mb_strimwidth不同,1就代表一个中文字符)
$encoding,编码,我设为 utf-8
例:截断文章标题,控制在15个文字
代码如下 |
复制代码 |
<?php echo mb_substr('www.111cn.net原创', 0, 15,"utf-8"); ?>
|
这样对于纯文本没问题,但是我的是中间有html标签的于是问题来了。怎样截断一篇文章。注意,这篇文章不仅仅是普通的字符串文本,而是包含了各种格式化标签和样式内容的文本。如果处理不当,这些闭合标签无法正常关闭,从而破坏整个文档流。
如果单纯是纯文本,下面这个函数差不多是够用的。
代码如下 |
复制代码 |
<?php
/**
* 字符串截取,支持中文和其他编码
*
* @param string $str 需要转换的字符串
* @param string $start 开始位置
* @param string $length 截取长度
* @param string $charset 编码格式
* @param string $suffix 截断字符串后缀
* @return string
*/
function substr_ext($str, $start=0, $length, $charset="utf-8", $suffix="")
{
if(function_exists("mb_substr")){
return mb_substr($str, $start, $length, $charset).$suffix;
}
elseif(function_exists('iconv_substr')){
return iconv_substr($str,$start,$length,$charset).$suffix;
}
$re['utf-8'] = "/[x01-x7f]|[xc2-xdf][x80-xbf]|[xe0-xef][x80-xbf]{2}|[xf0-xff][x80-xbf]{3}/";
$re['gb2312'] = "/[x01-x7f]|[xb0-xf7][xa0-xfe]/";
$re['gbk'] = "/[x01-x7f]|[x81-xfe][x40-xfe]/";
$re['big5'] = "/[x01-x7f]|[x81-xfe]([x40-x7e]|xa1-xfe])/";
preg_match_all($re[$charset], $str, $match);
$slice = join("",array_slice($match[0], $start, $length));
return $slice.$suffix;
} |
但是,如果需要截断是网页中的某部分格式化文本,上面的函数就不够用了。它不具备处理格式化标签的能力。
这时,需要一个新函数,它应该是以上函数的升级加强版,它必须有能力正确的处理标签,下面找到一个
strip_tags() 函数剥去 HTML、XML 以及 PHP 的标签。
例子 1
代码如下 |
复制代码 |
<?php
echo strip_tags("Hello <b>world!</b>");
?>
|
输出:
Hello world!
这样就好做了我们只要在上面基础上如下操作
代码如下 |
复制代码 |
<?php
$a = strip_tags("Hello <b>world!</b>");
substr_ext( $a,10) ;
但是发现html不见了这个也不是什么好的解决办法了。
?>
|
接着google 发现cns写了一个支持html截取字符串的函数
代码如下 |
复制代码 |
/**
* 获取字符在字符串中第N次出现的位置
* @param string $text 字符串
* @param string $key 字符
* @param int $int N
* @return int
*/
function strpos_int($text, $key, $int)
{
$keylen = strlen($key);
global $textlen;
if (!$textlen)
$textlen = strlen($text);
static $textpos = 0;
$pos = strpos($text, $key);
$int--;
if ($pos)
{
if ($int == 0)
$textpos+=$pos;
else
$textpos+=$pos + $keylen;
}
else
{
$int = 0;
$textpos = $textlen;
}
if ($int > 0)
{
strpos_int(substr($text, $pos + $keylen), $key, $int);
}
return $textpos;
}
/**
* 截取HTML
* @param string $string HTML 字符串
* @param int $length 截取的长度
* @param string $dot
* @param string $append
* @return string
*/
function cuthtml($string, $length, $dot = ' ...', $append = "")
{
$str = strip_tags($string);//先过滤标签
$new_str = iconv_substr($str, 0, $length, 'utf-8');
$last = iconv_substr($new_str, -1, 1, 'utf-8');
$sc = substr_count($new_str, $last);
$position = strpos_int($string, $last, $sc); //获取截取真实的长度
if (function_exists('tidy_parse_string'))//服务器开启tidy的话 直接用函数不全html代码即可
{
$options = array("show-body-only" => true);
return tidy_parse_string(mb_substr($string, 0, $position) . $dot . $append, $options, 'UTF8');
} else //没有开启tidy
{
if (strlen($string) <= $position)
{
return $string;
}
$pre = chr(1);
$end = chr(1);
$string = str_replace(array('&', '"', '<', '>'), array($pre . '&' . $end, $pre . '"' . $end, $pre . '<' . $end, $pre . '>' . $end), $string);
$strcut = '';
$n = $tn = $noc = 0;
while ($n < strlen($string))
{
$t = ord($string[$n]);
if ($t == 9 || $t == 10 || (32 <= $t && $t <= 126))
{
$tn = 1;
$n++;
$noc++;
} elseif (194 <= $t && $t <= 223)
{
$tn = 2;
$n += 2;
$noc += 2;
} elseif (224 <= $t && $t <= 239)
{
$tn = 3;
$n += 3;
$noc += 2;
} elseif (240 <= $t && $t <= 247)
{
$tn = 4;
$n += 4;
$noc += 2;
} elseif (248 <= $t && $t <= 251)
{
$tn = 5;
$n += 5;
$noc += 2;
} elseif ($t == 252 || $t == 253)
{
$tn = 6;
$n += 6;
$noc += 2;
} else
{
$n++;
}
if ($noc >= $position)
{
break;
}
}
if ($noc > $position)
{
$n -= $tn;
}
$strcut = substr($string, 0, $n);
$strcut = str_replace(array($pre . '&' . $end, $pre . '"' . $end, $pre . '<' . $end, $pre . '>' . $end), array('&', '"', '<', '>'), $strcut);
$pos = strrpos($strcut, chr(1));
if ($pos !== false)
{
$strcut = substr($strcut, 0, $pos);
}
return $strcut . $dot . $append;
}
}
|
标签:[!--infotagslink--]