首页
关于
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
篇文章
累计收到
29
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
560
篇与
的结果
2023-08-07
一个简单而精彩的方法获取中文字符串长度
一个简单而精彩的方法获取中文字符串长度今晚在写框架的表单验证类时,需要判断某个字符串长度是否在指定区间内,很自然地,想到了PHP中的 strlen 函数。$str = 'Hello world!'; echo strlen($str); // 输出12然而在PHP自带的函数中,strlen及 mb_strlen 都是通过计算字符串所占字节数来计算长度的,在不同的编码情况下,中文所占的字节数是不同的。在GBK/GB2312下,中文字符占2个字节,而在UTF-8下,中文字符占3个字节。$str = '你好,世界!'; echo strlen($str); // GBK或GB2312下输出12,UTF-8下输出18而我们在判断字符串长度时往往需要判断的是字符的数量,而非字符串所占字节数,如在UTF-8下的这段PHP代码:$name = '张耕畅'; $len = strlen($name); // 输出 FALSE,因为在UTF-8下三个中文占9个字节 if($len >= 3 && $len <= 8){ echo 'TRUE'; }else{ echo 'FALSE'; }那么有什么方便而实用的方法可以获得含中文字符串的长度呢?可以 用正则计算出中文字符的个数,在GBK/GB2312编码下除以2,UTF-8编码下则除以3,最后再加上非中文字符串的长度 ,但这样未免太过麻烦,WordPress中有一段更漂亮的代码,借鉴如下:$str = 'Hello,世界!'; preg_match_all('/./us', $str, $match); echo count($match[0]); // 输出9思想是 用正则表达式将字符串分割成单个字符,并直接用count计算出匹配到的字符数 ,便是我们想要的结果了。
2023年08月07日
21 阅读
0 评论
0 点赞
2023-08-04
360提供的PHP防注入代码
360提供的PHP防注入代码PHP代码 <?php//Code By Safe3function customError($errno, $errstr, $errfile, $errline){ echo "Error number: [$errno],error on line $errline in $errfile" ; die();} set_error_handler("customError",E_ERROR);$getfilter="'|(and|or)\b.+?(>|<|=|in|like)|\/\.+?\\/|<\s*script\b|\bEXEC\b|UNION.+?Select|Update.+?SET|Insert\s+INTO.+?VALUES|(Select|Delete).+?FROM|(Create|Alter|Drop|TRUNCATE)\s+(TABLE|DATABASE)" ;$postfilter="\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\.+?\\/|<\s*script\b|\bEXEC\b|UNION.+?Select|Update.+?SET|Insert\s+INTO.+?VALUES|(Select|Delete).+?FROM|(Create|Alter|Drop|TRUNCATE)\s+(TABLE|DATABASE)" ;$cookiefilter="\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\.+?\\/|<\s*script\b|\bEXEC\b|UNION.+?Select|Update.+?SET|Insert\s+INTO.+?VALUES|(Select|Delete).+?FROM|(Create|Alter|Drop|TRUNCATE)\s+(TABLE|DATABASE)" ;function StopAttack($StrFiltKey,$StrFiltValue,$ArrFiltReq){if(is_array($StrFiltValue)){ $StrFiltValue=implode($StrFiltValue);}if (preg_match("/".$ArrFiltReq."/is",$StrFiltValue)==1){//slog("<br><br>操作IP: ".$_SERVER["REMOTE_ADDR"]."<br>操作时间: ".strftime("%Y-%m-%d %H:%M:%S")."<br>操作页面:".$_SERVER["PHP_SELF"]."<br>提交方式: ".$_SERVER["REQUEST_METHOD"]."<br>提交参数: ".$StrFiltKey."<br>提交数据: ".$StrFiltValue); print "360websec notice:Illegal operation!" ; exit();}}//$ArrPGC=array_merge($_GET,$_POST,$_COOKIE);foreach($_GET as $key=>$value){ StopAttack($key,$value,$getfilter);}foreach($_POST as $key=>$value){ StopAttack($key,$value,$postfilter);}foreach($_COOKIE as $key=>$value){ StopAttack($key,$value,$cookiefilter);}if (file_exists('update360.php')) { echo "请重命名文件update360.php,防止黑客利用<br/>"; die();}function slog($logs){ $toppath=$_SERVER["DOCUMENT_ROOT"]."/log.htm"; $Ts=fopen($toppath,"a+"); fputs($Ts,$logs."\r\n"); fclose($Ts);}
2023年08月04日
23 阅读
0 评论
0 点赞
2023-08-04
深入理解PHP原理之foreach
深入理解PHP原理之foreach经常会有人问我, PHP的数组, 如果用foreach来访问, 遍历的顺序是固定的么? 以什么顺序遍历呢?比如:<?php$arr['laruence'] = 'huixinchen';$arr['yahoo'] = 2007;$arr['baidu'] = 2008;foreach ($arr as $key => $val) {//结果是什么?}又比如:<?php$arr[2] = 'huixinchen';$arr[1] = 2007;$arr[0] = 2008;foreach ($arr as $key => $val) {//现在结果又是什么?}要完全了解清楚这个问题, 我想首先应该要大家了解PHP数组的内部实现结构………PHP的数组在PHP中, 数组是用一种HASH结构(HashTable)来实现的, PHP使用了一些机制, 使得可以在O(1)的时间复杂度下实现数组的增删, 并同时支持线性遍历和随机访问.之前的文章中也讨论过, PHP的HASH算法, 基于此, 我们做进一步的延伸.认识HashTable之前, 首先让我们看看HashTable的结构定义, 我加了注释方便大家理解:typedef struct _hashtable {uint nTableSize; / 散列表大小, Hash值的区间 /uint nTableMask; / 等于nTableSize -1, 用于快速定位 /uint nNumOfElements; / HashTable中实际元素的个数 /ulong nNextFreeElement; / 下个空闲可用位置的数字索引 /Bucket pInternalPointer; / 内部位置指针, 会被reset, current这些遍历函数使用 */Bucket pListHead; / 头元素, 用于线性遍历 */Bucket pListTail; / 尾元素, 用于线性遍历 */Bucket *arBuckets; / 实际的存储容器 */dtor_func_t pDestructor;/ 元素的析构函数(指针) /zend_bool persistent;unsigned char nApplyCount; / 循环遍历保护 /zend_bool bApplyProtection;if ZEND_DEBUGint inconsistent;endif} HashTable;关于nApplyCount的意义, 我们可以通过一个例子来了解:<?php$arr = array(1,2,3,4,5,); $arr[] = &$arr; var_export($arr); //Fatal error: Nesting level too deep - recursive dependency?这个字段就是为了防治循环引用导致的无限循环而设立的.查看上面的结构, 可以看出, 对于HashTable, 关键元素就是arBuckets了, 这个是实际存储的容器, 让我们来看看它的结构定义:typedef struct bucket {ulong h; / 数字索引/hash值 /uint nKeyLength; / 字符索引的长度 /void pData; / 数据 */void pDataPtr; / 数据指针 */struct bucket pListNext; / 下一个元素, 用于线性遍历 */struct bucket pListLast; / 上一个元素, 用于线性遍历 */struct bucket pNext; / 处于同一个拉链中的下一个元素 */struct bucket pLast; / 处于同一拉链中的上一个元素 */char arKey[1]; / 节省内存,方便初始化的技巧 /} Bucket;我们注意到, 最后一个元素, 这个是flexible array技巧, 可以节省内存,和方便初始化的一种做法, 有兴趣的朋友可以google flexible array.h是元素的Hash值,对于数字索引的元素,h为直接索引值(通过nKeyLength=0来表示是数字索引).而对于字符串索引来说, 索引值保存在arKey中, 索引的长度保存在nKeyLength中.在Bucket中,实际的数据是保存在pData指针指向的内存块中,通常这个内存块是系统另外分配的。但有一种情况例外,就是当Bucket保存 的数据是一个指针时,HashTable将不会另外请求系统分配空间来保存这个指针,而是直接将该指针保存到pDataPtr中,然后再将pData指向本结构成员的地址。这样可以提高效率,减少内存碎片。由此我们可以看到PHP HashTable设计的精妙之处。如果Bucket中的数据不是一个指针,pDataPtr为NULL(本段来自Altair的”Zend HashTable详解”)结合上面的HashTable结构, 我们来说明下HashTable的总结构图:HashTable结构示意图HashTable结构示意图HashTable的pListhHead指向线性列表形式下的第一个元素, 上图中是元素1, pListTail指向的是最后一个元素0, 而对于每一个元素pListNext就是红色线条画出的线性结构的下一个元素, 而pListLast是上一个元素.pInternalPointer指向当前的内部指针的位置, 在对数组进行顺序遍历的时候, 这个指针指明了当前的元素.当在线性(顺序)遍历的时候, 就会从pListHead开始, 顺着Bucket中的pListNext/pListLast, 根据移动pInternalPointer, 来实现对所有元素的线性遍历.比如, 对于foreach, 如果我们查看它生成的opcode序列, 我们可以发现, 在foreach之前, 会首先有个FE_RESET来重置数组的内部指针, 也就是pInternalPointer(关于foreach可以参看深入理解PHP原理之foreach), 然后通过每次FE_FETCH来递增pInternalPointer,从而实现顺序遍历.类似的, 当我们使用, each/next系列函数来遍历的时候, 也是通过移动数组的内部指针而实现了顺序遍历, 这里有一个问题, 比如:<?php$arr = array(1,2,3,4,5);foreach ($arr as $v) {//可以获取}while (list($key, $v) = each($arr)) {//获取不到}?>了解到我刚才介绍的知识, 那么这个问题也就很明朗了, 因为foreach会自动reset, 而while这块不会reset, 所以在foreach结束以后, pInternalPointer指向数组最末端, while语句块当然访问不到了, 解决的办法就是在each之前, 先reset数组的内部指针.而在随机访问的时候, 就会通过hash值确定在hash数组中的头指针位置, 然后通过pNext/pLast来找到特点元素.增加元素的时候, 元素会插在相同Hash元素链的头部和线性列表的尾部. 也就是说, 元素在线性遍历的时候是根据插入的先后顺序来遍历的, 这个特殊的设计使得在PHP中,当使用数字索引时, 元素的先后顺序是由添加的顺序决定的,而不是索引顺序.也就是说, PHP中遍历数组的顺序, 是和元素的添加先后相关的, 那么, 现在我们就很清楚的知道, 文章开头的问题的输出是:huixinchen20072008所以, 如果你想在数字索引的数组中按照索引大小遍历, 那么你就应该使用for, 而不是foreachfor($i=0,$l=count($arr); $i<$l; $i++) { //这个时候,不能认为是顺序遍历(线性遍历)}
2023年08月04日
15 阅读
0 评论
0 点赞
2023-08-04
系统管理员应知:十大PHP最佳安全实践
系统管理员应知:十大PHP最佳安全实践导读:本文来自知名时尚媒体ELLE大陆版即《世界时装之苑》网站的香港工程师AnsonCheung文中他例举了有关PHP10个方面的最佳平安实践方式,供系统管理员学习与参考。原文是Top10PHPBestSecurPracticforSyAdmin以下是译文: PHP被广泛用于各种Web开发。而当服务器端脚本配置过失时会呈现各种问题。现今,大部分Web服务器是基于Linux环境下运行(比方:UbuntuDebian等)本文例举了十大PHP最佳平安实践方式,能够让您轻松、平安配置PHP 1.减少PHP内置模块 为了增强性能和安全性,强烈建议,减少PHP中的模块。来看看下面这个被执行命令装置的模块。 php–m 将会得到类似的结果: [PHPModules]apcbcmathbz2calendarCorectypecurldatedomeregexiffileinfofilterftpgdgettextgmphashiconvimapjsonlibxmlmbstringmemcachemysqlmysqliopensslpcntlpcrePDOpdo_mysqlpdo_sqlitePharreadlineReflectionsessionshmopSimpleXMLsocketsSPLsqlite3standardsuhosintokenizerwddxxmlxmlreaderxmlrpcxmlwriterxslzipzlib[ZendModules]Suhosin 删除一个模块,并执行此命令。例如:删除模块sqlite3 rm/etc/php.d/sqlite3.ini 或者 mv/etc/php.d/sqlite3.ini/etc/php.d/sqlite3.disableRestrict2.使PHP信息泄露最小化 默认PHP时在HTTP抬头处会生成一条线介于每个响应中,比方X-Powered-By:PHP/5.2.10而这个在系统信息中为攻击者创建了一个非常有价值的信息。 HTTP示例: HTTP/1.1200OKX-Powered-By:PHP/5.2.10Content-type:text/html;charset=UTF-8Vary:Accept-Encoding,COOKIEX-Vary-Options:Accept-Encoding;list-contains=gzip,COOKIE;string-contains=wikiToken;string-contains=wikiLoggedOut;string-contains=wiki_sessionLast-Modified:Thu,03Nov201122:32:55GMT... 因此,强烈建议,禁止PHP信息泄露,想要要禁止它要编辑/etc/php.d/secutity.ini并设置以下指令: expose_php=Off3.使PHP加载模块最小化 默认情况下,RHEL加载的所有模块可以在/etc/php.d/目录中找到要禁用或启用一个特定的模块,只需要在配置文件/etc/php.d/目录中中注释下模块名称。而为了优化PHP性能和安全性,当你应用顺序需要时,强烈建议建议启用扩展功能。举个例子:当禁用GD扩展时,键入以下命令: cd/etc/php.d/mvgd.{ini,disable}/etc/init.d/apache2restart 为了扩展PGPGD模块,然后键入以下命令: mvgd.{disable,ini}/sbin/servichttpdrestart4.记录PHP过失信息 为了提高系统和Web应用顺序的平安,PHP过失信息不能被暴露出。要做到这一点,需要编辑/etc/php.d/security.ini文件,并设置以下指令: display_errors=Off 为了便于开发者Bug修复,所有PHP过失信息都应该记录在日志中。 log_errors=Onerror_log=/var/log/httpd/php_scripts_error.log5.禁用远程执行代码 如果远程执行代码,允许PHP代码从远程检索数据功能,如FTP或Web通过PHP来执行构建功能。比方:file_get_cont 很多顺序员使用这些功能,从远程通过FTP或是HTTP协议而获得数据。然而,此法在基于PHP应用顺序中会造成一个很大的漏洞。由于大部分顺序员在传送用户提供的数据时没有做到适当的过滤功能,打开平安漏洞并且创立了代码时注入了漏洞。要解决此问题,需要禁用_url_fopenin/etc/php.d/security.ini并设置以下命令: allow_url_fopen=Off 除了这个,还建议禁用_url_includ以提高系统的平安性。 allow_url_include=Off6.禁用PHP中的危险函数 PHP中有很多危险的内置功能,如果使用不当,可能使你系统解体。可以创立一个PHP内置功能列表通过编辑/etc/php.d/security.ini来禁用它 disable_functions=exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_sourc7.资源控制 为了提高系统的稳定性,强烈建议设置每个脚本解析请求数据所花费的时间和脚本可能消耗的最大内存量。正确的配置这些参数可以防止PHP任何脚本消耗太多的资源或是内存,从而防止系统不安全或降低平安系数。 setinsecondmax_execution_time=30max_input_time=30memory_limit=40M8.限制PHP访问文件系统 该open_basedir指令指定的目录是允许PHP访问使用fopen等功能。如果任何脚本试图访问超出open_basdir定义的路径文件,PHP将拒绝打开。值得注意的不能使用一个符号链接作为一种变通方法。 ;LimitthePHPprocessfromaccessfileoutsid;ofspecifdesigndirectorisuchas/var/www/html/open_basedir="/var/www/html/";------------------------------------;Multipldirexampl;open_basedir="/home/httpd/vhost/cyberciti.biz/html/:/home/httpd/vhost/nixcraft.com/html/:/home/httpd/vhost/theos.in/html/";------------------------------------9.限制文件/目录访问 进行适当的平安设置:确保Apach作为非root用户运行,比方www-data或www对于文件和目录在基于/var/www/下同样属于非root用户。想要更改所有者,执行以下命令: chown-Rapache:apach/var/www/10.编译维护ApachPHP和MySQL配置文件 使用charrt命令编译维护配置文件 chattr+i/etc/php.inichattr+i/etc/php.d/*chattr+i/etc/my.inichattr+i/etc/httpd/conf/httpd.confchattr+i/etc/ 使用charrt命令可以编译维护PHP文件或者是文件中的/var/www/html目录: chattr+i/var/www/html/file1.phpchattr+i/var/www/html/
2023年08月04日
12 阅读
0 评论
0 点赞
2023-08-04
我们什么时候应该使用异常?
我们什么时候应该使用异常?PHP应该什么时候使用 Exception ? 它的性能如何?这个问题也算是一个久经争论的经典问题了. 我谈谈我的个人看法.异常与之对应的错误码(或者状态码), 到底各自有什么优点, 缺点, 我们应该怎么使用呢?错误码首先来说, 异常机制是在错误码机制之后才出现的, 那么根据进化论, 异常自然是避免了错误码机制的一些不足. 这些不足包括.错误信息不丰富函数, 只能有一个返回值(当然, Lua可以返回多个, 但其实也相当于在PHP中返回一个数组), 我们见过最多的函数说明就是: 成功时候返回*, 错误的时候返回FALSE, 然而一个函数出错我原因可能有多种, 出错的种类更有多种. 一个简单的FALSE, 并不能把具体的错误信息告诉调用者.于是, 我们也就见过一些, 这样的函数说明: 如果返回值大于0, 则表示成功的状态码, 如果返回值小于0, 则表示出错的状态码.然而, 这个要求函数是返回整形(或者数字), 对于一些其他函数, 我们并不能通过0, >0, <0来判别, 并且, 即使通过这样的方式, 我们还需要用返回的错误码和一些预定义宏(或者调用类似strerror())来获取具体的, 可读的错误信息. 于是, 就有一些函数使用全局的错误码, 和错误信息, 来保存具体的错误信息, 这个时候我们就看到这样的函数描述: 成功返回*, 出错的时候返回FALSE, 错误代码保存在全局变量$errno中(至少大多数Linux库函数是这样描述的, 呵呵). Okey, 这样的方式确实可以工作, 但是, 是不是觉得, 很丑陋呢?加入错误状态码可能需要改变函数签名假设, 你编写了一个函数, 这个函数很简单, 很简单, 你认为他绝对不会出错, 于是你申明为(用C语言为例, PHP没有返回类型提示):void dummy() {}但是后来你慢慢修改了这个函数, 给了它更多的功能, 此时这个函数可能会失败了. 而你现在根本无法为这个函数, 加入错误返回码了.也许有人说PHP没有返回值类型限制一说, 但是想想PHP的构造函数, 构造函数是没有返回值的, 当发生错误的时候, 如果你不使用异常, 我想你只能选择die, 或者使用2中的方法来错误继续执行了.另外, 在一个良好的软件系统中, 返回类型其实也是约定俗成的, 当所有的使用的函数的地方, 都没有检查返回值的时候, 你还是无法为这个函数加入错误返回码.错误状态码可能会被忽略当你的一个函数, 出错了, 返回了错误状态码, 而调用方并没有检测这个返回值, 会发生什么情况呢? -_#. 令一方面, 处处检测返回状态码, 会造成代码非常的,,ugly:<?php if (!call1()) { die();} if (call2() != SUCCESS) { die();} if (call3() < 0) { $msg = error_get_last(); die($msg["message"]);}异常机制那么现在我们来看看异常机制, 如果我们采用异常机制, 上面的代码可以写作:<?phptry { call1(); call2(); call3();} catch (Exception $e) { die($e->getMessage());}更方便的, 如果你的代码只是中间层, 你的调用方会负责处理错误的话, 你甚至可以简单的写作:<?phpfunction myFunc() { call1(); call2(); call3();}而一个异常对象, 可以包含更丰富的错误信息, 比如错误信息, 错误码, 错误的行数, 文件, 甚至出错上下文, 等等, 避免的"1.错误信息不丰富"的不足.我们也可以为一个返回void类型的函数增加异常, 而不改变他的函数签名, 也就不会有上面说的"2.加入错误状态码可能需要改变函数签名". 对于PHP来说, 如果我们新加入的错误没有被捕捉, 也不用担心, 会明显的出错的. 也就不会发生上面所说的"3. 错误状态码可能会被忽略"的情况.然而, 也有一些反对使用异常的声音:性能正如文章开头提问中的: "它的性能如何?", 异常机制确实要比返回状态码的方式昂贵一些, 对于C++来说, 在异常发生的时候, 还要发生堆栈解退(对于PHP来说, 没有这个逻辑, 具体的大家可以参看我之间写的一篇文章: 深入理解PHP原理之异常机制).性能和方便, 往往是一个矛盾体, 我只能说, 你需要权衡, 如果你写的是一个小的模块, 并且它的生命期可能很短, 也不需要什么特殊的设计模式, 那我觉得你可以不用异常.而如果你在为一个庞大的软件做开发, 我想你更应该看重的, 应该是, 它的可扩展性, 可维护性.太多可能的Uncaught Exception如果, 你调用了一个可能发生异常的函数, 但是却没有捕获这个异常, okey, Fatal Error了, 所以让我们的代码看起来:<?phptry {} catch () {}....try {} catch () {}....try {} catch () {}然而, 这个是可以经过良好设计避免的, 比如我在设计Yaf的时候, 就提供了全局异常处理, 也就是类似于, 你在最最顶层, 加上了一个try catch, 所有的异常错误逻辑都加到这个里面, 你也可以很方面的把你自己的异常加进去.结论
2023年08月04日
11 阅读
0 评论
0 点赞
1
...
102
103
104
...
112