#!/usr/bin/env bash # STEP048 - Porting Presenze 215.6 # # Audit rapido e mirato: # - rileva la versione reale del motore Stimulsoft legacy; # - analizza il ReportVersion del template attivo; # - cerca esclusivamente copie plausibili di SimpleList/report presenze; # - individua un eventuale template presenze compatibile con il motore 2017; # - controlla anche archivi ZIP locali, senza estrarli. # # Modalita': AUDIT ONLY - nessuna modifica. set -Eeuo pipefail umask 077 STEP_NAME="STEP048_2156_SILVELOX_STIMULSOFT_VERSION_COMPATIBLE_TEMPLATE_SEARCH_AUDIT_ONLY_VERIFIED_20260731" EXPECTED_HOST="${EXPECTED_HOST:-ax-accessi}" EXPECTED_IP_FRAGMENT="${EXPECTED_IP_FRAGMENT:-192.168.215.6}" TARGET_ROOT="${TARGET_ROOT:-/var/www/html/presenze.silvelox}" BASE_ROOT="${BASE_ROOT:-/var/www/html/presenze.distribuite}" CESARE_ROOT="${CESARE_ROOT:-/var/www/html/cesare}" TMP_ROOT="${TMP_ROOT:-/tmp}" ALLOW_TEST="${ALLOW_TEST:-0}" SKIP_ARCHIVES="${SKIP_ARCHIVES:-0}" LEGACY_JS="${LEGACY_JS:-$TARGET_ROOT/libs/stimulsoft_legacy/scripts/stimulsoft.reports.js}" LEGACY_VIEWER_JS="${LEGACY_VIEWER_JS:-$TARGET_ROOT/libs/stimulsoft_legacy/scripts/stimulsoft.viewer.js}" ACTIVE_REPORT="${ACTIVE_REPORT:-$TARGET_ROOT/libs/stimulsoft_legacy/reports/SimpleList.mrt}" ALT_ENGINE_JS="${ALT_ENGINE_JS:-$TARGET_ROOT/stimulsoftext/scripts/stimulsoft.reports.js}" STAMP="$(date +%Y%m%d_%H%M%S)" OUTPUT_ZIP="$PWD/${STEP_NAME}_${STAMP}.zip" WORKDIR="$(mktemp -d "$PWD/.${STEP_NAME}.XXXXXX")" REPORT="$WORKDIR/${STEP_NAME}_REPORT.txt" CANDIDATES="$WORKDIR/mrt_candidates.txt" ANALYSIS="$WORKDIR/mrt_candidate_analysis.tsv" COMPATIBLE="$WORKDIR/compatible_attendance_candidates.txt" ARCHIVES="$WORKDIR/archive_candidates.txt" ARCHIVE_MATCHES="$WORKDIR/archive_report_matches.txt" VERSIONS="$WORKDIR/stimulsoft_versions.txt" FINDINGS="$WORKDIR/automatic_findings.txt" PARSER="$WORKDIR/analyze_mrt.php" cleanup() { rm -rf -- "$WORKDIR" } on_error() { local rc=$? local line="${1:-?}" printf 'ERRORE linea %s, codice %s\n' "$line" "$rc" >&2 exit "$rc" } trap cleanup EXIT INT TERM trap 'on_error "$LINENO"' ERR section() { printf '\n\n================================================================\n%s\n================================================================\n' "$1" >> "$REPORT" } progress() { printf '%s\n' "$1" printf '\n[%s] %s\n' "$(date '+%H:%M:%S')" "$1" >> "$REPORT" } limited() { local seconds="$1" shift if command -v timeout >/dev/null 2>&1; then timeout --signal=TERM --kill-after=5s "${seconds}s" "$@" else "$@" fi } HOST_NOW="$(hostname 2>/dev/null || true)" IPS_NOW="$(hostname -I 2>/dev/null || true)" if [[ "$ALLOW_TEST" != "1" ]]; then if [[ "$HOST_NOW" != "$EXPECTED_HOST" && "$IPS_NOW" != *"$EXPECTED_IP_FRAGMENT"* ]]; then echo "ERRORE: server errato; atteso 215.6 / ax-accessi." >&2 exit 10 fi fi [[ -f "$LEGACY_JS" ]] || { echo "ERRORE: motore legacy non trovato: $LEGACY_JS" >&2 exit 11 } [[ -f "$ACTIVE_REPORT" ]] || { echo "ERRORE: template attivo non trovato: $ACTIVE_REPORT" >&2 exit 12 } PHP_BIN="$(command -v php5.6 || command -v php || true)" [[ -n "$PHP_BIN" ]] || { echo "ERRORE: PHP CLI non disponibile." >&2 exit 13 } for file in \ "$CANDIDATES" "$ANALYSIS" "$COMPATIBLE" "$ARCHIVES" \ "$ARCHIVE_MATCHES" "$VERSIONS" "$FINDINGS"; do : > "$file" done { echo "$STEP_NAME" echo "DATA: $(date --iso-8601=seconds 2>/dev/null || date)" echo "SERVER: $HOST_NOW" echo "IP: $IPS_NOW" echo "PORTALE: $TARGET_ROOT" echo "TEMPLATE ATTIVO: $ACTIVE_REPORT" echo "MOTORE ATTIVO: $LEGACY_JS" echo "MODALITA': AUDIT ONLY" echo "NESSUNA MODIFICA ESEGUITA" } > "$REPORT" progress "[1/6] Rilevamento versioni Stimulsoft" extract_version() { local file="$1" if [[ ! -f "$file" ]]; then echo "ASSENTE" return 0 fi limited 5 head -n 20 "$file" 2>/dev/null \ | grep -Eim1 'Version[[:space:]]*:' \ | sed -E 's/.*Version[[:space:]]*:[[:space:]]*//' \ | tr -d '\r' || true } LEGACY_VERSION="$(extract_version "$LEGACY_JS")" VIEWER_VERSION="$(extract_version "$LEGACY_VIEWER_JS")" ALT_VERSION="$(extract_version "$ALT_ENGINE_JS")" { printf 'legacy_reports_js\t%s\t%s\n' "$LEGACY_VERSION" "$LEGACY_JS" printf 'legacy_viewer_js\t%s\t%s\n' "$VIEWER_VERSION" "$LEGACY_VIEWER_JS" printf 'alternative_reports_js\t%s\t%s\n' "$ALT_VERSION" "$ALT_ENGINE_JS" } > "$VERSIONS" cat "$VERSIONS" >> "$REPORT" progress "[2/6] Analisi del template attivo e preparazione parser" cat > "$PARSER" <<'PHP' 0 ) { $firstPage = reset($data['Pages']); if (is_array($firstPage)) { $pageWidth = isset($firstPage['PageWidth']) ? (string) $firstPage['PageWidth'] : ''; $pageHeight = isset($firstPage['PageHeight']) ? (string) $firstPage['PageHeight'] : ''; } } $sources = array(); if ( isset($data['Dictionary']['DataSources']) && is_array($data['Dictionary']['DataSources']) ) { foreach ($data['Dictionary']['DataSources'] as $source) { if (is_array($source) && isset($source['Name'])) { $sources[] = (string) $source['Name']; } } } sort($sources, SORT_NATURAL | SORT_FLAG_CASE); $attendanceRequired = array( 'associazioni', 'time_day', 'time_lines', 'cauys_day_total' ); $attendanceHits = 0; foreach ($attendanceRequired as $required) { if (in_array($required, $sources, true)) { $attendanceHits++; } } $attendance = $attendanceHits === count($attendanceRequired) ? 'YES' : 'NO'; $compatible2017 = 'NO'; if ( preg_match('/^([0-9]+)[.]([0-9]+)/', $version, $matches) && (int) $matches[1] <= 2017 ) { $compatible2017 = 'YES'; } $expressions = 0; $components = 0; $walk = function ($value) use (&$walk, &$expressions, &$components) { if (!is_array($value)) { return; } if (isset($value['Ident'])) { $components++; } foreach ($value as $child) { if (is_string($child)) { $expressions += preg_match_all( '/\{[^{}]{1,300}\}/', $child, $unused ); } elseif (is_array($child)) { $walk($child); } } }; $walk($data); echo implode("\t", array( $file, filesize($file), $version, $name, $alias, $unit, $pageWidth, $pageHeight, implode(',', $sources), $attendance, $compatible2017, $expressions, $components )) . "\n"; PHP "$PHP_BIN" "$PARSER" "$ACTIVE_REPORT" > "$WORKDIR/active_report_analysis.tsv" { echo "path size report_version report_name report_alias unit page_width page_height data_sources attendance_signature compatible_with_2017 expressions components" cat "$WORKDIR/active_report_analysis.tsv" } >> "$REPORT" progress "[3/6] Ricerca mirata delle copie MRT plausibili" declare -a ROOTS=( "$TARGET_ROOT" "$BASE_ROOT" "$CESARE_ROOT" ) for root in "${ROOTS[@]}"; do [[ -d "$root" ]] || continue limited 35 find "$root" -xdev -type f -size -5M \ \( -iname 'SimpleList*.mrt' \ -o -iname '*presenz*.mrt' \ -o -iname 'Report_Base*.mrt' \ -o -iname 'ReportBase*.mrt' \) \ -print 2>/dev/null || true done | sort -u > "$CANDIDATES" CANDIDATE_COUNT="$(grep -c . "$CANDIDATES" 2>/dev/null || true)" { echo "CANDIDATI TROVATI: $CANDIDATE_COUNT" cat "$CANDIDATES" } >> "$REPORT" { echo -e "path\tsize\treport_version\treport_name\treport_alias\tunit\tpage_width\tpage_height\tdata_sources\tattendance_signature\tcompatible_with_2017\texpressions\tcomponents" while IFS= read -r file; do [[ -f "$file" ]] || continue limited 10 "$PHP_BIN" "$PARSER" "$file" || true done < "$CANDIDATES" } > "$ANALYSIS" cat "$ANALYSIS" >> "$REPORT" awk -F '\t' ' NR > 1 && $10 == "YES" && $11 == "YES" { print } ' "$ANALYSIS" > "$COMPATIBLE" progress "[4/6] Ricerca nei soli archivi ZIP locali plausibili" if [[ "$SKIP_ARCHIVES" == "1" ]]; then echo "Ricerca archivi saltata in ambiente simulato." > "$ARCHIVES" echo "Ricerca archivi saltata in ambiente simulato." > "$ARCHIVE_MATCHES" elif command -v unzip >/dev/null 2>&1; then for root in "$CESARE_ROOT" "$TMP_ROOT" "$TARGET_ROOT/cesare"; do [[ -d "$root" ]] || continue limited 20 find "$root" -xdev -maxdepth 3 -type f \ -size -500M -iname '*.zip' -print 2>/dev/null || true done | sort -u | head -n 80 > "$ARCHIVES" while IFS= read -r archive; do [[ -f "$archive" ]] || continue limited 8 unzip -Z1 "$archive" 2>/dev/null \ | grep -Ei \ '(^|/)(SimpleList[^/]*[.]mrt|[^/]*presenz[^/]*[.]mrt|Report_?Base[^/]*[.]mrt)$' \ | sed "s#^#$archive\t#" || true done < "$ARCHIVES" > "$ARCHIVE_MATCHES" else echo "unzip non disponibile." > "$ARCHIVE_MATCHES" fi cat "$ARCHIVE_MATCHES" >> "$REPORT" progress "[5/6] Verifica incompatibilita' versione" ACTIVE_VERSION="$( awk -F '\t' 'NR == 1 {print $3}' \ "$WORKDIR/active_report_analysis.tsv" )" ACTIVE_ATTENDANCE="$( awk -F '\t' 'NR == 1 {print $10}' \ "$WORKDIR/active_report_analysis.tsv" )" ACTIVE_COMPAT="$( awk -F '\t' 'NR == 1 {print $11}' \ "$WORKDIR/active_report_analysis.tsv" )" COMPATIBLE_COUNT="$(grep -c . "$COMPATIBLE" 2>/dev/null || true)" ARCHIVE_MATCH_COUNT="$(grep -c . "$ARCHIVE_MATCHES" 2>/dev/null || true)" VERSION_MISMATCH="NO" if [[ "$LEGACY_VERSION" =~ ^2017[.] && "$ACTIVE_VERSION" =~ ^(2018|2019|202[0-9])[.] ]]; then VERSION_MISMATCH="YES" fi { echo "Motore legacy: $LEGACY_VERSION" echo "Template attivo: $ACTIVE_VERSION" echo "Firma report presenze: $ACTIVE_ATTENDANCE" echo "Compatibile 2017 per versione dichiarata: $ACTIVE_COMPAT" echo "Mismatch motore/template: $VERSION_MISMATCH" echo "Template presenze <=2017 trovati su filesystem: $COMPATIBLE_COUNT" echo "Nomi compatibili trovati negli ZIP: $ARCHIVE_MATCH_COUNT" } > "$FINDINGS" cat "$FINDINGS" >> "$REPORT" progress "[6/6] Creazione ZIP" { echo echo "ESITO: AUDIT COMPLETATO" echo "NESSUNA MODIFICA ESEGUITA" } >> "$REPORT" ( cd "$WORKDIR" zip -q -9 "$OUTPUT_ZIP" \ "$(basename "$REPORT")" \ "$(basename "$VERSIONS")" \ "$(basename "$CANDIDATES")" \ "$(basename "$ANALYSIS")" \ "$(basename "$COMPATIBLE")" \ "$(basename "$ARCHIVES")" \ "$(basename "$ARCHIVE_MATCHES")" \ "$(basename "$FINDINGS")" \ active_report_analysis.tsv ) zip -T "$OUTPUT_ZIP" >/dev/null echo "STEP048 COMPLETATO" echo "ZIP: $OUTPUT_ZIP"