Skip to content

preg_split() deprecation warning in _parseParameters() when preg_replace() returns null in _stripQuoted() #520

@ndebarnot

Description

@ndebarnot

Description

In PHP 8.x, a deprecation warning is triggered in Zend_Db_Statement::_parseParameters() at line 140:

preg_split(): Passing null to parameter #2 ($subject) of type string is deprecated

Root Cause

The issue originates in Zend_Db_Statement::_stripQuoted(). When processing large SQL queries (especially those with many values in an IN (?) clause), the preg_replace() calls at lines 194, 200, and 212 can fail due to PCRE backtrack limit being exceeded.

When preg_replace() fails, it returns null instead of a string. This null value is then passed to preg_split() in _parseParameters(), triggering the deprecation warning.

Code References

_stripQuoted() - lines 194, 200, 212:

$sql = preg_replace("/$q([^$q{$escapeChar}]*|($qe)*)*$q/s", '', (string) $sql);
// ...
$sql = preg_replace("/\"(\\\\\"|[^\"])*\"/Us", '', (string) $sql);
// ...
$sql = preg_replace("/$d($de|\\\\{2}|[^$d])*$d/Us", '', (string) $sql);
_parseParameters() - line 140:

$this->_sqlSplit = preg_split('/(\?|\:[a-zA-Z0-9_]+)/',
    $sql, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);

Suggested Fix

Check for null return values from preg_replace() and keep the original SQL string in that case:

protected function _stripQuoted($sql)
{
    $sql = (string) $sql;

    $q = $this->_adapter->quote('a');
    $q = $q[0];
    $qe = $this->_adapter->quote($q);
    $qe = substr($qe, 1, 2);
    $qe = preg_quote($qe);
    $escapeChar = substr($qe, 0, 1);

    if (!empty($q)) {
        $escapeChar = preg_quote($escapeChar);
        $result = preg_replace("/$q([^$q{$escapeChar}]*|($qe)*)*$q/s", '', $sql);
        if ($result !== null) {
            $sql = $result;
        }
    }

    $result = preg_replace("/\"(\\\\\"|[^\"])*\"/Us", '', $sql);
    if ($result !== null) {
        $sql = $result;
    }

    $d = $this->_adapter->quoteIdentifier('a');
    $d = $d[0];
    $de = $this->_adapter->quoteIdentifier($d);
    $de = substr($de, 1, 2);
    $de = preg_quote($de);

    $result = preg_replace("/$d($de|\\\\{2}|[^$d])*$d/Us", '', $sql);
    if ($result !== null) {
        $sql = $result;
    }

    return $sql;
}

Environment

PHP version: 8.2.30
zf1-future version: latest

Current Workaround

Temporarily increasing pcre.backtrack_limit before executing queries:

$previousLimit = ini_get('pcre.backtrack_limit');
ini_set('pcre.backtrack_limit', 10000000);
// execute query
ini_set('pcre.backtrack_limit', $previousLimit);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions