See nmudiff... On Tue, Aug 19, 2025 at 1:25 AM Leandro Cunha <[email protected]> wrote: > > Control: tags 1110464 + patch > Control: tags 1110464 + pending > > Dear maintainer, > > I've prepared an NMU for libphp-adodb (versioned as 5.22.10-0.1) and > uploaded it to DELAYED/2. Please feel free to tell me if I > should cancel it. > > Regards.
diffstat for libphp-adodb-5.22.9 libphp-adodb-5.22.10
adodb.inc.php | 2 debian/changelog | 7 + docs/changelog.md | 18 +++ drivers/adodb-sqlite3.inc.php | 209 +++++++++++++++--------------------------- 4 files changed, 105 insertions(+), 131 deletions(-) diff -Nru libphp-adodb-5.22.9/adodb.inc.php libphp-adodb-5.22.10/adodb.inc.php --- libphp-adodb-5.22.9/adodb.inc.php 2025-05-01 08:49:24.000000000 -0300 +++ libphp-adodb-5.22.10/adodb.inc.php 2025-08-03 13:20:39.000000000 -0300 @@ -198,7 +198,7 @@ /** * ADODB version as a string. */ - $ADODB_vers = 'v5.22.9 2025-05-01'; + $ADODB_vers = 'v5.22.10 2025-08-03'; /** * Determines whether recordset->RecordCount() is used. diff -Nru libphp-adodb-5.22.9/debian/changelog libphp-adodb-5.22.10/debian/changelog --- libphp-adodb-5.22.9/debian/changelog 2025-05-02 10:48:03.000000000 -0300 +++ libphp-adodb-5.22.10/debian/changelog 2025-08-18 23:30:17.000000000 -0300 @@ -1,3 +1,10 @@ +libphp-adodb (5.22.10-0.1) unstable; urgency=high + + * Non-maintainer upload. + * New upstream version 5.22.10 (Closes: #1110464, CVE-2025-54119) + + -- Leandro Cunha <[email protected]> Mon, 18 Aug 2025 23:30:17 -0300 + libphp-adodb (5.22.9-0.1) unstable; urgency=high * Non-maintainer upload. diff -Nru libphp-adodb-5.22.9/docs/changelog.md libphp-adodb-5.22.10/docs/changelog.md --- libphp-adodb-5.22.9/docs/changelog.md 2025-05-01 08:49:24.000000000 -0300 +++ libphp-adodb-5.22.10/docs/changelog.md 2025-08-03 13:20:39.000000000 -0300 @@ -14,6 +14,23 @@ -------------------------------------------------------------------------------- +## [5.22.10] - 2025-08-03 + +### Security + +- pgsql: SQL injection in pg_insert_id() method (CVE-2025-54119) + [#1083](https://github.com/ADOdb/ADOdb/issues/1083) + +### Fixed + +- sqlite: metaForeignKeys() returns nothing when FOREIGN keyword is in lower case + [#1078](https://github.com/ADOdb/ADOdb/issues/1078) +- sqlite: metaForeignKeys() does not support column-levels constraints + [#1079](https://github.com/ADOdb/ADOdb/issues/1079) +- sqlite: metaForeignKeys() composite foreign keys are not supported + [#1080](https://github.com/ADOdb/ADOdb/issues/1080) + + ## [5.22.9] - 2025-05-01 ### Security @@ -1490,6 +1507,7 @@ - Adodb5 version,more error checking code now will use exceptions if available. +[5.22.10]: https://github.com/adodb/adodb/compare/v5.22.9...v5.22.10 [5.22.9]: https://github.com/adodb/adodb/compare/v5.22.8...v5.22.9 [5.22.8]: https://github.com/adodb/adodb/compare/v5.22.7...v5.22.8 [5.22.7]: https://github.com/adodb/adodb/compare/v5.22.6...v5.22.7 diff -Nru libphp-adodb-5.22.9/drivers/adodb-sqlite3.inc.php libphp-adodb-5.22.10/drivers/adodb-sqlite3.inc.php --- libphp-adodb-5.22.9/drivers/adodb-sqlite3.inc.php 2025-05-01 08:49:24.000000000 -0300 +++ libphp-adodb-5.22.10/drivers/adodb-sqlite3.inc.php 2025-08-03 13:20:39.000000000 -0300 @@ -19,6 +19,9 @@ * * @copyright 2000-2013 John Lim * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community + * + * @TODO Duplicate code is due to the legacy sqlite driver - delete this when removing the old driver + * @noinspection DuplicatedCode */ // security - hide paths @@ -95,7 +98,6 @@ { $fieldobj = $t; $t = $fieldobj->type; - $len = $fieldobj->max_length; } $t = strtoupper($t); @@ -162,28 +164,30 @@ function MetaColumns($table, $normalize=true) { global $ADODB_FETCH_MODE; - $false = false; $save = $ADODB_FETCH_MODE; $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; if ($this->fetchMode !== false) { $savem = $this->SetFetchMode(false); } - $rs = $this->Execute("PRAGMA table_info('$table')"); + + $rs = $this->execute("PRAGMA table_info(?)", array($table)); + if (isset($savem)) { $this->SetFetchMode($savem); } + if (!$rs) { $ADODB_FETCH_MODE = $save; - return $false; + return false; } + $arr = array(); while ($r = $rs->FetchRow()) { - $type = explode('(',$r['type']); + $type = explode('(', $r['type']); $size = ''; - if (sizeof($type)==2) { - $size = trim($type[1],')'); + if (sizeof($type) == 2) { + $size = trim($type[1], ')'); } - $fn = strtoupper($r['name']); $fld = new ADOFieldObject; $fld->name = $r['name']; $fld->type = $type[0]; @@ -192,7 +196,7 @@ $fld->default_value = $r['dflt_value']; $fld->scale = 0; if (isset($r['pk']) && $r['pk']) { - $fld->primary_key=1; + $fld->primary_key = 1; } if ($save == ADODB_FETCH_NUM) { $arr[] = $fld; @@ -207,58 +211,44 @@ public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false) { - global $ADODB_FETCH_MODE; - if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC - || $this->fetchMode == ADODB_FETCH_ASSOC) - $associative = true; + global $ADODB_FETCH_MODE; + if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) { + $associative = true; + } - /* - * Read sqlite master to find foreign keys - */ + // Read sqlite master to find foreign keys $sql = "SELECT sql - FROM ( - SELECT sql sql, type type, tbl_name tbl_name, name name - FROM sqlite_master - ) - WHERE type != 'meta' - AND sql NOTNULL - AND LOWER(name) ='" . strtolower($table) . "'"; - - $tableSql = $this->getOne($sql); + FROM sqlite_master + WHERE sql NOTNULL + AND LOWER(name) = ?"; + $tableSql = $this->getOne($sql, [strtolower($table)]); + + // Regex will identify foreign keys in both column and table constraints + // Reference: https://sqlite.org/syntax/foreign-key-clause.html + // Subpatterns: 1/2 = source columns; 3 = parent table; 4 = parent columns. + preg_match_all( + '/[(,]\s*(?:FOREIGN\s+KEY\s*\(([^)]+)\)|(\w+).*?)\s*REFERENCES\s+(\w+|"[^"]+")\(([^)]+)\)/i', + $tableSql, + $fkeyMatches, + PREG_SET_ORDER + ); $fkeyList = array(); - $ylist = preg_split("/,+/",$tableSql); - foreach ($ylist as $y) - { - if (!preg_match('/FOREIGN/',$y)) - continue; + foreach ($fkeyMatches as $fkey) { + $src_col = $fkey[1] ?: $fkey[2]; + $ref_table = $upper ? strtoupper($fkey[3]) : $fkey[3]; + $ref_col = $fkey[4]; - $matches = false; - preg_match_all('/\((.+?)\)/i',$y,$matches); - $tmatches = false; - preg_match_all('/REFERENCES (.+?)\(/i',$y,$tmatches); - - if ($associative) - { - if (!isset($fkeyList[$tmatches[1][0]])) - $fkeyList[$tmatches[1][0]] = array(); - $fkeyList[$tmatches[1][0]][$matches[1][0]] = $matches[1][1]; + if ($associative) { + $fkeyList[$ref_table][$src_col] = $ref_col; + } else { + $fkeyList[$ref_table][] = $src_col . '=' . $ref_col; } - else - $fkeyList[$tmatches[1][0]][] = $matches[1][0] . '=' . $matches[1][1]; } - if ($associative) - { - if ($upper) - $fkeyList = array_change_key_case($fkeyList,CASE_UPPER); - else - $fkeyList = array_change_key_case($fkeyList,CASE_LOWER); - } return $fkeyList; } - function _init($parentDriver) { $parentDriver->hasTransactions = false; @@ -371,24 +361,24 @@ */ var $_genSeqSQL = "create table %s (id integer)"; - function GenID($seq='adodbseq',$start=1) + function GenID($seqname='adodbseq', $startID=1) { // if you have to modify the parameter below, your database is overloaded, // or you need to implement generation of id's yourself! $MAXLOOPS = 100; //$this->debug=1; while (--$MAXLOOPS>=0) { - @($num = $this->GetOne("select id from $seq")); + @($num = $this->GetOne("select id from $seqname")); if ($num === false) { - $this->Execute(sprintf($this->_genSeqSQL ,$seq)); - $start -= 1; + $this->Execute(sprintf($this->_genSeqSQL ,$seqname)); + $startID -= 1; $num = '0'; - $ok = $this->Execute("insert into $seq values($start)"); + $ok = $this->Execute("insert into $seqname values($startID)"); if (!$ok) { return false; } } - $this->Execute("update $seq set id=id+1 where id=$num"); + $this->Execute("update $seqname set id=id+1 where id=$num"); if ($this->affected_rows() > 0) { $num += 1; @@ -397,7 +387,7 @@ } } if ($fn = $this->raiseErrorFn) { - $fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num); + $fn($this->databaseType, 'GENID', -32000, "Unable to generate unique id after $MAXLOOPS attempts", $seqname, $num); } return false; } @@ -430,111 +420,70 @@ return $this->_connectionID->close(); } - function metaIndexes($table, $primary = FALSE, $owner = false) + function metaIndexes($table, $primary = false, $owner = false) { - $false = false; // save old fetch mode global $ADODB_FETCH_MODE; $save = $ADODB_FETCH_MODE; $ADODB_FETCH_MODE = ADODB_FETCH_NUM; - if ($this->fetchMode !== FALSE) { - $savem = $this->SetFetchMode(FALSE); - } - - $pragmaData = array(); - - /* - * If we want the primary key, we must extract - * it from the table statement, and the pragma - */ - if ($primary) - { - $sql = sprintf('PRAGMA table_info([%s]);', - strtolower($table) - ); - $pragmaData = $this->getAll($sql); + if ($this->fetchMode !== false) { + $savem = $this->SetFetchMode(false); } - /* - * Exclude the empty entry for the primary index - */ - $sqlite = "SELECT name,sql - FROM sqlite_master - WHERE type='index' - AND sql IS NOT NULL - AND LOWER(tbl_name)='%s'"; - - $SQL = sprintf($sqlite, - strtolower($table) - ); + $table = strtolower($table); - $rs = $this->execute($SQL); + // Exclude the empty entry for the primary index + $sql = "SELECT name,sql + FROM sqlite_master + WHERE type='index' + AND sql IS NOT NULL + AND LOWER(tbl_name)=?"; + $rs = $this->execute($sql, [$table]); if (!is_object($rs)) { if (isset($savem)) { $this->SetFetchMode($savem); } $ADODB_FETCH_MODE = $save; - return $false; + return false; } - $indexes = array (); - - while ($row = $rs->FetchRow()) - { + $indexes = array(); + while ($row = $rs->FetchRow()) { if (!isset($indexes[$row[0]])) { $indexes[$row[0]] = array( - 'unique' => preg_match("/unique/i",$row[1]), - 'columns' => array() + 'unique' => preg_match("/unique/i", $row[1]), ); } - /** - * The index elements appear in the SQL statement - * in cols[1] between parentheses - * e.g CREATE UNIQUE INDEX ware_0 ON warehouse (org,warehouse) - */ - preg_match_all('/\((.*)\)/',$row[1],$indexExpression); - $indexes[$row[0]]['columns'] = array_map('trim',explode(',',$indexExpression[1][0])); + // Index elements appear in the SQL statement in cols[1] between parentheses + // e.g CREATE UNIQUE INDEX ware_0 ON warehouse (org,warehouse) + preg_match_all('/\((.*)\)/', $row[1], $indexExpression); + $indexes[$row[0]]['columns'] = array_map('trim', explode(',', $indexExpression[1][0])); } - if (isset($savem)) { - $this->SetFetchMode($savem); - $ADODB_FETCH_MODE = $save; - } - - /* - * If we want primary, add it here - */ + // If we want the primary key, we must extract it from the pragma if ($primary){ - - /* - * Check the previously retrieved pragma to search - * with a closure - */ - + $pragmaData = $this->getAll('PRAGMA table_info(?);', [$table]); $pkIndexData = array('unique'=>1,'columns'=>array()); $pkCallBack = function ($value, $key) use (&$pkIndexData) { - - /* - * As we iterate the elements check for pk index and sort - */ - if ($value[5] > 0) - { + // As we iterate the elements check for pk index + if ($value[5] > 0) { $pkIndexData['columns'][$value[5]] = strtolower($value[1]); - ksort($pkIndexData['columns']); } }; + array_walk($pragmaData, $pkCallBack); - array_walk($pragmaData,$pkCallBack); - - /* - * If we found no columns, there is no - * primary index - */ - if (count($pkIndexData['columns']) > 0) + // If we found no columns, there is no primary index + if (count($pkIndexData['columns']) > 0) { $indexes['PRIMARY'] = $pkIndexData; + } + } + + if (isset($savem)) { + $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; } return $indexes;

