day 3

复习

进程

系统为程序运行准备的资源

线程

在进程中运行逻辑的单位

pid linux用来管理进程的标识

ppid 父进程的id

init进程 系统第一个运行的进程,它没有父进程

父进程 在A进程运行时创建了B进程,那么A进程是B进程的父进程,B进程是A进程的子进程

子进程

僵尸进程 进程执行完毕资源没有释放。

孤儿进程 父进程结束时要结束子进程,如果父进程结束子进程没结束,这个子进程叫孤儿进程。此时init进程回来 接管孤儿进程。

ps aux 查看进程详细信息

kill pid 杀死pid对应的进程 kill -9 pid 必杀

find 遍历搜索路径,慢。

which 搜索命令可执行文件所在位置。

locate 在数据库中查找文件位置,不是实时的,sudo updatedb 手动更新数据库

压缩: tar cvfz dir.tar.gz dir

解压缩: tar xvfz dir.tar.gz -C 路径

c 创建压缩文件

x 解压缩

v 显示过程

f 多个文件

z zip格式

cat test.c|grep for 管道符 将左边命令的结果作为右边命令的输入

ls / > file.txt 重定向 改变输出方向 >会覆盖文件原有内容 >>在原文件中追加

ifconfig 查看网络信息

sudo ifconfig eth0 192.168.40.199 给网卡eth0设置ip地址

ping 192.168.40.101 测试网络通不通

gcc 编译

1 预处理 执行include,define

2 编译 将C语言翻译成汇编

3 汇编 将汇编语言翻译成机器码

4 链接 将调用的库函数的函数体编译到自己的可执行文件中

gcc -o test test.c

编译test.c文件,生成可执行文件名叫test

作业:选择题

1.请阅读以下程序:

main()

{

​ int a=5,b=0,c=0;

​ if(a=b+c) printf("***\n");

​ else printf("$$$\n");

}

以上程序: ( D )

A)有语法错不能通过编译 C) 可以通过编译但不能通过连接

B)输出*** D) 输出$$$

2.一个C语言程序是由 ( B ) 。

A)一个主程序和若干子程序组成 B)函数组成

C)若干过程组成 D)若干子程序组成

3.若x,i,j和k都是int型变量,则执行下面表达式后x的值为( C )。

x=(i=4,j=16,k=32)

A)4 B)16 C)32 D)52

4.0xff的二进制码是( 11111111 ), 十进制是( 255 )。

  1. 一个C程序的入口地址是( main )。

  2. int a = 5 / 3, 执行后a的值为( 1 ), int b = 5 % 3, 执行后b的值为( 2 )

  3. 下面程序错误的地方有

#include <stdio.h>

int mian() //1 main

{

​ a = 10; //2 a 没声明

​ printf(“a is %d\n”, a);

}

  1. sizeof(char) = ( 1 ), sizeof(short) = ( 2 ), sizeof(long) = ( 4 )

    sizeof(float) = ( 4 ), sizeof(double) = ( 8 )

long和int 都是4 long long 8

9 unsigned char表示( 无符号字符型),unsigned char a, a的取值范围是( 0~255 )

  1. x = 6, y = 8;

z = ++x + y++;

运行后x的值是( 7 ), y的值是( 9 ),z的值是( 15 )

作业1:

选村长:

请输入三个要竞选村长名字

进行投票10次,相当于选票,统计出结果打印出村长是谁

#include <stdio.h>
#include <string.h>
//定义结构体表示一个人
struct Person
{
	char name[20];//名字属性
	int score;//票数属性
};

int main()
{
	struct Person ps[3] = {
		{"", 0},
		{"", 0},
		{"", 0}
	};//初始化结构体数组
    int i;
    for(i = 0;i < 3;i++)
    {
        scanf("%s", ps[i].name);//ps[i]是一个结构体类型变量ps[i].name得到结构体变量里的name成员,因为name成员本身就是数组,所以ps[i].name得到的是一个数组名
    }

	for(i = 0;i < 10;i++)//循环10次  进行10次投票
	{
		char buf[20];//保存输入的名字
		scanf("%s", buf);//以输入名字的形式进行投票
		int j;
		for(j = 0;j < 3;j++)//在三个候选者中找到本次投票的哪一位
		{
			if(strcmp(buf, ps[j].name)==0)//判断名字相等
			{
				ps[j].score++;//票数+1
			}
		}
	}
	//找最大值
	int vill = 0;//假设第一个是最大的
	for(i = 1;i < 3;i++)
	{
		if(ps[i].score > ps[vill].score)
		{
			vill = i;
		}
	}
	printf("vill is %s\n", ps[vill].name);
	//查看结果
	for(i = 0;i < 3;i++)
	{
		printf("%s %d\n", ps[i].name, ps[i].score);
	}
	return 0;
}

