#!/usr/bin/env bash # STEP051B - Porting Presenze 215.6 # Audit-only: individua il vero costruttore JSON senza presumere nomi di funzione. set -Eeuo pipefail umask 077 STEP_NAME="STEP051B_2156_SILVELOX_PRINT_JSON_BUILDER_FUNCTION_DISCOVERY_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}" PRINT_ROOT="${PRINT_ROOT:-$TARGET_ROOT/components/templates/custom_templates/ax_attendance/ax_print_manager}" HELPER="${HELPER:-$PRINT_ROOT/ctrl/helper.php}" CONTROLLER="${CONTROLLER:-$PRINT_ROOT/ctrl/controllerCtrl.php}" APP_JS="${APP_JS:-$PRINT_ROOT/app/appCtrl.js}" JSON_FILE="${JSON_FILE:-$TARGET_ROOT/json_data/dataReportTable.json}" ALLOW_TEST="${ALLOW_TEST:-0}" 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" SOURCE_DIR="$WORKDIR/source" INVENTORY="$WORKDIR/source_inventory.tsv" PHP_SYMBOLS="$WORKDIR/php_classes_functions.tsv" MATCHES="$WORKDIR/relevant_matches.tsv" CONTEXT="$WORKDIR/relevant_source_context.txt" JS_FLOW="$WORKDIR/javascript_flow_matches.txt" JSON_SCHEMA="$WORKDIR/current_json_schema.txt" FINDINGS="$WORKDIR/automatic_findings.txt" PHP_ANALYZER="$WORKDIR/analyze_php.php" CONTEXT_EXTRACTOR="$WORKDIR/extract_context.php" JSON_ANALYZER="$WORKDIR/analyze_json.php" cleanup() { rm -rf -- "$WORKDIR"; } on_error() { local rc=$? local line="${1:-?}" trap - ERR printf 'ERRORE linea %s, codice %s\n' "$line" "$rc" >&2 exit "$rc" } trap cleanup EXIT INT TERM trap 'on_error "$LINENO"' ERR progress() { printf '%s\n' "$1" printf '\n[%s] %s\n' "$(date '+%H:%M:%S')" "$1" >> "$REPORT" } 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 for required in "$HELPER" "$CONTROLLER" "$APP_JS" "$JSON_FILE"; do [[ -f "$required" ]] || { echo "ERRORE: file richiesto non trovato: $required" >&2 exit 11 } done PHP_BIN="$(command -v php5.6 || command -v php || true)" [[ -n "$PHP_BIN" ]] || { echo "ERRORE: PHP CLI non disponibile." >&2; exit 12; } mkdir -p "$SOURCE_DIR" : > "$INVENTORY"; : > "$PHP_SYMBOLS"; : > "$MATCHES"; : > "$CONTEXT" : > "$JS_FLOW"; : > "$JSON_SCHEMA"; : > "$FINDINGS" { 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 "HELPER: $HELPER" echo "CONTROLLER: $CONTROLLER" echo "APP JS: $APP_JS" echo "JSON: $JSON_FILE" echo "MODALITA': AUDIT ONLY" echo "NESSUNA MODIFICA ESEGUITA" } > "$REPORT" progress "[1/5] Acquisizione integrale dei file reali" "$PHP_BIN" -l "$HELPER" >> "$REPORT" 2>&1 "$PHP_BIN" -l "$CONTROLLER" >> "$REPORT" 2>&1 { printf 'size\tmtime\tmode\towner\tsha256\tpath\n' for file in "$HELPER" "$CONTROLLER" "$APP_JS" "$JSON_FILE"; do printf '%s\t%s\t%s\t%s\t%s\t%s\n' \ "$(stat -c '%s' "$file")" \ "$(stat -c '%y' "$file")" \ "$(stat -c '%a' "$file")" \ "$(stat -c '%U:%G' "$file")" \ "$(sha256sum "$file" | awk '{print $1}')" \ "$file" done } > "$INVENTORY" cp -a -- "$HELPER" "$SOURCE_DIR/helper.php" cp -a -- "$CONTROLLER" "$SOURCE_DIR/controllerCtrl.php" cp -a -- "$APP_JS" "$SOURCE_DIR/appCtrl.js" cp -a -- "$JSON_FILE" "$SOURCE_DIR/dataReportTable.json" cat "$INVENTORY" >> "$REPORT" progress "[2/5] Elenco reale di classi e funzioni PHP" cat > "$PHP_ANALYZER" <<'PHP' "$PHP_SYMBOLS" { echo echo "===== CLASSI E FUNZIONI PHP =====" cat "$PHP_SYMBOLS" } >> "$REPORT" progress "[3/5] Ricerca riferimenti e contesto sorgente" PATTERN='dataReportTable[.]json|json_data|file_put_contents|json_encode|ax_new_time_day|ax_new_time_causali_month|ax_new_time_causali|ax_new_time([^_A-Za-z0-9]|$)|time_day|cauys_day|generaldata|ordinarie|assenze|straordinarie|maggiorazioni|overturno|bancaore|makeTable|makeReport|print|report' for file in "$HELPER" "$CONTROLLER"; do grep -nEi "$PATTERN" "$file" 2>/dev/null \ | while IFS=: read -r line text; do printf '%s\t%s\t%s\n' "$file" "$line" "$text" done || true done > "$MATCHES" cat > "$CONTEXT_EXTRACTOR" <<'PHP' = 2 && $parts[0] === $file) { $number = (int)$parts[1]; if ($number > 0) $numbers[$number] = true; } } fclose($handle); $wanted = array(); foreach (array_keys($numbers) as $number) { $start = max(1, $number - 12); $end = min(count($lines), $number + 12); for ($i = $start; $i <= $end; $i++) $wanted[$i] = true; } ksort($wanted); $previous = 0; foreach (array_keys($wanted) as $number) { if ($previous === 0 || $number > $previous + 1) { echo "\n===== " . $file . " da riga " . $number . " =====\n"; } printf("%6d %s", $number, $lines[$number - 1]); $previous = $number; } PHP for file in "$HELPER" "$CONTROLLER"; do "$PHP_BIN" "$CONTEXT_EXTRACTOR" "$file" "$MATCHES" >> "$CONTEXT" done grep -nEi \ 'helper|controller|make|table|report|print|stimulsoft|dataReportTable|json_data|getPhpData|post|ajax' \ "$APP_JS" > "$JS_FLOW" || true { echo echo "===== MATCH RILEVANTI =====" cat "$MATCHES" echo echo "===== CONTESTO SORGENTE =====" cat "$CONTEXT" echo echo "===== FLUSSO JAVASCRIPT =====" cat "$JS_FLOW" } >> "$REPORT" progress "[4/5] Struttura del JSON attuale" cat > "$JSON_ANALYZER" <<'PHP' $unused) { if ((string)$key !== (string)$expected) return false; $expected++; } return true; } function walk($value, $path, $depth) { if (!is_array($value) || $depth > 8) return; $kind = isListArray($value) ? 'LIST' : 'OBJECT'; echo ($path === '' ? '' : $path) . "\t" . $kind . "\tcount=" . count($value) . "\n"; if ($kind === 'LIST' && count($value) > 0) { $first = reset($value); if (is_array($first)) { $keys = array_keys($first); sort($keys, SORT_NATURAL | SORT_FLAG_CASE); echo ($path === '' ? '' : $path) . "\tFIRST_ROW_KEYS\t" . implode(',', $keys) . "\n"; } } $visited = 0; foreach ($value as $key => $child) { if (is_array($child)) { walk( $child, $path === '' ? (string)$key : $path . '.' . $key, $depth + 1 ); } if (++$visited >= 1000) break; } } walk($data, '', 0); PHP "$PHP_BIN" "$JSON_ANALYZER" "$JSON_FILE" > "$JSON_SCHEMA" cat "$JSON_SCHEMA" >> "$REPORT" progress "[5/5] Riepilogo e creazione ZIP" FUNCTION_COUNT="$(awk -F '\t' '$2=="FUNCTION"{c++}END{print c+0}' "$PHP_SYMBOLS")" MATCH_COUNT="$(grep -c . "$MATCHES" 2>/dev/null || true)" CONTEXT_LINES="$(wc -l < "$CONTEXT")" JS_MATCH_COUNT="$(grep -c . "$JS_FLOW" 2>/dev/null || true)" JSON_WRITER_MATCHES="$( grep -Eic 'dataReportTable[.]json|file_put_contents|json_encode' \ "$MATCHES" "$CONTEXT" 2>/dev/null || true )" { echo "Funzioni PHP individuate: $FUNCTION_COUNT" echo "Riferimenti rilevanti: $MATCH_COUNT" echo "Righe di contesto acquisite: $CONTEXT_LINES" echo "Riferimenti JavaScript: $JS_MATCH_COUNT" echo "Indicatori scrittura JSON: $JSON_WRITER_MATCHES" echo echo "ESITO: AUDIT COMPLETATO" echo "NESSUNA MODIFICA ESEGUITA" } > "$FINDINGS" cat "$FINDINGS" >> "$REPORT" ( cd "$WORKDIR" zip -q -9 -r "$OUTPUT_ZIP" \ "$(basename "$REPORT")" \ "$(basename "$INVENTORY")" \ "$(basename "$PHP_SYMBOLS")" \ "$(basename "$MATCHES")" \ "$(basename "$CONTEXT")" \ "$(basename "$JS_FLOW")" \ "$(basename "$JSON_SCHEMA")" \ "$(basename "$FINDINGS")" \ source ) zip -T "$OUTPUT_ZIP" >/dev/null echo "STEP051B COMPLETATO" echo "ZIP: $OUTPUT_ZIP"