Thinkphp 代码
获取客户端IP地址
获取客户端IP地址
$type表示返回类型 0 返回IP地址 1 返回IPV4地址数字
function get_client_ip($type = 0) {
$type = $type ? 1 : 0;
static $ip = NULL;
if ($ip !== NULL) return $ip[$type];
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$pos = array_search('unknown',$arr);
if(false !== $pos) unset($arr[$pos]);
$ip = trim($arr[0]);
}elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
}elseif (isset($_SERVER['REMOTE_ADDR'])) {
$ip = $_SERVER['REMOTE_ADDR'];
}
// IP地址合法验证
$long = ip2long($ip);
$ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
return $ip[$type];
}
文件字节大小格式化
字节格式化 把字节数格式为 B K M G T 描述的大小
function byte_format($size, $dec=2){
$a = array("B", "KB", "MB", "GB", "TB", "PB");
$pos = 0;
while ($size >= 1024) {
$size /= 1024;
$pos++;
}
return round($size,$dec)." ".$a[$pos];
}
或者
function get_size($s,$u='B',$p=1){
$us = array('B'=>'K','K'=>'M','M'=>'G','G'=>'T');
return (($u!=='B')&&(!isset($us[$u]))||($s<1024))?(number_format($s,$p)." $u"):(get_size($s/1024,$us[$u],$p));
}
显示彩虹字符串
用于显示彩虹字符串,支持UTF8和中文,效果如下:
function color_txt($str){
$len = mb_strlen($str);
$colorTxt = '';
for($i=0; $i<$len; $i++) {
$colorTxt .= '<span style="color:'.rand_color().'">'.mb_substr($str,$i,1,'utf-8').'</span>';
}
return $colorTxt;
}
function rand_color(){
return '#'.sprintf("%02X",mt_rand(0,255)).sprintf("%02X",mt_rand(0,255)).sprintf("%02X",mt_rand(0,255));
}
让PHP更快的提供文件下载
一般来说, 我们可以通过直接让URL指向一个位于Document Root下面的文件, 来引导用户下载文件.
但是, 这样做, 就没办法做一些统计, 权限检查, 等等的工作. 于是, 很多时候, 我们采用让PHP来做转发, 为用户提供文件下载.
<?php
$file = "/tmp/dummy.tar.gz";
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header("Content-Length: ". filesize($file));
readfile($file);
但是这个有一个问题, 就是如果文件是中文名的话, 有的用户可能下载后的文件名是乱码.
于是, 我们做一下修改(参考: :
<?php
$file = "/tmp/中文名.tar.gz";
$filename = basename($file);
header("Content-type: application/octet-stream");
//处理中文文件名
$ua = $_SERVER["HTTP_USER_AGENT"];
$encoded_filename = urlencode($filename);
$encoded_filename = str_replace("+", "%20", $encoded_filename);
if (preg_match("/MSIE/", $ua)) {
header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
} else if (preg_match("/Firefox/", $ua)) {
header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"');
} else {
header('Content-Disposition: attachment; filename="' . $filename . '"');
}
header('Content-Disposition: attachment; filename="' . $filename . '"');
header("Content-Length: ". filesize($file));
readfile($file);
恩, 现在看起来好多了, 不过还有一个问题, 那就是readfile, 虽然PHP的readfile尝试实现的尽量高效, 不占用PHP本身的内存, 但是实际上它还是需要采用MMAP(如果支持), 或者是一个固定的buffer去循环读取文件, 直接输出.
输出的时候, 如果是Apache + PHP mod, 那么还需要发送到Apache的输出缓冲区. 最后才发送给用户. 而对于Nginx + fpm如果他们分开部署的话, 那还会带来额外的网络IO.
那么, 能不能不经过PHP这层, 直接让Webserver直接把文件发送给用户呢?
今天, 我看到了一个有意思的文章: How I PHP: X-SendFile.
我们可以使用Apache的module mod_xsendfile, 让Apache直接发送这个文件给用户:
<?php
$file = "/tmp/中文名.tar.gz";
$filename = basename($file);
header("Content-type: application/octet-stream");
//处理中文文件名
$ua = $_SERVER["HTTP_USER_AGENT"];
$encoded_filename = urlencode($filename);
$encoded_filename = str_replace("+", "%20", $encoded_filename);
if (preg_match("/MSIE/", $ua)) {
header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
} else if (preg_match("/Firefox/", $ua)) {
header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"');
} else {
header('Content-Disposition: attachment; filename="' . $filename . '"');
}
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
//让Xsendfile发送文件
header("X-Sendfile: $file");
X-Sendfile头将被Apache处理, 并且把响应的文件直接发送给Client.
Lighttpd和Nginx也有类似的模块, 大家有兴趣的可以去找找看
配置htaccess文件隐藏index.php
用于在apache环境下面隐藏URL地址中的index.php
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>
去除PHP代码中的空白和注释
PHP内置了一个php_strip_whitespace方法用于读取php文件并去除代码中的空白和注释,但不支持直接读取内容去除空白和注释,下面的方法则可以支持读取字符串内容,并且ThinkPHP框架内置了该方法。
/**
* 去除代码中的空白和注释
* @param string $content 代码内容
* @return string
*/
function strip_whitespace($content) {
$stripStr = '';
//分析php源码
$tokens = token_get_all($content);
$last_space = false;
for ($i = 0, $j = count($tokens); $i < $j; $i++) {
if (is_string($tokens[$i])) {
$last_space = false;
$stripStr .= $tokens[$i];
} else {
switch ($tokens[$i][0]) {
//过滤各种PHP注释
case T_COMMENT:
case T_DOC_COMMENT:
break;
//过滤空格
case T_WHITESPACE:
if (!$last_space) {
$stripStr .= ' ';
$last_space = true;
}
break;
case T_START_HEREDOC:
$stripStr .= "<<<THINK\n";
break;
case T_END_HEREDOC:
$stripStr .= "THINK;\n";
for($k = $i+1; $k < $j; $k++) {
if(is_string($tokens[$k]) && $tokens[$k] == ';') {
$i = $k;
break;
} else if($tokens[$k][0] == T_CLOSE_TAG) {
break;
}
}
break;
default:
$last_space = false;
$stripStr .= $tokens[$i][1];
}
}
}
return $stripStr;
}
检查字符串是否是UTF8编码
用于判断某个字符串是否采用UTF8编码
function is_utf8($string){
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*$%xs', $string);
}
XSS安全过滤
来源于网络,用于对字符串进行XSS安全过滤。
function remove_xss($val) {
// remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
// this prevents some character re-spacing such as <java\0script>
// note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
$val = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '', $val);
// straight replacements, the user should never need these since they're normal characters
// this prevents like <IMG SRC=@avascript:alert('XSS')>
$search = 'abcdefghijklmnopqrstuvwxyz';
$search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$search .= '1234567890!@#$%^&*()';
$search .= '~`";:?+/={}[]-_|\'\\';
for ($i = 0; $i < strlen($search); $i++) {
// ;? matches the ;, which is optional
// 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
// @ @ search for the hex values
$val = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ;
// @ @ 0{0,7} matches '0' zero to seven times
$val = preg_replace('/(�{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ;
}
// now the only remaining whitespace attacks are \t, \n, and \r
$ra1 = array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'style', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');
$ra2 = array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
$ra = array_merge($ra1, $ra2);
$found = true; // keep replacing as long as the previous round replaced something
while ($found == true) {
$val_before = $val;
for ($i = 0; $i < sizeof($ra); $i++) {
$pattern = '/';
for ($j = 0; $j < strlen($ra[$i]); $j++) {
if ($j > 0) {
$pattern .= '(';
$pattern .= '(&#[xX]0{0,8}([9ab]);)';
$pattern .= '|';
$pattern .= '|(�{0,8}([9|10|13]);)';
$pattern .= ')*';
}
$pattern .= $ra[$i][$j];
}
$pattern .= '/i';
$replacement = substr($ra[$i], 0, 2).'<x>'.substr($ra[$i], 2); // add in <> to nerf the tag
$val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
if ($val_before == $val) {
// no replacements were made, so exit the loop
$found = false;
}
}
}
return $val;
}
COOKIE用法示例
cookie方法是ThinkPHP内置的函数,用于完成cookie的设置、获取和删除操作。
设置
cookie('name','value'); //设置cookie
cookie('name','value',3600); // 指定cookie保存时间为1小时
高级设置
cookie('name','value',array('expire'=>3600,'prefix'=>'think_')); // 指定有效期和前缀
// 下面的代码和上面等效
cookie('name','value','expire=3600&prefix=think_')
获取
$value = cookie('name');
无论是否设置了前缀参数,cookie方法会自动判断。
删除
删除某个cookie值,可以用:
cookie('name',null);
如果需要清空cookie,可以用:
cookie(null); // 清空当前设定前缀的所有cookie值
cookie(null,'think_'); // 清空指定前缀的所有cookie值
验证码不能显示?通常都是BOM信息惹的祸此代码能解决验证码不能显示问题.(批量去除BOM信息的代码)
有时,我们在本地测试环境中需要显示验证码的地方没有问题,一旦布置到服务器上去的时候.需要显示验证码的地方无法显示?如果你也碰到同样问题,请往下看.
问题的原因大部分是BOM头信息造成的,通常thinkphp的配置文件都要去除BOM头信息.什么是BOM头信息?百度一下就知道啦.
我通常的解决办法是,布置到服务器上去之后,新建一个去除所有文件的BOM头信息的代码文件.然后运行之即可.
比如:我在服务器根目录新建一个delBom.php文件.运行http://www.xxx.com/delBom.php即可.代码如下:
<?php
if (isset($_GET['dir'])){ //设置文件目录
$basedir=$_GET['dir'];
}else{
$basedir = '.';
}
$auto = 1;
checkdir($basedir);
function checkdir($basedir){
if ($dh = opendir($basedir)) {
while (($file = readdir($dh)) !== false) {
if ($file != '.' && $file != '..'){
if (!is_dir($basedir."/".$file)) {
echo "filename: $basedir/$file ".checkBOM("$basedir/$file")." <br>";
}else{
$dirname = $basedir."/".$file;
checkdir($dirname);
}
}
}
closedir($dh);
}
}
function checkBOM ($filename) {
global $auto;
$contents = file_get_contents($filename);
$charset[1] = substr($contents, 0, 1);
$charset[2] = substr($contents, 1, 1);
$charset[3] = substr($contents, 2, 1);
if (ord($charset[1]) == 239 && ord($charset[2]) == 187 && ord($charset[3]) == 191) {
if ($auto == 1) {
$rest = substr($contents, 3);
rewrite ($filename, $rest);
return ("<font color=red>BOM found, automatically removed._<a href=http://www.k686.com>http://www.k686.com</a></font>");
} else {
return ("<font color=red>BOM found.</font>");
}
}
else return ("BOM Not Found.");
}
function rewrite ($filename, $data) {
$filenum = fopen($filename, "w");
flock($filenum, LOCK_EX);
fwrite($filenum, $data);
fclose($filenum);
}
?>
U方法使用示例,地址方法,在模型或模板中都可以使用
U方法是ThinkPHP中用于自动生成URL地址的方法,能够帮助你因为不同的环境和配置而自动生成对应的URL地址。
特点如下:
1、自动识别当前的URL模式
2、自动识别当前的PATH_INFO分隔符
3、域名和二级域名支持
4、伪静态和锚点支持
5、路由地址支持
因此,在使用U方法的时候,你基本上不需要关注当前使用的是什么URL模式和什么配置参数,按照U方法统一的规则调用即可,在实际生成URL地址的时候U方法会自动识别。
下面是一些基本的用法:
// 当前模块的read操作地址,传入参数id为5
U('read','id=5');
如果要传入变量,则用:
U('read','id='.$vo['id']);
如果你的U方法是在模板调用,一般需要写成:
<a href="{:U('read','id=5')}">阅读文章</a>
生成Blog模块的index操作地址,并传入更多的参数:
U('blog/index','cate_id=5&type=1');
当然,也可以使用数组传参:
U('blog/index',array('cate_id'=>5,'type'=>1));
如果参数比较少,也可以直接在第一个参数中传入:
U('Blog/read?id=5');
U('Blog/cate?cate_id=1&status=1')
支持分组生成:
U('Home/Blog/read?id=5'); // Home分组下面的blog模块的read操作地址
U('Admin/Blog/cate?cate_id=1&status=1');// Admin分组
表示
U方法会自动加上当前配置的伪静态后缀,如果你配置了多个伪静态后缀,则默认会加上第一个,如果需要指定伪静态后缀,也可以使用:
U('Blog/read','id=1','xml');
表示输出伪静态后缀为.xml的URL地址
如果要使用U方法输出路由地址,则需要在第一个参数前加上"/",例如:
U('/news/1');
则表示要生成的URL地址是 news/1 这样的路由地址。
如果需要生成带域名的URL地址,可以使用:
U('Blog/read@blog.thinkphp.cn','id=1');
或者
U('Blog/read@blog','id=1');
表示采用当前域名的blog二级域名地址。
支持锚点生成(注意需要更新最新的Git版本才能支持)
U('Blog/read#review','id=5');
生成的URL地址最后会带上 #review 锚点,便于跳转到评论部分。
设置图片的HTTP缓存,也可以设置JS和CSS的
如果是Apache环境下面,可以在.htaccess文件中添加下面的代码,用于设置图片的HTTP缓存和有效期(需要开启apache的headers模块支持),减少网站的图片资源请求压力,提高访问速度和你的pagespeed值^_^。
<IfModule mod_headers.c>
<FilesMatch ".(gif|jpg|jpeg|png|ico)$">
Header set Cache-Control "max-age=604800"
</FilesMatch>
上面的代码设置了网站的图片使用为期一周的HTTP缓存,当然,你一样可以给js或者css文件加上http缓存哦。
检查字符串中是否有外链
/**
* all_external_link 检测字符串是否包含外链
* @param string $text 文字
* @param string $host 域名
* @return boolean false 有外链 true 无外链
*/
function all_external_link($text = '', $host = '') {
if (empty($host)) $host = $_SERVER['HTTP_HOST'];
$reg = '/http(?:s?):\/\/((?:[A-za-z0-9-]+\.)+[A-za-z]{2,4})/';
preg_match_all($reg, $text, $data);
$math = $data[1];
foreach ($math as $value) {
if($value != $host) return false;
}
return true;
}
在htaccess中设置域名重定向
仅用于Apache环境下面,可以在htaccess文件中添加下面的代码,当访问abc.com的时候会重定向到www.abc.com,当然你也可以设置重定向到其它的域名。
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^abc.com$ [NC]
RewriteRule ^(.*)$ http://www.abc.com/$1 [R=301,L]
</IfModule>
PHP获取客户端的IP、地理信息、浏览器信息、本地真实IP
<?php
// 作用取得客户端的ip、地理信息、浏览器、本地真实IP
class get_gust_info {
////获得访客浏览器类型
function GetBrowser(){
if(!empty($_SERVER['HTTP_USER_AGENT'])){
$br = $_SERVER['HTTP_USER_AGENT'];
if (preg_match('/MSIE/i',$br)) {
$br = 'MSIE';
}elseif (preg_match('/Firefox/i',$br)) {
$br = 'Firefox';
}elseif (preg_match('/Chrome/i',$br)) {
$br = 'Chrome';
}elseif (preg_match('/Safari/i',$br)) {
$br = 'Safari';
}elseif (preg_match('/Opera/i',$br)) {
$br = 'Opera';
}else {
$br = 'Other';
}
return $br;
}else{return "获取浏览器信息失败!";}
}
////获得访客浏览器语言
function GetLang(){
if(!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])){
$lang = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
$lang = substr($lang,0,5);
if(preg_match("/zh-cn/i",$lang)){
$lang = "简体中文";
}elseif(preg_match("/zh/i",$lang)){
$lang = "繁体中文";
}else{
$lang = "English";
}
return $lang;
}else{return "获取浏览器语言失败!";}
}
////获取访客操作系统
function GetOs(){
if(!empty($_SERVER['HTTP_USER_AGENT'])){
$OS = $_SERVER['HTTP_USER_AGENT'];
if (preg_match('/win/i',$OS)) {
$OS = 'Windows';
}elseif (preg_match('/mac/i',$OS)) {
$OS = 'MAC';
}elseif (preg_match('/linux/i',$OS)) {
$OS = 'Linux';
}elseif (preg_match('/unix/i',$OS)) {
$OS = 'Unix';
}elseif (preg_match('/bsd/i',$OS)) {
$OS = 'BSD';
}else {
$OS = 'Other';
}
return $OS;
}else{return "获取访客操作系统信息失败!";}
}
////获得访客真实ip
function Getip(){
if(!empty($_SERVER["HTTP_CLIENT_IP"])){
$ip = $_SERVER["HTTP_CLIENT_IP"];
}
if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){ //获取代理ip
$ips = explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']);
}
if($ip){
$ips = array_unshift($ips,$ip);
}
$count = count($ips);
for($i=0;$i<$count;$i++){
if(!preg_match("/^(10|172\.16|192\.168)\./i",$ips[$i])){//排除局域网ip
$ip = $ips[$i];
break;
}
}
$tip = empty($_SERVER['REMOTE_ADDR']) ? $ip : $_SERVER['REMOTE_ADDR'];
if($tip=="127.0.0.1"){ //获得本地真实IP
return $this->get_onlineip();
}else{
return $tip;
}
}
////获得本地真实IP
function get_onlineip() {
$mip = file_get_contents("http://city.ip138.com/city0.asp");
if($mip){
preg_match("/\[.*\]/",$mip,$sip);
$p = array("/\[/","/\]/");
return preg_replace($p,"",$sip[0]);
}else{return "获取本地IP失败!";}
}
////根据ip获得访客所在地地名
function Getaddress($ip=''){
if(empty($ip)){
$ip = $this->Getip();
}
$ipadd = file_get_contents("http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=".$ip);//根据新浪api接口获取
if($ipadd){
$charset = iconv("gbk","utf-8",$ipadd);
preg_match_all("/[\x{4e00}-\x{9fa5}]+/u",$charset,$ipadds);
return $ipadds; //返回一个二维数组
}else{return "addree is none";}
}
}
$gifo = new get_gust_info();
echo "你的ip:".$gifo->Getip();
echo "<br/>所在地:";
$ipadds = $gifo->Getaddress();
foreach($ipadds[0] as $value){
echo "\r\n ".iconv("utf-8","gbk",$value);
}
echo "<br/>浏览器类型:".$gifo->GetBrowser();
echo "<br/>浏览器语言:".$gifo->GetLang();
echo "<br/>操作系统:".$gifo->GetOs();
?>
URL安全的字符串base64编码和解码
如果直接使用base64_encode和base64_decode方法的话,生成的字符串可能不适用URL地址。下面的方法可以解决该问题: URL安全的字符串编码:
function urlsafe_b64encode($string) {
$data = base64_encode($string);
$data = str_replace(array('+','/','='),array('-','_',''),$data);
return $data;
}
URL安全的字符串解码:
function urlsafe_b64decode($string) {
$data = str_replace(array('-','_'),array('+','/'),$string);
$mod4 = strlen($data) % 4;
if ($mod4) {
$data .= substr('====', $mod4);
}
return base64_decode($data);
}
获取客户端浏览器信息
/**
* 获取客户端浏览器类型
* @param string $glue 浏览器类型和版本号之间的连接符
* @return string|array 传递连接符则连接浏览器类型和版本号返回字符串否则直接返回数组 false为未知浏览器类型
*/
function get_client_browser($glue = null) {
$browser = array();
$agent = $_SERVER['HTTP_USER_AGENT']; //获取客户端信息
/* 定义浏览器特性正则表达式 */
$regex = array(
'ie' => '/(MSIE) (\d+\.\d)/',
'chrome' => '/(Chrome)\/(\d+\.\d+)/',
'firefox' => '/(Firefox)\/(\d+\.\d+)/',
'opera' => '/(Opera)\/(\d+\.\d+)/',
'safari' => '/Version\/(\d+\.\d+\.\d) (Safari)/',
);
foreach($regex as $type => $reg) {
preg_match($reg, $agent, $data);
if(!empty($data) && is_array($data)){
$browser = $type === 'safari' ? array($data[2], $data[1]) : array($data[1], $data[2]);
break;
}
}
return empty($browser) ? false : (is_null($glue) ? $browser : implode($glue, $browser));
}
时间戳友好化格式化函数 显示刚刚,几秒前
在一些微博系统中经常要将时间于现在时间相比显示为多久以前发布的,如显示为:刚刚、5秒前、5小时前、5天前..这种
/**
*
+--------------------------------------------------------------------
* Description 友好显示时间
+--------------------------------------------------------------------
* @param int $time 要格式化的时间戳 默认为当前时间
+--------------------------------------------------------------------
* @return string $text 格式化后的时间戳
+--------------------------------------------------------------------
* @author yijianqing
+--------------------------------------------------------------------
*/
function mdate($time = NULL) {
$text = '';
$time = $time === NULL || $time > time() ? time() : intval($time);
$t = time() - $time; //时间差 (秒)
if ($t == 0)
$text = '刚刚';
elseif ($t < 60)
$text = $t . '秒前'; // 一分钟内
elseif ($t < 60 * 60)
$text = floor($t / 60) . '分钟前'; //一小时内
elseif ($t < 60 * 60 * 24)
$text = floor($t / (60 * 60)) . '小时前'; // 一天内
elseif ($t < 60 * 60 * 24 * 3)
$text = floor($time/(60*60*24)) ==1 ?'昨天 ' . date('H:i', $time) : '前天 ' . date('H:i', $time) ; //昨天和前天
elseif ($t < 60 * 60 * 24 * 30)
$text = date('m月d日 H:i', $time); //一个月内
elseif ($t < 60 * 60 * 24 * 365)
$text = date('m月d日', $time); //一年内
else
$text = date('Y年m月d日', $time); //一年以前
return $text;
}
使用此函数,我们只需在前台用
{$vo.time|mdate}
实现时间友好化显示了
将返回的数据集转换成树结构
/**
* 将返回的数据集转换成树
* @param array $list 数据集
* @param string $pk 主键
* @param string $pid 父节点名称
* @param string $child 子节点名称
* @param integer $root 根节点ID
* @return array 转换后的树
*/
function list_to_tree($list, $pk = 'id', $pid = 'pid', $child = '_child', $root=0) {
$tree = array();// 创建Tree
if(is_array($list)) {
// 创建基于主键的数组引用
$refer = array();
foreach ($list as $key => $data) {
$refer[$data[$pk]] =& $list[$key];
}
foreach ($list as $key => $data) {
// 判断是否存在parent
$parentId = $data[$pid];
if ($root == $parentId) {
$tree[$data[$pk]] =& $list[$key];
}else{
if (isset($refer[$parentId])) {
$parent =& $refer[$parentId];
$parent[$child][] =& $list[$key];
}
}
}
}
return $tree;
}
头像编辑-当不改变头像时
目前是这么做的 将上传判断代码段
/* if(!$upload->upload()) {// 上传错误提示错误信息
$this->error($upload->getErrorMsg());
}else{// 上传成功 获取上传文件信息
$info = $upload->getUploadFileInfo();
} */
改为:
$upload->upload();
$info = $upload->getUploadFileInfo();
这样即使不上传图片也不提示错误, 然后在上传页面 添加
<input type='file' name='face'>
<input type='hidden' name='face' value='{$data.face}'>
在update()方法中做如下判断:
if(is_null($info[0]["savename"])){
$data['face']=$_POST['face'];
}else{
$data['face']=$info[0]["savename"];
}
合并数组函数
调用PHP原生的array_merge时,如果第一个参数为空,则会导致返回结果为空。这个函数做了相应处理。
function MergeArray($list1,$list2)
{
if(!isEmpty($list1) && !isEmpty($list2))
{
return array_merge($list1,$list2);
}
else return (isEmpty($list1)?(isEmpty($list2)?null:$list2):$list1);
}
function isEmpty($data)
{
return null == $data || false == $data || "" == $data;
}
Google翻译插件调用,采用CURL调取
调用Google翻译的接口,需要开启curl支持。
<?php
/*
Google翻译函数 by QQ366958903
$text 要翻译的文本
$tl 目标语言
$sl 原语言
$ie 字符编码
*/
function translate($text='',$tl='zh-CN',$sl='auto',$ie='UTF-8'){
$ch = curl_init('http://translate.google.cn/');
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,"&hl=zh-CN&sl={$sl}&ie={$ie}&tl={$tl}&text=".urlencode($text));
$html = curl_exec($ch);
preg_match('#<span id=result_box class="short_text">(.*?)</span></div>#',$html,$doc);
return strip_tags($doc['1'],'<br>');
}
//示例:把文字翻译成英文
$text='你好';
echo translate($text,'en');
?>
语言简写对应表
'auto'=>'检测语言',
'sq'=>'阿尔巴尼亚语',
'ar'=>'阿拉伯语',
'az'=>'阿塞拜疆语 ALPHA',
'ga'=>'爱尔兰语',
'et'=>'爱沙尼亚语',
'be'=>'白俄罗斯语',
'bg'=>'保加利亚语',
'is'=>'冰岛语',
'pl'=>'波兰语',
'fa'=>'波斯语',
'af'=>'布尔文(南非荷兰语)',
'da'=>'丹麦语',
'de'=>'德语',
'ru'=>'俄语',
'fr'=>'法语',
'tl'=>'菲律宾语',
'fi'=>'芬兰语',
'ka'=>'格鲁吉亚语 ALPHA',
'ht'=>'海地克里奥尔语 ALPHA',
'ko'=>'韩语',
'nl'=>'荷兰语',
'gl'=>'加利西亚语',
'ca'=>'加泰罗尼亚语',
'cs'=>'捷克语',
'hr'=>'克罗地亚语',
'lv'=>'拉脱维亚语',
'lt'=>'立陶宛语',
'ro'=>'罗马尼亚语',
'mt'=>'马耳他语',
'ms'=>'马来语',
'mk'=>'马其顿语',
'no'=>'挪威语',
'pt'=>'葡萄牙语',
'ja'=>'日语',
'sv'=>'瑞典语',
'sr'=>'塞尔维亚语',
'sk'=>'斯洛伐克语',
'sl'=>'斯洛文尼亚语',
'sw'=>'斯瓦希里语',
'th'=>'泰语',
'tr'=>'土耳其语',
'cy'=>'威尔士语',
'uk'=>'乌克兰语',
'eu'=>'西班牙的巴斯克语 ALPHA',
'es'=>'西班牙语',
'iw'=>'希伯来语',
'el'=>'希腊语',
'hu'=>'匈牙利语',
'hy'=>'亚美尼亚语 ALPHA',
'it'=>'意大利语',
'yi'=>'意第绪语',
'hi'=>'印地语',
'ur'=>'印度乌尔都语 ALPHA',
'id'=>'印尼语',
'en'=>'英语',
'vi'=>'越南语',
'zh-TW'=>'中文(繁体)',
'zh-CN'=>'中文(简体)',
备份数据库,可备份整个库或者备份部分表
全写在模块内了,可备份整个库,也可以选择部分表备份
纠正一处错误,361行empty 用错了
<?php
class BaksqlAction extends CommonAction {
public $config = ''; //相关配置
public $model = ''; //实例化一个model
public $content; //内容
public $dbName = ''; //数据库名
public $dir_sep = '/'; //路径符号
//初始化数据
function _initialize() {
parent::_initialize();
header("Content-type: text/html;charset=utf-8");
set_time_limit(0); //不超时
ini_set('memory_limit','500M');
$this->config = array(
'path' => C('DB_BACKUP'), //备份文件存在哪里
'isCompress' => 0, //是否开启gzip压缩 【未测试】
'isDownload' => 0 //备份完成后是否下载文件 【未测试】
);
$this->dbName = C('DB_NAME'); //当前数据库名称
$this->model = new Model();
//$sql = 'set interactive_timeout=24*3600'; //空闲多少秒后 断开链接
//$this->model>execute($sql);
}
/* -
* +------------------------------------------------------------------------
* * @ 已备份数据列表
* +------------------------------------------------------------------------
*/
function index() {
$path = $this->config['path'];
$fileArr = $this->MyScandir($path);
foreach ($fileArr as $key => $value) {
if ($key > 1) {
//获取文件创建时间
$fileTime = date('Y-m-d H:i:s', filemtime($path . '/' . $value));
$fileSize = filesize($path . '/' . $value) / 1024;
//获取文件大小
$fileSize = $fileSize < 1024 ? number_format($fileSize, 2) . ' KB' :
number_format($fileSize / 1024, 2) . ' MB';
//构建列表数组
$list[] = array(
'name' => $value,
'time' => $fileTime,
'size' => $fileSize
);
}
}
$this->assign('list', $list);
$this->display();
}
/* -
* +------------------------------------------------------------------------
* * @ 获取数据表
* +------------------------------------------------------------------------
*/
function tablist() {
$list = $this->model->query("SHOW TABLE STATUS FROM {$this->dbName}"); //得到表的信息
//echo $Backup->getLastSql();
$this->assign('list', $list);
$this->display();
}
/* -
* +------------------------------------------------------------------------
* * @ 备份整个数据库
* +------------------------------------------------------------------------
*/
function backall() {
$tables = $this->getTables();
if ($this->backup($tables)) {
$this->success('数据库备份成功!', '/public/ok');
} else {
$this->error('数据库备份失败!');
}
}
/* -
* +------------------------------------------------------------------------
* * @ 按表备份,可批量
* +------------------------------------------------------------------------
*/
function backtables() {
$tab = $_REQUEST['tab'];
if (is_array($tab))
$tables = $tab;
else
$tables[] = $tab;
if ($this->backup($tables)) {
if (is_array($tab))
$this->success('数据库备份成功!');
else
$this->success('数据库备份成功!', '/public/ok');
} else {
$this->error('数据库备份失败!');
}
}
//还原数据库
function recover() {
if ($this->recover_file($_GET['file'])) {
$this->success('数据还原成功!', '/public/ok');
} else {
$this->error('数据还原失败!');
}
}
//删除数据备份
function deletebak() {
if (unlink($this->config['path'] . $this->dir_sep . $_GET['file'])) {
$this->success('删除备份成功!', '/public/ok');
} else {
$this->error('删除备份失败!');
}
}
/* -
* +------------------------------------------------------------------------
* * @ 下载备份文件
* +------------------------------------------------------------------------
*/
function downloadBak() {
$file_name = $_GET['file'];
$file_dir = $this->config['path'];
if (!file_exists($file_dir . "/" . $file_name)) { //检查文件是否存在
return false;
exit;
} else {
$file = fopen($file_dir . "/" . $file_name, "r"); // 打开文件
// 输入文件标签
header('Content-Encoding: none');
header("Content-type: application/octet-stream");
header("Accept-Ranges: bytes");
header("Accept-Length: " . filesize($file_dir . "/" . $file_name));
header('Content-Transfer-Encoding: binary');
header("Content-Disposition: attachment; filename=" . $file_name); //以真实文件名提供给浏览器下载
header('Pragma: no-cache');
header('Expires: 0');
//输出文件内容
echo fread($file, filesize($file_dir . "/" . $file_name));
fclose($file);
exit;
}
}
/* -
* +------------------------------------------------------------------------
* * @ 获取 目录下文件数组
* +------------------------------------------------------------------------
* * @ $FilePath 目录路径
* * @ $Order 排序
* +------------------------------------------------------------------------
* * @ 获取指定目录下的文件列表,返回数组
* +------------------------------------------------------------------------
*/
private function MyScandir($FilePath = './', $Order = 0) {
$FilePath = opendir($FilePath);
while ($filename = readdir($FilePath)) {
$fileArr[] = $filename;
}
$Order == 0 ? sort($fileArr) : rsort($fileArr);
return $fileArr;
}
/* * ******************************************************************************************** */
/* -
* +------------------------------------------------------------------------
* * @ 读取备份文件
* +------------------------------------------------------------------------
* * @ $fileName 文件名
* +------------------------------------------------------------------------
*/
private function getFile($fileName) {
$this->content = '';
$fileName = $this->trimPath($this->config['path'] . $this->dir_sep . $fileName);
if (is_file($fileName)) {
$ext = strrchr($fileName, '.');
if ($ext == '.sql') {
$this->content = file_get_contents($fileName);
} elseif ($ext == '.gz') {
$this->content = implode('', gzfile($fileName));
} else {
$this->error('无法识别的文件格式!');
}
} else {
$this->error('文件不存在!');
}
}
/* -
* +------------------------------------------------------------------------
* * @ 把数据写入磁盘
* +------------------------------------------------------------------------
*/
private function setFile() {
$recognize = '';
$recognize = $this->dbName;
$fileName = $this->trimPath($this->config['path'] . $this->dir_sep . $recognize . '_' . date('YmdHis') . '_' . mt_rand(100000000, 999999999) . '.sql');
$path = $this->setPath($fileName);
if ($path !== true) {
$this->error("无法创建备份目录目录 '$path'");
}
if ($this->config['isCompress'] == 0) {
if (!file_put_contents($fileName, $this->content, LOCK_EX)) {
$this->error('写入文件失败,请检查磁盘空间或者权限!');
}
} else {
if (function_exists('gzwrite')) {
$fileName .= '.gz';
if ($gz = gzopen($fileName, 'wb')) {
gzwrite($gz, $this->content);
gzclose($gz);
} else {
$this->error('写入文件失败,请检查磁盘空间或者权限!');
}
} else {
$this->error('没有开启gzip扩展!');
}
}
if ($this->config['isDownload']) {
$this->downloadFile($fileName);
}
}
private function trimPath($path) {
return str_replace(array('/', '\\', '//', '\\\\'), $this->dir_sep, $path);
}
private function setPath($fileName) {
$dirs = explode($this->dir_sep, dirname($fileName));
$tmp = '';
foreach ($dirs as $dir) {
$tmp .= $dir . $this->dir_sep;
if (!file_exists($tmp) && !@mkdir($tmp, 0777))
return $tmp;
}
return true;
}
//未测试
private function downloadFile($fileName) {
ob_end_clean();
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Length: ' . filesize($fileName));
header('Content-Disposition: attachment; filename=' . basename($fileName));
readfile($fileName);
}
/* -
* +------------------------------------------------------------------------
* * @ 给字符串添加 ` `
* +------------------------------------------------------------------------
* * @ $str 字符串
* +------------------------------------------------------------------------
* * @ 返回 `$str`
* +------------------------------------------------------------------------
*/
private function backquote($str) {
return "`{$str}`";
}
/* -
* +------------------------------------------------------------------------
* * @ 获取数据库的所有表
* +------------------------------------------------------------------------
* * @ $dbName 数据库名称
* +------------------------------------------------------------------------
*/
private function getTables($dbName = '') {
if (!empty($dbName)) {
$sql = 'SHOW TABLES FROM ' . $dbName;
} else {
$sql = 'SHOW TABLES ';
}
$result = $this->model->query($sql);
$info = array();
foreach ($result as $key => $val) {
$info[$key] = current($val);
}
return $info;
}
/* -
* +------------------------------------------------------------------------
* * @ 把传过来的数据 按指定长度分割成数组
* +------------------------------------------------------------------------
* * @ $array 要分割的数据
* * @ $byte 要分割的长度
* +------------------------------------------------------------------------
* * @ 把数组按指定长度分割,并返回分割后的数组
* +------------------------------------------------------------------------
*/
private function chunkArrayByByte($array, $byte = 5120) {
$i = 0;
$sum = 0;
$return = array();
foreach ($array as $v) {
$sum += strlen($v);
if ($sum < $byte) {
$return[$i][] = $v;
} elseif ($sum == $byte) {
$return[++$i][] = $v;
$sum = 0;
} else {
$return[++$i][] = $v;
$i++;
$sum = 0;
}
}
return $return;
}
/* -
* +------------------------------------------------------------------------
* * @ 备份数据 { 备份每张表、视图及数据 }
* +------------------------------------------------------------------------
* * @ $tables 需要备份的表数组
* +------------------------------------------------------------------------
*/
private function backup($tables) {
if (empty($tables))
$this->error('没有需要备份的数据表!');
$this->content = '/* This file is created by MySQLReback ' . date('Y-m-d H:i:s') . ' */';
foreach ($tables as $i => $table) {
$table = $this->backquote($table); //为表名增加 ``
$tableRs = $this->model->query("SHOW CREATE TABLE {$table}"); //获取当前表的创建语句
if (!empty($tableRs[0]["Create View"])) {
$this->content .= "\r\n /* 创建视图结构 {$table} */";
$this->content .= "\r\n DROP VIEW IF EXISTS {$table};/* MySQLReback Separation */ " . $tableRs[0]["Create View"] . ";/* MySQLReback Separation */";
}
if (!empty($tableRs[0]["Create Table"])) {
$this->content .= "\r\n /* 创建表结构 {$table} */";
$this->content .= "\r\n DROP TABLE IF EXISTS {$table};/* MySQLReback Separation */ " . $tableRs[0]["Create Table"] . ";/* MySQLReback Separation */";
$tableDateRow = $this->model->query("SELECT * FROM {$table}");
$valuesArr = array();
$values = '';
if (false != $tableDateRow) {
foreach ($tableDateRow as &$y) {
foreach ($y as &$v) {
if ($v=='') //纠正empty 为0的时候 返回tree
$v = 'null'; //为空设为null
else
$v = "'" . mysql_escape_string($v) . "'"; //非空 加转意符
}
$valuesArr[] = '(' . implode(',', $y) . ')';
}
}
$temp = $this->chunkArrayByByte($valuesArr);
if (is_array($temp)) {
foreach ($temp as $v) {
$values = implode(',', $v) . ';/* MySQLReback Separation */';
if ($values != ';/* MySQLReback Separation */') {
$this->content .= "\r\n /* 插入数据 {$table} */";
$this->content .= "\r\n INSERT INTO {$table} VALUES {$values}";
}
}
}
// dump($this->content);
// exit;
}
}
if (!empty($this->content)) {
$this->setFile();
}
return true;
}
/* -
* +------------------------------------------------------------------------
* * @ 还原数据
* +------------------------------------------------------------------------
* * @ $fileName 文件名
* +------------------------------------------------------------------------
*/
private function recover_file($fileName) {
$this->getFile($fileName);
if (!empty($this->content)) {
$content = explode(';/* MySQLReback Separation */', $this->content);
foreach ($content as $i => $sql) {
$sql = trim($sql);
if (!empty($sql)) {
$mes = $this->model->execute($sql);
if (false === $mes) { //如果 null 写入失败,换成 ''
$table_change = array('null' => '\'\'');
$sql = strtr($sql, $table_change);
$mes = $this->model->execute($sql);
}
if (false === $mes) { //如果遇到错误、记录错误
$log_text = '以下代码还原遇到问题:';
$log_text.="\r\n $sql";
set_log($log_text);
}
}
}
} else {
$this->error('无法读取备份文件!');
}
return true;
}
}
?>
$this->_get(); 用法示例自动过滤
$this->_get('a','b','c');
三个参数:
a、$_GET提交上来的变量名;
b、过滤函数(多个用逗号隔开,如:'trim' / 'trim,String');
c、默认值;
一个简单的返回指定错误代码,错误页面的函数
httpstatus('404');
将向客户端发送一个404错误,并且错误页面是可以自定义的。
将函数放在common.php内,自动加载即可随意调用了
/**
* 返回错误代码,将错误页面放在入口文件目录./Public/httpstatus下,命名为 404.html,403.html,503.html等等
* @param $string 错误代码
* @param $msg 错误信息例如NOT FOUND,可以省略
*/
function httpstatus($string="404",$msg=""){
header("http/1.1 {$string} {$msg}");
include './Public/httpstatus/'.$string.'.html';
exit;
}
相关推荐
在数据库设计中,这可以通过自引用的方式实现,即新闻分类表中有一个字段指向自身,表示父类别与子类别的关系。常见的实现方式有Adjacency List、Nested Set和Materialized Path等模型。 1. Adjacency List 模型是...
"ThinkPHP框架帮助扩展类"是指在ThinkPHP框架中,为了增强其核心功能或者解决特定问题而设计的一些自定义工具类。这些类通常被命名为"Util",表示它们是通用的实用工具,可以协助处理各种常见的编程任务。 "Excel...
本知识点将聚焦于ThinkPHP5中的一个特定功能——敏感词过滤类,以及如何使用DFA(Deterministic Finite Automaton,确定有限状态自动机)算法来实现这一功能。 首先,我们要理解敏感词过滤的背景。在网站内容管理中...
主要介绍了thinkPHP引入类的方法,结合引入phpmailer类的示例分析了thinkPHP中引入邮件发送类的步骤、实现方法与使用技巧,需要的朋友可以参考下
首先,`ThinkPHP 连接 SQL SERVER 类`指的是在ThinkPHP项目中创建一个类,专门用于处理与SQL Server数据库的连接、查询和其他操作。这通常涉及到创建自定义的数据驱动(driver)或适配器(adapter),使得ThinkPHP...
thinkphp的image.php文件,直接复制替换到框架的think/image类.重新类的方法处理图片透明水印问题
在Thinkphp中实现多条件查询时,可以使用框架提供的查询构建器(Query Builder),但是当涉及到MongoDB的复合查询时,比如需要使用AND和OR逻辑运算符进行多条件筛选,官方文档中提供的方法可能不足以满足需求。...
总结起来,ThinkPHP实现无限分类主要涉及数据库设计、模型方法的编写、控制器处理和视图渲染。理解并掌握这些概念和技术,能够帮助你在实际项目中灵活应对各种分类需求。通过分析和仿照提供的"tree"文件,你可以更...
总的来说,这个"thinkphp无限分类例子"提供了一个基础的无限分类实现,开发者可以通过阅读和理解代码,了解并掌握在ThinkPHP框架中实现无限分类的方法。这不仅有助于提升开发效率,也有助于扩展对PHP和ThinkPHP框架...
《深入浅出ThinkPHP5框架:模板开发与实践》 ThinkPHP5,作为国内开发者广泛使用的PHP框架之一,以其简洁的代码结构、强大的功能和完善的设计模式赢得了广大开发者的喜爱。本压缩包“thinkphp_thinkphp_thinkphp5_...
调用`Page`类的`getField()`方法可以获取当前页的数据,然后使用`limit()`方法设置查询范围。例如: ```php $list = M('User')->where($condition)->limit($Page->firstRow, $Page->listRows)->select(); // 获取...
集成一个thinkphp 的钉钉接口,实现大部分接口 如: 发送消息,部门管理,员工管理,素材管理等 使用方法: $options = array( 'ding_config' => array( 'CorpID' => 'ding34654fsdfs 80edd5-', 'CorpSecret' =>'...
文件缓存类还提供了其他一些方法,如`clean`(清空所有缓存)、`has`(检查是否存在指定缓存)、`read`(读取缓存文件但不设置)等,这些方法都是基于文件系统操作的。 6. **缓存策略**: ThinkPHP的文件缓存类在...
使用`D`助手函数的好处是它会自动去应用的模型目录下查找对应的类文件,但在实际开发中,直接使用`D`助手函数调用类可能会带来一些问题,比如依赖于模型目录的结构,以及可能会与内置的`D`函数发生冲突。 另一个更...
主要介绍了thinkPHP自定义类实现方法,结合实例形式分析了thinkPHP自定义模型类的定义与使用技巧,需要的朋友可以参考下,通过引入类实现,把类放到ORG下。调用方便不管Api文件夹下有多少类,都会自动加载。
6. **扩展Page类**:如果需要更复杂的定制,比如增加额外的分页功能,可以考虑继承Page类,创建一个新的类,然后在新的类中添加或修改方法。这样可以保持原有Page类的兼容性,同时实现个性化需求。 7. **配置文件...
当我们需要在ThinkPHP项目中与SQL Server进行交互时,就需要特定的连接类和配置。下面我们将详细讨论如何在ThinkPHP中建立与SQL Server的连接,以及相关工具的使用。 首先,我们来看核心文件`DbSqlsrv.class.php`。...
下面将详细解释该类的一些关键功能和使用方法: 1. **初始化客户端**:首先,你需要创建一个 SVN 客户端实例,通常会传入SVN仓库的URL、用户名和密码。例如: ```php $svn = new \ThinkSvn\Client('...