IT技术博客大学习 共学习 共进步

PHP

共 404 篇文章

IT 2020-02-01 14:41:51 / 累计浏览 1,953

令人困惑的strtotime

这篇讲的是PHP中strtotime函数的一个常见坑点。当开发者使用“-1 month”、“+1 month”或“next month”等相对日期字符串时,结果往往出人意料。比如从2018-07-31执行strtotime("-1 month"),会得到2018-07-01而非预期的2018-06-30,这让人对函数的可靠性产生疑惑。 问题的根因在于strtotime的内部处理逻辑:它先执行月份运算,再对日期进行规范化。以2018-07-31为例,减一月后得到06-31,但6月没有31天,于是日期被自动调整为07-01,就像时间计算中2点60分等于3点一样。文章通过多个代码示例验证了这一原理,例如在2017-08-31上加一月会得到2017-10-01,在2017-01-31上使用next month会跳到2017-03-03,因为2月天数不足导致规范化后月份再进位。 如何解决这个陷阱?作者指出,从PHP5.3版本

IT 2020-02-01 14:38:37 / 累计浏览 2,374

深入理解PHP7内核之Reference

这篇讲的是PHP7内核中对引用(Reference)机制的一次重要重构。作者从PHP5时代用标志位实现引用带来的性能瓶颈出发,剖析了为何在PHP7中必须将“引用”升级为一种独立的数据类型(IS_REFERENCE)。 文章的核心在于解释这个新类型如何解决实际问题。PHP7的zval结构被优化为直接存储简单类型(如整数),但引用需要计数,这产生了矛盾。解决方案是引入一个“间接层”:IS_REFERENCE类型的zval内含一个指向zend_reference结构体的指针,该结构体才真正持有引用计数和另一个zval。这个设计精巧地解决了“整数引用”这类问题。 更重要的是,文章通过代码示例对比了新旧机制在“写时复制”(Copy-On-Write)行为上的差异。在PHP5中,复制一个共享的引用变量会强制发生复制,导致内存开销;而在PHP7下,复制操作只会增加内层zval的引用计数,避免了不必要的内存拷贝,文章中的测试数据也直观证实了这一点。这使得引用的处理在内核层面变得更高效、更清晰。

IT 2019-01-01 21:04:14 / 累计浏览 2,657

PHP非阻塞实现方法

这篇讲的是如何让PHP在后端执行耗时任务时,仍能快速响应前端请求,避免阻塞页面加载。文章集中对比了8种实现非阻塞的技术方案。 作者从最简单的PHP-FPM内置函数`fastcgi_finish_request()`切入,它能立即结束会话,让后续代码在后台静默执行。对于需要发起异步HTTP请求的场景,介绍了利用`fsockopen()`设置非阻塞模式,以及使用cURL多句柄`curl_multi_*`函数的方法。 更进阶的方案涉及扩展与架构:`pcntl_fork()`能创建子进程来处理任务,优点是方便,但需要小心处理可能产生的僵尸进程;而Gearman和Swoole等异步框架则提供了更成熟的分布式任务处理能力。文章还提到了在高并发场景下常用的缓存与队列(如Redis)方案,将耗时操作解耦到后台执行。最后,也提及了通过系统命令或PHP原生协程(Coroutines)来实现的可能性。 总的来说,文章从不同技术层面剖析了PHP的非阻塞之道,为需要优化长任务处理的开发者提供了从快速实现到架构设计的多重选择。

IT 2018-06-26 12:25:17 / 累计浏览 1,829

通过Twemproxy提升PHP/Redis的性能

这篇文章讲的是如何用 Twemproxy 这个看似“古老”的 Redis 代理,来解决 PHP 应用中难以实现真正连接池的性能痛点。作者没有从复杂的理论入手,而是直接从一个已知的“曲线救国”方案(借助 Nginx Stream 模块)出发,转而尝试用现成的 Twemproxy 来达到相同目的。 核心方案是让 Twemproxy 与 PHP 部署在同一台服务器上,并通过本地 Unix Domain Socket 进行连接。经过初步压测,作者发现默认的单进程 Twemproxy 并没有带来性能提升,问题根源在于其单线程架构无法利用多核 CPU。因此,他调整策略,按照 CPU 核心数启动了多个 Twemproxy 进程,并让 PHP 请求随机分配到这些进程对应的 Socket 上。 最终的测试结果非常直观:性能提升了整整 100%。作者在文中指出了性能跃升的关键因素:Twemproxy 的 Pipelining 功能将多个请求打包发送,减少了网络 RTT,同时还优化了连接建立过程。文章不仅给出了具体的配置文件示例和压测命令,还提到了如 mbuf-size 设置和绑定 CPU 等实战细节,为读者提供了可直接参考的落地步骤。

