分类目录归档:技术

mysqli中多语句查询insert_id和affected_rows

在php的mysqli中有多条SQL语句执行的函数multi_query,可以一次执行多条SQL语句,对于不返回结果集的SQL语句在使用中发现获取insert_id和affected_rows不能自动进行多语句的累加数据,还得配合more_results「是否还有结果集」和next_result「下一个结果集」来进行计算,按照预计的来讲对于不返回结果集的SQL语句来说,应该能直接返回最后插入的ID和受影响的行数,结果却不然,在此记录一下。

<!--?php
/*
 *  使用mysqli的多语句查询multi_query中获得最后插入ID和受影响的行数
 *  数据库表为shops,字段有id,name,price,nums,desc,id为子增长字段
 */
header('Content-Type: text/html; charset=utf-8');

$mysqli = new mysqli("localhost", "root", "liutao", "test");

if($mysqli--->connect_error) {
  echo '错误:' . $mysqli-&gt;connect_error;
  exit;
}

$sqls = "insert into shops(name,price,nums,desc) 
  values('笔记本','1.2','1000','B5 笔记本');
insert into shops(name,price,nums,desc) 
  values('0.5中性笔','1.8','30','0.5的黑色中性笔');
insert into shops(name,price,nums,desc) 
  values('档案袋','2.2','100','A4透明塑料档案袋');
insert into shops(name,price,nums,desc) 
  values('订书钉','3.5','50','订书钉');";

if($mysqli-&gt;multi_query($sqls)) {
  $affectRows = 1; 
  do {
    $affectRows += $mysqli-&gt;affected_rows;
    $mysqli-&gt;next_result();
  } while($mysqli-&gt;more_results());
  echo "执行成功!<br> 最后插入的id:{$mysqli-&gt;insert_id} <br> ";
  echo "共影响的行数:{$affectRows} <br>";
} else {
  echo '错误:' . $mysqli-&gt;errno . '(' . $mysqli-&gt;error . ')';
}

$mysqli-&gt;close();

?&gt;

执行结果:

mutiquery_id_affectedrows

常见的腻子脚本功能摘要

经常见到一些网站中用一些腻子脚本「polyfill」,对其主要的功能进行一下摘要记录。

html5shiv.js  让IE8及更低版本的IE浏览器识别section、article、nav等HTML5元素;
selectivizr 让IE6/7/8 支持:first-child 等CSS选择符;
CSS3Pie 让低版本的IE支持圆角、渐变、边框图片、阴影等可视化CSS3功能;
Respond.js 让旧浏览器支持媒体查询;
-prefix-free 为需要厂商前缀的CSS3声明增加前缀;
borderBoxModel.js 让IE6/7支持CSS3的box-sizing属性;

这些腻子脚本主要用于弥补IE及低版本浏览器的不足,在GitHub有一个腻子脚本列表,参见「这里」。

php学习练习(1)-简单的日历类

追溯到我专职写程序的日子已经是若干年以前了,依稀记得从08年后半年开始,就没有在工作中专职全力写程序了,偶尔写点也是基于验证性的东西。当然不把写程序当作职业中的一部分是有很多借口,但都是借口,虽然年龄已经不小了,但是重新捡起来还是可以的,最近恰逢想要写一个系统,于是开始动手。

有「归零」的心态加上持续的练习是必不可少的,提高写程序的水平唯一方法就是不断的进行编码练习。当然练习是基于获取知识后的实践,再结合项目实际应用,积累一段时间后,自然会重新站起,在自己的博客上记录一下这段时间,今天从一个简单日历类开始。

实现基本的日历类Calendar功能,类向外公开一个display方法用于显示日历,能够按照月、年显示日历信息,简单日历类主要练习PHP的一部分日期时间函数,基于功能,类图如下:

calendar

display方法用于显示日历
weekList方法用于列出日历中的星期
daysList方法用于列出每个月的天数
editDate方法用于改变日历显示
构造方法完成对成员的初始化

