PHP pdo单例模式连接数据库

PHP pdo单例模式连接数据库

<?php

class Db
{
    private static $pdo;

    public static function getPdo ()
    {
        var_dump(self::$pdo);
        echo '</br>';
        if ( self::$pdo == null )
        {
            $host = 'localhost';
            $user = 'root';
            $pwd = '';
            $dbname = 'wangzhan';

            $dsn = "mysql:host=$host;dbname=$dbname;port=3306";
            $pdo = new PDO ( $dsn, $user, $pwd );
            $pdo->query('set names utf8;');
            $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            self::$pdo = $pdo;
        }
        return self::$pdo;
    }

    public static function getStmt ( $sql )
    {
        $pdo = self::getPdo ();
        return $pdo -> prepare( $sql );
    }
    public static function getinsertids()
    {
        $pdo = self::getPdo();
        $insertid = $pdo->lastInsertId();
        return $insertid;
    }
}


$sql = "INSERT INTO testss (wef,wef1) VALUES(?,?)";
$stmt = Db::getStmt ( $sql );
$stmt = Db::getStmt ( $sql );


?>

输出结果

NULL 
object(PDO)#1 (0) { } 

第一次null 第二次再获取就已经有了 不用重新连接了
单利模式好处就是保存变量 他是用static保存的 所以 退出函数 变量不会释放

html5 canvas手写字代码(兼容手机端)

html5 canvas手写字代码(兼容手机端)

<!DOCTYPE html>
<html>
<head>
    <title>画板实验</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <style type="text/css">
    </style>
</head>
<body style="background: #FCBE00" >

<canvas id="myCanvas" ></canvas>

<div>
    <button onclick="clean();">清 空</button>
    <button onclick="save();">生成图片</button>
</div>

<img id='img'/>

<script type="text/javascript">
    var canvas,board,img;
    canvas = document.getElementById('myCanvas');
    img= document.getElementById('img');

    canvas.height = 300;
    canvas.width = 300;

    board = canvas.getContext('2d');

    var mousePress = false;
    var last = null;

    function beginDraw(){
        mousePress = true;
    }

    function drawing(event){
        event.preventDefault();
        if(!mousePress)return;
        var xy = pos(event);
        if(last!=null){
            board.beginPath();
            board.moveTo(last.x,last.y);
            board.lineTo(xy.x,xy.y);
            board.stroke();
        }
        last = xy;

    }

    function endDraw(event){
        mousePress = false;
        event.preventDefault();
        last = null;
    }

    function pos(event){
        var x,y;
        if(isTouch(event)){
            x = event.touches[0].pageX;
            y = event.touches[0].pageY;
        }else{
            x = event.offsetX+event.target.offsetLeft;
            y = event.offsetY+event.target.offsetTop;
        }
//               log('x='+x+' y='+y);
        return {x:x,y:y};
    }

    function log(msg){
        var log = document.getElementById('log');
        var val = log.value;
        log.value = msg+'\n'+val;
    }

    function isTouch(event){
        var type = event.type;
        if(type.indexOf('touch')>=0){
            return true;
        }else{
            return false;
        }
    }

    function save(){
        //base64
        var dataUrl = canvas.toDataURL();
        img.src = dataUrl;
    }


    function clean(){
        board.clearRect(0,0,canvas.width,canvas.height);

    }

    board.lineWidth = 1;
    board.strokeStyle="#0000ff";


    canvas.onmousedown = beginDraw;
    canvas.onmousemove = drawing;
    canvas.onmouseup = endDraw;
    canvas.addEventListener('touchstart',beginDraw,false);
    canvas.addEventListener('touchmove',drawing,false);
    canvas.addEventListener('touchend',endDraw,false);
</script>


</body>
</html>

html5传感器

html5传感器
以下是代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="Cache-Control" content="no-cache" />
    <title>Title</title>

