Riepilogo post nella categoria Database Mysql

Soluzione errore 1256 mysql "data truncated for column"

Postato in Database Mysql | Backup

Stamattina mi è capitato un errore insolito, durante l'importazione di un file di dump di mysql da un server verso un altro server.

Inspiegabilmente, il conteggio delle righe di una tabella sul "server sorgente" era molto più alto rispetto al conteggio delle stesse righe sulla stessa tabella, ma del server di backup.

Quindi, per tentare di capire la ragione del problema, ho creato dapprima un dump della sola tabella "incriminata" dal server sorgente, con

mysqldump -u UTENTE -pPASSWORD --skip-add-locks --compact --quick --lock-tables=false --delayed-insert=true --no-create-info --skip-triggers DATABASE TABELLA | gzip > dump.sql.gz

Una volta effettuato il dump, ho provato ad importarlo sul server di backup, con

gunzip < dump.sql.gz | mysql -u UTENTE -pPASSWORD --force DATABASE

Risultato? Per quella tabella, durante l'importazione, venivano sollevati tantissimi errori da mysql, che recitavano:

ERROR 1265 (01000) at line 683: Data truncated for column 'column_name' at row 10

La ragione del problema? La configurazione del server mysql sul server di backup, in particolare la configurazione del parametro sql-mode su my.cnf, relativa alle impostazioni di safety dell'ambiente mysql.

Ho scoperto che quelle righe nel file di dump erano relative ad un vecchio sottoinsieme di valori che nel server principale erano stati scritti senza la modalità "NO_AUTO_VALUE_ON_ZERO", ovvero la modalità secondo la quale il server mysql non inserirà dei valori NULL di default per le colonne nullabili, se non direttamente specificato.

Per ovviare al problema, quindi, abbiamo 2 soluzioni: la prima è ricostruire la tabella "sorgente" con dei dati corretti, usando il metodo che più vi è comodo. La seconda soluzione è quella di disabilitare alcune impostazioni di safety sul server di backup.

Vi basterà quindi semplicemente rimuovere il token "NO_AUTO_VALUE_ON_ZERO" dalla configurazione di my.cnf per non ricevere più errori nell'importazione.

Ovviamente la soluzione 2 va bene sul server di backup perchè è appunto un server di backup, quindi nessuno vi verrà mai a dire nulla sulla coerenza dei dati o sulla bontà delle configurazioni di safety su quel server mysql. Ad ogni modo, la soluzione più corretta sarebbe quella di correggere le righe con errori di coerenza dei dati all'interno del server di origine e mantenere le impostazioni di safety così come sono per lavorare "allo stato dell'arte".

Nella fattispecie, per correggere la coerenza dei dati, dovrete necessariamente ciclare su tutte le righe della tabella, costruirvi una lista di insert, troncare la tabella, ed eseguire le insert calcolate prima.

Un buon sito si costruisce prima di tutto creandolo con funzionalità multilingua. Ovvero, sulla base dell'IP dell'utente, cercare di mandare in output il sito nel suo linguaggio senza troppi fronzoli tecnici.

Questo si traduce, nella pratica, nella creazione di un sito con una buona classe di traduzione delle stringhe on-the-fly, un pò come fa wordpress. Per esempio, wordpress fa uso dei file di traduzione *.po e *.mo.. Si definisce una stringa, con la sua "chiave primaria" nel linguaggio che si vuole, ad esempio:


<div id="test"><?php echo __ ( 'This is the main key for the string "this is the main key for the string"' ); ?></div>

A questo punto, aiutandovi con le funzioni di output buffering, e sulla base della geolocation dell'IP dell'utente che sta visualizzando il sito, potete mandare in output la traduzione corretta della stringa This is the main key for the string "this is the main key for the string"

In internet esistono svariate classi che permettono la geolocation. A me personalmente non piace fare le cose semplici, e mi piace avere la situazione sotto controllo. Quindi, mi sono documentato, e ho trovato un sito che permette il download di un file di mapping tra indirizzi IP e stati.

Avendo in mano un file del genere, è possibile creare un DB che abbia le referenziazioni tra IP e location, e così possiamo dare sfogo alla nostra creatività in termini di output da mandare all'utente ^^

