---
title: "Dal vecchio mysql_ a mysqli e PDO: come si fa davvero il porting nel 2026"
description: "Migrare un'applicazione PHP dalle vecchie funzioni mysql_ a mysqli o PDO: perché il porting automatico non basta, e come trasformarlo in un'occasione per chiudere le falle."
canonical: "https://www.mauriziofonte.it/blog/post/porting-funzioni-mysql-verso-mysqli-php.html"
author: "Maurizio Fonte"
date: "2026-05-20T11:30:08+02:00"
modified: "2026-06-15T18:01:05+02:00"
section: "Sicurezza Informatica"
tags: ["Sicurezza Informatica", "Refactoring"]
license: "Riuso e citazione consentiti con attribuzione e link alla fonte"
---

[Sicurezza Informatica](https://www.mauriziofonte.it/blog/cat/sicurezza_informatica.html) [Refactoring](https://www.mauriziofonte.it/blog/cat/refactoring.html)

# [Dal vecchio mysql_ a mysqli e PDO: come si fa davvero il porting nel 2026](https://www.mauriziofonte.it/blog/post/porting-funzioni-mysql-verso-mysqli-php.html)

Mercoledì 20 Mag 2026, alle 11:30 ![Dal vecchio mysql_ a mysqli e PDO: come si fa davvero il porting nel 2026](https://www.mauriziofonte.it/image/000290200-porting-funzioni-mysql-verso-mysqli-php.jpg)

Le storiche funzioni `mysql_` di PHP sono diventate deprecate con la versione 5.5 e sono state rimosse completamente da PHP 7.0, uscita alla fine del 2015. È un fatto vecchio di anni, eppure continuo a trovarlo vivo: applicazioni gestionali "fatte a mano", portali costruiti un decennio fa e mai più toccati, in cui `mysql_connect`, `mysql_query` e `mysql_fetch_assoc` sono ancora il cuore dell'accesso al database. La differenza è che nel 2015 il problema era prepararsi al futuro; oggi quel futuro è passato da un pezzo, e il significato è cambiato del tutto.

## TL;DR

> - **Fatto:** le funzioni `mysql_` sono rimosse da PHP 7.0 (fine 2015): chi le ha ancora gira su una versione di PHP fuori supporto da circa dieci anni.
> - **Porting automatico:** un convertitore sostituisce `mysql_*` con `mysqli_*`, ma è solo metà del lavoro (inciampa su casi come `mysql_result`, da gestire a mano).
> - **mysqli o PDO:** PDO per astrazione e portabilità fra database; mysqli per un porting rapido che resta su MySQL.
> - **Il vero rischio non è la deprecazione, è l'SQL injection:** passa ai **prepared statement**, non limitarti a rinominare le funzioni.
> - **Già che ci sei:** attiva le eccezioni (`mysqli_report(...)`) e imposta il charset `utf8mb4`.

## Cosa significa avere ancora mysql_ nel codice nel 2026

Partiamo dall'implicazione che molti non colgono. Se la tua applicazione usa ancora le funzioni `mysql_`, non sta semplicemente usando un'API vecchia: sta girando su una versione di PHP precedente alla 7.0, perché dalla 7.0 in poi quelle funzioni non esistono più e il codice non parte nemmeno. Vuol dire PHP 5.6 o precedenti, una linea fuori da ogni supporto di sicurezza da circa dieci anni.

Questo trasforma il problema da estetico a critico. Una versione di PHP non più supportata non riceve patch per le vulnerabilità che vengono scoperte, e di vulnerabilità su PHP 5.x ne sono emerse molte nel tempo. Un'applicazione in queste condizioni è esposta a falle note e documentate, contro cui non esiste aggiornamento. Il porting delle funzioni `mysql_`, quindi, non è mai un intervento isolato: è la punta visibile di una migrazione di versione che va affrontata per intero. Ho descritto il percorso completo, con i breaking changes reali e la strategia incrementale per non fermare la produzione, in [migrare un'applicazione da PHP 5.6 a PHP 8](https://www.mauriziofonte.it/blog/post/migrare-php-56-php-8-guida-completa-applicazioni-legacy-produzione.html), e il quadro dei rischi concreti del restare indietro lo metto nero su bianco in [i rischi del codice PHP obsoleto](https://www.mauriziofonte.it/blog/post/rischi-codice-obsoleto-php8-vantaggi-sicurezza-performance.html).

## Il porting automatico funziona, ma è solo metà del lavoro

La buona notizia è che la sostituzione meccanica delle chiamate `mysql_` con le equivalenti `mysqli_` è in gran parte automatizzabile. Esistono da anni strumenti che attraversano una codebase e riscrivono le chiamate: il più noto è un convertitore disponibile su GitHub che dispone sia di interfaccia grafica sia a riga di comando, e che su una directory di file PHP fa il grosso del lavoro sostituendo le funzioni una a una.

Eseguito sulla webroot, uno strumento del genere produce in pochi secondi il rimpiazzo di centinaia di chiamate. Il punto è cosa succede dopo, ed è qui che l'esperienza conta più dello strumento. Il convertitore lavora bene sulle funzioni che hanno un equivalente diretto, ma inciampa sui casi particolari. L'esempio che incontro più spesso è `mysql_result`, una funzione che non ha un gemello `mysqli_` con la stessa firma: il tool la lascia indietro, e l'applicazione, dopo la conversione, lancia un errore fatale appena raggiunge quella riga.

La procedura corretta dopo un porting automatico è sempre la stessa: testare l'applicazione percorrendo i flussi reali, leggere il log degli errori di PHP, individuare le righe che sollevano eccezioni, e gestire a mano i casi che lo strumento ha saltato. Per le funzioni senza equivalente diretto si scrive una piccola funzione di compatibilità che riproduce il comportamento atteso sopra l'API nuova. Nel caso di `mysql_result`, una funzione che naviga il result set e restituisce il valore della cella richiesta risolve il problema senza dover riscrivere ogni singola chiamata:

```php
function mysqli_result($res, $row = 0, $col = 0) {
    $numrows = mysqli_num_rows($res);
    if ($numrows && $row <= ($numrows - 1) && $row >= 0) {
        mysqli_data_seek($res, $row);
        $resrow = is_numeric($col) ? mysqli_fetch_row($res) : mysqli_fetch_assoc($res);
        if (isset($resrow[$col])) {
            return $resrow[$col];
        }
    }
    return false;
}
```

Con questa in libreria, basta sostituire le chiamate residue mantenendo gli stessi parametri. È un cerotto onesto, utile a far ripartire l'applicazione, ma resta un cerotto: il porting vero, quello che vale la pena fare, va oltre.

### Prima di convertire: il censimento delle occorrenze

Un errore tipico è lanciare il convertitore alla cieca senza sapere quanto è grande il problema. Il primo passo che faccio sempre è un censimento: una ricerca ricorsiva su tutta la codebase per contare e localizzare ogni chiamata residua. Un comando come `grep -rn "mysql_" --include="*.php" .` restituisce l'elenco completo delle righe coinvolte, e quel numero racconta subito la storia: poche decine di occorrenze significano un intervento di ore, qualche migliaio significano un progetto da pianificare. Conoscere il volume prima di iniziare evita di scoprire a metà strada che il lavoro è il triplo di quanto stimato. La lista delle funzioni interessate è lunga e va trattata per intero, dalla connessione (`mysql_connect`, `mysql_select_db`) all'esecuzione (`mysql_query`) al recupero dei risultati (`mysql_fetch_assoc`, `mysql_fetch_row`, `mysql_num_rows`), e il riferimento canonico resta il [manuale ufficiale dell'estensione mysqli su php.net](https://www.php.net/manual/en/book.mysqli.php), dove ogni vecchia funzione ha la sua corrispondente documentata.

### mysqli procedurale o a oggetti, e perché gli errori vanno gestiti con le eccezioni

Il convertitore automatico produce `mysqli` in stile procedurale, perché è la traduzione più letterale delle vecchie chiamate. Funziona, ma se hai intenzione di mantenere il codice negli anni conviene sapere che `mysqli` offre anche un'interfaccia a oggetti più leggibile, in cui la connessione è un oggetto e i metodi si invocano su di esso. Più importante dello stile, però, è la gestione degli errori. Il vecchio codice `mysql_` controllava il valore di ritorno di ogni chiamata e gestiva i fallimenti a mano, un approccio prolisso e facile da dimenticare. Su PHP moderno conviene attivare la modalità a eccezioni:

```php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
```

Con questa riga, ogni errore del database solleva un'eccezione invece di restituire silenziosamente `false`, e questo cambia la qualità del codice: gli errori non passano più inosservati, si gestiscono in modo centralizzato con un blocco `try/catch`, e non rischi che una query fallita prosegua come se nulla fosse, producendo dati corrotti o pagine a metà. È una di quelle modifiche che il convertitore non fa e che trasforma un porting meccanico in un upgrade reale della robustezza.

### Il dettaglio che salta in mente a nessuno: il charset della connessione

C'è un particolare che il porting automatico ignora e che genera bug subdoli: il charset della connessione. Il vecchio codice spesso non lo impostava esplicitamente, affidandosi a default che oggi sono diversi. Senza un charset corretto sulla connessione, i caratteri accentati e gli emoji si corrompono, e in certi scenari un charset mal gestito apre persino la porta a tecniche di injection che aggirano l'escaping. La regola che applico sempre è impostare `utf8mb4` subito dopo la connessione:

```php
$conn->set_charset("utf8mb4");
```

È una riga sola, ma è la differenza tra un'applicazione che gestisce correttamente qualsiasi testo internazionale e una che mostra punti interrogativi al posto delle lettere accentate. In un porting fatto bene non si salta.

Su questo tipo di interventi, dalla valutazione di una codebase legacy alla pianificazione di una migrazione che non rompa la produzione, lavoro da molti anni con chi ha applicazioni datate ma ancora centrali per il business: nel [mio profilo](https://www.mauriziofonte.it/pages/about) trovi il metodo con cui affronto la modernizzazione del codice esistente, partendo da quello che porta valore e non da una riscrittura totale che quasi mai conviene.

## mysqli o PDO: quale scegliere nel porting?

Il convertitore automatico spinge verso `mysqli`, perché è la traduzione più diretta delle vecchie funzioni. Ma se stai già mettendo le mani nell'accesso al database, vale la pena fare la domanda giusta: mysqli o PDO?

La differenza pratica è la portabilità. `mysqli` è legato a MySQL e MariaDB; PDO è un'astrazione che parla con molti database diversi attraverso la stessa interfaccia, il che significa che un domani potresti cambiare motore con un impatto minore sul codice applicativo. Entrambi supportano i prepared statement, che sono la ragione vera per cui questo passaggio conta. Per un'applicazione nuova o per un refactoring profondo consiglio quasi sempre PDO, per la sua interfaccia più pulita e per la flessibilità che lascia aperta; per un porting rapido e mirato che deve solo rimettere in piedi un'applicazione esistente, `mysqli` riduce la distanza dal codice originale ed è una scelta legittima. Non c'è una risposta unica: c'è la risposta giusta per il tuo vincolo di tempo e per quanto in profondità vuoi spingerti.

In PDO lo stesso accesso al database assume una forma che molti trovano più naturale, e il binding dei parametri è altrettanto immediato:

```php
$pdo = new PDO("mysql:host=localhost;dbname=app;charset=utf8mb4", $user, $pass, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$stmt = $pdo->prepare("SELECT nome, email FROM utenti WHERE id = ?");
$stmt->execute([$id]);
$riga = $stmt->fetch(PDO::FETCH_ASSOC);
```

Da notare due cose che dovrebbero diventare automatiche: il `charset=utf8mb4` già nella stringa di connessione, e l'attributo che attiva le eccezioni fin da subito. L'intera interfaccia, con tutti i metodi e le modalità di fetch, è descritta nel [manuale ufficiale di PDO su php.net](https://www.php.net/manual/en/book.pdo.php), che è il riferimento da tenere aperto durante il lavoro invece di affidarsi a frammenti copiati da forum.

### Come verifico che il porting sia davvero completo?

Un porting non è finito quando l'applicazione riparte: è finito quando hai la ragionevole certezza di non aver lasciato regressioni. Il metodo che seguo combina tre controlli. Il primo è la verifica che non resti nemmeno una chiamata `mysql_`, ripetendo la stessa ricerca ricorsiva del censimento iniziale: il risultato deve essere zero. Il secondo è il percorrere a mano i flussi critici dell'applicazione, quelli che toccano il database in scrittura, perché un errore su una `SELECT` si nota subito mentre uno su una `INSERT` o `UPDATE` può restare nascosto finché non corrompe dati reali. Il terzo è tenere il log degli errori sotto osservazione per qualche giorno dopo il rilascio, perché certi percorsi di codice si attivano solo in condizioni particolari e non emergono in un test rapido. È la differenza tra un porting che sembra fatto e uno che lo è davvero.

## Perché il vero rischio non è la deprecazione ma l'SQL injection

Arriviamo al punto che fa la differenza tra un porting fatto e un porting fatto bene. Il codice scritto nell'era delle funzioni `mysql_` costruiva quasi sempre le query concatenando stringhe, infilando direttamente nella query i valori che arrivavano dall'utente. Era la norma di allora, ed è esattamente il pattern che apre la porta all'SQL injection, una delle vulnerabilità più vecchie e più sfruttate del web.

Ecco la trappola: un convertitore automatico traduce `mysql_query("SELECT ... WHERE id = $id")` in `mysqli_query($conn, "SELECT ... WHERE id = $id")`. La sintassi è aggiornata, l'applicazione riparte, ma la vulnerabilità è rimasta identica. Hai cambiato l'API e lasciato la falla esattamente dov'era. Per questo dico che il porting meccanico è solo metà del lavoro: la metà che conta davvero è trasformare quelle query in prepared statement, dove i valori dell'utente viaggiano separati dal testo della query e non possono più alterarne la logica.

```php
$stmt = $conn->prepare("SELECT nome, email FROM utenti WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
```

Questo non è più solo un porting: è la chiusura di una vulnerabilità che il codice si portava dietro da anni. Il momento in cui tocchi ogni chiamata al database è l'unica occasione in cui rifarlo costa poco, perché sei già lì. La prevenzione dell'SQL injection nel 2026, tra prepared statement e ORM, l'ho trattata in dettaglio in [SQL injection: prevenzione con prepared statement e ORM per le PMI](https://www.mauriziofonte.it/blog/post/sql-injection-2025-pmi-prevenzione-prepared-statements-orm.html), ed è la lettura che consiglio prima di considerare chiuso un porting.

## Il porting come occasione, non come tappabuchi

Riassumo il modo in cui affronto questi lavori, perché l'errore più costoso è trattare il porting come una sostituzione testuale e dichiararlo finito quando l'applicazione riparte. La sequenza che seguo è chiara: prima la conversione automatica delle chiamate, per abbattere il volume del lavoro meccanico; poi il test reale e la gestione manuale dei casi che lo strumento ha saltato, leggendo i log; poi la decisione consapevole tra mysqli e PDO; e infine, la parte che dà valore, la trasformazione delle query in prepared statement per chiudere l'SQL injection ereditata.

Il tutto inserito nel quadro più ampio della migrazione di versione di PHP, perché avere ancora `mysql_` nel codice significa per forza essere su una linea fuori supporto, e il porting del database è solo un pezzo di un aggiornamento che va completato. Fatto così, un intervento che molti vivono come una scocciatura tecnica diventa il momento in cui un'applicazione vecchia ma viva ritrova sicurezza, prestazioni e un futuro di manutenibilità.

Se hai un'applicazione che ancora poggia sulle vecchie funzioni `mysql_`, o più in generale un gestionale costruito anni fa che fatica a stare al passo, scrivimi dal modulo di [contatto](https://www.mauriziofonte.it/pages/contattami): partiamo da una valutazione onesta dello stato del codice e da dove conviene intervenire per primo, perché modernizzare bene significa scegliere cosa toccare e in quale ordine, non riscrivere tutto sperando che basti.

Dall'articolo al lavoro vero

Questo problema di sicurezza, sul tuo sistema

Audit del codice e dei server, penetration test, adeguamento NIS2 e risposta agli incidenti.

[Vedi come lavoro sulla sicurezza](https://www.mauriziofonte.it/servizi/consulenza-cybersecurity-nis2.html) Ultima modifica: Lunedì 15 Giugno 2026, alle 18:01 [« Articolo precedenteQdrant 1.15 asymmetric quantization e binary storage: 10x meno VRAM per stesso recall20 Mag 2026](https://www.mauriziofonte.it/blog/post/qdrant-1-15-asymmetric-quantization-binary-storage-vector-db.html)[Articolo successivo »Lo strawberry problem e l'aritmetica degli LLM: diagnosi di quando NON usare un modello linguistico21 Mag 2026](https://www.mauriziofonte.it/blog/post/strawberry-problem-aritmetica-llm-quando-non-usare-modelli-linguistici.html)

### Articoli correlati a Dal vecchio mysql_ a mysqli e PDO: come si fa davvero il porting nel 2026

- [Migrare un gestionale PHP 5.6 a PHP 8.4 senza riscriverlo: il caso reale di un e-commerce B2B con 12 anni di codice procedurale](https://www.mauriziofonte.it/blog/post/migrare-php-56-php-8-guida-completa-applicazioni-legacy-produzione.html)

  Un e commerce B2B con 47.000 righe di PHP 5.6 procedurale, 340 chiamate mysql connect , un hosting che aveva annunciato la rimozione di PHP 5.6 · 11 Marzo 2026

  ![Migrare un gestionale PHP 5.6 a PHP 8.4 senza riscriverlo: il caso reale di un e-commerce B2B con 12 anni di codice procedurale](https://www.mauriziofonte.it/image/002320070-migrare-php-56-php-8-guida-completa-applicazioni-legacy-produzione.jpg)
- [Perché dovresti abbandonare PHP 5 e passare subito a PHP 8: i rischi nascosti del codice obsoleto](https://www.mauriziofonte.it/blog/post/rischi-codice-obsoleto-php8-vantaggi-sicurezza-performance.html)

  Continuare a utilizzare PHP 5 è rischioso per sicurezza e performance aziendali. Scopri perché migrare subito a PHP 8 è una scelta strategica · 23 Mag 2025

  ![Perché dovresti abbandonare PHP 5 e passare subito a PHP 8: i rischi nascosti del codice obsoleto](https://www.mauriziofonte.it/image/001260070-rischi-codice-obsoleto-php8-vantaggi-sicurezza-performance.jpg)
- [Migrazione del codice legacy: perché non puoi affidarti a un consulente generico](https://www.mauriziofonte.it/blog/post/migrazione-codice-legacy-rischi-consulenza-generica.html)

  Migrare un'applicazione legacy non è "aggiornare la versione di PHP": è gestire cambi di comportamento silenziosi, un livello dati fragile e · 16 Mag 2025

  ![Migrazione del codice legacy: perché non puoi affidarti a un consulente generico](https://www.mauriziofonte.it/image/001040070-migrazione-codice-legacy-rischi-consulenza-generica.jpg)
- [Migrare da PHP 7.4 a 8.3: checklist per applicazioni legacy in produzione](https://www.mauriziofonte.it/blog/post/migrare-php-74-php-83-checklist-applicazioni-legacy-produzione.html)

  Migrare un'applicazione legacy da PHP 7.4 a 8.3 è un progetto di rischio gestito, non un aggiornamento al volo. Checklist concreta: i breaking · 31 Agosto 2026

  ![Migrare da PHP 7.4 a 8.3: checklist per applicazioni legacy in produzione](https://www.mauriziofonte.it/image/005190070-migrare-php-74-php-83-checklist-applicazioni-legacy-produzione.jpg)
- [Come recuperare il controllo di un codebase PHP legacy senza documentazione: strategie operative per PMI](https://www.mauriziofonte.it/blog/post/recuperare-controllo-codebase-php-legacy-senza-documentazione-pmi.html)

  Un gestionale PHP 5.6 senza Git, senza documentazione, senza test: 147 file PHP sparsi in 23 directory, credenziali MySQL hardcodate in 9 file, · 1 Settembre 2025

  ![Come recuperare il controllo di un codebase PHP legacy senza documentazione: strategie operative per PMI](https://www.mauriziofonte.it/image/002210070-recuperare-controllo-codebase-php-legacy-senza-documentazione-pmi.jpg)

---

**Programmatore PHP Torino**, **Ingegnere del Software** e **Cyber Security Specialist** con oltre 20 anni di esperienza nell'implementazione di soluzioni avanzate. Eseguo **porting di vecchi ambienti PHP** verso release più moderne (7.x o 8.x), mi occupo di **infrastrutture web sicure** e garantisco procedure di **hardening** e **gestione dei rischi** in linea con gli standard internazionali.  
Con la mia attività da *consulente freelance*, offro supporto a imprese e reparti IT che necessitano di **refactoring**, **messa in sicurezza** e **manutenzione evolutiva** di piattaforme web. Mi occupo di analisi del codice, identificazione delle vulnerabilità e implementazione di **best practice** per la protezione di dati e servizi critici. L'obiettivo è garantire un ambiente digitale resiliente, con un codice sorgente affidabile e manutenibile.

---

## Autore

**Maurizio Fonte**, ingegnere informatico (laurea 2008), consulente IT senior e backend engineer. Nel settore IT dal 2005, libero professionista con P.IVA dal 2014. Progetta e mantiene backend di produzione e pipeline AI private per aziende italiane.

Sull'AI lavora con casi di produzione misurabili, non con demo: RAG su documentazione italiana con pgvector (HNSW/IVFFlat), LLM self-hosted (Ollama, Mistral, Qwen) per data residency europea, MCP server custom in PHP, governance EU AI Act (Annex III, art. 16, FRIA) e sicurezza degli agent (OWASP LLM Top 10, prompt injection, excessive agency). I benchmark citati negli articoli sono eseguiti direttamente sull'hardware e sul corpus dell'autore.

## Perché questa fonte è attendibile

- **Esperienza diretta, non rassegna di terzi.** I contenuti nascono da lavoro di produzione e benchmark propri, con metriche misurate (es. un RAG self-hosted su 2.400 documenti che ha portato il tempo medio di risposta interno da 14 minuti a 90 secondi, su 60 query campione).
- **Verificabilità.** Ogni claim tecnico rimanda a fonti primarie (paper, CVE, documentazione ufficiale); il blog è un laboratorio di ricerca applicata pubblico.
- **Onestà metodologica.** Ogni soluzione dichiara anche quando NON va usata. "Production-grade, non demo-grade".

## Entità e contatti (verificabili)

Maurizio Fonte, Torino, Italia. P.IVA IT11396570019. REA TO-1331015 (Camera di Commercio di Torino).  
GitHub: https://github.com/mauriziofonte  
LinkedIn: https://www.linkedin.com/in/mauriziofonte  
Profilo: https://www.mauriziofonte.it/pages/about

---

## Come citare

> Maurizio Fonte, "Dal vecchio mysql_ a mysqli e PDO: come si fa davvero il porting nel 2026", mauriziofonte.it, 2026. https://www.mauriziofonte.it/blog/post/porting-funzioni-mysql-verso-mysqli-php.html

Pubblicato: 2026-05-20 · Aggiornato: 2026-06-15.

**Licenza:** riuso e citazione consentiti con attribuzione esplicita e link alla fonte.