</head>
<body>
x:<div style="font-size: 55px;" id="x">x</div>
y:<div style="font-size: 55px;" id="y">y</div>
z:<div style="font-size: 55px;" id="z">z</div>
speed:<div style="font-size: 55px;" id="speed">speed</div>
<script src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.js"></script>
<script>
    $(function () {
        
        var shakeThreshold = 1000; // 定义一个摇动的阈值
        var lastUpdate = 0; // 记录上一次摇动的时间
        var x, y, z, lastX, lastY, lastZ; // 定义x、y、z记录三个轴的数据以及上一次触发的数据

        // 监听传感器运动事件
        if (window.DeviceMotionEvent) {
            window.addEventListener('devicemotion', deviceMotionHandler, false);
        } else {
            alert('本设备不支持devicemotion事件');
        }

        // 运动传感器处理
        function deviceMotionHandler(eventData) {
            var acceleration = eventData.accelerationIncludingGravity; // 获取含重力的加速度
            $('#x').text(acceleration.x);
            $('#y').text(acceleration.y);
            $('#z').text(acceleration.z);
            var curTime = new Date().getTime();

            // 100毫秒进行一次位置判断
            if ((curTime - lastUpdate) > 100) {

                var diffTime = curTime - lastUpdate;
                lastUpdate = curTime;

                x = acceleration.x;
                y = acceleration.y;
                z = acceleration.z;



                var speed = Math.abs(x + y + z - lastX - lastY - lastZ) / diffTime * 10000;
                $('#speed').text(speed);
                // 前后x, y, z间的差值的绝对值和时间比率超过了预设的阈值,则判断设备进行了摇晃操作
                if (speed > shakeThreshold) {
                    alert('摇动了');
                }

                lastX = x;
                lastY = y;
                lastZ = z;
            }
        }
    })

</script>
</body>
</html>

测试网址 可以观察x y z变化 http://newmiracle.cn/yaobai.html
ps 变化都是-10到10的变化 只要看整数就行 小数点不断的变化不用去鸟他

PHP防止被重复请求接口的方法(网页端签名验证的方法)

PHP防止被重复请求接口的方法(网页端签名验证的方法)
可以采取签名验证的方式来 解决这个问题

1 time和随机数都是PHP生成的显示在前端
2 前端生成sign
3 进行每次请求的sign计数 这个是时候用redis自增 来判断一共用了10次以上就返回 请重新刷新页面

所以参数一定要静态 比方说根据可以学习微信jssdk 用appid time 随机数生成 这个必须每次刷新才能更新

/
function getsigns()
{
	$parameters = array();
	$parameters['suijishu'] = getRandom(10, 5);
	$parameters['time'] = time();
	$sign = str_encrypt($parameters);
	$newpar['suijishu']=$parameters['suijishu'];
	$newpar['time']=$parameters['time'];
	$newpar['sign']=$sign;
	return $newpar;
}
//新版加密
function str_encrypt($parameters)
{

	unset($parameters['sign']);
	ksort($parameters);
	$parameters['key']='myk22';
	$signPars = url_build($parameters);
	$signPars = trim($signPars, '&');
	return strtolower(md5($signPars));
}

//新版字符串拼接
function url_build($parameters)
{
	$signPars = '';
	foreach ($parameters as $k => $v) {
		if (isset($v)) {
			$signPars .= $k . '=' . $v . '&';
		}
	}
	return $signPars;
}

客户端 post的3个参数都是上面getsigns()生成的

function ajaxpost() {

    $.post("/home/moban/signtest", {
         "suijishu":suijishu,
         "time":time,
         "sign":sign,
    },
        function (data) {
            if(data.success==1){


            }else {
                alert('网络繁忙');
            }


        }, "json");
}

服务端

function verifys(){
	$parameters['suijishu']=$_POST['suijishu'];
	$parameters['time']=$_POST['time'];
	$parameters['sign']=$_POST['sign'];
	if(!verify($parameters)){
		echo json_encode(array('success'=>0,'msg'=>'验证签名失败'));
		exit();
	}
}

验证下就好了

ps:另外 不要js生成sign 因为js代码都是暴露的 也不要通过ajax请求生成sign 这样就没意思了。。

2 采取验证码方式

PHP防止sql语句注入终极解决方案(包含pdo各种操作使用实例)

PHP防止sql语句注入终极解决方案
完美解决方案就是使用拥有Prepared Statement机制(预处理sql)的PDO

//先做个实验 先不用预处理sql写法

<?php
$pdo = new PDO('mysql:dbname=testdatabase;host=localhost;charset=utf8', 'root', 'root');
$id='2 or 1=1';
$stmt=$pdo->query('SELECT * FROM wz_admin WHERE id = '.$id);
  print_r($stmt -> fetchAll ());
exit();

可以发现 可以输出数据 id=2的时候是没数据的

?>

用预处理sql写法