IT 2016-12-22 23:28:32 / 累计浏览 3,191

PHP的性能演进(从PHP5.0到PHP7.1的性能全评测)

这篇评测通过CPU基准测试脚本,系统比较了PHP从5.0到7.1各主要版本的性能表现。作者发现,性能提升主要发生在主版本迭代时,而非小版本更新。例如,PHP 5.1比5.0性能翻倍,PHP 5.4有一次显著跃升,而PHP 7.0则实现了重大突破,其重新设计的Zend Engine使性能得到质的飞跃。 测试数据直观展示了这一历程:在bench.php脚本中,PHP 7.0比5.0快了数倍,而试验性的JIT分支(预览PHP 8)更是将差距拉大到40倍以上。文章也梳理了各版本的核心优化点,从PHP 5.1的编译变量与执行器优化,到PHP 5.4的内部字符串优化,再到PHP 7.0全面重构的数据结构与内存管理。 除了回顾,文章也展望了引入JIT编译技术的PHP 8,指出这将是另一个性能飞跃点,但同时也提醒其效果因场景而异。对于PHP开发者而言,这份横跨十余年的评测,不仅验证了每次重大升级的价值,也为性能优化与版本升级决策提供了扎实的数据参考。

IT 2016-04-05 13:52:36 / 累计浏览 3,611

PHP返回内容过长时被nginx截断的解决办法

这篇讲的是作者升级博客环境后,发现后台编辑器界面莫名“消失”——页面内容被截断,功能完全无法使用。他没有急于胡乱配置,而是沉下心分析问题。 排查过程一度很曲折,从复杂的网络抓包入手绕了远路,但最终从 nginx 的错误日志中找到了关键线索:一行 `Permission denied` 错误。原来,当 PHP 返回的响应内容过大时,nginx 会先将其缓存到本地临时文件中,但由于该临时目录(`/var/lib/nginx/tmp/fastcgi/`)的权限不正确,nginx 无法写入文件,从而导致连接中断、内容截断。 解决方案其实很简单:将该目录的权限修改为 775。作者复盘时指出,这次本可快速解决的问题耗费了大量时间,核心教训是:面对异常,应当优先检查系统日志、基于线索推理,而非凭借假设盲目测试。一次具体的踩坑经历,清晰地揭示了 PHP 与 nginx 协作时一个容易被忽略的权限配置细节。

IT 2016-03-30 16:00:26 / 累计浏览 3,149

wordpress/nginx安全设置

这篇讲的是如何给WordPress博客加固登录安全,作者从两个实战层面入手:插件增强认证与通信链路加密。 首先,文章详细演示了如何通过Google Authenticator插件为WordPress登录添加双重验证。这类似于谷歌账户的“两步验证”,原理是在密码之外,增加一道由手机App动态生成的验证码,能有效防范密码泄露风险。作者还梳理了其他类似安全插件,如一次性密码、IP锁定等,提供了更全面的选择思路。 其次,更进阶的一步是配置Nginx反向代理下的SSL(HTTPS)登录。作者不仅说明了如何在WordPress配置文件中启用强制SSL,还提供了从生成自签名证书到编写完整Nginx配置的全过程。过程中特别指出了一个典型坑点:Nginx配置不当会导致后台CSS文件的MIME类型错误,并给出了具体的修正配置,这部分对实际操作很有参考价值。 整个方案从认证加固到传输加密,层层递进,解决的是WordPress站点常见的登录安全隐患,过程细节扎实,踩坑点清晰。

IT 2016-03-30 15:57:09 / 累计浏览 2,252

PHP扩展内如何定义类、方法?

这篇讲的是PHP扩展开发中的核心操作——如何在C语言层面定义一个PHP类。作者从PHP类的底层数据结构`zend_class_entry`入手,解释了这个结构体如何容纳类名、方法表、属性以及各类魔术方法。 文章的核心思路是,首先声明一个类入口指针(通常命名为`xxx_ce`),然后在模块初始化阶段(`PHP_MINIT_FUNCTION`)完成类的注册。具体步骤包括:声明方法实现、通过`zend_function_entry`数组绑定方法到类,最后调用`INIT_CLASS_ENTRY`和`zend_register_internal_class`完成类的注册。作者还分享了一个实用技巧:把类入口定义放在文件靠前位置,便于后续代码引用。 整篇文章从底层结构到具体实现代码,完整演示了从零开始在PHP扩展中“创建”一个类的过程。对于需要编写PHP扩展的开发者来说,这清晰地揭示了PHP面向对象特性在底层的实现起点。

