Go to comments

PHP Mysql

一、连接Mysql

PHP八种数据类型,已经学了六种,还有资源型和对象没学

resource mysql_connect( [ string $server [,string $username [,string $password [,bool $new_link]]]] ); 

第四个参数$new_link是否重新链接

$con = mysql_connect('localhost', 'root', '');

if($con){
	print_r($con); // Resource id #3
}else{
	echo '没有链接上';
}

返回值是Resource id #3,Resource就是资源的意思


第一次链接$con,第二次$other又再一次链接上了服务器,两次返回的都是"Resource id #3",说明$con和$other两个链接都是一个资源,

因为链接是很耗费服务器资源的,出于减少链接的目的,对于同样的参数的mysql_connect()函数调用返回的是一个资源。

$other = mysql_connect('localhost', 'root', '');
if($other){
	print_r($other); // Resource id #3
}else{
	echo '没有链接上';
}

$other = mysql_connect('localhost', 'root', '');
if($other){
	print_r($other); // Resource id #3
}else{
	echo '没有链接上';
}

如果非要链接2次,得到不同的资源,要用第四个参数$new_link是否重新链接为true

强制重新链接,打印链接返回一个新资源Resource id #5

$con = mysql_connect('localhost', 'root', '', true);
if($con){
	print_r($con); // Resource id #3
}else{
	echo '没有链接上';
}


$other = mysql_connect('localhost', 'root', '', true);
if($other){
	print_r($other); // Resource id #5
}else{
	echo '没有链接上';
}

mysql默认占用的是3306

mysql对外链接,和apache一样需要占一个端口,端口就是商场的柜台号,你想为客户服务,就得租个柜台

mysql默认占用的是3306,mysql_connect没有指定端口,PHP会默认用3306来链接。

$con = mysql_connect('localhost:3306', 'root', '', true);

if($con){
	print_r($con); // Resource id #3
}else{
	echo '没有链接上';
}

如果端口是3307 mysql_connect( 'localhost:3307', 'root', '', true ) 可以这样来指定端口


在PHP中还可以用mysqli和PDO来链接mysql服务器

mysql_connect系列函数,是面向过程的写法

mysqli是把链接mysql的功能封装成类,是面相对象的写法

PDO是一个统一的数据库接口,屏蔽了数据库之间的不一致,无论什么数据库用PDO的写法都一致,PDO也是面相对象的用法。

二、资源的概念及发送sql查询

创建数据库db_orange,数据表regist,为下面学习做准备

create database db_orange charset utf8;

create table regist(
	id int(8) unsigned primary key auto_increment,
	name varchar(100) not null default '',
	age varchar(10) not null default ''
)engine=myisam default charset=utf8;

1、Resource资源型

链接上mysql服务器后,遇到一个新的概念叫Resource是资源型

资源型的变量是什么?

资源型非常容易理解,资源就是一个管道。

以PHP链接Mysql为例,PHP客户端和mysql服务器之间建立起了链接,这个链接就是资源型,资源型就是通道,PHP操作Mysql沿着通道走。

一旦链接mysql之后,既通道形成,我们就可以沿着通道发送sql语句了。

2、发送添加语句

连上mysql之后,只要是合法的sql语句都可以通过通道发送给mysql服务器,具体用 mysql_query() 函数发送sql语句

1. mysql_query( 'use db_orange', '资源' )  选则数据库,返回一个布尔值

2. mysql_query( 'set names utf8', '资源 ')  设置字符集

3. mysql_query( $sql, '资源' ) 增加一条数据,返回一个布尔值

$con = mysql_connect('localhost:3306', 'root', '');

if(!$con){
	echo '链接失败';
	exit;
}

$rs = mysql_query('use db_orange', $con);

// var_dump($rs); // bool(true)

mysql_query('set names utf8', $con);

$sql = "insert into regist (id, name)values('', '".rand(1, 100).time()."')";

if(mysql_query($sql, $con)){
	echo '添加数据成功'.mysql_insert_id();
}else{
	echo '添加失败';
}

3、删除数据

从地址栏上接收一个id  index.php?id=1 

$con = mysql_connect('localhost:3306', 'root', '');

if(!$con){
	echo '链接失败';
	exit;
}

$rs = mysql_query('use db_orange', $con);

mysql_query('set names utf8', $con);

$id = isset($_GET['id']) ? $_GET['id']: '';

$sql = "delete from regist where id = $id";

