PHPUnit使用笔记

1.引入composer
composer require  phpunit/phpunit

2.编写测试代码

<?php
require_once './vendor/autoload.php';
require_once './Demo.php';

use PHPUnit\Framework\TestCase;
use Mydemo\Demo;
class DemoTest extends TestCase
{
    public function testone()
    {
        //判断真假
        $this->assertTrue(Demo::add(1,2) == 3);
        //判断总数是否正确
        $this->assertEquals(5, count(Demo::fetchAll()));
        //判断结果是否包含
        $this->assertContains(1, Demo::fetchAll());
    }
}
更多内容参考:https://phpunit.de/manual/current/zh_cn/appendixes.assertions.html

3.编写类

<?php

namespace Mydemo;

class Demo
{
    public static function add($a, $b)
    {
        return $a + $b;
    }
    
    public static function fetchAll()
    {
        return [1,2,3,4,5];
    }
}

TDD、BDD和DDD

1.TDD,测试驱动开发
TDD指的是Test Drive Development,简单地说,TDD 就是在写代码前先写测试,并严格遵守(错误》正确》重构)的流程

2.BDD,行为驱动开发
BDD指的是Behavior Drive Development,实际上BDD可以看作是对TDD的一种补充,当然你也可以把它看作TDD的一个分支

3.DDD,领域驱动开发
DDD是指Domain Drive Design,也就是领域驱动开发,这是一种非常好的思想。在我们刚开始学习程序,甚至刚开始学习三层架构的时候,我们曾经面临过很多疑惑,比如如何来实现我们的数据层?后来我们开始学习MVC,MVP等架构,如何设计Model层又成了我们的新问题。我们见过太多这种情况,Model变成了单纯的数据容器,也就是我们经常说的贫血模式。DDD实际上也是建立在这个基础之上,因为它关注的是Service层的设计,着重于业务的实现,因此不可避免的以贫血模式为基础而存在。

SSO

1、什么是SSO(单点登录Single Sign On)
SSO是一种统一认证和授权机制,指访问同一服务器不同应用中的受保护资源的同一用户,只需要登录一次,即通过一个应用中的安全验证后,再访问其他应用中的受保护资源时,不再需要重新登录验证。
2、解决问题
解决了用户只需要登录系统一次就可以访问相互信任的应用系统
3、SSO原理
所有认证都在SSO认证中心认证
SSO认证中心通过一些方法通知WEB当前用户是否已认证用户
SOO认证中心和WEB应用要有信任关系
4、CAS原理
4.1访问服务
4.2定向认证
4.3用户认证
4.4发放Ticket
4.5验证Ticket
4.6传输用户信息

svnmanager安装

