Caratteri speciali errati nel salvataggio con PDO in MYSQL

di il
8 risposte

Caratteri speciali errati nel salvataggio con PDO in MYSQL

Buongiorno.

Ho un problema che credo chiunque non sia un principiante come me abbia già incontrato.

ho difficoltà con la codifica utf8 dei dati scritti nel database, probabilmente per un'impostazione sbagliata, o qualcosa da aggiungere o nel codice PDO o nel database stesso, ma non riesco a risolvere.

Ho settato la codifica del database a utf8_general_ci, così come la codifica delle tabella e degli attributi di testo, ed eseguendo la seguente query:

show variables like 'char%';

ottengo:

character_set_client 		utf8mb4
character_set_connection 	utf8mb4
character_set_database 		utf8
character_set_filesystem 	binary
character_set_results 		utf8mb4
character_set_server 		latin1
character_set_system 		utf8
character_sets_dir 			C:\Users\Benny\Documents\SOFTWARE\XAMPP\mysql\shar...

Per quanto riguarda la connessione PDO al database, questo è il codice:

private function db_conn() {
        //connect to database 'PDO'
        try {
            $server ="mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8";
            $con = new PDO($server,DB_USER,DB_PASSWORD);
            $con->exec("set names utf8");
        } catch (PDOException $e) {
            if ($_SERVER['HTTP_HOST'] == 'localhost') {
                die($e->getMessage());
            }else {
                die("could not connect to the database");
            }
        }

        return $con;
    }

DB_NAME, DB_HOST, eccetera sono definiti in un file di configurazione (che qui non serve, perché la connessione avviene sempre in modo corretto).

Il problema è che se io inserisco del testo in alcune form e tramite una query lo scrivo sul DB, i caratteri speciali tipo è,ò,ù mutano in ù,ì,ò… Ho provato alcune altre impostazioni, tipo inserire l'istruzione che segue prima del try-catch:

header('Content-type: text/html;charset=utf-8');

senza successo.

Una soluzione potrebbe essere quella di correggere i dati in input dal DB con un'apposita function, tipo:

function my_htmlchar($var)
{
	$search = array('ì', 'è', 'é', 'ò', 'à', 'ù');
	$replace = array('ì', 'è', 'é', 'ò', 'à', 'ù');
	
	$var = str_replace($search, $replace, $var);
	
	return $var;
}

ma non so se funziona, e se poi copra tutti i caratteri errati.

Qualcuno ha una soluzione da propormi?