if($id){
	
	$rs = mysql_query($sql, $con); // 发送sql语句,沿着con通道进行

	echo '删除成功';
	
}else{
	echo '没有传id';
}

4、一个非常简单sql注入

1. php?id=16 or 1

2. sql语句是 delete from regist where id = 9 or 1 

    9 or 1 1恒为真,所有行都满足条件,都被删除了

3. sql语句变成 delete from regist where id = true 

    因此所有的行都满足条件,都被删除了

4.  delete from regist where id = 33 or 0  就不会出现全部删除的情况

$con = mysql_connect('localhost:3306', 'root', '');

if(!$con){
	echo '链接失败';
	exit;
}

$rs = mysql_query('use db_orange', $con);

mysql_query('set names utf8', $con);

$id = isset($_GET['id'])?$_GET['id']:'';

$sql = "delete from regist where id = $id";

if(isset($_GET['id'])){
	$rs = mysql_query($sql, $con);
	echo $sql;
}

5、处理sql注入

合法的id应该是整形,不应该是字符串,因此处理也比较简单

字符串直接加0变成整形了,字符串加0变成整形了,就不会再有注入的功能了

$id = isset($_GET['id']) ? $_GET['id']+0 : '';

$con = mysql_connect('localhost:3306', 'root', '');

if(!$con){
	echo '链接失败';
	exit;
}

$rs = mysql_query('use db_orange', $con);

mysql_query('set names utf8', $con);

$id = isset($_GET['id']) ? $_GET['id']+0 : '';

$sql = "delete from regist where id = $id";

if($id){
	
	$rs = mysql_query($sql, $con);
	
	echo '删除成功';
	
}else{
	echo '没有传id';
}

用intval()函数也可以处理这个注入问题

$con = mysql_connect('localhost:3306', 'root', '');
if(!$con){
	echo '链接失败';
	exit;
}
$rs = mysql_query('use db_orange', $con);
mysql_query('set names utf8', $con);


$id = isset($_GET['id']) ? intval($_GET['id']) : ''; // intval函数处理$_GET['id']

echo $sql = "delete from regist where id = $id";

if($id){
	$rs = mysql_query($sql, $con);
	echo '删除成功';
}else{
	echo '没有传id';
}

三、修改表数据

update语句

$con = mysql_connect('localhost:3306', 'root', '');

if(!$con){
	echo '链接失败';
	exit;
}

mysql_query('set names utf8', $con); 

// 选择数据库db_orange,$con是资源(通道),沿着通道把sql语句发送给mysql服务器
// 返回bool值,这里还可以进行判断
$rs = mysql_query('use db_orange', $con);

if(!$rs){
	echo '请检查选择的数据库';
	exit;
}

$sql = "update regist set name = '新名子' where id = 41";

if(mysql_query($sql, $con)){
	echo '修改成功:',$sql;
}else{
	echo '修改失败:',$sql;
}

表单提交修改数据,为后面学习表单添加注入语句做准备

<?php
$con = mysql_connect('localhost:3306', 'root', '');
$rs = mysql_query('use db_orange', $con);
mysql_query('set names utf8', $con);

if($_POST){

    $sql = "update regist set 
    name = '".$_POST['user']."', 
    age = '".$_POST['age']."' 
    where id = '".$_POST['uid']."'
    ";
    
    if(mysql_query($sql, $con)){
        echo '修改成功:',$sql;
    }else{
        echo '修改失败:',$sql;
    }
}

?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>表单提交修改</title>
</head>
<body>
    <form method="post" action="">
        ID:<input type="text" name="uid" value="" /><br/>
        姓名:<input type="text" name="user" value="" /><br/>
        年龄:<input type="text" name="age" value="" /><br/>
        <input type="submit" value="提交" />
    </form>
</body>
</html>

sql注入问题

1. 表单输入 努力同学', age='10000' where id = 5# 5是要修改的id

2. 打印出真正的sql语句,后面有一个#井号 update regist set name = '努力同学', age='90000' where id = 5#', age = '100' where id = '5' 

3. 在sql里#号是注释,意思是#号后面的 ', age = '100' where id = '5' 就不发挥作用了

<?php
$con = mysql_connect('localhost:3306', 'root', '');
$rs = mysql_query('use db_orange', $con);
mysql_query('set names utf8', $con);

if($_POST){

    $sql = "update regist set name = '".$_POST['user']."', age = '".$_POST['age']."' where id = '".$_POST['uid']."'";
    
    if(mysql_query($sql, $con)){
        echo '修改成功:',$sql;
    }else{
        echo '修改失败:',$sql;
    }

}