apt-get update
apt-get install apache2 subversion libapache2-svn
apt-get install apache2-utils
a2enmod dav_svn
apt-get install mysql-server mysql-client
apt-get install php5 php5-mysql php5-sqlite php-pear
pear install versionControl_svn
Failed to download pear/versionControl_svn within preferred state “stable”, latest release is version 0.5.2, stability “alpha”, use “channel://pear.php.net/versionControl_svn-0.5.2” to install
install failed
这样可能是软件的BUG,那就指定版本,注意不要安装0.5.0不然会报错
pear install versionControl_svn-0.4.0
apt-get install phpmyadmin
apt-get install php5-mcrypt
php5enmode mcrypt
创建SVN版本库父目录
mkdir /var/www/svn
创建验证用户访问权限文件
touch /var/www/svn/access
创建验证用户密码文件
touch /var/www/svn/passwd
更改文件权限
chmod 666 access passwd
新增站点
<VirtualHost *:80>
ServerName dev.svn
DocumentRoot /var/www/svn
<Directory /var/www/svn>
order allow,deny
Deny from all
</Directory>
Include /etc/apache2/svn/*.conf
</VirtualHost>
新建svn
<Location />
DAV svn
#如果是多个站点可以用这个
SVNParentPath /var/www/svn
Authtype Basic
AuthName ‘SVN’
AuthzSVNAccessFile /var/www/svn/access
AuthUserFile /var/www/svn/passwd
Require valid-user
</Location>

部署svnmanager
wget http://prdownloads.sourceforge.net/svnmanager/svnmanager-1.08.tar.gz
mkdir /var/www/html/svnadmin
搭建站点
<VirtualHost *:80>
DocumentRoot /var/www/html/svnadmin
ServerName svnadmin
<Directory /var/www/html/svnadmin>
Options -Indexes +FollowSymLinks
AllowOverride All
Order Allow,Deny
Allow from all
</Directory>
ErrorLog /var/www/logs/svnadmin.error.log
CustomLog /var/www/logs/svnadmin.access.log common
</VirtualHost>
为svnmanager创建数据库
create database svnmanager;
grant all privileges on svnmanager.* to ‘svnmanager’@’localhost’ identified by ‘123456’;
flush privileges;
exit
配置svnmanager
cp config.php.linux ./config.php
编辑config.php
$htpassword_cmd = “/usr/bin/htpasswd”;
$svn_cmd = “/usr/bin/svn”;
$svnadmin_cmd = “/usr/bin/svnadmin”;

//Subversion locations
$svn_config_dir = “/var/www/svn/svnconfig”;
$svn_repos_loc = “/var/www/svn”;
$svn_passwd_file = “/var/www/svn/passwd”;
$svn_access_file = “/var/www/svn/access”;
$dsn = “mysql://svnmanager:123456@localhost/svnmanager”;
错误提示
Fatal error: Class ‘PEAR_ErrorStack’ not found in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\
svnmanager\svnmanager\
RepositoryModule\UserPrivilegesEditPage.php on line 204

解决方法:
pear uninstall VersionControl_SVN-0.5.0 卸掉0.5.0
pear install PEAR-1.9.4
pear install VersionControl_SVN-0.4.0 重装0.4.0就没报这个错了

 

CSRF原理和防范

一.CSRF
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
二.影响
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账……造成的问题包括:个人隐私泄露以及财产安全。
三.过程
要完成一次CSRF攻击,受害者必须依次完成两个步骤:
1.登录受信任网站A,并在本地生成Cookie。
2.在不登出A的情况下,访问危险网站B。
看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:
1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了……)
3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
四.CSRF的防御
1.所有表单都包含同一个伪随机值(TOKEN)
2.验证码
3.检测refer

为何GPS坐标和百度坐标不一致?

美国GPS使用的 是WGS84的坐标系统,以经纬度的形式来表示地球平面上的某一个位置。但在我国,出于国家安全考虑,国内所有导航电子地图必须使用国家测绘局制定的加密 坐标系统,即将一个真实的经纬度坐标加密成一个不正确的经纬度坐标,在业内将前者称之为地球坐标,后者称之为火星坐标。

《条例》要求地图不得“危害国家统一、主权和领土完整;危害国家安全、损害国家荣誉和利益;国家秘密;影响民族团结、侵害民族风俗习惯”,规定互联网地图服务必须经过审批,要求“从事互联网地图服务的,应当将存放地图数据的服务器设在中华人民共和国境 内,建立互联网地图数据安全管理制度和保障措施,并具有经测绘行政主管部门考核合格的互联网地图安全审校人员。”由于地图涉及“国家机密”,中国官方要求 地图服务商加装“国家保密插件”,以“保障国家安全”。此插件会将真实的坐标加密成虚假的坐标,且此加偏并非线性加偏,所以各地的偏移情况都会有所不同。

国家保密插件,也叫做加密插件或者加偏或者SM模组,其实就是对真实坐标系统进行人为的加偏处理,按照几行代码的算法,将真实的坐标加密成虚假的坐标,而这个加偏并不是线性的加偏,所以各地的偏移情况都会有所不同。而加密后的坐标也常被人称为火星坐标系统。

所有的电子地图所 有的导航设备,都需要加入国家保密插件。第一步,地图公司测绘地图,测绘完成后,送 到国家测绘局,将真实坐标的电子地图,加密成“火星坐标”,这样的地图才是可以出版和发布的,然后才可以让GPS公司处理。第二步,所有的GPS公司,只 要需要汽车导航的,需要用到导航电子地图的,统统需要在软件中加入国家保密算法,将COM口读出来的真实的坐标信号,加密转换成国家要求的保密的坐标,这 样,GPS导航仪和导航电子地图就可以完全匹配,GPS也就可以正常工作。

定位div到窗口固定位置

代码来自网络~

/*任意位置浮动固定层*/
/*调用:
1 无参数调用:默认浮动在右下角
$("#id").floatdiv();

2 内置固定位置浮动
//右下角
$("#id").floatdiv("rightbottom");
//左下角
$("#id").floatdiv("leftbottom");
//右下角
$("#id").floatdiv("rightbottom");
//左上角
$("#id").floatdiv("lefttop");
//右上角
$("#id").floatdiv("righttop");
//居中
$("#id").floatdiv("middle");

另外新添加了四个新的固定位置方法

middletop(居中置顶)、middlebottom(居中置低)、leftmiddle、rightmiddle

3 自定义位置浮动
$("#id").floatdiv({left:"10px",top:"10px"});
以上参数,设置浮动层在left 10个像素,top 10个像素的位置
*/
jQuery.fn.floatdiv=function(location){
		//判断浏览器版本
	var isIE6=false;
	var Sys = {};
    var ua = navigator.userAgent.toLowerCase();
    var s;
    (s = ua.match(/msie ([\d.]+)/)) ? Sys.ie = s[1] : 0;
	if(Sys.ie && Sys.ie=="6.0"){
		isIE6=true;
	}
	var windowWidth,windowHeight;//窗口的高和宽
	//取得窗口的高和宽
	if (self.innerHeight) {
		windowWidth=self.innerWidth;
		windowHeight=self.innerHeight;
	}else if (document.documentElement&&document.documentElement.clientHeight) {
		windowWidth=document.documentElement.clientWidth;
		windowHeight=document.documentElement.clientHeight;
	} else if (document.body) {
		windowWidth=document.body.clientWidth;
		windowHeight=document.body.clientHeight;
	}
	return this.each(function(){
		var loc;//层的绝对定位位置
		var wrap=$("
"); var top=-1; if(location==undefined || location.constructor == String){ switch(location){ case("rightbottom")://右下角 loc={right:"0px",bottom:"0px"}; break; case("leftbottom")://左下角 loc={left:"0px",bottom:"0px"}; break; case("lefttop")://左上角 loc={left:"0px",top:"0px"}; top=0; break; case("righttop")://右上角 loc={right:"0px",top:"0px"}; top=0; break; case("middletop")://居中置顶 loc={left:windowWidth/2-$(this).width()/2+"px",top:"0px"}; top=0; break; case("middlebottom")://居中置低 loc={left:windowWidth/2-$(this).width()/2+"px",bottom:"0px"}; break; case("leftmiddle")://左边居中 loc={left:"0px",top:windowHeight/2-$(this).height()/2+"px"}; top=windowHeight/2-$(this).height()/2; break; case("rightmiddle")://右边居中 loc={right:"0px",top:windowHeight/2-$(this).height()/2+"px"}; top=windowHeight/2-$(this).height()/2; break; case("middle")://居中 var l=0;//居左 var t=0;//居上 l=windowWidth/2-$(this).width()/2; t=windowHeight/2-$(this).height()/2; top=t; loc={left:l+"px",top:t+"px"}; break; default://默认为右下角 location="rightbottom"; loc={right:"0px",bottom:"0px"}; break; } }else{ loc=location; var str=loc.top; str=str.replace("px",""); top=str; } /*fied ie6 css hack*/ if(isIE6){ if (top>=0) { wrap=$("
"); }else{ wrap=$("
"); } } $("body").append(wrap); wrap.css(loc).css({position:"fixed", z_index:"999"}); if (isIE6) { wrap.css("position","absolute"); //没有加这个的话,ie6使用表达式时就会发现跳动现象 $("body").css("background-attachment","fixed").css("background-image","url(n1othing.txt)"); } //将要固定的层添加到固定层里 $(this).appendTo(wrap); }); };

导出excel

/**
     * 导出数据为excel表格
     *@param $data    一个二维数组,结构如同从数据库查出来的数组
     *@param $title   excel的第一行标题,一个数组,如果为空则没有标题
     *@param $filename 下载的文件名
     */
    public static function exportexcel($data=array(),$title=array(),$filename='report'){
        header("Content-type:application/octet-stream;charset=utf-8");
        header("Accept-Ranges:bytes");
        header("Content-type:application/vnd.ms-excel");
        header("Content-Disposition:attachment;filename=".$filename.".xls");
        header("Pragma: no-cache");
        header("Expires: 0");
        //导出xls 开始
        if (!empty($title)){
            foreach ($title as $k => $v) {
                $title[$k]=iconv("UTF-8", "GB2312",$v);
            }
            $title= implode("\t", $title);
            echo "$title\n";
        }
        if (!empty($data)){
            foreach($data as $key=>$val){
                foreach ($val as $ck => $cv) {
                    $data[$key][$ck]=iconv("UTF-8", "GB2312", $cv);
                }
                $data[$key]=implode("\t", $data[$key]);
    
            }
            echo implode("\n",$data);
        }
    }

 

PHP面试常见问题汇总

1、PHP抽象类和接口的区别?
a)接口中不可以声明成员变量(包括类静态变量),但是可以声明类常量。抽象类中可以声明各种类型成员变量,实现数据的封装。
b)接口没有构造函数,抽象类可以有构造函数
c)接口中的方法默认都是public类型的,而抽象类中的方法可以使用private,protected,public来修饰。
一个类可以同时实现多个接口,但一个类只能继承于一个抽象类
2、Redis和Memcache的区别?
a)redis数据类型有String(字符串)、Hash(哈希)、List(队列)、Set(集合)、Sorted Set(有序集合Zset);Memcache仅仅String
b)Redis支持分布式
c)Redis可以持久化
d)redis可以通过aof恢复
3、Redis的优缺点以及持久化方式?
a)Redis 有各种丰富的数据结构
b)持久化方面快照方式指定时间写入磁盘,代价大;aof可以追加变化数据,恢复速度慢
c)aof、rdb是两种redis持久化的机制,用于crash后,redis的恢复。
4、服务器性能优化方式?
CPU、网络、IO、代码结构层、缓存、DB、请求等方面进行回答
5、Cookie和Session区别?
a)Cookie数据存放在客户的浏览器上,session数据放在服务器上
b)cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
c)单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie
6、客户端禁用了Cookie,Session还能用吗?
这个要怎么回答呢?因为可以通过get传递就可以继续用session了,一般面试基本问这个就是要这个解决方案的
7、如何共享Session?
memcache共享,主要是根据session_id来复原session
8、建立表需要考虑的因素有哪些?
a)char和varchar区别,用固定长度MyISAM用char,Innodb用varchar
b)存储引擎,Innodb支持事务
c)主键、外键
d)选用字段长度最小、优先使用定长型、尽可能的定义 “NOT NULL”、数值型字段中避免使用“ZEROFILL” 、如果要储存的数据为字符串,且可能值已知且有限, 优先使用 enum 或 set
e)索引
f)查询语句的优化
9、Myisam和Innodb区别?
MyISAM:不是事务安全的,也不支持外键。如果事物回滚将造成不完全回滚,不具有原子性。如果执行大量的SELECT,MyISAM是更好的选择;MyISAM的索引和数据是分开的,并且索引是有压缩的,内存使用率就对应提高了不少。能加载更多索引。表格可以被压缩,而且它们支持全文搜索;读性能较强;整表锁;建议使用固定长度的数据列代替可变长的数据列
InnoDB:事务安全的、支持外键。你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表;Innodb是索引和数据是紧密捆绑的,没有使用压缩从而会造成Innodb比MyISAM体积庞大不小;写性能较强;行级锁;
10、说出5个http状态码以及含义
参考:百科 博客

