Costruire un agente AI per l'analisi tecnica di codebase PHP legacy con Claude API
La prima settimana di ogni subentro su un codebase PHP legacy è la più ripetitiva del mio lavoro: aprire file, leggere codice, annotare dipendenze, cercare credenziali hardcodate, mappare le connessioni al database, identificare i pattern architetturali (o la loro assenza) e produrre un inventario tecnico. Su un gestionale da 40.000 righe distribuito su 300 file, questa fase richiede 3-5 giorni di lavoro manuale prima ancora di poter dare al titolare un quadro chiaro della situazione. Dopo aver fatto questo lavoro almeno quindici volte negli ultimi tre anni, ho deciso di automatizzarlo.
A settembre 2025 ho costruito un agente basato sull'API di Claude che analizza un codebase PHP in modo semi-automatico: riceve il path della directory, esplora i file in autonomia usando il tool use nativo dell'API, costruisce una mappa delle dipendenze, identifica vulnerabilità di sicurezza e pattern problematici, e produce un report strutturato in JSON e Markdown. Il tempo di analisi è passato da 3-5 giorni a 2-4 ore per un codebase di dimensioni tipiche di PMI. In questo articolo ti racconto come funziona, quali sono i limiti reali, e perché il risultato non è un sostituto dell'audit umano ma un acceleratore che cambia la dinamica dell'intervento.
Stai cercando un Consulente Informatico esperto in automazione AI e analisi di codebase PHP legacy? Nel mio profilo professionale trovi l'esperienza concreta su Claude Code, LLM automation e modernizzazione di applicazioni PHP. Contattami per una consulenza diretta.
Perché un LLM è adatto all'analisi di codice legacy e dove fallisce?
Un LLM come Claude è sorprendentemente efficace nell'analisi di codice PHP legacy per tre ragioni. Prima: il PHP legacy ha pattern riconoscibili - mysql_query con variabili concatenate, include senza validazione, $_GET stampato senza escaping - che un LLM identifica con altissima precisione perché li ha visti milioni di volte nei dati di training. Seconda: il contesto di business che un LLM riesce a inferire dal codice - "questo sembra un modulo di fatturazione", "questa funzione calcola uno sconto" - riduce il tempo di comprensione che per un umano è la parte più costosa. Terza: la produzione di report strutturati (JSON, Markdown con heading, tabelle, checklist) è il punto di forza naturale di un LLM.
Dove fallisce: logica di business complessa che dipende da convenzioni aziendali non esplicite nel codice, interazioni tra sistemi esterni non documentate, e soprattutto il giudizio su cosa è critico per il business e cosa no. Un LLM ti dice "questa query è vulnerabile a SQL injection" - ma non sa che quella query viene eseguita solo da un cron interno che non accetta input esterno, quindi il rischio reale è basso. Il giudizio di prioritizzazione resta umano.
L'architettura dell'agente: tool use per navigare il filesystem
L'agente non riceve tutto il codice in un singolo prompt - un codebase da 40.000 righe non entra nella context window, e anche se entrasse, l'attenzione del modello degraderebbe. Invece, l'agente usa il tool use dell'API Claude per esplorare il filesystem in autonomia: elenca le directory, legge i file che gli servono, cerca pattern con grep, e costruisce incrementalmente la sua comprensione del progetto.
Gli strumenti che ho definito per l'agente:
tools = [
{
"name": "list_files",
"description": "Elenca file PHP in una directory con dimensioni",
"input_schema": {
"type": "object",
"properties": {
"path": {"type": "string"},
"pattern": {"type": "string", "default": "*.php"}
},
"required": ["path"]
}
},
{
"name": "read_file",
"description": "Legge il contenuto di un file (max 500 righe)",
"input_schema": {
"type": "object",
"properties": {
"path": {"type": "string"},
"start_line": {"type": "integer", "default": 1},
"end_line": {"type": "integer", "default": 500}
},
"required": ["path"]
}
},
{
"name": "search_pattern",
"description": "Cerca un pattern regex nei file PHP del progetto",
"input_schema": {
"type": "object",
"properties": {
"pattern": {"type": "string"},
"path": {"type": "string", "default": "."}
},
"required": ["pattern"]
}
},
{
"name": "save_finding",
"description": "Registra un risultato dell'analisi",
"input_schema": {
"type": "object",
"properties": {
"category": {"type": "string", "enum": [
"security", "architecture", "dependency",
"performance", "maintainability", "credential"
]},
"severity": {"type": "string", "enum": ["critical", "high", "medium", "low"]},
"file": {"type": "string"},
"line": {"type": "integer"},
"description": {"type": "string"},
"recommendation": {"type": "string"}
},
"required": ["category", "severity", "description"]
}
}
]L'agente riceve un prompt di sistema che definisce la sua missione - "Sei un auditor tecnico che analizza un codebase PHP legacy. Esplora il progetto sistematicamente, identifica vulnerabilità, pattern architetturali e debito tecnico" - e poi opera in autonomia nel loop tool use: legge un file, analizza, salva i finding, decide quale file leggere successivamente. Il loop si ferma quando l'agente decide di aver coperto abbastanza del codebase o quando raggiunge un budget di token predefinito.
Il chunking: come gestire codebase grandi con context window limitata
Un file PHP legacy può avere migliaia di righe - ho visto file da 8.000 righe con logica di business, HTML e SQL mescolati. L'agente non legge mai un file intero se supera le 500 righe: usa read_file con offset per leggere sezioni. Ma la strategia più efficace è il chunking per responsabilità: l'agente prima scansiona la struttura del progetto con list_files, poi legge i primi 50 righe di ogni file per capire cosa fa (il "preambolo" - require, use, class declaration), e solo dopo fa deep dive nei file che ha identificato come critici.
# Il loop principale dell'agente (semplificato)
import anthropic
client = anthropic.Anthropic()
findings = []
def run_agent(project_path: str, max_iterations: int = 100):
messages = [{"role": "user", "content": f"""
Analizza il codebase PHP in {project_path}.
Fase 1: list_files per mappare la struttura.
Fase 2: read_file sui file principali (index.php, config, autoload).
Fase 3: search_pattern per vulnerabilità note (SQL injection, XSS, credenziali).
Fase 4: deep dive sui file più critici.
Usa save_finding per ogni problema trovato.
"""}]
for i in range(max_iterations):
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=4096,
tools=tools,
messages=messages
)
# Processsa i tool call
if response.stop_reason == "tool_use":
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result
})
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
else:
# L'agente ha finito
break
return findingsIl costo per un'analisi tipica (codebase 30.000-50.000 righe, 200-400 file) è nell'ordine di 2-5 dollari di token API con Claude Sonnet - un costo trascurabile rispetto ai 3-5 giorni di lavoro umano che risparmia.
Cosa trova l'agente: il report di un caso reale
Su un gestionale PHP 7.0 di un cliente emiliano - 38.000 righe, 247 file, zero framework - l'agente ha completato l'analisi in 3 ore e 12 minuti, consumando circa 800.000 token di input e 200.000 di output. Il report prodotto:
- 14 SQL injection in endpoint raggiungibili senza autenticazione (severity: critical)
- 31 punti XSS con
echo $_GEToecho $_POSTsenza escaping (severity: high) - 9 file con credenziali hardcodate - stesso pattern
$db_pass = "..."in file diversi (severity: critical) - 4 file upload senza validazione del tipo MIME (severity: high)
- 23 funzioni deprecate (
mysql_connect,ereg,each) (severity: medium) - Mappa delle dipendenze: 12 entry point, 34 file di libreria, 18 file di configurazione
- Pattern architetturale: nessuno - MVC assente, logica e presentazione mescolate
La verifica manuale ha confermato il 91% dei finding (83 su 91): 8 erano falsi positivi - principalmente XSS segnalati in contesti dove l'output era dentro un commento HTML o un attributo non sfruttabile. Zero falsi negativi rilevanti trovati nella successiva revisione manuale - l'agente aveva coperto tutti i vettori di attacco principali.
Quel report - che manualmente avrebbe richiesto 4 giorni - è diventato la base per l'audit di sicurezza completo che ho poi condotto con verifica manuale e Psalm taint analysis. L'agente non sostituisce l'audit: lo accelera di un ordine di grandezza.
I limiti che ho scoperto in produzione
Dopo sei mesi di utilizzo dell'agente su una dozzina di codebase, i limiti sono chiari.
Falsi positivi su codice morto. L'agente non distingue codice eseguito da codice morto - segnala una SQL injection in un file che nessun punto di ingresso include. La verifica della raggiungibilità richiede un'analisi del call graph che il tool use dell'agente non riesce a fare con sufficiente precisione.
Dipendenze esterne invisibili. Se il codebase chiama un'API esterna o un web service SOAP, l'agente vede la chiamata ma non può sapere cosa restituisce - e quindi non può analizzare come quel dato viene usato dopo. Le integrazioni esterne restano un punto cieco.
Context window e "dimenticanza." Su codebase molto grandi (>100.000 righe), l'agente perde coerenza tra la prima parte dell'analisi e l'ultima. La soluzione è segmentare l'analisi per directory o per modulo funzionale, producendo report separati che poi sintetizzo manualmente.
Non sostituisce il giudizio. L'agente elenca problemi e assegna severità basandosi su pattern - ma la prioritizzazione reale dipende dal contesto di business che solo il consulente umano (e il titolare) conoscono. Una SQL injection in un endpoint pubblico è critica; la stessa SQL injection in un cron interno raggiungibile solo da localhost è medium. L'agente non fa questa distinzione.
Ho descritto l'approccio completo all'audit tecnico iniziale nei primi 30 giorni - dove l'agente AI copre la fase di discovery e l'umano copre la fase di giudizio - e i limiti reali della generazione di codice con LLM che si applicano anche all'analisi.
L'automazione dell'analisi di codice con un agente Claude non è il futuro - è il presente. Il costo è trascurabile, il tempo risparmiato è misurabile, e la qualità dei finding è sorprendentemente alta per un processo automatico. Ma il valore reale non è nell'agente in sé - è nel fatto che libera il consulente umano dal lavoro meccanico di lettura e catalogazione, permettendogli di concentrarsi su ciò che un LLM non sa fare: giudicare, prioritizzare e decidere. Se gestisci codebase PHP legacy e vuoi capire come integrare l'analisi AI nel tuo workflow di audit, contattami.