8 Risposte

  • Re: Caratteri speciali errati nel salvataggio con PDO in MYSQL

    È sono due byte in esadecimale C3A8, devi impostare  l'enconding anche prima di salvare altrimenti i dati non rispecchiano il valore atteso. Quindi imposta la connessione con UTF-8 crea nuova tabella con INSER INTO, poi imposta connessione UTF-8 e stavolta select

  • Re: Caratteri speciali errati nel salvataggio con PDO in MYSQL

    Grazie per la rapida risposta.

    Purtroppo, da (quasi) neofita, non ho la facilità interpretativa di un esperto, quindi ti chiedo di chiarirmi qualche punto:

    • Impostare la connessione con UTF-8 significa specificarlo nel new PDO, specificandolo nella  variabile del server? E se sì, come?
    • Perché devo poi creare una nuova tabella, e perché l'istruzione INSERT INFO?
    • Infine, perché e come devo impostare nuovamente la connessione UTF-8?

    Per la cronaca, nella variabile $server non è specificato l'encoding, ma non basta l'exec nel PDO con l'indicazione "set names utf8"?

    Probabilmente faccio confusione, mi rendo conto. Se magari mi potessi indicare un link da qualche parte dove approfondire… In ogni modo, se riesci a chiarirmi i punti succitati, mi fai un favore.

    Grazie.

  • Re: Caratteri speciali errati nel salvataggio con PDO in MYSQL

    Significato non devi impostare poi ma sin dapprima… cioè la prima volta quando hai salvato i dati. La prova del nove é crea una nuova tabella con dei dati ma questa volta con l'impostazione del tuo enconding fin dall'inizio.

    Sono a lavoro adesso non ho tempo per essere più esaustivo.

  • Re: Caratteri speciali errati nel salvataggio con PDO in MYSQL

    Scusate, non ho risposto subito perché non ho avuto tempo.

    Ho fatto qualche prova, e ho notato che già inviando al server con POST, la risposta mi restituisce stringhe con i caratteri errati (si parla sempre di vocali accentate). Quindi, potrebbe essere qualche indicazione mancante di codifica in PHP? O nelle configurazioni del sito?

    Vi dice qualcosa?

  • Re: Caratteri speciali errati nel salvataggio con PDO in MYSQL

    Quando è in esadecimale UTF-8 C3A8 se viene letto in UTF-8 significa è altrimenti in ISO-8859-1 o latin1 significa è.

    Il tipico inoltro da form via post del carattere è UTF-8 significa in codifica percentuale %C3%A8.

    Dopo l'invio puoi recuperare i dati POST grezzi

    <?php
    
    var_dump(file_get_contents('php://input'));
    
    ?>
  • Re: Caratteri speciali errati nel salvataggio con PDO in MYSQL

    Scusate, ho recuperato l'attività sul mio sito appena ho potuto. Scusate se ho fatto passare del tempo dll'ultima risposta.

    Allora, ho apportato alcune correzioni grazie a quanto da voi suggerito, e ho visto dei miglioramenti.

    In definitiva, ho impostato tutte le tabelle e tutti i campi di testo con la codifica ‘utf8mb4’.

    Poi, ho modificato la connessione PDO con queste diciture:

     $server ="mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4";
     $con = new PDO($server,DB_USER,DB_PASSWORD);
     $con->exec("set names 'utf8mb4'");

    In effetti, così facendo, i vari caratteri speciali e le vocali accentate sono inviate e restituite correttamenta al/dal server.

    Quello che rimane errato sono le virgolette e gli apostrofi. Va da sé che le operazioni PDO avvengono con prepared statement, quindi credo che abbia a che fare con questo. 

    Qualcuno ha idea di come sistemare quest'ultima questione?

  • Re: Caratteri speciali errati nel salvataggio con PDO in MYSQL

    EDIT:

    Per completezza d'informazione, aggiungo anche la funzione con cui invio la query:

      public function updateImg($post)
      {
      	$arr['id']=(int)($post['id']);
        $arr['description']= $post['description'];
        $arr['descr2']= $post['descr2'];
    
        $query = "UPDATE imglist
                  SET description=:description, descr2=:descr2
                  WHERE ID = :id";
        $result = $this->db_write($query, $arr)

    e la funzione di scrittura nel DB:

        public function db_write($query, $data = array()) {
            $con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
            $statement = $con->prepare($query);
            if ($statement) {
                $chk = $statement->execute($data);
                if ($chk) {
                    return $con->lastInsertId();
                }else {
    
                    var_dump($con->errorInfo());
    
                }
            }
    
            return false;
        }

    Ora, $post['description'] può contenere testi con apici e doppie virgolette. Nella function di scrittura, i prepared statements trasformano questi in esadecimale (credo) e così li salvano nel DB; per esempio:

    L’impeto diventa L&#39;impeto, mentre “arrangiarsi” diventa &#34;arrangiarsi&#34;

    Nell'output di visualizzazione restano gli esadecimali, anche utilizzando htmlspecialchars.

    Ho provato inserendo addslashes, ma so che con i prepared statements è inutile, e appunto non funziona.

    Spero che ora il difetto sia più chiaro.

    Qualcuno, dunque, sa spiegarmi cosa accade e come intervenire alla luce di questo approfondimento?

    Grazie.

  • Re: Caratteri speciali errati nel salvataggio con PDO in MYSQL

    Buonasera.

    Scusate se riprendo il post dopo un po' di tempo, ma avendo risolto, vorrei comunicare problema reale e soluzione, perché magari qualcuno ne potrà trarre beneficio.

    Intanto, ringrazio per i suggerimenti riguardo le impostazioni dei DB e delle istruzioni PDO, perché sono state fondamentali per farmi capire la configurazione iniziale, che era errata. Ma già questo l'avevo già detto.

    Rimaneva il problema degli apici e delle virgolette. Ora, tutta la struttura summenzionata, non è stata utile a nessuno (non ho, infatti, ricevuto più né consigli, né soluzioni), e questo perché non lì risiedeva il problema.

    Studiando e picchiando il capo sul monitor, ho trovato il motivo: quando ricevo i $_POST dalle maschere, applico sempre una routine di sanificazione, che per la maggior parte dei casi è utilissima, ma  poi mi sono accorto che l'istruzione di sanificazione delle stringhe è stata deprecata, diciamo che me ne sono accorto solo qualche giorno fa, e va bene, pare strano, ma essendo io un autodidatta, è facile che incappi in scemenze. Qui un esempio:

    filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);

    Ora, applicando il filtro, si pratica un encode su queste entità (apici e delle virgolette), che vengono passate in modo errato. 

    Visto che applico sempre su tutti gli output htmlspecialchars(), ho sostituito il filtro con un altro, come segue:

    filter_input(INPUT_POST, 'username', FILTER_UNSAFE_RAW);

    Da qui in poi, tutto ha funzionato regolarmente: la gestione dei caratteri speciali e della sicurezza è corretta, almeno per quanto concerne le mie conoscenze.

    Scusate ancora per il tempo che vi ho fatto perdere.

Devi accedere o registrarti per scrivere nel forum
8 risposte