11、PHP的运行原理是?
参考
12、include和require区别是?
require是致命错误,require性能比include高
13、如何避免重复包含文件?
inluce_once或者require_once
14、SQL当中的内连接和左外连接、右外连接区别是?

15、echo、print、print_r的区别?
print是函数,有返回值;echo是语句,print_r是可以打印对象或者数组
16、下面的程序输出是多少?
$num = 10;
function add() {
$num = $num + 10;
}
add();
echo $num;
输出10;主要考察变量作用域
17、如何获取服务器IP、客户端IP?
客户端 $_SERVER[REMOTE_ADDR]
服务器 $_SERVER[SERVER_ADDR]
18、索引是什么?
可以提高查询效率
19、优化SQL的方案?
可以从索引、字段类型、查询语句等
20、GD库是用来做什么的?
图形处理
21、用什么方法可以加快页面加载速度?
页面大小、页面连接数(合并请求,异步等)、服务器抗压(php加速等)、网络等
22、如何防止SQL注入?
转义和数据类型检查
23、php程序引用传递和值传递的区别?
引用传递会更改原值
24、empty、isset区别
isset()函数 一般用来检测变量是否设置
empty()函数 判断值为否为空
25、大流量网站采用什么方式来解决访问量?
确认是否可以支持当前流量;优化数据库访问;禁止盗链;控制大文件下载;分流;流量分析
26、高并发量网站解决方案
html静态化、图片服务器分离、数据库集群库表三列、缓存、镜像、负载均衡、CDN加速
27、秒杀抽奖抢购等问题
利用队列,事务;多台服务器进行分流;具体问题具体分析

