Skip to content
Merged
2 changes: 1 addition & 1 deletion Core/DbQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ public function orderBy(string $field, string $order = 'ASC'): self
// permitimos LOWER(), UPPER(), CAST() y COALESCE()
if (preg_match('/^(LOWER|UPPER)\([a-zA-Z0-9_.]+\)$/i', $field) ||
preg_match('/^CAST\([a-zA-Z0-9_.]+ AS [a-zA-Z0-9_ ]+\)$/i', $field) ||
preg_match('/^COALESCE\([a-zA-Z0-9_., ]+\)$/i', $field)) {
preg_match("/^COALESCE\([a-zA-Z0-9_.]+\s*,\s*(?:'[^']*'|-?\d+(?:\.\d+)?)\)$/i", $field)) {
$this->orderBy[] = $field . ' ' . $order;
return $this;
}
Expand Down
14 changes: 8 additions & 6 deletions Core/Lib/ReceiptGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -265,16 +265,17 @@ protected function updateCustomerReceipts($invoice): bool

// calculate outstanding amount
$amount = $this->getOutstandingAmount($receipts, $invoice->total);
if (empty($amount)) {
return true;
}

// calculate new receipt number
$newNum = 1;
foreach ($receipts as $receipt) {
// try to update open receipts
if ($receipt->pagado === false) {
if (empty($amount) && $receipt->coddivisa === $invoice->coddivisa) {
continue;
}
$receipt->importe += $amount;
$receipt->coddivisa = $invoice->coddivisa;
return $receipt->save();
}

Expand All @@ -299,16 +300,17 @@ protected function updateSupplierReceipts($invoice): bool

// calculate outstanding amount
$amount = $this->getOutstandingAmount($receipts, $invoice->total);
if (empty($amount)) {
return true;
}

// calculate new receipt number
$newNum = 1;
foreach ($receipts as $receipt) {
// try to update open receipts
if ($receipt->pagado === false) {
if (empty($amount) && $receipt->coddivisa === $invoice->coddivisa) {
continue;
}
$receipt->importe += $amount;
$receipt->coddivisa = $invoice->coddivisa;
return $receipt->save();
}

Expand Down
39 changes: 32 additions & 7 deletions Core/Model/CodeModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -272,26 +272,51 @@ public static function setLimit(int $newLimit): void
/**
* Valída que un nombre de campo sea seguro para usar en consultas SQL.
* Solo permite letras, números, guiones bajos y puntos (para campos con alias de tabla).
* También permite el uso de las funciones lower() y upper().
* También permite el uso de algunas funciones SQL concretamente:
* - lower() y upper()
* - substring() con sintaxis substring(campo, start, length) donde start y length son números enteros positivos
* - concat() con sintaxis concat(arg1, arg2, ...) donde arg es un identificador o un string literal simple (entre comillas simples, sin comillas internas)
*
* @param string $fieldName
*
* @return bool
*/
protected static function isValidFieldName(string $fieldName): bool
{
// permite campos vacíos (se usan valores por defecto en algunos casos)
if (empty($fieldName)) {
// permite campos vacíos (valores por defecto)
if ($fieldName === '') {
return true;
}

// permite lower() y upper() con un campo válido dentro
if (preg_match('/^(lower|upper)\(([a-zA-Z0-9_\.]+)\)$/i', $fieldName, $matches)) {
// Identificador: campo o tabla.campo (sin espacios, sin comillas)
$fieldName = trim($fieldName);
$ident = '[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)?';

// Campo directo
if (preg_match('/^' . $ident . '$/', $fieldName)) {
return true;
}

// lower(field) / upper(field)
if (preg_match('/^(lower|upper)\((' . $ident . ')\)$/i', $fieldName)) {
return true;
}

// substring(field, start, len) con números
if (preg_match('/^substring\((' . $ident . '),\s*(\d+)\s*,\s*(\d+)\s*\)$/i', $fieldName, $m)) {
$start = (int)$m[2];
$len = (int)$m[3];
// límites razonables (ajusta a tu caso)
return $start >= 1 && $len >= 1 && $len <= 1000;
}

// concat(arg1, arg2, ...) donde arg es un identificador o literal simple '...'(sin comillas internas o escapadas)
$arg = "(?:$ident|'[^']*')";
if (preg_match('/^concat\(\s*' . $arg . '(?:\s*,\s*' . $arg . ')+\s*\)$/i', $fieldName)) {
return true;
}

// permite letras, números, guiones bajos y puntos (para tabla.campo)
return preg_match('/^[a-zA-Z0-9_\.]+$/', $fieldName) === 1;
return false;
}

protected static function db(): DataBase
Expand Down
Loading