作业2:

实现一个随机点名程序,每次运行程序随机打印班级一位同学的名字。

#include <stdio.h>
#include <stdlib.h>

int main()
{
	//我们可以使用一个指针变量指向一个字符串常量
	//于是我们定义了一个字符指针数组保存N个字符指针
	//这些字符指针将会分别指向N个字符串常量
	char* names[] = {
		"meiyangyang",
		"lanyangyang",
		"huitailang",
		"xiaohuihui",
		"jiaotailang",
		"datouerzi"
	};

	srand(time(0));

	int index = rand()%6;
	printf("%s\n", names[index]);

	return 0;
}

1、认识shell脚本

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-54pYIhpU-1645664484780)(C:\Users\mudonghai\Desktop\linux&C高级\day3\image-20220119163308435.png)]

1. 什么是脚本

脚本:新华词典解释——表演戏剧、曲艺,摄制电影等所依据的本子,里面记载台词、故事情节等。

脚本文件,编写脚本代码-----------相当于剧本

解析器,阅读脚本中的代码,根据代码中的指令做事---------相当于演员

常见的脚本语言:

python

js ----- javascript

脚本语言的特点(解释型语言):

脚本语言不需要编译,脚本语言的解析器可以直接阅读脚本语言并按照指令执行。解析器本身就是一个程序,被CPU执行的程序。脚本语言的特点注定脚本语言的执行效率不可能比编译型语言高。

脚本语言简单易学。

编译型语言:

C语言

C++语言

java 是半编译半解释型语言,java虚拟机(jvm)运行java。java虚拟机不是直接运行java代码,java代码也需要编译,但是不是编译给cpu看,而是编译给java虚拟机看。

什么是 shell 脚本 ? linux命令的有序集合。用来批处理linux命令。

shell脚本是专门为了批处理linux指令而诞生的脚本语言,并不适合表达复杂逻辑。

shell脚本的解析器 bash

编程语言分类:

(1)解释性语言: 无需编译,执行即可。

shell

python

html5 (标签语言)

(2)编译型语言: 先编译,在没有错误之后,才能正确运行。

c

c++

2.初识 shell 脚本

1. 开头

#!/bin/bash # 告诉系统,当前脚本由哪个程序运行。

2. 示例:

vi test.sh

#! /bin/bash #告诉系统,使用bash解析器作为当前脚本的解析器

clear # 执行clear命令,清屏

ls # 执行ls 命令

date # 执行date命令 输出日期

touch file.txt #执行touch file.txt

ls # 执行ls命令

3. 脚本的执行

方式一; 添加权限: chmod +x test.sh ./test.sh

方式二: 脚本解释bash : bash test.sh

4. 注释:

#

5. 变量

(1) 为了方便识别变量,变量名通常用大写字符

(2) 不能以数字开头,开头必须是字母或者下划线

(3) 不能使用标点符号

脚本语言是弱类型,定义变量不需要指定类型,直接赋值就可以。

示例:

#! /bin/bash

NUMBER=2 #定义了一个变量,变量里的值是2 赋值运算符两边不能写空格

echo NUMBER #会输出NUMBER

#在任何情况下想使用变量里面的值,要在变量前面加$

echo KaTeX parse error: Expected 'EOF', got '#' at position 11: NUMBER #̲在变量前,是读取变量的值,所以这一行输出2

echo 输出一行内容

6. 位置参数 与 预设变量

1)位置参数: 0 1 2 3 4 …

位置参数的值,如何取值: 用$

示例代码:

echo $0

echo $1

echo $2

echo $3

#!/bin/bash

echo $0

echo $1

echo $2

linux@ubuntu:~/22011$ ./test.sh hehe haha heihei

./test.sh
hehe
haha

#!/bin/bash

echo $3

linux@ubuntu:~/22011$ ./test.sh hehe haha heihei
heihei

2)预设变量: # *

$# : 位置参数的个数。

$* : 位置参数都有谁,用空格隔开,把所有的位置参数都保存在这个预设变量里