IT 2016-03-21 23:50:24 / 累计浏览 3,156

PHP内存耗尽错误分析

这篇讲的是一个让人困惑的PHP内存报错问题:明明报错信息显示“试图分配的内存(1.4MB)小于允许的上限(33.7MB)”,脚本却依然因内存耗尽而崩溃。作者从WordPress插件的实际报错出发,通过设计两组对比实验揭开了谜底。 实验首先确认了PHP的`memory_limit`机制本身工作正常。关键在于第二个实验:当设置15MB内存限制并连续加载两次10MB文件时,报错信息显示的是“试图分配10MB”而非累计的20MB。这揭示了根因——PHP报错时只提示引发最终崩溃的那一次内存申请量,而实际内存消耗是整个脚本运行期间所有操作的累加值。那个看起来“小得多”的数字,仅仅是压垮内存配额的“最后一根稻草”。 因此,直接调高`memory_limit`只是治标之策。更稳妥的方式是通过监控(例如在脚本关闭时记录`memory_get_usage`)来分析站点实际内存消耗模式,从而设定一个既安全又够用的合理阈值。这个案例很好地提醒我们,解读错误日志时,需要理解其背后的累计逻辑,避免被表面数字误导。

IT 2016-03-21 23:49:02 / 累计浏览 2,796

PHP输出缓冲及其应用

这篇讲的是PHP里一个常被忽略但挺实用的特性:输出缓冲。作者从计算机科学里“缓冲”这个基础概念切入,清晰区分了缓冲(写时用)与缓存(读时用)的差异,为理解PHP行为打下了基础。 核心内容围绕PHP的“ob_”系列函数展开。文章用简单代码演示了,为什么即使调用了sleep,浏览器也会一次性显示所有内容——秘密就在于PHP脚本执行完后才一次性发送数据。更实用的是,利用ob_start()、ob_get_contents()等函数,我们能在数据发送前“截获”并修改它,比如实现URL协议替换这种操作。 文章还深入探讨了php.ini中的output_buffering配置。有趣的是,即使关闭它,由于系统层面和浏览器的缓冲存在,也无法简单实现分段输出。最终,作者给出了一个结合flush()函数的可行方案,并延伸到一个实际应用:如何用缓冲机制实现简易的服务器推送(Comet),让内容像“挤牙膏”一样分批到达客户端。这让我们看到了缓冲技术从原理到实战的完整链条。

IT 2016-03-21 13:46:42 / 累计浏览 2,490

WordPress 插件工作原理剖析

这篇文章从一个资深开发者的视角出发,剖析了 WordPress 插件系统背后精巧的实现逻辑。作者首先拆解了插件的发现与管理过程:系统通过扫描特定目录并解析文件头部的注释块来获取插件列表和描述信息。 文章的核心在于揭示插件的“激活”与“工作”机制。它并非简单地将代码塞进系统,而是依托一套优雅的“钩子(Hook)”与“事件(Action)”体系。每个启用的插件在页面加载时都会被包含进来,并利用 `add_action` 等函数将自身功能注册到系统预定义的扩展点(如 `admin_head`、`publish_post`)上。当系统执行到对应环节时(通过 `do_action` 触发),便会调用所有已挂接的插件函数。 这种类似“插销”与“插座”的设计,使得功能扩展变得异常灵活且低侵入。无论是后台界面输出一段文字,还是添加一个管理菜单,插件只需关注自己要挂接的事件,无需修改核心代码。正是这种开放且规范的插件架构,成为了 WordPress 生态能够蓬勃发展的重要基石。

IT 2016-03-18 14:03:25 / 累计浏览 3,617

PHP-FPM中backlog参数变更的一些思考

这篇讲的是PHP-FPM中`backlog`参数两次关键默认值变更背后的技术权衡。作者从2013年PHP 5.5.6将默认值从-1提升至65535说起——当时的初衷是避免因队列满而静默丢弃TCP连接,宁愿报错也不悄悄丢包。但到了2014年,这个值又被调整为511,理由是65535的队列过长,容易导致前端Nginx因等待超时而关闭连接,最终PHP-FPM处理完请求写回时遇到“Broken Pipe”,白白浪费资源。文章指出,调整后的511与Nginx、Redis等常见组件的默认值对齐,更符合实际生产中的连接超时节奏。作者还结合Linux手册中对`listen()`系统调用的说明,梳理了`backlog`队列在不同内核版本中的行为演变,并对比了各方修改补丁的论述,揭示了这个看似简单的参数在高并发场景下对系统吞吐与资源效率的深刻影响。