类文件名为:calendar.class.php ,测试文件为:test.php ,具体代码如下:

year = isset($_GET['year']) ? $_GET['year'] : date('Y');
    $this->month = isset($_GET['month']) ? $_GET['month'] : date('m');
    $this->daysOfMonth = date('t', mktime(0, 0, 0, $this->month, 1, $this->year));
    $this->dayOfWeek = date('w', mktime(0, 0, 0, $this->month, 1, $this->year));
  }

  function display() {
    echo '';
    $this->editDate();
    $this->weekList();
    $this->daysList();
    echo '
} private function weekList() { $week = array('日','一','二','三','四','五','六'); echo ''; for($i = 0; $i < count($week); $i++) { echo ''. $week[$i] .''; } echo ''; } private function daysList() { echo ''; for($col = 0; $col < $this->dayOfWeek; $col++) echo ' '; for($day = 1; $day <= $this->daysOfMonth; $day++) { $col++; if($day == date('d')) { echo ''. $day .' } else { echo ''. $day .''; } if($col % 7 == 0) { echo ''; } } echo ''; } private function editDate() { echo ''; echo '<<'; echo '<'; echo ''. $this->year . '年'. $this->month .'月'; echo '>'; echo '>>'; echo ''; } private function prevYear($year, $month) { $year--; if($year == 1970) { $year = 1970; } return 'year=' . $year . '&month=' . $month; } private function prevMonth($year, $month) { $month--; if($month<1) { $month = 12; $year--; } return 'year=' . $year . '&month=' . $month; } private function nextMonth($year, $month) { $month++; if($month > 12) { $month = 1; $year++; } return 'year=' . $year . '&month=' . $month; } private function nextYear($year, $month) { $year++; return 'year=' . $year . '&month=' . $month; } } ?>

测试文件test.php,代码如下:

display();
?>

测试结果:
calendar.test

到这里就完成了这个简单的日历类,当然该类是仅仅用于展示日历的一个练习,如果用于实际则需要进一步改进,有几个方面可进一步改进:

1. 日历类一般用于前端,用javascript实现日历类在实际项目中应用应该好于用php这个服务器的脚本语言实现;
2. 如用php则应该非本练习中这样整页面向服务器提交请求,而应该使用AJAX就该日历部分展示与服务器进行异步数据传输;
3. 就功能上可增加输入年跟月来获取日历的方式;
4. 就展现上可采用模板,并用层叠样式表来设定样式;

–EOF–

PDO(PHP Data Object)扩展学习(一)

1、PDO知识学习
(1)了解PDO及建立数据库连接
PDO(PHP Data Object)扩展是一个与数据库通讯交互的扩展,与以往使用的mysql或mysqli类似,旨在解决不同数据库的连接及处理一致性问题,奈何在这个追求个性的时代,各个数据库厂家之间的SQL脚本都有自家的个性,有所差异,目前PDO还未完全解决针对所有数据库交互的一致性。
PDO针对数据库提供了一组相对比较简洁的功能,用于查询及获取数据集。其使用相对也比较简单,首先是一如既往的要跟将要操作的数据库取得联系,然后完成各种操作,与数据库取得联系,一般要创建一个PDO对象,然后核对暗号(DNS),匹配后该PDO对象就打入敌人内部,从而开展各项活动,该向外传递情报就传递,该破坏敌人内部就破坏。以MySQL为例我们来一个示例。

$dbConn = new PDO('mysql:host = localhost; dbname=db', 'dbuser', 'dbpwd');

创建成功后再$dbConn中存储PDO对象,然后就可以该干啥干啥了。
(2)基础查询
先看看基础查询,基础查询主要使用PDO对象的query方法,该方法接受SQL查询语句,返回一个叫PDOStatement的对象,返回的对象的fetch方法或者fetchAll方法就可以获得数据集了,具体如下:

$dbConn = new PDO('mysql:host = localhost; dbname=db', 'dbuser', 'dbpwd');
$stmt = $dbConn->query('SELECT Field1,Field2 FROM table_name');
while($row = $stmt->fetch()) {
    echo $row['field1'] . ' ---' $row['field2'] . "\n";
}

(3)数据提取模式
PDOStatement对象的fetch方法与fetchAll方法可接受相应的参数,该参数用于指定数据提取模式,主要反映在结果数据集格式化的模式,共有四个常量,分别是:FETCH_ASSOC、FETCH_NUM、FETCH_BOTH、FETCH_CLASS,其中FETCH_BOTH为默认值。
FETCH_ASSOC:返回的结果集为数组,以查询字段名作为数组的键值,上面的基础查询中输出中的应用;
FETCH_NUM:返回的结果集为数组,以数字作为数组的键值;
FETCH_BOTH:返回的结果集为数组,包含上两者,既有以字段名作为数组的键值,又有以数字作为数组的键值;
FETCH_CLASS:返回的结果集为一个已经命名的类的对象,以查询列名设置到类对象的属性中;
(4)参数及预处理
PDO扩展还可以对查询脚本参数进行预处理操作,可以在SQL语句中针对查询条件设定参数,可以在执行过程中给参数设定具体的值,等于说将PDOStatement对象的Query分为两步来运行,先传入预处理SQL语句,然后再赋值执行。使用预处理的好处是编译一次,多次执行,能够提高效率,要快于query查询,另外可以有效的防止SQL注入。另外参数也可以用?来代替,需要顺序给参数赋值。预处理还中的参数可以绑定一个值,也可以绑定一个变量。

// 基本操作
$sql = "SELECT * FROM tablename WHERE field = :param";
$stmt = $dbConn->prepare($sql);
$stmt->execute(array("field" => value));
$result = $stmt->fetch();
// 用?代替参数
$sql = "SELECT * FROM tablename WHERE field1 = ? AND field2 = ?";
$stmt = $dbConn->prepare($sql);
$stmt->execute(array(value1,value2));
$result = $stmt->fetch();
// 绑定值、预处理中的变量
$sql = "SELECT * FROM tablename WHERE field1 = :field1 AND field2 = :field2;
$stmt = $dbConn->prepare($sql);
$stmt->bindValue(':field1', value1);
$stmt->bindValue(':field2', value2);
$stmt->execute();
$result = $stmt->fetch();
// 可改变某一参数绑定的值,继续执行
$stmt->bindValue(':field2', value3);
$stmt->execute();
$result2 = $stmt->fetch();
// 还可以给参数绑定变量
$stmt->bindParam(':field2',$value4);
$value4 = value;
$stmt->execute();
$result3 = $stmt->fetch();

(6)数据库操作中的常用操作
(A)获取新插入数据的ID
执行后调用PDO对象的lastInsertId()方法可获得新插入数据的ID。

$sql = "INSERT INTO tablename(field1,field2,field3) VALUES(:field,:field2,:field3)";
$stmt = $dbConn->prepare($sql);
$stmt->execute(array(
        ':field1' => value1,
        ':field2' => value2,
        ':field3' => value3)
);
echo "New insert id : " . $dbConn->lastInsertId();  

(B)获取操作影响的行数
执行后调用PDOStatement对象的rowCount方法获得操作影响到行数,参考数据删除操作影响的行数。
(C)数据删除

$sql = "DELETE FROM tablename WHERE field = :field";
$stmt = $dbConn->prepare($sql);
$stmt->execute(array(":field" => value));
echo $stmt->rowCount() . ' rows deleted';

(7)异常处理
连接数据库失败会抛出PDOException异常,预处理失败会返回false或抛出PDOException,可使用getMessage方法获得抛出异常的原因,执行成功返回true,失败返回false,如果执行失败,可使用PDOStatement对象的errorInfo方法获得错误产生的原因。提取数据错误返回false,同样可以使用errorInfo方法获得错误的信息,需要注意的是提取数据会返回空数组或者其他 依据数据提取模式结果,这是没有错误状态的。

        try {
              $dbConn = new PDO("...");
        } catch (PDOException $e) {
              echo "Could not connect to database";
              exit;        
        }
        $sql = "...";
        try {
              $stmt = $dbConn->prepare($sql);
              if($stmt) {
                   if($stmt->execute(...)) {
                       $result = $stmt->fetch();
                   } else {
                       $error = $stmt->errorInfo();
                       ...
                   }
              }
        } catch(PDOException $e) {
            echo $e->getMessage();
        }

(8)PDO的事务处理
PDO对于事物处理的前提是数据库要支持事务处理,对于MySQL来讲表类型为Inno的支持事务,对于一组SQL语句需要进行事务处理,在任何SQL语句运行前调用PDO对象的beginTransaction方法启动事务,所有SQL语句运行成功后,调用PDO对象的commit方法,在运行中改组SQL语句有一个没运行成功,调用PDO对象的rollback方法回滚。

–未完待续 —

php html解析器Simple HTML Dom

最近在每天工作之余抽取一点小时间做一个小的web应用,中间需要一些原始数据的抓取,用于测试,在网上找到了PHP Simple HTML Dom,是一个简单的HTML DOM解析器,支持PHP5+以上版本,支持无效的HTML,提供了比较简单的方法来处理HTML元素。是一个开源项目。

在使用中基本能够满足目前的需要,相对对于HTML的处理还是比较方便的,就是效率跟占用内存貌似不太理想,可能是对其使用上不是很对路。总来的来说,用这个东西入门还是比较快速的。

1. 开始使用

首先下载解压缩,然后将simple_html_dom.php文件包含进要编写的脚本文件中,加载要处理的html,支持三种模式的html加载,分别是『从url中加载,从字符串中加载,从文件中加载』。

Hello World!');
//从文件中加载
$html = file_get_html('example.htm');

从字符串加载网上文件需要先从网络下下载,使用cURL比较好一些,需要在php配置文件中打开php扩展php_curl。

$url = 'http://www.example.com';
$ci = curl_init();
curl_setopt($ci,CURLOPT_URL,$url);
curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ci, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ci);

2. 查找html元素

使用find函数查找,返回包含对象的数组,常见的查找如下。

//查找超链接元素
$alink = $html->find('a');
//查找第n个连接元素
$alink = $html->find('a',5);
//查找id为main的div
$mainDiv = $html->find('div[id=main]');
//查找所有定义了id的div
$idDiv = $html->find('div[id]');
//查找所有定义了id的元素
$idAll = $html->find('[id]');
//查找样式类为info的元素
$classInfo = $html->find('.info');
//支持嵌套子元素查找
$ret = $html->find('ul li');
//查找多个html元素
$ret = $html->find('a,img,p');
//....

3. 其他

可以使用内置的函数来进行元素的定位,返回父元素parent,返回子元素数组children,返回第一个子元素first_child,返回最后一个子元素last_child,返回前一个相邻元素prev_sibling,返回后一个相邻元素next_sibling等。

提供简单的正则表达式来过滤属性选择器,类似于[attribute]的格式。

每个对象都有4个基本属性:
tag — 返回html标签名
innertext — 返回innerHTML
outertext — 返回outerHTML
plaintext — 返回HTML标签中的文本

返回元素属性值

//返回$alink的href值
$link = $alink->href;

通过设置元素的属性值可以对元素进行添加、修改、删除操作。

//删除url连接
$alink->href = null;
//元素的修改
$ret->outertext = '
';
$ret->outertext = '';
$ret->outertext = $ret->outertext . '
other
';
$ret->outertext = '
Welcome
' . $ret->outertext;

-EOF-