?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>sql注入问题</title>
</head>
<body>
    <form method="post" action="">
        ID:<input type="text" name="uid" value="5" /><br/>
        姓名:<input type="text" name="user" value="努力同学', age='90000' where id = 5#" /><br/>
        年龄:<input type="text" name="age" value="100" /><br/>
        <input type="submit" value="提交" />
    </form>
</body>
</html>

更严重的sql注入问题

Discuz论坛数据表中有一个groupid列,groupid=1 是超级管理员

1. 给regist表添加一个groupid列  Alter table regist add groupid tinyint unsigned not null default '0'; 

2. 模拟一下通过注入成为超级管理员,表单输入  ', age='3', groupid=1 where id = 4# 

<?php
$con = mysql_connect('localhost:3306', 'root', '');
$rs = mysql_query('use db_orange', $con);
mysql_query('set names utf8', $con);

if($_POST){

    $sql = "update regist set name = '".$_POST['user']."', age = '".$_POST['age']."' where id = '".$_POST['uid']."'";
    
    if(mysql_query($sql, $con)){
        echo '修改成功:',$sql;
    }else{
        echo '修改失败:',$sql;
    }
}

?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>更严重的sql注入问题</title>
</head>
<body>
    <form method="post" action="">
        ID:<input type="text" name="uid" value="5" /><br/>
        姓名:<input type="text" name="user" value="超级管理员', age='3', groupid=1 where id = 40#" /><br/>
        年龄:<input type="text" name="age" value="100" /><br/>
        <input type="submit" value="提交" />
    </form>
</body>
</html>

提交后,一下子就变成超级管理员了:

修改成功:update regist set name = '超级管理员', age='3', groupid=1 where id = 4#', age = '100' where id = '5'

之所以出现问题是因为,这个单引号被看成sql语句中的一部分了 超级管理员', age='3', groupid=1 where id = 4#  

解决这个注入问题

提交表单的时候,难免有真的单引号,把单引号转义成字符串的单引号

addslashes() 函数转义一下表单提交的数据  $_POST['name'] = addslashes($_POST['name']); 

注入是因为利用传值故意传一些sql语句的关键字,如果单引号、井号等

转义,是把单引号转成\',这样单引号就和普通的字符一样了,没有语法含义了。

<?php
$con = mysql_connect('localhost:3306', 'root', '');
$rs = mysql_query('use db_orange', $con);
mysql_query('set names utf8', $con);

if($_POST){

    $_POST['user'] = addslashes($_POST['user']);
    $_POST['age'] = addslashes($_POST['age']);
    $_POST['groupid'] = addslashes($_POST['groupid']);
    $id = $_POST['uid'] + 0;
    
    $sql = "update regist set name = '".$_POST['user']."', age = '".$_POST['age']."', groupid = '".$_POST['groupid']."' where id = '".$_POST['uid']."'";
    
    if(mysql_query($sql, $con)){
        echo '修改成功:',$sql;
    }else{
        echo '修改失败:',$sql;
    }

}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>转义</title>
</head>
<body>

    <form method="post" action="">
        ID:<input type="text" name="uid" value="5" /><br/>
        姓名:<input type="text" name="user" value="超级管理员', age='3', groupid=1 where id = 4#" /><br/>
        年龄:<input type="text" name="age" value="100" /><br/>
        管理权限:<input type="text" name="groupid" value="9" /><br/>
        <input type="submit" value="提交" />
    </form>

</body>
</html>

测试一下,这个注入的问题,用PDO链接数据库的方式也是存在的,最终还要通过转义解决

<?php
$con = new PDO("mysql:host=localhost;dbname=db_orange", "root", "");

$con->exec('set names utf8');

if($_POST){

    $sql = "update regist set name = '".$_POST['user']."', age = '".$_POST['age']."' where id = '".$_POST['uid']."'";
    //$sql = "update regist set name = '".addslashes($_POST['user'])."', age = '".$_POST['age']."' where id = '".$_POST['uid']."'";
    
    if($con->exec($sql)){
        echo '修改成功:',$sql;
    }else{
        echo '修改失败:',$sql;
    }

}

?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>PDO方式下测试注入问题</title>
</head>
<body>
    <form method="post" action="">
        ID:<input type="text" name="uid" value="5" /><br/>
        姓名:<input type="text" name="user" value="同学', age='999', groupid=1 where id = 3#" /><br/>
        年龄:<input type="text" name="age" value="100" /><br/>
        <input type="submit" value="提交" />
    </form>
