因为NexusPHP较早就停止维护,所以官方源码基本只能停留在PHP5.3-5.6版本使用,无法使用PHP7,然而随着PHP5.x(甚至PHP7.0)已经完全停止维护,势必有必要将NPHP推进到PHP7.x。然而主要阻碍这种推进的原因是因为:
- Mysql库在PHP7中不存在,必须更换到 Mysqli库。
- Memcache库在PHP7出现兼容性问题,需要调整连接代码,或更换到 Memcached库 或者 Redis库。
- Github或其他开源代码库中没有PHP7版本的NexusPHP。
基于以上原因,本文给出相关方法实现:
- 使用psr-4相关方法,加载
/classes
目录中库文件。 - 替换Cache组件的后端为Redis。
- 使用单例模式的Mysqli wrapper组件替换原Mysql库相关方法,将Mysql连接改成只有第一次执行query或相关方法时才连接,避免NPHP遭受CC攻击时,大量连接请求直接拖垮Mysql导致服务不可用;并提供stmt方法支持,可以通过更换写法的形式组件将NPHP的real_query实现改成stmt实现,防止SQL注入。
- 移除PHP 7中不存在的相关方法,例如
get_magic_quotes_gpc
等。
以下讲解和代码patch均基于本人fork的官方源码 Rhilip/NexusPHP(v1.5.beta5.20120707),不提供除本文外的任何形式的说明以及免费讲解。
具体请见:Rhilip/NexusPHP#2
请注意:
- 可以使用该库 MySQL wrapper for MySQLi ,快速提供mysqli库在mysql方法名下的支持,但因为其过于简单,且无法使用到stmt特性,故本文不做额外说明。
- 部分小细节,比如
$arr[id]
,PHP 4 style constructors 等未在此步骤中体现。你应该参照PHP官方升级教程 Migrating from PHP 5.6.x to PHP 7.0.x 或使用 PHPStan 等静态工具进行进一步的检查。
详细步骤说明
在
composer.json
中注册namespace,之后使用composer dumpautoload
刷新依赖,假定此处的命名空间为NexusPHP
。(@744d83d)"autoload": { "psr-4": { "NexusPHP\\": "classes/" } }
- 修改原
classes/
目录下的组件,并优化使用这些组件的相关PHP脚本。(@684ed5a)(注意,我们这里会全局使用类似\NexusPHP\Components\Cache
的形式调用这些组件,而不是用use声明。因为这样可以最快速的进行全局替换) - 将Cache组件的后端改为Redis,并使用魔法方法
__call()
封装的形式提供Redis原生方法支持。(@1605687) - 构造Database组件,并提供原有mysql相关方法。(@4da4f84)
使用全局替换的形式对原mysql_方法进行替换(@35dc3ea),替换规则如下(注意替换顺序从下到上不要错误):
# 以下启用Match模式 mysql_query( -> \NexusPHP\Components\Database::query( mysql_real_escape_string( -> \NexusPHP\Components\Database::real_escape_string( mysql_error() -> \NexusPHP\Components\Database::error() mysql_affected_rows() -> \NexusPHP\Components\Database::affected_rows() mysql_errno() -> \NexusPHP\Components\Database::errno() mysql_insert_id() -> \NexusPHP\Components\Database::insert_id() mysql_fetch_array( -> mysqli_fetch_array( mysql_fetch_assoc( -> mysqli_fetch_assoc( mysql_fetch_row( -> mysqli_fetch_row( mysql_num_rows( -> mysqli_num_rows( mysql_connect( -> mysqli_connect( mysql_free_result( -> mysqli_free_result( sqlesc( -> \NexusPHP\Components\Database::escape( sql_query( -> \NexusPHP\Components\Database::query( get_row_count( -> \NexusPHP\Components\Database::count( get_row_sum( -> \NexusPHP\Components\Database::sum( get_single_value( -> \NexusPHP\Components\Database::single( # 以下启用Match,Regex模式 array_map\(['"]sqlesc['"], ?(array\(.+?\)|\$.+?)?\) -> \\NexusPHP\\Components\\Database::escape($1)
并修改dbconn(),仅保留其中userlogin相关部分,移除散落的 dbconn_announce(), sql_query(), sqlesc(), get_row_count(),get_row_sum(), get_single_value()
方法定义。注意,除dbconn_announce() 方法之外,其他函数及变量的定义可能在之前的全局替换中被修改了,请定位到其原先位置然后删除。
然后同样使用全局搜索,检查是否还有遗漏mysql_方法未清理完成,剩下的应该只有lang以及settings里面的一些变量定义,这些可以不管。
- 移除在
inculde/core.php
中定义的全局数组$query_name
,并使用\NexusPHP\Components\Database::getQueryHistory()
方法进行替换。到这里,我们的NPHP基本已经可以在PHP7+Redis环境中运行了。(@118fcad) 打开
include/core.php
中的debug方法,并移除一些PHP7中已经不兼容的一些方法,比如get_magic_quotes_gpc()。除此以外,NPHP还有类似$arr[id]
的一些不规范写法,在打开debug之后你可以看到notice的提示,你需要进行相关修正。(@17ba5c4)error_reporting(E_ALL); ini_set('display_errors', 1);
使用stmt方法进行优化,防止SQL注入(此处仅作示例) (@f9ddf9a)
function write_log($text, $security = "normal") { \NexusPHP\Components\Database::query("INSERT INTO sitelog (added, txt, security_level) VALUES(NOW(), ?, ?)", [$text, $security]) or sqlerr(__FILE__, __LINE__); }
hi,
Interesting project, but don't you think that the number of dependency (RidPT) risks discouraging a lot of people?
While other scripts do the job with less prerequisites and therefore easily installable, perhaps not as optimized but which works relatively well.
I don't think so. Though you see a lot of pre-requests, The only extra needed is the Swoole Extenstion for PHP. And other pre-request software like Redis or Memcached, MySQL is needed for every Private Tracker Software.
functions.php中的format_comment和format_url模式中使用了php7已废弃的正则匹配模式PREG_REPLACE_EVAL,可参考https://www.php.net/manual/zh/reference.pcre.pattern.modifiers.php。应该将/正则/e这种替换成不包含e模式的。否则就无法展示编辑的内容了,例如首页的最新消息(学习中,刚看到这里
是的,这一块没有在文章中体现,应该做补充。此外,替换的Database组件在实际应用过程中,也发现了一些问题,由于个人和站点原因,相关commit并没有体现在公开repo中。
tjupt 就是用的php7
R酱,有研究怎样升级到php8吗?期待教程!
PHP8并没有实质性更新,能升级到PHP7的基本可以无痛升级到PHP8