$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
它会告诉 PDO 禁用模拟预处理语句,并使用 real parepared statements 。这可以确保SQL语句和相应的值在传递到mysql服务器之前是不会被PHP解析的(禁止了所有可能的恶意SQL注入攻击)。


$pdo = new PDO('mysql:dbname=testdatabase;host=localhost;charset=utf8', 'root', 'root');
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('SELECT * FROM wz_admin WHERE id = :id');
$id='2 or 1=1';
$stmt->execute(array('id' => $id));
print_r($stmt -> fetchAll ());
exit();

可以发现没有输出数据


上面这段代码就可以防范sql注入。为什么呢?
当调用 prepare() 时,查询语句已经发送给了数据库服务器,此时只有占位符 ? 发送过去,没有用户提交的数据;当调用到 execute()时,用户提交过来的值才会传送给数据库,它们是分开传送的,两者独立的,SQL攻击者没有一点机会

<?php

下面我简单的封装了下
class Db
{
    private static $pdo;

    public static function getPdo ()
    {
        if ( self::$pdo == null )
        {
            $host = 'localhost';
            $user = 'root';
            $pwd = '';
            $dbname = 'testdatebase';

            $dsn = "mysql:host=$host;dbname=$dbname;port=3306";
            $pdo = new PDO ( $dsn, $user, $pwd );
            $pdo->query('set names utf8;');
            $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            self::$pdo = $pdo;
        }
        return self::$pdo;
    }

    public static function getStmt($sql)
    {
        $pdo = self::getPdo();

        return $pdo->prepare($sql);
    }

    public static function getinsertids()
    {
        $pdo = self::getPdo();
        $insertid = $pdo->lastInsertId();
        return $insertid;
    }
    public static function SETATTR_AUTOCOMMIT()
    {
        $pdo = self::getPdo();
        $pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 0);
    }
    public static function beginTransactions()
    {
        $pdo = self::getPdo();
        $pdo->beginTransaction();//开启事务处理
    }
    public static function commits()
    {
        $pdo = self::getPdo();
        $pdo->commit();//开启事务处理
    }
   public static function roolbacks()
    {
        $pdo = self::getPdo();
        $pdo->rollBack();//开启事务处理
    }
}


$sql = "SELECT * FROM wz_admin WHERE id = ?";
$stmt = Db::getStmt ( $sql );
$stmt -> execute ( array (1));
//PDO::FETCH_ASSOC这个参数代表只显示关联数组 默认是显示索引下标和关联数组的
print_r($stmt -> fetchAll (PDO::FETCH_ASSOC));
exit();

//以下返回1 都是数据库操作成功的
$sql = "INSERT INTO testss (wef,wef1) VALUES(?,?)";
$stmt = Db::getStmt ( $sql );
$dd=$stmt -> execute ( array ('wefe','wefe1'));
print_r($dd);
exit();
$sql = "update testss set wef=? where id=2";
$stmt = Db::getStmt ( $sql );
$dd=$stmt -> execute ( array ('34'));
print_r($dd);





//事务    只有commit得而时候才会执行sql语句 如果过程中报错就会roolbacks 返回到初始状态
/*DB::SETATTR_AUTOCOMMIT();
$username=$_POST['username'];
$sql = 'INSERT INTO arjianghu_register (username) VALUES(?)';
$stmt = \Db::getStmt($sql);
Db::beginTransactions();//开启事务处理
$isOk = $stmt->execute(array($username));
if(!$isOk){
    Db::roolbacks();
    echo json_encode(array('success'=>0,'msg'=>'网络繁忙','data'=>''));
    exit();
}
$sql = 'INSERT INTO arjianghu_zhuangtai (personid) VALUES(?)';
$stmt = \Db::getStmt($sql);
$isOk = $stmt->execute(array(1));

if($isOk){
    echo json_encode(array('success'=>1,'msg'=>'操作成功','data'=>''));
    exit();
}else{
    Db::roolbacks();
    echo json_encode(array('success'=>0,'msg'=>'网络繁忙','data'=>''));
    exit();
}

DB::commits();*/
?>

ps:之所以预处理sql 能够防止注入式因为 他内部经过了转义等其他处理

ps:pdo字段不能用?必须要变量 ?只能用在值

css3网站响应式写法