shell脚本的定位,是在linux系统中做命令的批处理的脚本语言,并不适合表达严谨的逻辑。

练习:

请编写shell脚本: 创建目录文件,目录文件的名字由位置参数决定。

创建完目录之后,在目录中再创建一个普通文件,名字也由位置参数决定。

./test.sh hehe haha

mkdir hehe

touch hehe/haha

#!/bin/bash 

mkdir $1
touch $1/$2

7. 功能语句

输出: echo 输出一行

输入: read 输入 脚本运行后的输入

示例:

vi read.sh

#! /bin/bash

read -p "enter string1 and string2: " STRING1 STRING2

echo $STRING1 $STRING2

练习:

创建一个目录文件,然后,在此目录下创建一个普通文件。 文件名字由输入决定。

#!/bin/bash 
read -p "please input dir name" DIRNAME
mkdir $DIRNAME
read -p "please input file name" FILENAME
touch $DIRNAME/$FILENAME

8. “” 与 ''

示例:

#! /bin/bash

FILE=m.txt

echo “$FILE” #不完全输出 用变量的值代替变量

echo ‘$FILE’ #完全输出 完全按照写的样子输出

2、shell 的计算

1. `` :反引号

vi scan.sh

#! /bin/bash

OUTPUT=`ls /` # ls /本来应该是输出, 但是加上反引号后变成了表达式,本应输出的内容变成了表达式的结果赋值给了变量OUTPUT

echo $OUTPUT

在shell脚本里写的所有的命令的用法,和在终端敲命令是一样的。

2.expr 运算语句

expr关键是是“表达式“的缩写

vi calc.sh

#! /bin/bash

NUM1=1

NUM2=6

X=`expr $NUM1 + $NUM2` #反引号和里面的表达式之间不要写空格,+两边的空格必须有

echo " $X " #此处的双引号可以省略

3. 注意:

  1. 赋值符号的左右两侧一定 不要 有 空格!!!

  2. 运算符两侧一定 一定 要 放空格

  3. 乘法运算符号: ‘*’ \* 因为*在linux命令中是通配符,所以shell脚本中的乘法不能用*

练习:

分别简单检测各运算: (加、减、乘(*)、除、模除),自己写+ - ‘*’ / %法运算

3、shell 的 if

1. if 的格式:

if [ 条件 ] #条件为真 执行then []和条件之间必须有空格

then

​ 语句1

elif [ 条件 ]

then

​ 语句2

else

​ 语句3

fi

2. if判断的对象:

3类 字符串 数值 文件类型

1)字符串

示例1:

if [ “aBc” = “abc” ] #判定俩字符串是否相等

then

​ echo “equal”

fi

示例2:

read -p "enter string : " STRING

if [ -z $STRING ] # 判定是否为空串

then

​ echo “empty”

fi

练习:

请输入你的名字,判定是否是“xiaoming”同学。

#!/bin/bash 

read -p "input name: " NAME
if [ $NAME = "xiaoming" ]
then
	echo "yes"
else
	echo "no"
fi

2)数值

-eq 相等 equal

-ne 不等 not equal

-gt 大于 greater than

-ge 大于等于 greater equal

-lt 小于 less than

-le 小于等于 less equal

示例:

vi number.sh

read -p "enter number: " NUMBER

if [ $NUMBER -gt 0 ]

then

​ echo " greater than 0 "

elif [ $NUMBER -eq 0 ]

then

​ echo "equal to 0 "

else

​ echo "less than 0 "

fi

练习:

输入两个数A B,判定大小。

A>B 输出 “A>B”

AB 输出“AB”

A<B 输出“A<B”

#!/bin/bash 

read -p "input two nums: " NUM1 NUM2
if [ $NUM1 -gt $NUM2 ]
then
	echo "A > B"
elif [ $NUM1 -eq $NUM2 ]
then
	echo "A == B"
else
	echo "A < B"
fi

练习:

输入一个数值,判定此数值是否是偶数。

#!/bin/bash 

read -p "input a num: " NUM
if [ `expr $NUM % 2` -eq 0 ]
then
	echo "偶数"
else
	echo "奇数"
fi

3)文件类型

测试语句:

-f filename 判断文件是否为普通文件 file

-d filename 判断文件是否为目录文件 directory

-e filename 判断文件是否存在 exist

-L filename 判断文件是否为链接文件 link