IT 2016-03-09 23:40:33 / 累计浏览 2,227

php word 转 html

这篇讲的是如何通过PHP调用Windows Office的COM接口,将Word文档高质量地转换为HTML。 作者开宗明义,指出要想获得“完美”的转换效果(尤其是保留复杂排版),依赖微软Office自身的渲染引擎是目前最可靠的路径,而开源方案如LibreOffice往往会有瑕疵。文章的核心在于一个具体的实现方案:启用PHP的COM模块,并通过几行简洁的代码调用Word应用程序的`SaveAs`方法。 实现的关键在于环境配置。文章详细指导了如何检查并启用`com_dotnet`模块,澄清了关于内置模块的常见误区,并提供了具体的`php.ini`配置示例。核心转换函数代码清晰,直接展示了打开、转换、退出的完整流程。 作者同时给出了极具实战意义的提醒:转换生成的HTML源码结构会比较冗余;进程会实际调用`winword.exe`;如果遇到转换卡死,尝试重命名文档再执行。这些细节正是实践中容易踩坑的地方,让这份简短的指南更具参考价值。

IT 2016-03-09 23:38:31 / 累计浏览 2,895

php 去掉 头尾   空格 2种方法

这篇讲的是PHP开发中一个常见但容易踩坑的问题:如何高效去除字符串头尾的空白字符,特别是那些由 生成的特殊空格。文章作者从实际编码困境出发,指出直接使用trim()函数无法处理 这种HTML实体编码的空格,因为它并非标准空白符。 文章核心提供了两种解决方案并做了比较。第一种是使用preg_replace正则替换,通过匹配头尾的 和\s来实现通用去除,作者特别推荐了这种方法。第二种是结合html_entity_decode先解码实体,再用trim配合UTF-8空格字符(chr(0xc2).chr(0xa0))进行去除。 作者进一步指出了编码兼容性的关键细节:第二种trim方法在UTF-8下工作良好,但在GBK或GB2312编码中可能引发乱码,同时也会影响json_encode对中文的处理。因此,文章最终给出了明确建议:在现代Web开发中,推荐统一使用UTF-8编码以避免此类陷阱。整个解析从问题现象到原理,再到具体实现与环境考量,非常贴近实际开发场景。

IT 2016-03-01 23:45:37 / 累计浏览 3,314

PHP 用 curl 读取 HTTP chunked 数据

这篇讲的是在PHP中使用curl处理流式HTTP chunked数据时,遇到的一个实际坑点与解决方法。当需要实时处理服务器推送的每个数据块(比如对接icomet这类服务)时,开发者自然想到使用`CURLOPT_WRITEFUNCTION`回调。但实际会发现,一个逻辑上的chunk数据,回调函数可能会被多次触发,每次只收到大约16k的片段,破坏了数据的完整性。 文章指出了问题的根源:curl底层传输机制导致回调被分割,而非按应用层chunk边界返回。作者给出的解决方案巧妙且实用:在回调函数内维护一个静态缓冲区,将每次收到的片段拼接起来,并以特定分隔符(如`\n`)为界进行分割,确保每次只处理一个完整的应用层数据块。这种方法兼顾了实时性与数据完整性,是处理此类流式接口时一个值得借鉴的细节技巧。

IT 2016-02-16 20:34:00 / 累计浏览 2,136

iphp 框架增加 lazyload 特性

这篇讲的是iphp框架如何通过引入lazyload特性来解决一个常见的性能优化问题。 作者从基类设计的便利性出发,指出现实中的痛点:为了使用方便,基类通常会一次性加载所有可能用到的属性到Context对象中。但这会导致不必要的数据库查询,造成性能浪费。为了解决这个问题,作者实现了`Context::lazyload()`方法。 核心思路非常巧妙:它允许开发者声明一个属性,并绑定一个回调函数。这个属性只有在第一次被实际访问时,才会触发回调函数去执行真正的数据加载(比如查询数据库)。如果整个请求流程中该属性从未被使用,则完全不会产生开销。文章通过一个具体的`AppController`示例清晰地展示了这一机制:`account`属性被延迟加载,只有在子类中需要用户账户信息时,才会去查询,否则不会发生任何数据库请求。 通过这种方式,iphp框架将资源的加载控制权交给了实际的使用场景,在保持代码简洁性的同时,显著提升了应用的响应速度和资源利用效率。