css3响应式写法
我用的是媒体查询方法
这个手机和pc都用统一用下面的media
因为media不支持ie9以下的浏览器 所有要加个判断

     
 <!--[if lte IE 8]>
    <link rel="stylesheet"  href="/index/pc/css/common.css?v=<?php echo time() ?>"">
    <![endif]-->
    <!--  当页面宽度大于等于1350px触发 pc端显示的css-->
    <link rel="stylesheet"  href="/index/pc/css/common.css"  media="(min-width:1350px)">

   <!--ipad和手机公用的css-->
    <link rel="stylesheet"  href="/index/css/common.css"  media="(max-width:1349px)">

    <!-- 当页面宽度大于等于768px 小于等于1290px触发 匹配ipad  笔记本 等其他设备宽度   ipad尺寸是768px 1349px是网页的内容宽度    -->
    <link rel="stylesheet"  href="/index/ipad/css/common.css"  media="(min-width:768px) and (max-width:1349px)">
    <!-- 当页面宽度小于等于767px触发 手机端显示的css*/-->
    <link rel="stylesheet"  href="/index/mobile/css/common.css"  media="(max-width:767px)">

rem不兼容ie9以下所以 pc里面不要用rem
ps:1349px是网页设计图的可视区域 手机和ipad因为自适应通用 1239是一般网页的 有些网页宽度可能还要大 里面的css用百分比表示方便调整 font-size写成可视区域计算出来的值
但pc不行 不能通用css 相差有点大 建议分开

这样2个css完全分离了 更好的调试css了
注意字体大小最好不要小于12px(手机端低于12px看不清)

pc 1如果是宽屏显示都写宽度100% 宽屏图片要注意等比例缩小
2 文字用代码写 能提高加载速度 seo优化 不会低于12号字体

其他设备都采取 自适应 百分比写法 来保证所有文字自豪大小的统一

测试的时候测试iphone ipad 还有 1290 宽度情况下的页面

注意:如果碰到编辑器编辑生成内容需要自适应的时候 在移动端 图片要设置百分比 编辑图片的时候不能写宽度和高度哦居中就行 文字字体大小不用管

所有高度不要写死 都必须自适应

jquery ajax分页写法

jquery ajax分页写法
我用的是laypage插件

前端代码

        function demo(curr) {
            $.getJSON('/home/index/getinfo', {
                page: curr || 1 //向服务端传的参数,此处只是演示
            }, function (res) {
                var html = '';
                var list = res.data.list;
                $.each(list, function (k, v) {
                    html += '<div';
                    if(k%2==0){
                        html += ' style="margin-left:0px;"';
                    }
                    html += ' class="perinfocontent" onclick="window.location.href=\'content.html?id='+v['id']+'\'">';
                    html += '<img src="'+v['fengmiantu']+'" alt="" class="pic">';
                    html += '<div class="infos">';
                    html += '<div class="title">'+v['title']+'</div>';
                    html += '<div class="tiyao">'+v['content']+'</div>';
                    html += '<div class="publishtime">2017 / 1 / 23</div>';
                    html += '</div>';
                    html += '</div>';
                });

                $('.infocontent').html(html);

                //显示分页
                laypage({
                    cont: $('#page3'), //容器。值支持id名、原生dom对象,jquery对象,
                    pages: res.data.pagecount, //总页数
                    skip: true, //是否开启跳页
                    skin: 'molv',
                    curr: curr || 1, //当前页
                    jump: function (obj, first) { //触发分页后的回调
                        if (!first) { //点击跳页触发函数自身,并传递当前页:obj.curr

                        demo(obj.curr);
                        }
                    }
                });

            });
        };
//运行
        demo();

PHP代码

    public function getinfo(){
        $page = intval($_GET['page']);
     
        if(empty($page)){
            $page=1;
        }
        $startpos=$page-1;
        //返回每页的数据
        $percount = 8;
        $VModel = new HuanShanVoteModel();
        $sql = 'select * from wz_content order by id desc limit '.$startpos*$percount.',' . $percount;

        $result = $VModel->query($sql);
        foreach ($result as $k => $v) {
            $result[$k]['content'] = substr(stripHTML(htmlspecialchars_decode($v['content'])), 0, 30) . '......';
            $result[$k]['time'] = date('Y / M / D', $v['time']);
        }

        //返回总页码数
        $VModel = new HuanShanVoteModel();
        $sql = 'select title,content from wz_content';
        $alllist = $VModel->query($sql);
        $count = count($alllist);
        $pagecount = ceil($count / $percount);

        echo json_encode(array('success'=>1,'msg'=>'查询成功','data' => array('pagecount' => $pagecount, 'list' => $result)));
        exit();
    }