You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级至PHP8.1时gmdate报类型错误,RECTOR未检测该问题

PHP8.1升级后gmdate函数报错:Unsupported operand types: string + float

升级CMS系统到PHP8.1时,触发Unsupported operand types: string + float错误,该错误与gmdate函数的时间戳参数计算有关。原代码在PHP7.4环境下可正常运行,多次使用RECTOR工具未检测到问题。

问题代码

if ( $userdata['user_id'] != ANONYMOUS )
{
    switch ( $userdata['user_time_mode'] )
    {
        case MANUAL_DST:
            $dst_sec = $userdata['user_dst_time_lag'] * 60;
            return ( !empty($translate) ) ? strtr(gmdate($format, $gmepoch + (3600 * $tz) + $dst_sec), $translate) : gmdate($format, $gmepoch + (3600 * $tz) + $dst_sec);
            break;
        case SERVER_SWITCH:
            if (!empty($gmepoch) && is_long($gmepoch)) {
                $dst_sec = date('I', $gmepoch) * $userdata['user_dst_time_lag'] * 60;
            } else {
                $dst_sec = date('I') * $userdata['user_dst_time_lag'] * 60;
            }
            return ( !empty($translate) ) ? strtr(gmdate($format, $gmepoch + (3600 * $tz) + $dst_sec), $translate) : gmdate($format, $gmepoch + (3600 * $tz) + $dst_sec);
            break;
        case FULL_SERVER:
            return ( !empty($translate) ) ? strtr(date($format, $gmepoch), $translate) : date($format, $gmepoch);
            break;
        case SERVER_PC:
            if ( isset($pc_dateTime['pc_timezoneOffset']) )
            {
                $tzo_sec = $pc_dateTime['pc_timezoneOffset'];
            } else
            {
                $user_pc_timeOffsets = explode("/", (string) $userdata['user_pc_timeOffsets']);
                $tzo_sec = $user_pc_timeOffsets[0];
            }
            return ( !empty($translate) ) ? strtr(gmdate($format, $gmepoch + $tzo_sec), $translate) : gmdate($format, $gmepoch + $tzo_sec);
            break;
        case FULL_PC:
            if ( isset($pc_dateTime['pc_timeOffset']) )
            {
                $tzo_sec = $pc_dateTime['pc_timeOffset'];
            } else
            {
                $user_pc_timeOffsets = explode("/", (string) $userdata['user_pc_timeOffsets']);
                $tzo_sec = $user_pc_timeOffsets[1] ?? '';
            }
            return ( !empty($translate) ) ? strtr(gmdate($format, $gmepoch + $tzo_sec), $translate) : gmdate($format, $gmepoch + $tzo_sec);
            break;
        default:
            return ( !empty($translate) ) ? strtr(gmdate($format, $gmepoch + (3600 * $tz)), $translate) : gmdate($format, $gmepoch + (3600 * $tz));
            break;
    }
} else
{
    switch ( $board_config['default_time_mode'] )
    {
        case MANUAL_DST:
            $dst_sec = $board_config['default_dst_time_lag'] * 60;
            return ( !empty($translate) ) ? strtr(@gmdate($format, $gmepoch + (3600 * $tz) + $dst_sec), $translate) : @gmdate($format, $gmepoch + (3600 * $tz) + $dst_sec);
            break;
        case SERVER_SWITCH:
            if (!empty($gmepoch) && is_long($gmepoch)) {
                $dst_sec = date('I', $gmepoch) * $userdata['user_dst_time_lag'] * 60;
            } else {
                $dst_sec = date('I') * $userdata['user_dst_time_lag'] * 60;
            }
            return ( !empty($translate) ) ? strtr(@gmdate($format, $gmepoch + (3600 * $tz) + $dst_sec), $translate) : @gmdate($format, $gmepoch + (3600 * $tz) + $dst_sec);
            break;
        case FULL_SERVER:
            return ( !empty($translate) ) ? strtr(@date($format, $gmepoch), $translate) : @date($format, $gmepoch);
            break;
        case SERVER_PC:
            if ( isset($pc_dateTime['pc_timezoneOffset']) )
            {
                $tzo_sec = $pc_dateTime['pc_timezoneOffset'];
            } else
            {
                $tzo_sec = 0;
            }
            return ( !empty($translate) ) ? strtr(@gmdate($format, $gmepoch + $tzo_sec), $translate) : @gmdate($format, $gmepoch + $tzo_sec);
            break;
        case FULL_PC:
            if ( isset($pc_dateTime['pc_timeOffset']) )
            {
                $tzo_sec = $pc_dateTime['pc_timeOffset'];
            } else
            {
                $tzo_sec = 0;
            }
            return ( !empty($translate) ) ? strtr(@gmdate($format, $gmepoch + $tzo_sec), $translate) : @gmdate($format, $gmepoch + $tzo_sec);
            break;
        default:
            return ( !empty($translate) ) ? strtr(@gmdate($format, $gmepoch + (3600 * $tz)), $translate) : @gmdate($format, $gmepoch + (3600 * $tz));
            break;
    }
}

错误原因

PHP8.0及以上版本对类型运算的严格性显著提升,不再自动将非数值字符串隐式转换为数字。原代码中存在多个风险点:

  • FULL_PC分支中,当user_pc_timeOffsets拆分后无对应值时,$tzo_sec默认赋值为空字符串'',与数字类型的$gmepoch相加触发类型错误。
  • 从$userdata、$board_config读取的配置字段(如user_dst_time_lag、user_pc_timeOffsets拆分后的值)可能为字符串类型,PHP7.4会自动转换为数字,PHP8.1则直接报错。
  • is_long()函数已被废弃,PHP8.0+应使用is_int()或is_integer(),虽然这不是直接报错原因,但会导致逻辑判断异常。

