* * GPL v3 (siehe COPYING). */ /** * \file htdocs/custom/mahnung/ajax/regex_preview.php * \ingroup mahnung * \brief AJAX-Endpoint: Live-Vorschau für Tracking-Regex auf der Setup-Seite. * * POST: regex (string), sample (string, max 10 KB), url_template (string) * Response (JSON): { valid: bool, match: string|null, preview_url: string|null, error: string|null } */ if (!defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); if (!defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); require_once $_SERVER['DOCUMENT_ROOT'].'/main.inc.php'; global $user, $langs; $langs->load('mahnung@mahnung'); header('Content-Type: application/json; charset=utf-8'); if (!$user->admin && !$user->hasRight('mahnung', 'setup')) { echo json_encode(array('valid' => false, 'error' => 'access denied')); exit; } // ReDoS-Schutz: Eingaben begrenzen + Zeitlimit $regex = (string) GETPOST('regex', 'nohtml'); $sample = (string) GETPOST('sample', 'nohtml'); $urlTemplate = (string) GETPOST('url_template', 'alphanohtml'); if (strlen($regex) > 255) { echo json_encode(array('valid' => false, 'error' => 'regex too long (max 255)')); exit; } if (strlen($sample) > 10240) { $sample = substr($sample, 0, 10240); } // Whitelist: Delimiter / # ~ if ($regex === '' || !in_array($regex[0], array('/', '#', '~'), true)) { echo json_encode(array('valid' => false, 'error' => 'allowed delimiters: / # ~')); exit; } // ReDoS-Schutz via PCRE-Backtrack-Limit (klein halten) $prevBacktrack = ini_get('pcre.backtrack_limit'); $prevRecursion = ini_get('pcre.recursion_limit'); @ini_set('pcre.backtrack_limit', '100000'); @ini_set('pcre.recursion_limit', '10000'); $matches = array(); $ret = @preg_match($regex, '', $matches); // erst leerer String — testet Syntax if ($ret === false) { @ini_set('pcre.backtrack_limit', (string) $prevBacktrack); @ini_set('pcre.recursion_limit', (string) $prevRecursion); $err = preg_last_error_msg(); echo json_encode(array('valid' => false, 'error' => 'invalid regex'.($err && $err !== 'No error' ? ': '.$err : ''))); exit; } // Echtes Sample matchen $match = null; if ($sample !== '') { $ret = @preg_match($regex, $sample, $matches); if ($ret === 1) { $match = !empty($matches[1]) ? $matches[1] : $matches[0]; } } @ini_set('pcre.backtrack_limit', (string) $prevBacktrack); @ini_set('pcre.recursion_limit', (string) $prevRecursion); $previewUrl = null; if ($match !== null && strpos($urlTemplate, 'https://') === 0 && strpos($urlTemplate, '{nr}') !== false) { $previewUrl = str_replace('{nr}', rawurlencode($match), $urlTemplate); } echo json_encode(array( 'valid' => true, 'match' => $match, 'preview_url' => $previewUrl, 'error' => null, )); exit;