</body>
</html>

四、查询表数据

对于增删改insert, delete, update语句用法一样,只要把sql语句写好,然后mysql_query( $sql )执行就可以了,返回值只有true/false两种情况

而对应select语句,执行失败了返回false,如果执行成功返回资源型。


故意写错select语句中的数据表名称,返回布尔值false

$conn = mysql_connect('localhost:3306', 'root', '');
if(!$conn){
	echo '链接失败';
	exit;
}
mysql_query('set names utf8', $conn);
mysql_query('use db_orange', $conn);


$sql = 'select * from stusss'; // 故意写错数据表名

$result = mysql_query($sql, $conn);

var_dump($result); // bool(false),返回false

链接成功返回resource资源型

$conn = mysql_connect('localhost:3306', 'root', '');
if(!$conn){
	echo '链接失败';
	exit;
}
mysql_query('set names utf8', $conn);
mysql_query('use db_orange', $conn);


$sql = 'select * from regist';

$result = mysql_query($sql, $conn);

var_dump($result); // resource(4) of type (mysql result),返回资源型

此时的$result是通道,是豆浆的吸管


沿着通道把资源取出来,有三个专门的工具函数(常用的前两个)

mysql_fetch_assoc()

mysql_fetch_row()

mysql_fetch_array()

其实还有一个

mysql_fetch_object()


mysql_fetch_assoc()函数

每执行一次取一条数据,游标向下移动,直到数据取完返回false

$conn = mysql_connect('localhost:3306', 'root', '');
if(!$conn){
	echo '链接失败';
	exit;
}
mysql_query('set names utf8', $conn);
mysql_query('use db_orange', $conn);


$sql = 'select * from regist';

$result = mysql_query($sql, $conn);

// 参数传 资源
print_r(mysql_fetch_assoc($result)); // Array ( [id] => 1 [name] => 同学', age='999', grou [age] => 100 [groupid] => 0 )

print_r(mysql_fetch_assoc($result)); // Array ( [id] => 2 [name] => 员', age='3', groupid [age] => 10000 [groupid] => 10 )

用while循环一次性把数据取出来

$conn = mysql_connect('localhost:3306', 'root', '');
if(!$conn){
	echo '链接失败';
	exit;
}
mysql_query('set names utf8', $conn);
mysql_query('use db_orange', $conn);


$sql = 'select * from regist';

$result = mysql_query($sql, $conn);

while($row = mysql_fetch_assoc($result)){
	print_r($row);
}


这四条语句之间的区别

mysql_fetch_assoc()  取出来的是关联数组,数组key是表的字段名

mysql_fetch_row()     取出来的是索引数组,索引从0开始依次增加

mysql_fetch_array()   取出的结果又有关联索引,又有索引索引,是前两着的并集

mysql_fetch_object() 返回的是对象,这样取值 $obj->id 

$conn = mysql_connect('localhost:3306', 'root', '');
if(!$conn){
	echo '链接失败';
	exit;
}
mysql_query('set names utf8', $conn);
mysql_query('use db_orange', $conn);


$sql = 'select * from regist';

$result = mysql_query($sql, $conn);

print_r(mysql_fetch_assoc($result));

print_r(mysql_fetch_row($result));

print_r(mysql_fetch_array($result));

print_r(mysql_fetch_object($result));

五、PHP操作mysql常用函数

严重注意:

对应insert、detele、update、select的操作,返回值是true/false两种情况,

其中insert操作返回true,代表数据肯定是插入成功了


对于update和detele操作返回true,代表这个sql语句的语法没问题执行成功了

是从语法角度,执行成功了

但是语句未必能影响到数据,比如 where id = 999 条件不对

要想真正判断有没有删/改数据,要看实际影响行数为准。

如何获取受影响行数?

在执行delete或update语句后立即调用 mysql_affected_rows() 函数,可以得到delete/update语句影响的行数。

$conn = mysql_connect('localhost:3306', 'root', '');
if(!$conn){
	echo '链接失败';
	exit;
}
mysql_query('set names utf8', $conn);
mysql_query('use db_orange', $conn);


$id = isset($_GET['id']) ? $_GET['id'] : 0;

$sql = 'delete from regist where id ='. $id;

mysql_query($sql, $conn);

$cnt = mysql_affected_rows($conn);

if($cnt){
	echo '删除了'.$cnt.'行数据'; // 删除一条成功后返回,删除了1行数据
}else{
	echo '没有数据被删掉';
}

