$in * @return array{id:int, title:string, intro:string, topics:list, show_name:bool, ack:bool, active:bool}|null */ public static function normalize(int $id, array $in): ?array { $title = self::line((string) ($in['title'] ?? ''), self::TITLE_MAX); if ($title === '' || $id <= 0) { return null; } $topics = $in['topics'] ?? []; if (is_string($topics)) { $topics = preg_split('/\R/u', $topics) ?: []; } $clean = []; foreach ((array) $topics as $t) { $t = self::line((string) $t, self::TOPIC_MAX); if ($t !== '' && !in_array($t, $clean, true)) { $clean[] = $t; } if (count($clean) >= self::MAX_TOPICS) { break; } } return [ 'id' => $id, 'title' => $title, 'intro' => self::text((string) ($in['intro'] ?? ''), self::INTRO_MAX), 'topics' => $clean, 'show_name' => !empty($in['show_name']), 'ack' => !empty($in['ack']), 'active' => !empty($in['active']), ]; } /** One line of plain text: tags and control characters removed, whitespace collapsed, cut to $max characters. */ public static function line(string $v, int $max): string { // phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags -- pure class without WordPress; the text is escaped wherever it is shown $v = trim((string) preg_replace('/\s+/u', ' ', strip_tags((string) preg_replace('/[\x00-\x1F\x7F]/', ' ', $v)))); return mb_substr($v, 0, $max); } /** Plain text with line breaks kept (tags and other control characters removed). */ public static function text(string $v, int $max): string { // phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags -- pure class without WordPress; the text is escaped wherever it is shown $v = str_replace("\r\n", "\n", strip_tags((string) preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $v))); return trim(mb_substr(trim($v), 0, $max)); } /** * Whether $candidate may be saved next to the other definitions: the active limit and the total limit. * * @param array> $others every OTHER stored definition, keyed by ID * @param array $candidate * @return string '' when allowed, otherwise 'too_many_active' or 'too_many_forms' */ public static function limitProblem(array $others, array $candidate, bool $isNew): string { if ($isNew && count($others) >= self::MAX_TOTAL) { return 'too_many_forms'; } $active = count(array_filter($others, static fn(array $f): bool => !empty($f['active']))); if (!empty($candidate['active']) && $active >= self::MAX_ACTIVE) { return 'too_many_active'; } return ''; } }