首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
182 阅读
2
php接口优化 使用curl_multi_init批量请求
144 阅读
3
《从菜鸟到大师之路 ElasticSearch 篇》
107 阅读
4
2024年备考系统架构设计师
104 阅读
5
PHP 文件I/O
92 阅读
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
登录
Search
标签搜索
php函数
php语法
性能优化
安全
错误和异常处理
问题
vue
Composer
Session
缓存
框架
Swoole
api
并发
异步
正则表达式
php-fpm
mysql 索引
开发规范
协程
dafenqi
累计撰写
786
篇文章
累计收到
30
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
560
篇与
的结果
2023-08-07
php函数
随机函数gmp_random — 产生一个随机数lcg_value — 组合线性同余发生器(返回范围为 (0, 1) 的一个伪随机数)mt_rand — 生成更好的随机数(最大值2147483647)rand — 产生一个随机整数(最好用mt_rand代替)(win下默认最大值32767,最大值2147483647)str_shuffle — 随机打乱一个字符串array_rand — 从数组中随机取出一个或多个单元shuffle — 将数组打乱安全相关函数以下PHP内置函数能增加PHP代码的安全性:类型转换(非函数)(int), (integer) - 转换为整数(bool), (boolean) - 转换为布尔值(float), (double), (real) - 转换为浮点数(string) - 转换为字符串(array) - 转换为数组//防止sql注入mysql_real_escape_string — 转义 SQL 语句中使用的字符串中的特殊字符( NUL (ASCII 0), \n, \r, \, ', ", and Control-Z.),并考虑到连接的当前字符集。不转义 % and _.mysqli::real_escape_string —(mysqli_real_escape_string) 转义特殊字符( NUL (ASCII 0), \n, \r, \, ', ", and Control-Z.)到一个字符串中用于SQL语句,考虑到当前编码的连接.不转义 % and _.//防止上传漏洞exif_imagetype 判断一个图像的类型getimagesize 函数将测定任何图像文件的大小并返回图像的尺寸以及文件类型和一个可以用于普通 HTML 文件中 IMG 标记中的 height/width 文本字符串。finfo_file — 返回一个文件的信息(PHP 5 >= 5.3.0)escapeshellcmd — 过滤用作命令的字符串中的特殊字符(转义shell元字符)转义( #&;`|*?~<>^()[]{}$\, \x0A and \xFF. ' and ")stream_filter_append — 为数据流添加过滤器(附加一个过滤器到一个数据流)stream_filter_prepend — 为数据流预备添加过滤器(附加一个过滤器到一个数据流)stream_filter_register — 注册一个用户定义的数据流过滤器rawurldecode — 对已编码的 URL 字符串进行解码rawurlencode — 按照 RFC 3986 对 URL 进行编码返回字符串,此字符串中除了 -_. 之外的所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数。这是在 » RFC 3986 中描述的编码,是为了保护原义字符以免其被解释为特殊的 URL 定界符,同时保护 URL 格式以免其被传输媒体(像一些邮件系统)使用字符转换时弄乱urldecode — 解码已编码的 URL 字符串urlencode — 编码 URL 字符串 返回字符串,此字符串中除了 -_. 之外的所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号(+)。此编码与 WWW 表单 POST 数据的编码方式是一样的,同时与 application/x-www-form-urlencoded 的媒体类型编码方式一样。由于历史原因,此编码在将空格编码为加号(+)方面与 RFC1738 编码(参见 rawurlencode())不同。str_replace子字符串替换preg_filter — 执行一个正则表达式搜索和替换(PHP 5 >= 5.3.0)preg_grep — 返回匹配模式的数组条目(返回与模式匹配的数组单元)preg_match_all — 执行一个全局正则表达式匹配preg_match — 执行一个正则表达式匹配preg_quote — 转义正则表达式字符 正则表达式特殊字符有. \ + * ? [ ^ ] $ ( ) { } = ! < > | : -preg_replace_callback — 执行一个正则表达式搜索并且使用一个回调函数进行替换preg_replace — 执行一个正则表达式的搜索和替换htmlentities — 转换所有合适的字符为HTML实体htmlspecialchars — 转换特殊字符为HTML实体(转换',",<,>,&)quotemeta — 引用元字符(在. \ + * ? [ ^ ] ( $ )前添加反斜杠)addcslashes — 以 C 语言风格使用反斜线转义字符串中的指定字符(转义自定义字符)addslashes — 使用反斜线转义字符串(在',",\,NUL前添加反斜杠)strip_tags — 从字符串中去除 HTML 和 PHP 标记array_filter — 用回调函数过滤数组中的元素array_map — 将回调函数作用到给定数组的单元上array_walk_recursive — 对数组中的每个成员递归地应用用户函数array_walk — 对数组中的每个成员应用用户函数ctype_alnum — 检测是否符合字母数字格式ctype_alpha —检测是否都是字母ctype_cntrl — 是否都是控制字符ctype_digit — 是否都是数字ctype_graph — 检测是否都是可以显示的字符(不包含空格)ctype_print — 检测是否都是可以显示的字符(包含空格)ctype_punct — 检测是否是可以显示的字符,但是不包含字母数字和空格(注:是否都是键盘上的标点符号和特殊字符)//数据筛选 可验证:布尔值,email,整数,浮点数,IP,url,正则等。filter_has_var — 检查是否存在指定类型的变量filter_input_array — 从脚本外部获取多项输入,并进行过滤(得到多个外部变量并选择性地过滤它们)filter_input — 从脚本外部获取输入,并进行过滤(获得一个特定的外部变量的名称,并选择性地过滤它)filter_list — 返回一个所有支持的过滤器的列表filter_var_array — 得到多个变量并选择性地过滤它们filter_var — 用一个指定过滤器过滤一个变量gettype — 获取变量的类型*intval — 获取变量的整数值 var 可以是任何标量类型。 intval() 不能用于 array 或 object。floatval — 获取变量的浮点值 var 可以是任何标量类型。你不能将 floatval() 用于数组或对象。strval — 获取变量的字符串值 var 可以是任何标量类型。不能将 strval() 用于数组或对象。is_array — 检测变量是否是数组is_bool — 检测变量是否是布尔型is_float — 检测变量是否是浮点型is_int — 检测变量是否是整数is_null — 检测变量是否为 NULLis_numeric — 检测变量是否为数字或数字字符串is_scalar — 检测变量是否是一个标量is_string — 检测变量是否是字符串settype — 设置变量的类型
2023年08月07日
18 阅读
0 评论
0 点赞
2023-08-07
Session的本质
Session的本质有一点我们必须承认,大多数web应用程序都离不开session的使用。这篇文章将会结合php以及http协议来分析如何建立一个安全的会话管理机制。我们先简单的了解一些http的知识,从而理解该协议的无状态特性。然后,学习一些关于cookie的基本操作。最后,我会一步步阐述如何使用一些简单,高效的方法来提高你的php应用程序的安全性以及稳定行。我想大多数的php初级程序员一定会认为php默认的session机制的安全性似乎是有一定保障的,事实恰好相反 – php团队只是提供了一套便捷的session的解决方案提供给程序员使用,至于安全性的话,应该由程序员来加强,这是应用程序开发团队的责任。因为,这里面的方法很多,可以这么说吧,没有最好,只有更好。攻击的方式在不断变化,防守方也需要不断变招,所以,我个人认为php团队的做法还是比较明智的。无状态性Http是一种无状态性的协议。这是因为此种协议不要求浏览器在每次请求中标明它自己的身份,并且浏览器以及服务器之间并没有保持一个持久性的连接用于多个页面之间的访问。当一个用户访问一个站点的时候,用户的浏览器发送一个http请求到服务器,服务器返回给浏览器一个http响应。其实很简单的一个概念,客户端一个请求,服务器端一个回复,这就是整个基于http协议的通讯过程。因为web应用程序是基于http协议进行通讯的,而我们已经讲过了http是无状态的,这就增加了维护web应用程序状态的难度, 对于开发者来说,是一个不小的挑战。Cookies是作为http的一个扩展诞生的,其主要用途是弥补http的无状态特性,提供了一种保持客户端与服务器端之间状态的途径,但是由于出于安全性的考虑,有的用户在浏览器中是禁止掉cookie的。这种情况下,状态信息只能通过url中的参数来传递到服务器端,不过这种方式的安全性很差。事实上,按照通常的想法,应该有客户端来表明自己的身份,从而和服务器之间维持一种状态,但是出于安全性方面的考虑,我们都应该明白一点 – 来自客户端的信息都是不能完全信任的。尽管这样,针对维持web应用程序状态的问题,相对来说,还是有比较优雅的解决方案的。不过,应该说是没有完美的解决方案的,再好的解决方案也不可能适用所有的情况。这篇文章将介绍一些技术。这些技术可以用来比较稳定地维持应用程序的状态以及抵御一些针对session的攻击,比如会话劫持。并且你可以学习到cookie是怎样工作的,php 的session做了那些事情,以及怎样才能劫持session。HTTP 概览如何才能保持web应用程序的状态以及选择最合适的解决方案呢?在回答这个问题之前,必须得先了解web的底层协议 – Hypertext Transfer Protocol (HTTP)。当用户访问http://example.com这个域名的时候,浏览器就会自动和服务器建立tcp/ip连接,然后发送http请求到example.com的服务器的80端口。该个请求的语法如下所示:GET / HTTP/1.1Host: example.org以上第一行叫做请求行,第二个参数(一个反斜线在这个例子中)表示所请求资源的路径。反斜线代表了根目录;服务器会转换这个根目录为服务器文件系统中的一个具体目录。Apache的用户常用DocumentRoot这个命令来设置这个文档根路径。如果请求的url是http://example.org/path/to/script.php,那么请求的路径就是/path/to/script.php。假如document root 被定义为usr/lcoal/apache/htdocs的话,整个请求的资源路径就是/usr/local/apache/htdocs/path/to/script.php。第二行描述的是http头部的语法。在这个例子中的头部是Host, 它标识了浏览器希望获取资源的域名主机。还有很多其它的请求头部可以包含在http请求中,比如user-Agent头部,在php可以通过$_SERVER['HTTP_USER_AGENT']获取请求中所携带的这个头部信息。但是遗憾的是,在这个请求例子中,没有任何信息可以唯一标识当前这个发出请求的客户端。有些开发者借助请求中的ip头部来唯一标识发出此次请求的客户端,但是这种方式存在很多问题。因为,有些用户是通过代理来访问的,比如用户A通过代理B连接网站www.example.com, 服务器端获取的ip信息是代理B分配给A的ip地址,如果用户这时断开代理,然后再次连接代理的话,它的代理ip地址又再次改变,也就说一个用户对应了多个ip地址,这种情况下,服务器端根据ip地址来标识用户的话,会认为请求是来自不同的用户,事实上是同一个用户。 还用另外一种情况就是,比如很多用户是在同一个局域网里通过路由连接互联网,然后都访问www.example.com的话,由于这些用户共享同一个外网ip地址,这会导致服务器认为这些用户是同一个用户发出的请求,因为他们是来自同一个ip地址的访问。保持应用程序状态的第一步就是要知道如何来唯一地标识每个客户端。因为只有在http中请求中携带的信息才能用来标识客户端,所以在请求中必须包含某种可以用来标识客户端唯一身份的信息。Cookie设计出来就是用来解决这一问题的。Cookies如果你把Cookies看成为http协议的一个扩展的话,理解起来就容易的多了,其实本质上cookies就是http的一个扩展。有两个http头部是专门负责设置以及发送cookie的,它们分别是Set-Cookie以及Cookie。当服务器返回给客户端一个http响应信息时,其中如果包含Set-Cookie这个头部时,意思就是指示客户端建立一个cookie,并且在后续的http请求中自动发送这个cookie到服务器端,直到这个cookie过期。如果cookie的生存时间是整个会话期间的话,那么浏览器会将cookie保存在内存中,浏览器关闭时就会自动清除这个cookie。另外一种情况就是保存在客户端的硬盘中,浏览器关闭的话,该cookie也不会被清除,下次打开浏览器访问对应网站时,这个cookie就会自动再次发送到服务器端。一个cookie的设置以及发送过程分为以下四步:客户端发送一个http请求到服务器端服务器端发送一个http响应到客户端,其中包含Set-Cookie头部客户端发送一个http请求到服务器端,其中包含Cookie头部服务器端发送一个http响应到客户端这个通讯过程也可以用以下下示意图来描述:在客户端的第二次请求中包含的Cookie头部中,提供给了服务器端可以用来唯一标识客户端身份的信息。这时,服务器端也就可以判断客户端是否启用了cookies。尽管,用户可能在和应用程序交互的过程中突然禁用cookies的使用,但是,这个情况基本是不太可能发生的,所以可以不加以考虑,这在实践中也被证明是对的。GET and POST Data除了cookies,客户端还可以将发送给服务器的数据包含在请求的url中,比如请求的参数或者请求的路径中。 我们来看一个例子:GET /index.php?foo=bar HTTP/1.1Host: example.org以上就是一个常规的http get 请求,该get请求发送到example.org域名对应的web 服务器下的index.php脚本, 在index.php脚本中,可以通过$_GET['foo']来获取对应的url中foo参数的值,也就是’bar’。大多数php开发者都称这样的数据会GET数据,也有少数称它为查询数据或者url变量。但是大家需要注意一点,不是说GET数据就只能包含在HTTP GET类型的请求中,在HTTP POST类型的请求中同样可以包含GET数据,只要将相关GET数据包含在请求的url中即可,也就是说GET数据的传递不依赖与具体请求的类型。另外一种客户端传递数据到服务器端的方式是将数据包含在http请求的内容区域内。 这种方式需要请求的类型是POST的,看下面一个例子:POST /index.php HTTP/1.1Host: example.orgContent-Type: application/x-www-form-urlencodedContent-Length: 7foo=bar在这种情况下,在脚本index.php可以通过调用$_POST['foo']来获取对应的值bar。开发者称这个数据为POST数据,也就是大家熟知的form以post方式提交请求的方式。在一个请求中,可以同时包含这两种形式的数据:POST /index.php?myget=foo HTTP/1.1Host: example.orgContent-Type: application/x-www-form-urlencodedContent-Length: 11mypost=bar这两种传递数据的方式,比起用cookies来传递数据更稳定,因为cookie可能被禁用,但是以GET以及POST方式传递数据时,不存在这种情况。我们可以将PHPSESSID包含在http请求的url中,就像下面的例子一样:GET /index.php?PHPSESSID=12345 HTTP/1.1Host: example.org以这种方式传递session id的话,可以跟用cookie头部传递session id一样,达到同样的效果, 但是,缺点就是需要开发者认为地将session id附加在url中或者作为隐藏字段加入到表单中。不像cookie一样,只要服务器端指示客户端创建cookie成功以后,客户端在后续的请求中,会自动第将对应的没有过期的cookie传递给服务器端。当然,php在开启session.use_trans_sid后,也可以自动地将session id 附加在url中以及表单的隐藏字段中,但是这个选项不建议开启,因为存在安全问题。这样的话,容易泄露session id, 比如有的用户会bookmark一个url或者分享一个url,那么session id也就暴露了,加入这个session id还没有过期,那是有一定的安全问题存在的,除非服务器端,除了session id外,还附加了其它方式进行验证用户的合法性!尽管以POST的方式来传递session id的话,相对GET的方式来说,会安全的多。但是,这种方式的缺点就是比较麻烦,因为这样的话,在你的应用程序中比较将所有的请求都转换成post的请求,这显然是不太合适的。Session的管理直到现在,我只讨论了如何维护应用程序的状态,只是简单地涉及到了如果保持请求之间的关系。接下来,我阐述下在实际中用到比较多的技术 – Session的管理。涉及到session的管理,就不是单单地维持各个请求之间的状态,还需要维持会话期间针对每个特定用户使用到的数据。我们常常把这种数据叫做session数据,因为这些数据是跟某个特定用户与服务器之间的会话相关联的。如果你使用php内置的session的管理机制,那么session数据一般是保存在/tmp这个服务器端的文件夹中,并且其中的session数据会被自动地保存到超级数组$_SESSION中。一个最简单的使用session的例子,就是将相关的session数据从一个页面传递(注意:实际传递的是session id)到另一个页面。下面用示例代码1, start.php, 对这个例子加以演示:<?php session_start(); $_SESSION['foo'] = 'bar'; ?> continue.php 假如用户点击start.php中的链接访问continue.php,那么在continue.php中就可以通过$_SESSION['foo']获取在start.php中的定义的值’bar’。看下面的示例代码2:示例代码2 – continue.php<?php session_start(); echo $_SESSION['foo']; / bar / ?> 是不是非常简单,但是我要指出的话,如果你真的这样来写代码的话,说明你对php底层的对于session的实现机制还不是非常了解透彻。在不了解php内部给你自动做了多少事情的情况下,你会发现如果程序出错的话,这样的代码将变的很难调试,事实上,这样的代码也完全没有安全性可言。Session的安全性问题一直以来很多开发者都认为php内置的session管理机制是具有一定的安全性,可以对一般的session攻击起到防御。事实上,这是一种误解,php团队只实现了一种方便有效的机制。具体的安全措施,应该有应用程序的开发团队来实施。 就像开篇谈到的,没有最好的解决方案,只有最合适你的方案。现在,我们来看下一个比较常规的针对session的攻击:用户访问http://www.example.org,并且登录。example.org的服务器设置指示客户端设置相关cookie – PHPSESSID=12345攻击者这时访问http://www.example.org/,并且在请求中携带了对应的cookie – PHPSESSID=12345这样情况下,因为example.orge的服务器通过PHPSESSID来辨认对应的用户的,所以服务器错把攻击者当成了合法的用户。整个过程的描述,请看下面的示例图:当然这种攻击的方式,前提条件是攻击者必须通过某种手段固定,劫持或者猜测出某个合法用户的PHPSESSID。虽然这看起来难度很高,但是也不是不可能的事情。安全性的加强有很多技术可以用来加强Session的安全性,主要思想就是要使验证的过程对于合法用户来说,越简单越好,然后对于攻击者来说,步骤要越复杂越好。当然,这似乎是比较难于平衡的,要根据你应用程序的具体设计来做决策。最简单的居于HTTP/1.1请求包括请求行以及一些Host的头部:GET / HTTP/1.1Host: example.org如果客户端通过PHPSESSID传递相关的session标识符,可以将PHPSESSID放在cookie头部中进行传递:GET / HTTP/1.1Host: example.orgCookie: PHPSESSID=12345同样地,客户端也可以将session标识符放在请求的url中进行传递。GET /?PHPSESSID=12345HTTP/1.1Host: example.org当然,session标识符也可以包含在POST数据中,但是这对用户体验有影响,所以这种方式很少采用。因为来自TCP/IP信息也不一定可以完全信任的,所以,对于web开发者来说,利用TCP/IP中的信息来加强安全性也是不太合适的。 不过,攻击者也必须提供一个合法用户的唯一的标识符,才能假扮成合法用户进入系统。因此,看起来唯一能够有效的保护系统的措施,就是尽量地隐藏session标识符或者使之难于猜测出来。最好就是两者都能实施。PHP会自动生成一个随机的session ID,基本来说是不可能被猜测出来的,所以这方面的安全还是有一定保障的。但是,要防止攻击者获取一个合法的session ID是相当困难的,这基本上不是开发者所能控制的。事实上,许多情况下都有可能导致session ID的泄露。 比如说,如果通过GET数据来传递session ID的话,就有可能暴露这个敏感的身份信息。因为,有的用户可能会将带有session ID的链接缓存,收藏或者发送在邮件内容中。Cookies是一种像相对来说安全一点的机制,但是用户是可以在客户端中禁止掉cookies的!在一些IE的版本中也有比较严重的安全漏洞,比较有名的就是会泄露cookies给一些有安全隐患的邪恶站点。因此,作为一个开发者,可以肯定session ID是不能被猜测出来的,但是还是有可能被攻击者使用某些方法获取到。所以,必须采取一些额外的安全措施来防止此类情况在你的应用程序中发生。实际上,一个标准的HTTP请求中除了Host等必须包含的头部,还包含了一些可选的头部.举一个例子,看下面的一个请求:GET / HTTP/1.1Host: example.orgCookie: PHPSESSID=12345User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1Accept: text/html;q=0.9, /;q=0.1Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66Accept-Language: en我们可以看到,在以上的一个请求例子中包含了四个额外的头部,分别是User-Agent, Accept, Accept-Charset以及Accept-Language。因为这些头部不是必须的,所以完全依赖他们在你的应用程序中发挥作用是不太明智的。但是,如果一个用户的浏览器确实发送了这些头部到服务器,那么可以肯定的是在接下来的同一个用户通过同一个浏览器发送的请求中,必然也会携带这些头部。当然,这其中也会有极少数的特殊情况发生。假如以上例子是由一个当前的跟服务器建立了会话的用户发出的请求,考虑下面的一个请求:GET / HTTP/1.1Host: example.orgCookie: PHPSESSID=12345User-Agent: Mozilla/5.0因为有相同的session id包含在请求的Cookie头部中,所以相同的php session将会被访问到。但是,请求里的User-Agent头部跟先前的请求中的信息是不同的,系统是否可以假定这两个请求是同一个用户发出的?像这种情况下,发现浏览器的头部改变了,但是不能肯定这是否是一次来自攻击者的请求的话,比较好的措施就是弹出一个要求输入密码的输入框让用户输入,这样的话,对用户体验的影响不会很大,又能很有效地防止攻击。当然,你可以在系统中加入核查User-Agent头部的代码,类似示例3中的代码:示例代码3<?php session_start(); if (md5($_SERVER['HTTP_USER_AGENT']) != $_SESSION['HTTP_USER_AGENT']) { / 弹出密码输入框 / exit; } ?> 当然,你先必须在第一次请求时,初始化session的时候,用MD5算法加密user agent信息并且保存在session中,类似下面示例4中的代码:示例代码4<?php session_start(); $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']); ?> 虽然不一定需要用MD5来加密这个User-Agent信息,但使用这种方式以后就不需要再过滤这个$_SERVER['HTTP_USER_AGENT']数据了。不然的话,在使用这个数据以前必须要进行数据过滤,因为任何来自客户端的数据都是不可信任的,必须要注意这一点。在你检查这个User-Agent客户端头部信息以后,做为一个攻击者必须要完成两步才能劫持一个session:获取一个合法的session id包含一个相同的User-Agent头部在伪造的请求中你可能会说,居然攻击者能获得有效的session id,那么以他的水平,伪造一个相同的User-Agent不是件难事。不错,但是我们可以说这至少给他添加了一些麻烦,在一定程度上也增加了session机制的安全性。你应该也能想到了,既然我们可以检查User-Agent这个头部来加强安全性,那么不妨再利用其它的一些头部信息,把他们组合起来生成一个加密的token,并且让客户端在后续的请求中携带这个token!这样的话,攻击者基本上不可能猜测出这样一个token是怎么生成出来的。这好比你用信用卡在超市付款,一个你必须有信用卡(好比session id),另外你也必须输入一个支付密码(好比token),这有这两者都符合的情况下,你才能成功进入账号付款。 看下面一段代码:<?php session_start(); $token = 'SHIFLETT' . $_SERVER['HTTP_USER_AGENT']; $_SESSION['token'] = md5($token . session_id()); ?> 注意:Accept这个头部不应该被用来生成token,因为有些浏览器会自动改变这个头部,当用户刷新浏览器的时候。 在你的验证机制中加入了这个非常难于猜测出来的token以后,安全性会得到很大的提升。假如这个token通过像session id一样的方式来进行传递,这种情况下,一个攻击者必须完成必要的3步来劫持用户的session:获取一个合法的session ID在请求中加入相同的User-Agent头部,用与生成token在请求中携带被攻击者的token这里面有个问题。如果session id以及token都是通过GET数据来传递的话,那么对于能获取session ID的攻击者,同样就能够获取到这个token。所以,比较安全靠谱的方式应该是利用两种不同的数据传递方式来分别传递session id以及token。例如,通过cookie来传递session id,然后通过GET数据来传递token。因此,假如攻击者通过某种手段获得了这个唯一的用户身份标识,也是不太可能同时轻松地获取到这个token,它相对来说依然是安全的。还有很多的技术手段可以用来加强你的session机制的安全性。希望你在大致了解session的内部本质以后,可以设计出适合你的应用系统的验证机制,从而大大的提高系统的安全性。毕竟,你是最熟悉当下你开发的系统的开发者之一,可以根据实际情况来实施一些特有的,额外的安全措施。总结以上只是大概地描述了session的工作机制,以及简单地阐述了一些安全措施。但要记住,以上的方法都是能够加强安全性,不是说能够完全保护你的系统,希望读者自己再去调研相关内容。在这个调研过程中,相信你会学到很有实际使用价值的方案。
2023年08月07日
13 阅读
0 评论
0 点赞
2023-08-07
PHP性能优化技巧【译】
PHP性能优化技巧【译】今天在逛微博的时候看到了别人转的一篇谷歌的的文章《PHP performance tips》,看了觉得很有用,于是就翻译保存下来。概括出你的代码的瓶颈所在当你尝试让你的网站更快的时候,你需要记住Hoare的名言:不成熟的优化是万恶之源。在你修改你的代码之前,你需要明确是什么造成了网站运行的慢。更新你的PHP版本这些年,PHP开发团队为PHP引擎做了很多重大的性能的提升。如果你的服务器上还是运行的比较老的PHP版本(比如PHP3 或者 PHP4)的话,那在你优化你的代码之前你需要先升级你的PHP版本Migrating from PHP 4 to PHP 5.0.xMigrating from PHP 5.0.x to PHP 5.1.xMigrating from PHP 5.1.x to PHP 5.2.x使用缓存使用类似Memcache或者Smarty这样支持缓存的模板引擎的缓存模块,通过缓存数据库中数据或者已经渲染好的页面的方法可以提高网站的性能。使用输出缓冲PHP使用内存缓冲区来保存脚本要输出的所有的数据。由于缓存区必须被填满之后才会将数据发送给用户,所以你的页面看上去会比较慢Output Buffering Control尽量避免使用setter和getter当使用PHP的类的时候,直接使用类中的属性比使用setter和getter可以节省编码时间,也能让你的脚本的运行速度更快。在下面的例子中,dog类中使用setName()和getName()方法来访问name属性:class dog { public $name = ''; public function setName($name) { $this->name = $name; } public function getName() { return $this->name; } }注意,在这里setName和getName除了存储和返回name的值,其他什么也不做。$rover = new dog(); $rover->setName('rover'); echo $rover->getName();直接设置和调用name属性可以让运行效率提升一倍,也能减少我们的开发时间。$rover = new dog(); $rover->name = 'rover'; echo $rover->name;不要随便就复制变量有时候为了使 PHP 代码更加整洁,一些 PHP 新手(包括我)会把预定义好的变量复制到一个名字更简短的变量中,其实这样做的结果是增加了一倍的内存消耗,只会使程序更加慢。试想一下,在 下面的例子中,如果用户恶意插入 512KB 字节的文字到文本输入框中,这样就会导致 1MB 的内存被消耗!BAD:$description = $_POST['description']; echo $description;GOOD:echo $_POST['description'];对字符串使用单引号PHP 引擎允许使用单引号和双引号来封装字符串变量,但是这个是有很大的差别的!使用双引号的字符串告诉 PHP 引擎首先去读取字符串内容,查找其中的变量,并改为变量对应的值。一般来说字 符串是没有变量的,所以使用双引号会导致性能不佳。最好是使用字符串连接而不是双引号字符串。BAD:$output = "This is a plain string";GOOD:$output = 'This is a plain string';GOOD经过测试并不是原文上所说的那样,所以加以改正:$type = "mixed"; $output = "This is a $type string";BAD:$type = 'mixed'; $output = 'This is a ' . $type .' string';使用 echo 函数来输出字符串使用 echo() 函数来打印结果出了有更容易阅读之外,在下个例子中,你还可以看到有更好的性能。BAD:print($myVariable);GOOD:echo $myVariable;不要在 echo 中使用连接符很多 PHP 程序员(有包括我)不知道在用 echo 输出多个变量的时候,其实可以使用逗号来分开的,而不必用字符串先把他们先连起来,如下面的第一个例子中,由于使用了连接符就会有性能问题,因为这样就会需要 PHP 引擎首先把所有的变量连接起来,然后在输出,而在第二个例子中,PHP 引擎就会按照循序输出他们。BAD:echo 'Hello, my name is' . $firstName . $lastName . ' and I live in ' . $city;GOOD:echo 'Hello, my name is' , $firstName , $lastName , ' and I live in ' , $city;使用 switch/case 代替 if/else对于只有单个变量的判断,使用 switch/case 语句而不是 if/else 语句,会有更好的性能,并且代码更加容易阅读和维护。BAD:if($_POST['action'] == 'add') { addUser(); } elseif ($_POST['action'] == 'delete') { deleteUser(); } elseif ($_POST['action'] == 'edit') { editUser(); } else { defaultAction(); }GOOD:switch($_POST['action']) { case 'add': addUser(); break; case 'delete': deleteUser(); break; case 'edit': editUser(); break; default: defaultAction(); break; }避免在循环里面执行sql一个很常见的问题就是在循环里面执行sql。这样多次连接并从数据库得到数据会显著的将脚本运行速度变慢。在下面的例子中,你可以改变之前的循环执行,将SQL改造成一条单独的sql然后一次性插入你的所有数据。foreach ($userList as $user) { $query = 'INSERT INTO users (first_name,last_name) VALUES("' . $user['first_name'] . '", "' . $user['last_name'] . '")'; mysql_query($query); }插入语句:INSERT INTO users (first_name,last_name) VALUES("John", "Doe")代替使用循环,可以将所有的数据组合进一条单独的sql中并执行。$userData = array(); foreach ($userList as $user) { $userData[] = '("' . $user['first_name'] . '", "' . $user['last_name'] . '")'; } $query = 'INSERT INTO users (first_name,last_name) VALUES' . implode(',', $userData); mysql_query($query);插入语句:INSERT INTO users (first_name,last_name) VALUES("John", "Doe"),("Jane", "Doe")...自己第一次翻译,英语比较差,所以练习一下,也增进自己的自己,好记性不如烂笔头嘛。
2023年08月07日
13 阅读
0 评论
0 点赞
2023-08-07
PHP扩展开发(写一个加法的例子)
PHP扩展开发(写一个加法的例子)5.1 您的第一个扩展配置文件才开始,我们先用最快的(不是最标准的)的方式来建立一个代码最少的扩展。在php源码文件夹的ext目录下创建一个新的文件夹,这里我取的名字叫做walu,它往往就是我们扩展的名字。其实这个文件夹可以放在任何一个位置,但是为了我们在后面介绍win32的编译与静态编译,我们还是把它放在php源码的ext目录下。 现在,我们在这个目录下创建一个config.m4文件,并输入以下内容:PHP_ARG_ENABLE(walu,[Whether to enable the "walu" extension], [ enable-walu Enable "walu" extension support]) if test $PHP_WALU != "no"; thenPHP_SUBST(WALU_SHARED_LIBADD) PHP_NEW_EXTENSION(walu, walu.c, $ext_shared)fi上面PHP_ARG_ENABLE函数有三个参数,第一个参数是我们的扩展名(注意不用加引号),第二个参数是当我们运行./configure脚本时显示的内容,最后一个参数则是我们在调用./configure --help时显示的帮助信息。也许有人会问,为什么有的扩展的开启方式是 --enable-extname的形式,有的则是 --with-extname的形式呢?其实两者并没有什么本质的不同,只不过enable多代表不依赖外部库便可以直接编译,而with大多需要依赖于第三方的lib。 现在,我们的扩展并不需要依赖其它的库文件,所以我们直接使用--enable-walu便可以了。在第17章的时候我们将接触通过CFLAGS和LDFLAGS来配置自己的扩展,使其依赖第三方库文件才能被编译成php扩展。如果我们显示运行./configure --enable-walu,那么终端环境便会自动将$PHP_WALU变量设置为yes,而PHP_SUBST函数只不过是php官方对autoconf里的AC_SUBST函数的一层封装。 最后重要的一点是,PHP_NEW_EXTENSION函数声明了这个扩展的名称、需要的源文件名、此扩展的编译形式。如果我们的扩展使用了多个文件,便可以将这多个文件名罗列在函数的参数里,如:PHP_NEW_EXTENSION(sample, sample.c sample2.c sample3.c, $ext_shared)最后的$ext_shared参数用来声明这个扩展不是一个静态模块,而是在php运行时动态加载的。下面,我们来编写实现扩展主逻辑的源文件walu.c://加载config.h,如果配置了的话ifdef HAVE_CONFIG_Hinclude "config.h"endif//加载php头文件include "php.h"define phpext_walu_ptr &walu_module_entry//module entryzend_module_entry walu_module_entry = {if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER,endif"walu", //这个地方是扩展名称,往往我们会在这个地方使用一个宏。 NULL, /* Functions */ NULL, /* MINIT */ NULL, /* MSHUTDOWN */ NULL, /* RINIT */ NULL, /* RSHUTDOWN */ NULL, /* MINFO */if ZEND_MODULE_API_NO >= 20010901"2.1", //这个地方是我们扩展的版本endifSTANDARD_MODULE_PROPERTIES};ifdef COMPILE_DL_WALUZEND_GET_MODULE(walu)endif这就是所有的代码了,不过鉴于我们平时的开发习惯,往往会把这一份代码分成两份,一个.h文件,一个.c文件。上面的代码只是生成了一基本的框架,而没有任何实际的用处。 紧接着,创建一个zend_module_entry结构体,你肯定已经发现了,依据ZEND_MODULE_API_NO 是否大于等于 20010901,这个结构体需要不同的定义格式。20010901大约代表PHP4.2.0版本,所以我们现在的扩展几乎都要包含STANDARD_MODULE_HEADER这个元素了。 其余六个成员我们可以先赋值为NULL,其实看看它们各自后面的注释你就应该大体上了解它们各自是负责哪一方面的工作了。 最后,最底下的代码用来标志我们的这个扩展是一个共享模块。它是干么的呢?我也说不清楚,反正带上就对了,否则扩展会工作不正常。原文解释:这个简短的条件只是在动态加载扩展时使用 Zend 使用的一个引用。不要担心它做了什么或它是如何做的;只要确保它就在附近,否则下一部分将不起作用。标准一些根据我们平时的开发习惯,应该不会把所有代码都写在这一个文件里的,我们需要把上述代码放在两个文件里,一个头文件,一个c文件。//php_walu.hifndef WALU_Hdefine WALU_H//加载config.h,如果配置了的话ifdef HAVE_CONFIG_Hinclude "config.h"endif//加载php头文件include "php.h"define phpext_walu_ptr &walu_module_entryextern zend_module_entry walu_module_entry;endif下面的是c文件//walu.cinclude "php_walu.h"//module entryzend_module_entry walu_module_entry = {if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER,endif"walu", //这个地方是扩展名称,往往我们会在这个地方使用一个宏。 NULL, /* Functions */ NULL, /* MINIT */ NULL, /* MSHUTDOWN */ NULL, /* RINIT */ NULL, /* RSHUTDOWN */ NULL, /* MINFO */if ZEND_MODULE_API_NO >= 20010901"2.1", //这个地方是我们扩展的版本endifSTANDARD_MODULE_PROPERTIES};ifdef COMPILE_DL_WALUZEND_GET_MODULE(walu)endif链接5 你的第一次延期
2023年08月07日
15 阅读
0 评论
0 点赞
2023-08-07
PHP —-MySQL 数据库
PHP —-MySQL 数据库MySQL数据库操作1.创建数据库.在MySQL中应用 create database 语句创建数据库.格式如下:create database db_name;db_name 为数据库名,必须为合法名称.规定如下:a.不能与其他数据库重名.b.名字可以是任意的字母,阿拉伯数字,下划线或者"$"组成.可以使用以上任意的字符开头,但不能是使用单独的数字,哪样会造成与数字混淆.c.名字最长可由64个字符组成(包括表,列和索引),而别名最多可长达256个字符.d.不能使用MySQL关键字作为数据库名称和表名.ps: 执行过程:在创建数据库时,首先连接MySQL服务器,用户名是root,密码也是root,然后编写"create database db_name;" sql语句,数据库创建成功.2.选择数据库.use 语句用于选择一个数据库,使其成为当前默认数据库.格式如下:use db_name;3.删除数据库.删除数据库使用 drop database 语句.格式如下:drop database db_nameps.对于删除数据库的操作应该谨慎使用.一旦删除数据库中的所有结构和数据都将会被删除,没有恢复的可能,除非数据库中有备份.MySQL 数据库表上面将完数据库的操作,下面讲一下数据库中,对表的操作.MySQL 数据库表的操作包括 创建,查看,修改,重命名和删除.1.创建表.创建表使用 create table 语句.格式如下:create [temporary] table [if not exists] 数据表名 [(create_definition,...)][table_options][select_statement]a. temporary ,如果使用该关键字,表示创建一个临时表.b. if not exists ,该关键字用于避免创建表时,表存在时 MySQL报告的错误.c. create_definition,这是表的列表属性部分.MySQL要求在创建表时,表至少要包含一列.create_deifnition 格式如下:col_name type [not null] [default default_value] [auto_increment] [primary key] [reference_definition]col_name:字段名. type:字段类型. not null|null:指出该列是否允许空值.not null 表示不允许空值.default default_value:表示默认值.auto_increament:表示默认值.primary key:表示是否为主键,一个表中只能有一个primary key.如果没有primary key ,而某些应用要求primary key,服务器将返回第一个没有null 列的unique 键作为primary key.d. table_option, 表的一些特性参数.e. select_statement,select语句描述部分,用它可以快速地创建表.2.查看表.对于创建成功的表,使用 show columns 语句或 describe 语句查看指定数据表的表结构.格式如下:show columns 语句:show [full] columns from 数据表名 [from 数据库名]; 或者 show [full] columns from 数据表名.数据库名;describe 语句,describe 可以简写成DESC.describe 数据表名; 或者 describe 数据表名 列名;3.修改表.修改表结构使用 alter table 语句.其中,修改表结构的操作又包括:增加或者删除字段,修改字段名称或者字段类型,设置/取消主键或者外键,设置/取消索引以及修改表的注释等.格式如下:alter [ignore] TABLE 数据表名 alter_spec[,alter_spec]....如果指定参数 ignore,当出现重复行时,则只执行一行,其他重复行将被删除.其中alter_spec 子句定义要修改的内容,格式如下:alter_specification: add [column] create_definition [FIRST | AFTER column_name],//添加新字段 add index [index_name] (index_col_name,....),//添加索引名称 add primary key (index_col_name,...),//添加主键名称 add unique [index_name] (index_col_name,...),//添加唯一的索引 alter [column] col_name {SET DEFAULT literal | DROP DEFAULT},//修改字段名称 change [column] old_col_name create_definition //修改字段类型 modify [column] create_definition,//修改字句定义的字段 drop [column] col_name ,//删除字段名称 drop primary key,//删除主键名称 drop indEX index_name, //删除索引名称 rename [AS] new_tbl_name,//更改表名 table_optionsalter table 语句允许制定多个动作,其动作使用逗号分隔,每个动作表示对表的一个修改.通过alter 修改表列的前提是必须将表中的数据全部删除.4. 重命名表.重命名表使用rename table 语句.格式如下:rename table 数据表名1 to 数据表名2;//rename table 语句可以同时对多个数据表进行重命名,多个表之间以逗号分隔.5. 删除表删除数据表使用语句 drop table .格式如下:drop table 数据表名; 或者 drop table if exists 数据表名; //防止删除不存在的表,导致的报错.删除数据表,将同样导致没有备份的数据无法恢复.ps:在执行create table,alter table和drop table中的任何操作时,首先必须选择数据库,否则将无法对数据表进行操作.MySQL 数据表中的数据下面总结数据表中的数据.如何更好的操作和使用这些数据才是使用MySQL数据库的根本.1.添加(插入)数据.创建完数据库和数据表后,要向表中添加数据.添加数据主要有三种语法方式:a.列出所有新添加数据的所有的值.insert into table_name values(value1,value2,.....);//语句缺点 当列过多的时候,不易明确知道匹配值.b.给出要赋值的列,然后再给出值.insert into table_name (column_name1,column_name2,...) values ( value1,value2,....);//缺点同上c.用col_name =value 的形式给出列和值.insert into table_name set column_name1 = value1 ,column_name2 = value2 , ....;//弥补以上缺点,但导致语句过长.批量添加数据begin 数据的批量添加使用 load data 和MySQLimport 语句实现.load data 通过大量读取本地文件系统上的文件,可以将大量数据添加到数据库中.格式如下:load data local infile "filename.txt" into table table_name;MySQLimport语句实现程序直接从文件读取批量数据.它相当于load data 语句的一个接口.格式如下:%MySQLimport -local table_name filename.txt;MySQLimport可以自动生成一个load data 语句,该语句把filename.txt 文件中的数据装入table_name 表.MySQLimport 将文件名中第一个圆点前的的字符作为新的表名,并且将文件中的数据导入到新表中.如 文件名 com.youfilename.txt. 那么将会将数据导入到表com 中.2.修改数据.修改数据使用update语句.格式如下:update table_name set column_name1=new_Value1,column_name2 =new_value2,... where condition;condition 为条件语句,如user_name='张三'. 必须保证condition条件的准确性,否则将会导致破坏表中的数据.3.删除数据.删除数据使用 delete 语句.格式如下:delete from table_name where condition;psa.删除某条数据时,一般选择该数据的id 作为条件,以避免产生不必要的错误.b.当到删除整个表的数据,因效率问题,不推荐使用delete操作.可以使用truncate 语句,它可以很快的删除表中的所有内容.4.查询数据.从数据库表中查询数据用与操作以及显示,是对数据进行操作比较重要的一环.下面将会作详细的解释.首先,对MySql数据库表进行数据查询用到select 语句.格式如下:select selection_list //要查询的内容,选择查询的列. from table_list //从何表中查询,从何处选择行. where primaryz_constraint //查询时,需要满足的条件. group by grouping_columns //如何对查询结果进行分组. order by sorting_columns //如何对结果进行排序 having secondary_constraint //查询时满足的第二条件. limit count //限定输出的结果.a. select_list 表示要查询的内容.如果要查询表中所有的列,可以用" * "表示.如果查询多列,可以直接输入列名,并使用" , "分隔.b. table_list 从指定的表中查询.既可以从一个表中查询;也可以从多个表中查询,多表查询使用 " ," 分隔,并且在where 字句中使用连接运算符号来确定表与表之间的关系.当使用多表查询的使用,如果表中有相同的字段,为了告诉服务器要显示的那个表中的字段信息,需要在字段前加上表名.格式如下:table_name.columns_name; //表名.字段名.使用 " = "符号将表连接起来,叫做等同连接.比如.tb_student.name = tb_gradeOne.name ;如果不使用等号连接,那么产生的结果将是两个表的笛卡尔积,叫做全连接.c.where 条件语句用于通过相应条件获取对应信息.格式为 columns_name 比较运算符 value.d. group by 实现对查询得到的数据进行划分并加以分组,从而实现分组查询.在查询时,所查询的列必须包含在分组的列中,目的是使查询到的数据没有矛盾.在与avg() 或则sum()函数一起使用时,group by 语句能够发挥最大的作用.e.使用distinct 在结果中去除重复行.f.order by.使用order by 可以对结果进行升序和降序(DESC),在默认情况下,order by 按照升序输出结果.如果要降序可以使用DESC 来实现.当对含有null值的列进行排序时,升序,null值排在最前,降序,null 排在最后.g.like 模糊查询. like 属于较常用的运算符,通过它可以实现模糊查询,他有两种通配符,即"%"和下划线"_"."%"可以实现匹配一个或多个字符,而"_"只匹配一个字符.h. 使用concat 联合多列.使用concat 函数可以联合多个字段,从而构成一个总的字符串.例如把书名与价格合并,并使用as 为字段起一个别名.select id ,concat(bookname,":",price) as bookInfo form tb_mkbook;i.使用limit 限定结果函数.使用limit字句可以对结果的记录条数进行限定,从而控制它输出的行数. 例如:limit 3 --表示显示3条数据.limit 5,10---表示从编号为5的记录开始,往下读10条数据用于显示.j.函数表达式.常用的统计函数有:avg(columns_name);//获取指定列的平均值.count(columns_name);//统计出制定列的非空记录的条数. 加distinct限定关键字,则统计不同值的条数,相同值的被认为为一条记录.count(*),则统计包含空记录的数目.max(columns_name) 或者 min(columns_name);//获取指定字段的最大/最小值.std(columns_name) 或者 stdtev(columns_name);//指定字段的标准背离值.sum(columns_name);//指定字段所有记录的值的和.ps.常见的数据类型有 数字类型,字符串类型,时间和日期类型.详细情况,请参考php相关知料与文档.MySQL 数据库的操作步骤以上对mysql数据库结构层次总结如下,下面介绍对数据库的操作步骤.1.连接到mysql服务器.使用mysql_connect()函数创建与MySQL服务器连接.方法格式如下:<?php $conn = mysql_connect('hostname' , 'username' , ' password ') or die( "数据库服务器连接失败".mysql_error()); //hostname: mysql服务器的主机名或者ip.如果省略端口号,则默认为3306; //username:登陆mysql数据库服务器的名称 //password: mysql服务器的用户密码. //改函数的返回值表示对这个数据库的连接,如果成功,则返回一个资源. if($conn){ //服务器连接成功 } ?>从上可以知道,可以指定非本机的机器名作为数据库服务器,这样就为数据库的异地存储和数据库的的安全隔离提供了保障.外界用户往往通过www服务器的直接访问权限,如果数据库直接放在www服务器上,就会给MySQL数据库带来安全隐患;如果为数据库系统安装防火墙,那么php可以直接通过局域网访问数据库,而局域网的计算机对外部不可见,这样保证了s数据库不受外来攻击.为了方便查询数据库连接错误,可以加上die()函数进行屏蔽的错误处理机制.mysql_error()用于提取错误文本信息,如果没有出错则返回空字符;如果出错,连兰奇上将会显示错误信息.ps.对于用户而言,建议在mysql_connect()前面添加@符号,用于屏蔽错误信息,这样做是为了让用户看到一堆莫名其妙的错误信息.但是对于开发者而言,在调试的过程中,不使用@能让我们快速定位错误信息.2.选择MySQL数据库.使用mysql_select_db()函数选择MySQL数据库服务器上的数据库,并与数据库创建连接.格式如下:mysql_select_db(string 数据库名 [,resource link_identifier]); //string 数据库名:要选择的MySQL数据库名称 //resource link_identifier: MySQL服务器的连接标识.//例子,同上一步. <?php if($conn){ $selected = sql_select_db("db_webBookStore",$conn); if($selected){ //数据库连接成功; } } ?>3.执行sql语句.使用mysql_query()函数执行sql语句.sql语句操作在前面已经讲过,此处不在阐述.主要介绍mysql_query()函数的用法,格式如下:$result = mysql_query(string sql [,resource link_identifier]); //如果sql语句为查询语句,成功则返回结果集合,否则返回false //如果sql语句为插入,删除或更新,成功则返回true,否则返回false. //ps.改函数也可以用于选择数据库,和设置数据库编码格式. //如:mysql_query('user db_database13',$conn); // mysql_query(' set names utf8');提高: mysql_unbuffered_query() ,顾名思义改函数为不缓存结果查询.它仅向服务器发送一条sql查询语句,但不获取和缓存结果的行.它不像mysql_query哪样自动获取并缓存结果集.优点在于,当处理很大的结果集时,会节省客观的内存;另一方面,可以在获取第一行数据后立即对结果集进行操作,而不用等到整个SQL语句都执行完毕.mysql_fetch_array()函数,用于将结果集合返回到数组中.格式为:$array = mysql_fetch_array(resource result [,int result_type]); //resource result:资源类型的参数,要传入的是由mysql_query()返回的资源数据指针. //int result_type:可选项,要传入的整型参数,可以是:mysql_assoc(关联索引),mysql_num(数字索引),mysql_both(同时包含前两者).默认为mysql_both. //注意,本函数返回的字段名区分大小写. mysql_fetch_row()函数,从结果集中获取一行来作为枚举数组.格式为: $array = mysql_fetch_row(resource result); //根据所获取的行数据,生成数组.如果没有更多的行,则返回false. //数组偏移量下标从0开始. //本函数返回的字段名区分大小写. 本函数只能使用数字索引,而mysql_fetch_array()两者都可使用.如:数字索引:$array[0],关联索引:$array[type]; mysql_num_rows()函数,用于获取查询结果集中的记录数.格式为: int mysql_num_rows(resource result); //返回结果集中行的数目.此命令只对select语句有效.要获取其他sql语句的操作所影响的数据集行数目,需要使用mysql_affected_rows()4.数据执行完后,需要关闭结果集,以释放资源.语法如下:mysql_free_result(resource result);如果在网页中要频繁的对数据库进行访问,可以通过创建与服务器数据库持续连接来提高效率.这样就避免了,每次连接服务器请求多带来的长时间请求和较大的资源开销.持续连接数据库使用mysql_pconnect()函数来替换mysql_connect()函数.创建的持续连接,在程序结束前将不会调用mysql_close()来关闭数据库请求.当再次调用mysql_pconnect()去连接数据库的时,服务器将返回已经创建的持续连接的ID号,而不去重新创建数据库连接.5.关闭MySQL服务器.每次使用mysql_connect()和mysql_query(),都会消耗系统资源.在少量用户访问web网站时候问题还不大,但当大量用户连接超过一定的数量,就会造成系统性能的下降,甚至死机.为了避免这种情况,在完成数据库操作后,应调用改函数来关闭与MySQL服务器的连接,以节省系统的资源.格式如下:mysql_close($conn);ps.php中与数据库的连接是非持久连接,系统会自动回收,一般不用设置关闭.但如果一次性返回的结果集比较大,或者网站访问量比较多,则最好使用改函数手动释放.提高:数据库乱码问题,使用mysql_query()函数设置数据库编码. 编码格式建议使用utf-8 .如果使用gbk2312,如果用户没有安装中文编码(如一些美洲,欧洲用户的机器查看中文网站),则在输出时将会导致乱码.utf-8 的使用返回更广,可移植性更高,也更被国际化支持.
2023年08月07日
14 阅读
0 评论
0 点赞
1
...
97
98
99
...
112