-w filename 判断是否有写权限 write

-x filename 判断是否有执行权限 excute

示例:

#! /bin/bash

read -p "enter file name : " NAME

if [ -f $NAME ]

then

​ echo "file "

elif [ -d $NAME ]

then

​ echo “dir”

fi

练习:

请输入文件名称,判定此文件是否拥有执行权限。 -x

#!/bin/bash 

read -p "input a file name: " FILENAME

if [ -x $FILENAME ]
then
	echo "yes"
else
	echo "no"
fi

练习:

创建一个目录文件,进入目录后,再创建个普通文件。 目录文件和普通文件名都是输入的。

添加条件: 1. 判断该目录文件是否存在:如果存在,就不创建。如果不存在,创建。

判断普通文件是否存在。 -e

#!/bin/bash 

read -p "input a dir name: " DIRNAME
if [ -e $DIRNAME ]
then
	echo "文件夹已经存在"
else
	mkdir $DIRNAME
fi

cd $DIRNAME
read -p "input a file name: " FILENAME
if [ -e $FILENAME ]
then
	echo "文件已经存在"
else
	touch $FILENAME
fi

4、shell 中的 case

1.格式:

case $(变量) in # 读取变量的值

a)

​ 语句。

​ ;; # 相当于C语言的break

​ b)

​ 语句。

​ ;;

​ *) # 相当于C语言的default

​ ;;

esac # case结构结束

示例:

#! /bin/bash

read -p "enter : " WEEK

case $WEEK in

​ 1)

​ echo “Monday”

​ ;;

​ 5)

​ echo “Friday”

​ ;;

​ *)

​ echo “Other day”

​ ;;

esac

作业:

编写shell脚本,实现按键 asdw 控制输出上下左右

作业:

选择题

  1. 下面的代码执行后a的值为( )

int a = 10;

if(a = 1)

{

a++;

}

else

{

a--;

}

printf("%d", a);

2 下面的代码a的值是( )

int a = 10;

if(a < 10)

{

a++;

}

  1. ‘3’ 的Ascii码用16进制表示是( ) 10进制是( )。

4 . int main()

{

int a;

scanf("%d", &a);

switch(a) 

{

case 1:

	printf("Monday\n");

case 2:

	printf("Tuesday\n");

case 3:

	printf("Wednesday\n");

default:

	printf("Error\n");

}

}

如果用户输入了2, 那么输出是( )

  1. 如果int a = 3, 输出003,那么输出表达式为( )

6 .下面的语句有什么错误

int main()

{

int a;

scanf("%d", a);      

printf("%f", a);  

return 0;

}

  1. float money = 12.1, 如果输出的金额保留小数点两位,则输出表达是为( )

  2. int main()

{

int i = 0, sum = 0;

for(i = 0; i < 100; i++)

{

	if(i % 5 == 0)

		continue;  

	sum += i;

}

}

上面程序的作用是( )

  1. int main()

{

int number = 0;

while(1)        

{

	scanf("%d", &number);

	if(number == 0)  

	{

		break;    	

	}

}

}

上面程序的作用是( )

  1. for( ; ; )

上面语句的作用是( )

  1. 下面程序的运行结果为( )。

for(k = 0; k < 5; ++k)

{

if(k == 3)  

	continue;

printf("%d",k);

}

作业:

}

  1. ‘3’ 的Ascii码用16进制表示是( ) 10进制是( )。

4 . int main()

{

int a;

scanf("%d", &a);

switch(a) 

{

case 1:

	printf("Monday\n");

case 2:

	printf("Tuesday\n");

case 3:

	printf("Wednesday\n");

default:

	printf("Error\n");

}

}

如果用户输入了2, 那么输出是( )

  1. 如果int a = 3, 输出003,那么输出表达式为( )

6 .下面的语句有什么错误

int main()

{

int a;

scanf("%d", a);      

printf("%f", a);  

return 0;

}

  1. float money = 12.1, 如果输出的金额保留小数点两位,则输出表达是为( )

  2. int main()

{

int i = 0, sum = 0;

for(i = 0; i < 100; i++)

{

	if(i % 5 == 0)

		continue;  

	sum += i;

}

}

上面程序的作用是( )

  1. int main()

{

int number = 0;

while(1)        

{

	scanf("%d", &number);

	if(number == 0)  

	{

		break;    	

	}

}

}

上面程序的作用是( )

  1. for( ; ; )