获取还剩下多少条数据

循环计算删除成功后还剩下多少行数据

$conn = mysql_connect('localhost:3306', 'root', '');
if(!$conn){
	echo '链接失败';
	exit;
}
mysql_query('set names utf8', $conn);
mysql_query('use db_orange', $conn);


// 删除数据
// $id = isset($_GET['id'])? $_GET['id']:0;
// $sql = 'delete from regist where id ='. $id;
// mysql_query($sql, $conn);
// $cnt = mysql_affected_rows($conn);
// if($cnt){
// 	echo "删除了 $cnt 行数据<br>";
// }else{
// 	echo "没有数据被删掉<br/>";
// }


// 还剩下多少条数据
$sql = 'select id from regist';

$result = mysql_query($sql, $conn);

$num = 0;

while(mysql_fetch_assoc($result)){
	$num++;	
}

echo "还剩下 $num 条数据";


int mysql_num_rows( resource $result )  作用返回select语句的结果的行数

返回int类型,参数是select语句执行返回结果集的资源(不是链接数据库的资源)

在运行select后立即调用 mysql_num_rows() 可以得到这次select的行数

// 链接数据库
$conn = mysql_connect('localhost:3306', 'root', '');
mysql_query('set names utf8', $conn);
mysql_query('use db_orange', $conn);

// 还剩下多少条数据
$result = mysql_query('select id from regist', $conn);
$num = mysql_num_rows($result);
echo "还剩下 $num 条数据";

mysql的调错

当mysql_query执行失败时,

可以用mysql_errno()打印出错误号,和mysql_error()函数打印出错误信息

$conn = mysql_connect('localhost:3306', 'root', '');
mysql_query('use xdb_orange', $conn);
$result = mysql_query('select id from regist', $conn);

if($result){
	echo '查询成功';
}else{
	echo '查询失败<br/>';
	echo mysql_error(),'<br/>'; // No database selected
	echo mysql_errno(); // 1046
}

账户密码不对

$conn = mysql_connect('localhost:3306', 'root', 'x');  // Warning: mysql_connect(): Access denied for user 'root'@'localhost' (using password: YES) in……

释放资源

mysql服务器链接资源是有限的,因此处理完业务逻辑后,要把链接资源释放

mysql_close()  释放资源

mysql链接是有限的,默认安装一般同时只能链15个,完成数据增删改查后,要及时的关闭数据库的链接资源。

对于PHP在运行结束后,一切资源会自动释放,对于小网站不会有太大问题,对应大网站来说就比较明显了。

$conn = mysql_connect('localhost:3306', 'root', '');
mysql_query('use db_orange', $conn);
$result = mysql_query('select id from regist', $conn);
if($result){
	echo '链接成功';
}

// mysql_close($conn); // 数据要及时关闭

// 故意让while循环5秒
$i = 0;
while($i<5){
	echo $i++;
	sleep(1);
}

if(mysql_close($conn)){
	echo '关闭成功';
}

六、查询与修改综合运用

<?php
// 链接数据库
$conn = mysql_connect('localhost:3306', 'root', '');
if(!$conn){
echo '链接失败';
exit;
}
mysql_query('set names utf8', $conn);
mysql_query('use db_orange', $conn);


// 查询数据库
$id = isset($_GET['id'])?$_GET['id']:0;
$sql = 'select * from regist where id ='.$id;
$result = mysql_query($sql, $conn); // 返回资源类型
if(!$result){
echo '查询失败'; // 资源
exit;
}

$row = mysql_fetch_assoc($result);
if(empty($row)){
var_dump($row);
echo '没有这个用户'; // 数据是空的
exit;
}


// 修改数据
if($_POST){
$sql = "update regist set 
name = '".$_POST['user']."',
age = '".$_POST['age']."',
groupid = '".$_POST['groupid']."' 
where id = '".$_POST['id']."'";

if(mysql_query($sql)){
echo '修改成功';
header("Location: 004.php");
}
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>

<form action="edit.php?id=<?php echo $row['id']?>" method="post">
<input type="hidden" name='id' value="<?php echo $row['id']?>">
user:<input type="text" name='user' value="<?php echo $row['name']?>"><br/>
age:<input type="text" name='age' value="<?php echo $row['age']?>"><br/>
groupid:<input type="text" name='groupid' value="<?php echo $row['groupid']?>"><br/>
<input type="submit" value="提交">
</form>

</body>
</html>



Leave a comment 0 Comments.

Leave a Reply

换一张