IT 2016-02-06 11:17:20 / 累计浏览 2,952

PHP扩展迁移为兼容PHP7记录

这篇讲的是PHP7扩展开发中,由于内核API的多项变更,在迁移旧版扩展代码时需要处理的兼容性问题。作者详细记录了多个具体函数签名的变化与修正方法。 核心问题在于PHP7对底层进行了重构。很多常用函数如`add_assoc_stringl`、`RETURN_STRINGL`的参数个数减少了;`zval`变量的内存分配方式从堆(使用`ALLOC_INIT_ZVAL`)改为栈(直接声明`zval sarray_l;`)。此外,类型系统也发生了变化,例如布尔类型`IS_BOOL`被拆分为`IS_TRUE`和`IS_FALSE`,相关的宏`Z_BVAL`和`Z_TYPE_PP`也不再存在。 文章还解决了一些编译错误,例如缺少`INT64_MAX`定义时需要手动添加`#include `和相关宏定义;对于字符串,需使用`ZSTR_VAL()`宏将新的`zend_string`类型转换为传统的`char*`;在创建对象时,需要自定义一个`fetch_object`函数来替代旧的`zend_object_store_get_object`。 对于正在迁移或维护PHP扩展的开发者来说,这些来自一线的“踩坑”记录,清晰地指出了代码调整的具体方向,提供了实用的排查和修改参考。

IT 2016-01-27 22:45:22 / 累计浏览 3,608

PHP7扩展开发之hello word

这篇讲的是如何从零开始构建一个PHP7扩展,并让PHP脚本调用其中的函数输出“hello word”。作者以最简功能为例,拆解了扩展开发的核心步骤:从使用 `ext_skel` 工具生成骨架代码,到修改 `config.m4` 配置文件启用扩展,再到编写 C 代码实现 `say` 函数并将其注册到PHP函数表中。 整个过程清晰展示了扩展从代码到加载的完整链条,尤其是 `config.m4` 中注释配置的选择,以及函数注册这一步骤,是理解PHP扩展工作原理的关键。文章最后给出了编译安装和测试验证的完整命令,并附上了源码下载,适合想动手实践PHP底层开发的读者按图索骥。

IT 2015-12-26 20:25:31 / 累计浏览 2,917

白话PHP7扩展开发之创建对象

这篇讲的是在PHP7扩展开发中如何创建一个对象。作者很巧妙地将这个过程比喻为一个孩子从“出生”到“成长”的完整历程,让底层C语言的实现步骤变得直观易懂。 文章将创建对象拆解为几个清晰的阶段:首先定义`zend_class_entry`这个“原型”,相当于“办准生证”;接着用`INIT_CLASS_ENTRY`给对象“取名”并声明方法;然后通过`zend_register_internal_class`完成“上户口”登记。这之后,才是为对象“培养”能力——包括使用`zend_declare_property_*`系列方法定义属性(教授知识),以及通过`zend_function_entry`数组来注册具体的方法(培养行为能力)。 文章的亮点在于,它没有停留在概念阐述,而是紧贴每一个比喻阶段,给出了对应的、可运行的C代码片段。从声明内存属性到定义一个能接收参数的`learn`方法,最终汇聚成一份完整的扩展源代码。文末还附上了PHP端的调用示例和输出结果,让整个流程形成闭环。对于想动手实践的读者,作者直接提供了完整的源代码下载链接。

IT 2015-12-13 22:13:09 / 累计浏览 4,680

让PHP7达到最高性能的几个Tips

这篇讲的是PHP 7性能调优的实战经验。作者(鸟哥)指出,尽管PHP 7性能相比前代已有大幅提升,但通过一系列精准的配置和编译优化,还能进一步榨取其潜力。文章提供了五个具体可操作的Tips。 核心建议包括:**务必启用Zend Opcache**(PHP 7未启用时已比PHP 5.6启用后快,但开启后仍有收益);**使用GCC 4.8以上版本编译**,可获得约5%的性能提升;**配置HugePage**以减少TLB Miss;以及开启**Opcache File Cache**(实验性)和针对特定项目使用**PGO(Profile Guided Optimization)** 进行定制化编译优化。 这些方案从基础配置到高阶编译技巧层层递进,作者通过WordPress等实例说明了PGO等优化如何为特定应用带来量身定制的性能提升,为追求极致PHP性能的开发者提供了清晰的技术路线。