上面语句的作用是( )

  1. 下面程序的运行结果为( )。

for(k = 0; k < 5; ++k)

{

if(k == 3)  

	continue;

printf("%d",k);

}

作业:

编写脚本,实现简单的计算功能。 示例: bash a.sh 3 + 4

<think>我们正在讨论的是不使用预处理语句(即不使用prepare和execute)来执行UPDATE查询。在PDO中,我们可以使用`exec()`方法或`query()`方法直接执行SQL语句。但是,请注意,直接执行SQL语句需要我们自己构建SQL字符串,这可能会引入SQL注入的风险。因此,如果使用这种方式,必须确保所有插入到SQL语句中的值都是安全的(例如,已经过适当的转义或验证)。 然而,用户提供的SQL语句中有参数(用?占位),这通常用于预处理语句。如果我们不使用预处理语句,就需要将这些参数值直接插入到SQL字符串中。因此,我们需要做以下几步: 1. 获取所有要更新的值(即原本绑定到?的值)。 2. 将这些值进行适当的转义(防止SQL注入)。 3. 构建完整的SQL字符串。 4. 使用`exec()`或`query()`执行。 但是,请注意,PDO提供了`quote()`方法用于转义字符串,但要注意它可能会在字符串周围添加单引号,所以对于非字符串类型(如整数)可能需要额外处理(或者确保在SQL语句中字符串值有引号,而数字则不需要)。 另外,由于用户提供的SQL语句中使用了?占位符,我们需要将这些占位符替换为实际的值,并确保字符串值被正确引用。 示例SQL语句: UPDATE ctb_eeee SET day1=?, day2=?, day3=?, day4=?, day5=?, day6=? WHERE project=? AND module=? AND eeee=? 假设我们有一个数组$data,包含day1到day6的值,以及$project, $module, $eeee三个值。 步骤: 1. 创建一个数组,包含所有要更新的字段值(day1到day6)和条件值(project, module, eeee),顺序与SQL中的?顺序一致。 2. 遍历这个数组,对每个值进行适当的转义和格式化(字符串需要加引号,数字可以不加,但为了安全,我们使用PDO::quote(),它会自动处理字符串,并返回带引号的字符串。对于数字,我们可以选择不转义,但为了统一,我们可以判断类型,或者全部用quote转义,但要注意quote转义后字符串有引号,所以SQL语句中原本的占位符在替换时,如果是字符串,替换后就是带引号的,而数字则会被转成字符串并带引号,这可能导致SQL错误(因为数字字段不应该有引号)。因此,我们需要知道每个参数的数据类型。 由于不确定每个字段的类型,这里有一个折中的办法:对于数字类型的字段,我们使用强制类型转换(如(int)),然后直接拼接到SQL中(因为数字是安全的,不需要引号)。对于字符串,使用PDO::quote()进行转义。 但是,我们不知道每个字段的类型,所以另一种方法是全部使用quote转义,然后替换。这样,数字字段也会被加上引号,但SQLite是弱类型,所以可能可以接受(但这不是好习惯)。 因此,最好的做法是知道每个字段的类型,然后分别处理。如果不知道,我们可以假设所有day字段都是数字,而条件字段(project, module, eeee)是字符串。但实际情况可能不同。 为了简化,我们假设所有值都是字符串,并使用PDO::quote()进行转义。这样生成的SQL语句中,每个值都被单引号括起来。在SQLite中,如果字段是数值类型,它会自动转换,但可能影响性能,也可能导致类型错误(如果字段是整数,但传入的字符串不能转换为整数,则可能出错)。 因此,我们根据用户的具体情况来处理。以下是一个示例代码: 假设: $day1, $day2, ... $day6 是数值(整数或浮点数),而$project, $module, $eeee是字符串。 那么我们可以这样构建: 注意:由于数值类型不需要引号,所以我们可以直接使用,但必须确保这些值是安全的(即不包含SQL代码)。如果这些数值来自用户输入,我们不能完全信任,但因为是数值,我们可以强制转换成数字类型(如intval, floatval)来确保安全。 步骤: 1. 将数值类型的字段转换为数字(整数或浮点数),这样它们就是安全的,可以直接拼接到SQL字符串中。 2. 对于字符串类型的字段,使用PDO::quote()进行转义。 例如: $day1 = (float)$Day1; // 或者根据实际情况用intval // 然后直接拼接,因为数字是安全的 但是,在SQL语句中,数字可以直接写,所以我们可以这样构建: 示例代码: ```php // 假设我们有以下变量 $day1 = 10; // 这些值可能是从用户输入获取的,但我们已经转换为数字 $day2 = 20; $day3 = 30; $day4 = 40; $day5 = 50; $day6 = 60; $project = "some project"; // 字符串 $module = "some module"; $eeee = "some eeee"; // 创建数据库连接 $db = new PDO(&#39;sqlite:yourdatabase.sqlite&#39;); // 构建SET部分,将数值字段直接转换为字符串(注意:确保是数字,安全) $setClause = "day1=" . $day1 . ", " . "day2=" . $day2 . ", " . "day3=" . $day3 . ", " . "day4=" . $day4 . ", " . "day5=" . $day5 . ", " . "day6=" . $day6; // 构建WHERE条件,字符串需要转义 $whereClause = "project=" . $db->quote($project) . " AND " . "module=" . $db->quote($module) . " AND " . "eeee=" . $db->quote($eeee); $sql = "UPDATE ctb_eeee SET " . $setClause . " WHERE " . $whereClause; // 使用exec执行 $affected = $db->exec($sql); if ($affected === false) { // 处理错误 $error = $db->errorInfo(); echo "Error: " . $error[2]; } else { echo "Updated $affected rows"; } ``` 但是,如果day1等字段也可能是字符串(比如包含非数字字符),那么我们就不能直接转换为数字。这时,我们需要知道它们的数据类型。如果都是字符串,那么我们可以全部使用quote转义。 假设所有字段都是字符串,那么: ```php $setClause = "day1=" . $db->quote($day1) . ", " . "day2=" . $db->quote($day2) . ", " . "day3=" . $db->quote($day3) . ", " . "day4=" . $db->quote($day4) . ", " . "day5=" . $db->quote($day5) . ", " . "day6=" . $db->quote($day6); ``` 然后条件部分同样用quote。 所以,关键在于知道字段的类型。如果混合类型,就要分别处理。 另外,注意如果字段值为NULL,那么quote会将其转成空字符串(不是SQL的NULL)。所以,如果允许NULL值,我们需要特殊处理: 例如: $value = $db->quote($value); 如果$value是null,quote会返回一个空字符串(即两个单引号),但我们需要的是NULL(不带引号)。所以,我们可以: ```php function pdoValue($db, $value) { if ($value === null) { return &#39;NULL&#39;; } return $db->quote($value); } ``` 然后使用这个函数来构建每个值。 总结:不使用预处理语句执行UPDATE查询,我们需要手动构建SQL字符串,并确保所有值都被正确转义和格式化,以避免SQL注入和语法错误。 但是,强烈建议使用预处理语句,因为它们更安全、更方便。只有在特殊情况下才使用直接执行。 现在,针对用户的具体SQL语句,我们可以这样写(假设所有值都是字符串,并且处理NULL的情况): ```php // 假设$data包含day1到day6的值,以及$project, $module, $eeee $values = [ &#39;day1&#39; => $Day1, &#39;day2&#39; => $Day2, &#39;day3&#39; => $Day3, &#39;day4&#39; => $Day4, &#39;day5&#39; => $Day5, &#39;day6&#39; => $Day6 ]; $conditions = [ &#39;project&#39; => $project, &#39;module&#39; => $module, &#39;eeee&#39; => $eeee ]; // 构建SET部分 $setParts = []; foreach ($values as $field => $value) { $setParts[] = "$field=" . ($value === null ? &#39;NULL&#39; : $db->quote($value)); } $setClause = implode(&#39;, &#39;, $setParts); // 构建WHERE条件 $whereParts = []; foreach ($conditions as $field => $value) { $whereParts[] = "$field=" . ($value === null ? &#39;NULL&#39; : $db->quote($value)); } $whereClause = implode(&#39; AND &#39;, $whereParts); $sql = "UPDATE ctb_eeee SET $setClause WHERE $whereClause"; $affected = $db->exec($sql); // 检查错误... ``` 注意:如果字段是数值类型,并且我们想避免加引号,那么我们需要在循环中判断字段类型(比如根据字段名),但这样需要额外的类型信息。如果无法获得类型信息,且字段可能是数值类型,那么我们可以尝试判断$value是否是数字字符串(使用is_numeric),如果是,则不加引号直接使用(但要确保安全,因为数字字符串是安全的)。但注意,如果数字字符串包含非数字字符(如千位分隔符),则不能直接使用。 因此,最安全的方式还是使用预处理语句。 由于问题要求不使用预处理语句,我们提供了上述方法,但请谨慎使用,并确保数据的安全性。 最后,如果使用SQLite,还可以使用事务来批量执行,但这里只是更新操作,所以不需要。 相关问题: 1. 在PDO中,如何防止SQL注入攻击? 2. 使用PDO的exec()方法和预处理语句在性能上有什么差异? 3. 在SQLite中,如何处理NULL值? 4. 如何安全地构建动态SQL查询?</think>### 在 PHP 中不使用预处理语句执行 UPDATE 查询 是的,可以在 PHP 中不使用预处理语句执行 UPDATE 查询,但需注意**安全风险**。以下是两种替代方法及其实现: --- ### 方法 1:使用 `PDO::exec()` 直接执行 SQL 字符串 ```php // 构建完整的 SQL 字符串(注意安全风险!) $sql = sprintf( "UPDATE ctb_eeee SET day1=&#39;%s&#39;, day2=&#39;%s&#39;, day3=&#39;%s&#39;, day4=&#39;%s&#39;, day5=&#39;%s&#39;, day6=&#39;%s&#39; WHERE project=&#39;%s&#39; AND module=&#39;%s&#39; AND eeee=&#39;%s&#39;", $day1, $day2, $day3, $day4, $day5, $day6, $project, $module, $eeee ); // 直接执行 SQL $affectedRows = $db->exec($sql); if ($affectedRows === false) { echo "更新失败: " . implode(", ", $db->errorInfo()); } else { echo "成功更新 $affectedRows 行"; } ``` **注意事项**: 1. **SQL 注入风险**:所有值必须手动转义 ```php // 使用 PDO::quote() 转义每个值 $safeDay1 = $db->quote($day1); $safeProject = $db->quote($project); // ...其他变量同理 ``` 2. **类型处理**:数字类型值不应加引号 ```php // 假设 day1 是整数 $day1Part = is_numeric($day1) ? $day1 : $db->quote($day1); ``` --- ### 方法 2:使用 `PDO::query()` 执行完整 SQL ```php // 构建安全 SQL(包含转义) $sql = "UPDATE ctb_eeee SET day1=" . $db->quote($day1) . ", day2=" . $db->quote($day2) . ", day3=" . $db->quote($day3) . ", day4=" . $db->quote($day4) . ", day5=" . $db->quote($day5) . ", day6=" . $db->quote($day6) . " WHERE project=" . $db->quote($project) . " AND module=" . $db->quote($module) . " AND eeee=" . $db->quote($eeee); // 执行查询 $stmt = $db->query($sql); if ($stmt) { echo "更新成功"; } else { echo "错误: " . implode(", ", $db->errorInfo()); } ``` --- ### ⚠️ 关键安全警告 1. **必须手动转义所有用户输入值** 使用 `$db->quote($value)` 对每个变量进行转义 ```php // 危险示例(SQL 注入漏洞) $sql = "UPDATE ... WHERE project=&#39;$_GET[project]&#39;"; // 安全做法 $sql = "UPDATE ... WHERE project=" . $db->quote($_GET[&#39;project&#39;]); ``` 2. **数字类型特殊处理** 数值类型不应加引号: ```php // 错误(导致 SQL 错误) $sql = "SET day1=&#39;" . $intValue . "&#39;"; // 正确 $sql = "SET day1=" . (int)$intValue; ``` 3. **NULL 值处理** 需特殊处理 NULL 值: ```php $value = ($day1 === null) ? &#39;NULL&#39; : $db->quote($day1); ``` --- ### 最佳实践建议 | **场景** | **推荐方法** | **原因** | |------------------------------|----------------------------|------------------------------| | 含动态参数 | 预处理语句 (`prepare`+`execute`) | 唯一可靠的防注入方式 | | 完全可信的静态数据 | `PDO::exec()` | 简洁高效 | | 需要结果集 | `PDO::query()` | 直接获取结果集 | | 批量操作 | 事务+预处理语句 | 保证原子性和性能[^1] | > **强烈建议**:除非是处理完全可信的内部数据,否则**始终使用预处理语句**。这是防止 SQL 注入的唯一可靠方法[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

encounter♌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值