修复方案

  1. 强制转换数值类型:对所有参与算术运算的变量,使用(int)或intval()强制转换为整数类型,确保运算时类型统一。
  2. 修正默认值:将空字符串默认值改为0,避免字符串与数字相加。
  3. 替换废弃函数:将is_long()替换为is_int(),适配PHP8+的类型判断。

修改后的代码

if ( $userdata['user_id'] != ANONYMOUS )
{
    switch ( $userdata['user_time_mode'] )
    {
        case MANUAL_DST:
            // 强制转换为整数
            $dst_sec = (int)$userdata['user_dst_time_lag'] * 60;
            return ( !empty($translate) ) ? strtr(gmdate($format, $gmepoch + (3600 * (int)$tz) + $dst_sec), $translate) : gmdate($format, $gmepoch + (3600 * (int)$tz) + $dst_sec);
            break;
        case SERVER_SWITCH:
            if (!empty($gmepoch) && is_int($gmepoch)) { // 替换is_long为is_int
                $dst_sec = date('I', $gmepoch) * (int)$userdata['user_dst_time_lag'] * 60;
            } else {
                $dst_sec = date('I') * (int)$userdata['user_dst_time_lag'] * 60;
            }
            return ( !empty($translate) ) ? strtr(gmdate($format, $gmepoch + (3600 * (int)$tz) + $dst_sec), $translate) : gmdate($format, $gmepoch + (3600 * (int)$tz) + $dst_sec);
            break;
        case FULL_SERVER:
            return ( !empty($translate) ) ? strtr(date($format, $gmepoch), $translate) : date($format, $gmepoch);
            break;
        case SERVER_PC:
            if ( isset($pc_dateTime['pc_timezoneOffset']) )
            {
                $tzo_sec = (int)$pc_dateTime['pc_timezoneOffset'];
            } else
            {
                $user_pc_timeOffsets = explode("/", (string) $userdata['user_pc_timeOffsets']);
                // 确保转换为整数,避免空字符串
                $tzo_sec = isset($user_pc_timeOffsets[0]) ? (int)$user_pc_timeOffsets[0] : 0;
            }
            return ( !empty($translate) ) ? strtr(gmdate($format, $gmepoch + $tzo_sec), $translate) : gmdate($format, $gmepoch + $tzo_sec);
            break;
        case FULL_PC:
            if ( isset($pc_dateTime['pc_timeOffset']) )
            {
                $tzo_sec = (int)$pc_dateTime['pc_timeOffset'];
            } else
            {
                $user_pc_timeOffsets = explode("/", (string) $userdata['user_pc_timeOffsets']);
                // 默认值改为0,而非空字符串
                $tzo_sec = $user_pc_timeOffsets[1] ?? 0;
                // 强制转换为整数
                $tzo_sec = (int)$tzo_sec;
            }
            return ( !empty($translate) ) ? strtr(gmdate($format, $gmepoch + $tzo_sec), $translate) : gmdate($format, $gmepoch + $tzo_sec);
            break;
        default:
            return ( !empty($translate) ) ? strtr(gmdate($format, $gmepoch + (3600 * (int)$tz)), $translate) : gmdate($format, $gmepoch + (3600 * (int)$tz));
            break;
    }
} else
{
    switch ( $board_config['default_time_mode'] )
    {
        case MANUAL_DST:
            $dst_sec = (int)$board_config['default_dst_time_lag'] * 60;
            return ( !empty($translate) ) ? strtr(@gmdate($format, $gmepoch + (3600 * (int)$tz) + $dst_sec), $translate) : @gmdate($format, $gmepoch + (3600 * (int)$tz) + $dst_sec);
            break;
        case SERVER_SWITCH:
            if (!empty($gmepoch) && is_int($gmepoch)) { // 替换is_long为is_int
                $dst_sec = date('I', $gmepoch) * (int)$userdata['user_dst_time_lag'] * 60;
            } else {
                $dst_sec = date('I') * (int)$userdata['user_dst_time_lag'] * 60;
            }
            return ( !empty($translate) ) ? strtr(@gmdate($format, $gmepoch + (3600 * (int)$tz) + $dst_sec), $translate) : @gmdate($format, $gmepoch + (3600 * (int)$tz) + $dst_sec);
            break;
        case FULL_SERVER:
            return ( !empty($translate) ) ? strtr(@date($format, $gmepoch), $translate) : @date($format, $gmepoch);
            break;
        case SERVER_PC:
            if ( isset($pc_dateTime['pc_timezoneOffset']) )
            {
                $tzo_sec = (int)$pc_dateTime['pc_timezoneOffset'];
            } else
            {
                $tzo_sec = 0;
            }
            return ( !empty($translate) ) ? strtr(@gmdate($format, $gmepoch + $tzo_sec), $translate) : @gmdate($format, $gmepoch + $tzo_sec);
            break;
        case FULL_PC:
            if ( isset($pc_dateTime['pc_timeOffset']) )
            {
                $tzo_sec = (int)$pc_dateTime['pc_timeOffset'];
            } else
            {
                $tzo_sec = 0;
            }
            return ( !empty($translate) ) ? strtr(@gmdate($format, $gmepoch + $tzo_sec), $translate) : @gmdate($format, $gmepoch + $tzo_sec);
            break;
        default:
            return ( !empty($translate) ) ? strtr(@gmdate($format, $gmepoch + (3600 * (int)$tz)), $translate) : @gmdate($format, $gmepoch + (3600 * (int)$tz));
            break;
    }
}

内容的提问来源于stack exchange,提问作者Ernest Allen Buffington

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 15:00:49