Prima di tutto, prepariamo i DB che contengono i dati del DB IP-to-country


CREATE TABLE IF NOT EXISTS `ip_to_country` (
  `id` int(11) NOT NULL auto_increment,
  `ip_start_integer` int(11) NOT NULL,
  `ip_end_integer` int(11) NOT NULL,
  `country_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `ip_start_integer_index` (`ip_start_integer`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `country_list` (
  `id` int(11) NOT NULL auto_increment,
  `country_code` varchar(10) character set utf8 collate utf8_bin NOT NULL,
  `country_name_en` varchar(255) character set utf8 collate utf8_bin NOT NULL,
  `country_name_it` varchar(255) character set utf8 collate utf8_bin NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `country-name` (`country_name_en`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

Adesso, passiamo alla parte divertente, cioè al parsing del file di mapping IP-country e al relativo salvataggio dei dati nelle nostre 2 tabelle mysql


<?php
	/*
		http://www.ipinfodb.com/
		
		API KEY: bisogna registrarsi per averla
		http://lite.ip2location.com/?file=IP2LOCATION-LITE-DB1.CSV.ZIP&key=	
	*/

	// CONNESSIONE AL DB - DA INSERIRE QUI
	
	$stream_ZIPFILE = __CURL_getURL( 'http://lite.ip2location.com/?file=IP2LOCATION-LITE-DB1.CSV.ZIP&key=la-chiave-api-del-sito-ipinfodb.com', 'http://www.ipinfodb.com/download.php?file=IP2LOCATION-LITE-DB1.CSV.ZIP' );
	file_put_contents ( 'tempzipfile', $stream_ZIPFILE );
	$stream_ZIPFILE = ''; // releasing memory for this variable
	
	$zip = zip_open ( 'tempzipfile' );
	unlink ( 'tempzipfile' );
	do {
		$entry = zip_read($zip);
	} while ($entry && zip_entry_name($entry) != "IP2LOCATION-LITE-DB1.CSV");
	
	zip_entry_open($zip, $entry, "r");
	$entry_content = zip_entry_read($entry, zip_entry_filesize($entry));
	$entry_content = str_replace ( chr(13).chr(10), chr(10), $entry_content );
	
	$linee = explode ( chr(10), $entry_content );
	$entry_content = ''; // releasing memory for entry_content ( it's a long string )
	
	// flushing ip_to_country DB
	$sql = "TRUNCATE TABLE ip_to_country";
	mysql_query($sql);
	
	// parsing Text DB Lines
	foreach ( $linee as $linea ) {
		list ( $start_ip_integer, $end_ip_integer, $country_code, $country_name ) = explode ( ',', str_replace ( '"', '' , $linea ) );
		
		// inserting country into country DB  (if needed)
		$sql = "SELECT id FROM country_list WHERE country_name_en='" . $country_name . "'";
		$rs = mysql_query ( $sql );
		if ( $rs && mysql_num_rows ( $rs ) == 1 ) $idCountry = mysql_result ( $rs, 0 );
		else {
			// translating country in Italian
			$stream_TRANSLATE = __CURL_getURL( 'https://www.googleapis.com/language/translate/v2?key=la-tua-api-key-google.translate&q=' . urlencode ( $country_name ) . '&source=en&target=it', 'http://www.google.it/' );
			$stream_TRANSLATE_array = json_decode ( $stream_TRANSLATE );
			$countryname_IT = strtoupper ( $stream_TRANSLATE_array -> data -> translations[0] -> translatedText );
			
			$sql = "INSERT INTO country_list ( country_code, country_name_en, country_name_it ) VALUES ( '$country_code', '$country_name', '$countryname_IT' )";
			mysql_query ( $sql );
			
			$idCountry = mysql_insert_id();
		}
		
		$sql = "INSERT INTO ip_to_country ( ip_start_integer, ip_end_integer, country_id ) VALUES ( '$start_ip_integer', '$end_ip_integer', '$idCountry' )";
		mysql_query ( $sql );
	}


	function __CURL_getURL($url, $referer) {
		$header[0] = "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
		$header[] = "Cache-Control: max-age=0";
		$header[] = "Connection: keep-alive";
		$header[] = "Keep-Alive: 300";
		$header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7";
		$header[] = "Accept-Language: it-it,it;q=0.8,en-us;q=0.5,en;q=0.3";
		$header[] = "Pragma: ";
		$header[] = "Referer: " . $referer;

		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $header); 
		curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3");
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_VERBOSE, true);
		curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
		curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
		$result = curl_exec($ch);
		curl_close($ch);

		return $result;
	}

?>

Per avviare questo codice, avrete bisogno di 2 api key:

  • Una api key del servizio http://www.ipinfodb.com/ - rimpiazza la stringa "la-chiave-api-del-sito-ipinfodb.com" all'interno del sorgente qui sopra con la tua api key
  • Una api key del servizio Google Translate API - rimpiazza la stringa "la-tua-api-key-google.translate" all'interno del sorgente qui sopra con la tua api key

Una volta fatto tutto, potete schedulare questo script per l'esecuzione automatica con un cronjob. Anche una volta alla settimana va bene, non è necessario farlo partire ogni ora ^^

Ora, ti starai chiedendo: e come faccio a stabilire la geolocation dell'utente con questi due database? Bene, ecco le poche linee di codice per sfruttare le tabelle.


// ottenere la "country_id" dal database delle country per un particolare IP
$ip = $_SERVER['REMOTE_ADDR']; // o qualsiasi ip nel formato 123.123.123.123 ottenuto con qualsiasi metodo
$sql = "SELECT country_id FROM ip_to_country WHERE ip_start_integer <= " . ip2long ( $ip ) . " ORDER BY ip_start_integer DESC LIMIT 1";
$rs = mysql_query ( $sql );
if ( $rs ) $country_id = mysql_result ( $rs, 0 );

Con la country_id per un particolare IP, sarà vostro compito stabilire quale lingua mandare in output all'utente.
Ovviamente, questo database può avere tantissimi risvolti pratici. Un altro che mi viene in mente è la geolocalizzazione di server proxy, o la geolocalizzazione degli IP di una applicazione di tracciamento degli utenti.

Insomma, con le tabelle IP-to-country avrete a disposizione tantissime possibilità di sviluppo e soprattutto, avendo in mano i dati nel vostro DB, potrete generare i volumi di traffico che desiderate per quanto riguarda le geolocation calcolate per ora. Infatti, alcuni servizi online di geolocalizzazione, vi impediscono di fare più di un tot di query all'ora.

Se hai un sito qualsiasi, dove richiedi la registrazione per usufruire del sito, molto probabilmente non hai mai pensato che le email che gli utenti utilizzano per registrarsi possano diventare denaro..

L'argomento che andrò a trattare oggi è un pò scottante, lo ammetto: le email di spam, pubblicitarie, sono davvero fastidiose. Ma se abbiamo un sito, e stiamo richiedendo la verifica dell'email dopo la registrazione, quelle email valgono oro.

Il problema, però è il seguente: nessun advertiser accetterà mai delle liste di email nelle quali l'utente non abbia specificatamente dichiarato di voler ricevere delle email pubblicitarie.

Quindi, come facciamo a trasformare un semplice e scarno database di contatti email in un vero e proprio database di email DOUBLE OPT-IN?

Beh, lasciamo fare il lavoro sporco a PHP+mySQL. Per prima cosa, creiamo le tabelle del database per eseguire gli script che faranno funzionare il gioco:


CREATE TABLE IF NOT EXISTS `email_marketing_contacts` (
  `id` int(11) NOT NULL auto_increment,
  `email` varchar(255) character set utf8 collate utf8_bin NOT NULL,
  `subscribed` tinyint(1) NOT NULL default '0',
  `unsubscribed` tinyint(1) NOT NULL default '0',
  `info_emails` tinyint(1) NOT NULL default '0',
  `double_opt_in` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`id`),
  KEY `index-emails` (`email`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `email_marketing_lists` (
  `id` int(11) NOT NULL auto_increment,
  `email_subject` varchar(255) NOT NULL,
  `email_content_text` longtext NOT NULL,
  `email_content_html` longtext NOT NULL,
  `creation_date` datetime NOT NULL,
  `active` tinyint(1) NOT NULL default '1',
  `completion_date` datetime NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `email_marketing_emailstocrons` (
  `id` int(11) NOT NULL auto_increment,
  `listid` int(11) NOT NULL,
  `contactid` int(11) NOT NULL,
  `email` varchar(255) character set utf8 collate utf8_bin NOT NULL,
  `sent` tinyint(1) NOT NULL default '0',
  `sent_date` datetime NOT NULL,
  `status` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

Ovviamente, all'inizio, tutti i contatti dovranno essere inseriti dentro il database "email_marketing_contacts". Sarà vostro compito creare uno script che tenga aggiornato il database dei contatti, senza sovrascritture delle email o compagnia bella.

A questo punto, diamo un'occhiata agli script PHP per creare la nostra bella lista di email double opt-in. Servono:

  • Uno script per la creazione di "newsletter" da mandare a tutti i contatti di "email_marketing_contacts"
  • Uno script ( magari cronnato ) che invii le email, magari a scaglioni di 100 per volta, per evitare che i servizi di web hosting economici rompano le scatole se inviamo troppe email per volta
  • Una pagina cliccabile nell'email che arriverà agli utenti, nella quale l'utente possa scegliere se iscriversi double opt-in oppure disiscriversi completamente

Codice 1: Creazione delle Email


<?php
	if ( isset ( $_POST['email_subject'] ) && strlen ( $_POST['email_subject'] ) > 0 ) {
		
		// CONNESSIONE AL DB - INSERIRE QUI
		
		$sql = "INSERT INTO email_marketing_lists ( email_subject, email_content_text, email_content_html, creation_date ) VALUES ( '" . mysql_real_escape_string ( $_POST['email_subject'] ) . "', '" . mysql_real_escape_string ( $_POST['email_content_text'] ) . "', '" . mysql_real_escape_string ( $_POST['email_content_html'] ) . "', '" . date ( 'Y-m-d H:i:s' ) . "' )";
		mysql_query ( $sql );
		
		if ( strlen ( mysql_error() ) == 0 ) {
			$listID = mysql_insert_id();
			
			$sql = "SELECT id, email FROM email_marketing_contacts ORDER BY id ASC";
			$rs = mysql_query ( $sql );
			while ( $rw = mysql_fetch_assoc ( $rs ) ) {
				$sql = "INSERT INTO email_marketing_emailstocrons ( listid, contactid, email ) VALUES ( '$listID', '" . $rw['id'] . "', '" . $rw['email'] . "' )";
				mysql_query ( $sql );
				$contatti_a_cron++;
			}
		}
	}
	
	if ( $contatti_a_cron > 0 ) echo '<p>Lista creata con successo! Aggiunti ' . $contatti_a_cron . ' contatti alla lista</p>';
?>

<form method="post">
	Oggetto Email: <input type="text" name="email_subject" /><br />
	Parte Testuale Email: <br />
<txtarea name="email_content_text" style="width: 1000px; height: 200px;"></txtarea><br />
	Parte HTML Email: <br />
<txtarea name="email_content_html" style="width: 1000px; height: 200px;"></txtarea><br />
<input type="submit" value="Invia" />
</form>

Codice 2: Invio delle Email Effettivo


<?php
	// CONNESSIONE AL DB - INSERIRE QUI
	
	$sql = "SELECT * FROM email_marketing_lists WHERE active='1' LIMIT 1";
	$rs = mysql_query ( $sql );
	if ( $rs && mysql_num_rows ( $rs ) == 1 ) {
		// esiste una lista attiva, vediamo che succede...
		$rw = mysql_fetch_assoc ( $rs );
		
		$listID = $rw['id'];
		$subject = stripslashes ( $rw['email_subject'] );
		$emailTextPart = wordwrap ( stripslashes ( $rw['email_content_text'] ), 50 );
		$emailHtmlPart = wordwrap ( stripslashes ( $rw['email_content_html'] ), 50 );
		
		$sql = "SELECT * FROM email_marketing_emailstocrons WHERE sent='0' AND listid='$listID' LIMIT 100";
		$rs2 = mysql_query ( $sql );
		if ( $rs2 && mysql_num_rows ( $rs2 ) >= 1 ) {
			// invio effettivo delle email...
			
			while ( $rw2 = mysql_fetch_assoc ( $rs2 ) ) {
				// prima di tutto, rimpiazzo la variabile di UTENTE con una stringa calcolata adesso
				$idUtente = base_convert( $rw2['contactid'] + 12445, 10, 36 );
				
				// Invio effettivo della email con il metodo doppio
				$random_hash = md5(microtime());
				$header = "From: Quello che vuoi <quellochevuoi@ciaociao.it>\n";
				$header .= "X-Mailer: PHP-simple-email-boundary\n";
				$boundary = "==String_Boundary_x" . md5(time()). "x";
				$header .= "MIME-Version: 1.0\n";
				$header .= "Content-Type: multipart/alternative;\n";
				$header .= " boundary=\"$boundary\";\n\n";
				
				$messaggio = "Se visualizzi questo testo, manda una email ad quellochevuoi@ciaociao.it specificando che non e' stato possibile leggere questa email \n\n";
				$messaggio .= "--$boundary\n";
				$messaggio .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
				$messaggio .= "Content-Transfer-Encoding: 7bit\n\n";
				$messaggio .= str_replace ( '$$ID_UTENTE$$', $idUtente, $emailTextPart ) . "\n\n";
				$messaggio .= "--$boundary\n";
				$messaggio .= "Content-Type: text/html; charset=\"iso-8859-1\"\n";
				$messaggio .= "Content-Transfer-Encoding: 7bit\n\n";
				$messaggio .= str_replace ( '$$ID_UTENTE$$', $idUtente, $emailHtmlPart ) . "\n";
				
				$status = mail( $rw2['email'], $subject, $messaggio, $header );
				
				sleep ( 8 ); // mandiamone 1 ogni 8 secondi...
				
				$sql = "UPDATE email_marketing_emailstocrons SET sent='1', sent_date='" . date ( 'Y-m-d H:i:s' ) . "', status='$status' WHERE id='" . $rw2['id'] . "'";
				mysql_query ( $sql );
			}
		}
		else {
			// questa lista è stata completata! Quindi aggiorniamo la variabile "active" e settiamo la completion della lista ad adesso
			$sql = "UPDATE email_marketing_lists SET active='0', completion_date='" . date ( 'Y-m-d H:i:s' ) . "' WHERE id='$listID'";
			mysql_query ( $sql );
		}
	}
?>

Codice 3: Pagina di Ponte da linkare nell'email, per fare in modo che l'utente faccia la sua scelta


<html>
<head>
<title>pagina di ponte</title>
<style type="text/css">
	* { font-family: "Lucida Sans","Lucida Sans Regular","Lucida Grande","Lucida Sans Unicode",Geneva,Verdana,sans-serif; margin: 0; outline: 0 none; padding: 0; }
	body { background: none no-repeat scroll 0 0 #555555; font-size: 80%; }
	div#wrapper { background: none no-repeat scroll 0 0 #FFFFFF; border-left: 1px solid #888888; border-right: 1px solid #888888; box-shadow: 0 0 15px 5px #FFFFEE; margin: 0 auto; padding: 0 15px; position: relative; width: 650px; }
	div#header { height: 90px; position: relative; }
	div#header div#logo { height: 90px; left: 0; position: absolute; top: 0; width: 500px; }
	div#header div#logo a { background: url() no-repeat scroll 0 0 transparent; display: block; height: 90px; width: 315px; }
	div#header div#logo h2 { color: #7CA431; font-size: 11px; left: 65px; padding: 1px 3px; position: absolute; top: 5px; }
	div#header div#logo p { bottom: 0; color: transparent; font-size: 1px; height: 1px; left: -9000px; margin: 0; padding: 0; position: absolute; }
	h1 strong, h1 strong, h3 strong { left: -9000px; position: absolute; text-indent: -9000px; top: 0; }
	div#content { margin-top: 20px; }
	h3 { margin: 5px 0; color: #007BB4; }
	div#module { margin: 20px 0; border-top: 1px solid #888888; border-bottom: 1px solid #888888; background-color: #FFEEEE; padding: 30px; }
	
	form { text-align: center; margin-top: 15px; }
	form p { text-align: left; }
	input.submit { border: 1px solid #007BB4; font-weight: bold; font-size: 16px; padding: 5px; background-color: #FFF; text-align: left; }
	input.submit:hover { border: 1px solid #7CA431; background-color: #EEFFFF; }
</style>

<script type="text/javascript">
	function checkCheckboxes () {
		
		if ( ! document.getElementById ( 'infemails' ).checked && ! document.getElementById ( 'advemails' ).checked ) {
			if ( ! document.getElementById ( 'infemails' ).checked ) {
				var el = document.getElementById ( 'infemails' ).parentNode;
				el.style.backgroundColor = '#FCAC98';
				el.style.padding = '10px';
			}
			if ( ! document.getElementById ( 'advemails' ).checked ) {
				var el = document.getElementById ( 'advemails' ).parentNode;
				el.style.backgroundColor = '#FCAC98';
				el.style.padding = '10px';
			}
			var go = confirm ( 'Per iscriverti alla newsletter, e\' necessario mettere la spunta sia su "email informative" sia su "email pubblicitarie".\nVuoi continuare lo stesso con questa scelta? Cosi\' facendo non sarai iscritto alla newsletter,\ne non potrai rimanere aggiornato sulle novita\'.' );
			
			if ( go ) return true;
			else return false;
		}
		else return true;
	}
</script>
</head>
<body>
<div id="wrapper">
	<div id="header">
		<div id="logo">
			logo & header
		</div>
	</div>
<?php
	if ( isset ( $_POST['action'] ) && strlen ( $_POST['action'] ) > 0 ) {
		
		// CONNESSIONE AL DB QUI
		
		$id_utente = $_POST['id_utente'];
		
		// gestione POST
		switch ( $_POST['action'] ) {
			case 'sub':
				// sottoscrizione
				
				$infemails = ( isset ( $_POST['infemails'] ) && $_POST['infemails'] == 1 ) ? 1 : 0;
				$advemails = ( isset ( $_POST['advemails'] ) && $_POST['advemails'] == 1 ) ? 1 : 0;
				
				$sql = "SELECT * FROM email_marketing_contacts WHERE id='$id_utente'";
				$rs = mysql_query ( $sql );
				if ( $rs && mysql_num_rows ( $rs ) == 1 ) {
					$sql = "UPDATE email_marketing_contacts SET subscribed='1', unsubscribed='0', info_emails='$infemails', double_opt_in='$advemails' WHERE id='$id_utente'";
					mysql_query ( $sql );
				}
				break;
			case 'unsub':
				// disiscrizione
				$sql = "SELECT * FROM email_marketing_contacts WHERE id='$id_utente'";
				$rs = mysql_query ( $sql );
				if ( $rs && mysql_num_rows ( $rs ) == 1 ) {
					$sql = "UPDATE email_marketing_contacts SET unsubscribed='1', subscribed='0', info_emails='0', double_opt_in='0' WHERE id='$id_utente'";
					mysql_query ( $sql );
				}
				break;
			default: break;
		}
	}
	else if ( isset ( $_GET['u'] ) && strlen ( $_GET['u'] ) > 0 ) {
		$idUtente = ( base_convert( $_GET['u'], 36, 10 ) - 12445 );
?>
	<div id="content">
		 contenuto della email
	</div>
	<div id="module">
		<h2>Modulo di iscrizione/disiscrizione alla Newsletter</h2>
		<form method="post">
			<input type="hidden" name="action" value="unsub" />
			<input type="hidden" name="id_utente" value="<?php echo $idUtente; ?>" />
			<input type="submit" class="submit" value="Disiscrivimi per sempre dalla lista" />
		</form>
		<h3 style="margin-top 15px; text-align: center;">... oppure ...</h3>
		<form method="post" onsubmit="return checkCheckboxes();">
			<p style="text-align: left; font-size: 14px; margin: 5px 0;">Mantienimi iscritto alle email informative: <input type="checkbox" name="infemails" id="infemails" value="1" /> <strong>*</strong></p>
			<p style="text-align: left; font-size: 14px; margin: 5px 0;">Mantienimi iscritto alle email pubblicitarie: <input type="checkbox" name="advemails" id="advemails" value="1" /> <strong>*</strong></p>
			<input type="hidden" name="id_utente" value="<?php echo $idUtente; ?>" />
			<input type="hidden" name="action" value="sub" />
			<input type="submit" class="submit" value="Rimani iscritto alla newsletter" />
		<form>
		<p> </p>
		<p><strong>N.B.</strong></p>
		<p>Per <strong>rimanere iscritti alla newsletter</strong>, è necessario rimanere iscritti <strong>sia alle email informative, sia alle email pubblicitarie.</strong></p>
	</div>
<?php
	}
	else echo 'error';
?>
</div>
</body>
</html>

Capito tutto? In pratica, creiamo delle email con lo script 1. Le email saranno inviate in doppia modalità testuale+html, per rendere le email un pò più professionali. Questo significa che dovrete creare un testo e un sorgente html per la vostra email. Quindi, darete in pasto questi 2 sorgenti a questo script, che creerà un oggetto "email_marketing_lists" con oggetto, parte html e parte testo del vostro messaggio.

Una volta creata questa riga nel DB, non vi resterà che settare con un cronjob lo script di invio delle email ( il mio consiglio è di settare il cronjob per eseguire lo script ogni ora ).

Poi, tutto il resto lo farà la pagina di settaggio delle opzioni delle email degli utentu (script 3). Sarà vostro compito inserire, all'interno dell'email ( sia in formato testo che html ) un link alla pagina di modifica opzioni in questo formato:

http://www.ilmiodominio.it/lamiacartella/unaltra/index.php?u=$$ID_UTENTE$$

Lo script di invio delle email rimpiazzerà automaticamente questo placeholder con l'id effettivo del DB dei contatti di quella email. Il risultato? L'utente andrà a cliccare su un link che lo porterà ad una pagina che è già impostata sul suo id, quindi modificherà i dati suoi.

Avete visto quant'è semplice creare una lista di email double opt-in partendo da una lista che non è stata pensata per questo? Qualsiasi email si può trasformare in un potenziale introito di denaro extra con le email pubblicitarie!

Chi amministra un server web sa quanto è importante il discorso del salvataggio di quanto è stato creato, sia a livello di database sia a livello di file, di righe di codice scritte.

Per fortuna alcuni svegli programmatori di ngcoders.com hanno pensato a questo problema e hanno creato un piccolissimo script in grado di creare una copia di backup del filesystem e del database in una sola passata.
Sinceramente non ho trovato il nome di questo script, penso che lo chiamerò con un nome eloquente come 1-click filesystem and database backup tool

Il file .zip scaricato si compone di 3 file principali, scritti in php:

  • backup.php : lo script principale da richiamare per avviare il processo di backup
  • functions.php : le classi e le funzioni principali che creano fisicamente i backup
  • config.php : il file di configurazione semplice nel quale specificare le opzioni del backup che vogliamo ottenere

Il file di configurazione è assai semplice, come ho sottolineato prima, ecco una anteprima e qualche istruzione per completarlo:

<?php
// Quali directory/file da backuppare ( i nomi delle directory con lo slash iniziale )
// e' un array, quindi ricordatevi la virgola dopo ogni elemento tra le virgolette
$configBackup = array('../');
// Quali directory da saltare durante il processo di backup
$configSkip   = array('backup/');  
// Dove piazzare i file di backup a completamento dei processi? (ricordarsi lo slash finale)
$configBackupDir = 'backup/';
// I database dei quali effettuare il backup. Possono essere multipli. (Se l'array delle tabelle contiene delle entry, verranno salvate SOLO quelle tabelle!)
$configBackupDB[] = array(
'server' => 'localhost',
'username' => 'root',
'password' => '',
'database' => 'databasename',
'tables' => array('tabella1', 'tabella2', 'tabella3')
);
// Se vogliamo che il backup ci venga spedito via posta elettronica, specifichiamo un indirizzo valido
$configEmail = 'test@test.example.com';
?>

Niente di più semplice e niente di più funzionale: uno di quei tool che un Web Developer dovrebbe sempre tenere sotto mano, una sorta di chiave inglese da 10 del programmatore php/mysql

Ecco il link per scaricare il programma: script per la creazione di backup di file e database
Buon lavoro!