附:欢迎补充指正

PHP统计目录总大小、文件和子目录个数

php 
function getDirectorySize($path)
{
  $totalsize = 0;
  $totalcount = 0;
  $dircount = 0;
  if ($handle = opendir ($path))
  {
    while (false !== ($file = readdir($handle)))
    {
      $nextpath = $path . '/' . $file;
      if ($file != '.' && $file != '..' && !is_link ($nextpath))
      {
        if (is_dir ($nextpath))
        {
          $dircount++;
          $result = getDirectorySize($nextpath);
          $totalsize += $result['size'];
          $totalcount += $result['count'];
          $dircount += $result['dircount'];
        }
        elseif (is_file ($nextpath))
        {
          $totalsize += filesize ($nextpath);
          $totalcount++;
        }
      }
    }
  }
  closedir ($handle);
  $total['size'] = $totalsize;
  $total['count'] = $totalcount;
  $total['dircount'] = $dircount;
  return $total;
}
 
function sizeFormat($size)
{
    $sizeStr='';
    if($size<1024)
    {
        return $size." bytes";
    }
    else if($size<(1024*1024))
    {
        $size=round($size/1024,1);
        return $size." KB";
    }
    else if($size<(1024*1024*1024))
    {
        $size=round($size/(1024*1024),1);
        return $size." MB";
    }
    else
    {
        $size=round($size/(1024*1024*1024),1);
        return $size." GB";
    }
 
}
 
$path="D:/wamp/www/bak/tools";
$ar=getDirectorySize($path);
 
echo "

路径 : $path

"; echo "目录大小 : ".sizeFormat($ar['size'])."
"; echo "文件数 : ".$ar['count']."
"; echo "目录术 : ".$ar['dircount']."
"; //print_r($ar);