<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>vito tardia</title>
	<atom:link href="http://www.vtardia.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.vtardia.com</link>
	<description>web designer / developer</description>
	<lastBuildDate>Sun, 22 Apr 2012 16:47:51 +0000</lastBuildDate>
	<language>it</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Applicazioni sulla nuvola con Heroku e Facebook SDK</title>
		<link>http://www.vtardia.com/blog/applicazioni-sulla-nuvola-con-heroku-e-facebook-sdk/</link>
		<comments>http://www.vtardia.com/blog/applicazioni-sulla-nuvola-con-heroku-e-facebook-sdk/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 11:49:04 +0000</pubDate>
		<dc:creator>Ragman</dc:creator>
				<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Cloud Computing]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.vtardia.com/?p=615</guid>
		<description><![CDATA[Ho conosciuto Heroku quando era un servizio dedicato solamente al linguaggio Ruby, quindi l&#8217;ho archiviato come &#8220;potenzialmente interessante&#8221;. Dopo qualche tempo però c&#8217;è stata la partnership con Facebook, che ha reso possibile creare le proprie applicazioni sociali direttamente sui server di Heroku. La cosa è diventata d&#8217;un tratto molto più interessante. La domanda che mi [...]]]></description>
			<content:encoded><![CDATA[<p>Ho conosciuto Heroku quando era un servizio dedicato solamente al linguaggio Ruby, quindi l&#8217;ho archiviato come &#8220;potenzialmente interessante&#8221;. Dopo qualche tempo però c&#8217;è stata la partnership con Facebook, che ha reso possibile creare le proprie applicazioni sociali direttamente sui server di Heroku. La cosa è diventata d&#8217;un tratto molto più interessante.</p>
<p>La domanda che mi sono posto è stata: posso creare un&#8217;applicazione in PHP su Heroku che funzioni sia dentro sia fuori da Facebook? La risposta è sì e sto per dirvi anche come.<span id="more-615"></span></p>
<p>In questo articolo creerò una semplice applicazione per condividere dei link. Ogni utente può condividere un indirizzo web e assegnare un titolo e una descrizione. Ogni utente è identificato con il proprio indirizzo email (mantenuto privato) e se è autenticato all&#8217;interno di Facebook i suoi dati saranno recuperati dal profilo.</p>
<h2>Creazione di un account Heroku</h2>
<p>Tutto quello che serve per cominciare a lavorare con Heroku è creare un account. È una procedura che richiede 5 minuti di tempo e un&#8217;indirizzo email.</p>
<p>L&#8217;utilizzo base di Heroku è gratuito. Come riporta la documentazione &#8220;ogni applicazione ha accesso a 750 <em>ore dyno</em> al mese e a un database di 5Mb&#8221;. Un <em>dyno</em> è un singolo processo web che risponde alle richieste HTTP e le passa alla vostra applicazione.</p>
<p>Per utilizzare invece HTTPS dovete verificare il vostro account e fornire il numero di carta di credito. Ė necessario se volete che la vostra applicazione sia visibile quando Facebook utilizza la modalità sicura, ma se utilizzate il componente SSL di base sarà sempre gratuito.</p>
<h2>Installazione degli strumenti di sviluppo</h2>
<p>Il flusso di sviluppo di Heroku è interamente basato su Ruby e Git &#8211; la stessa console di Heroku altro non è che una gemma, e ogni volta che si esegue un comando <code>git push</code> l&#8217;applicazione è aggiornata in tempo reale. Quindi avremo bisogno di:</p>
<ul>
<li>installare Ruby (se usate OSX avete già la versione 1.8.x che è sufficiente);</li>
<li>installare Git;</li>
<li>installare la console Heroku (con il comando <code>sudo gem install heroku</code> o con <a title="Heroku command line utility installer" href="http://devcenter.heroku.com/articles/heroku-command">l&#8217;installer ufficiale</a>);</li>
<li>impostare l&#8217;ambiente di lavoro con le credenziali di Heroku e la vostra chiave SSH.</li>
</ul>
<p>Il modo migliore per fare tutte questo cose è seguire la guida rapida “<a title="Guida rapida ad Heroku (inglese)" href="http://devcenter.heroku.com/articles/quickstart">Getting Started with Heroku</a>”.</p>
<p>Per questo progetto è inoltre utile installare la gemma Taps che ci aiuterà ad esportare il nostro database.</p>
<pre class="console"><code>MyLaptop:~ ragman$ sudo gems install taps</code></pre>
<h2>Creare l&#8217;applicazione</h2>
<p>Il primo passo per creare l&#8217;applicazione è farlo sulla vostra macchina di sviluppo locale, poi si deve inizializzare il repository Git e successivamente si pubblica su Heroku.</p>
<h3>Creazione dell&#8217;app in locale</h3>
<p>Create una cartella vuota per l&#8217;applicazione e impostatela sul vostro web server.</p>
<pre class="console">MyLaptop:~ ragman$ cd /Users/Shared/WebServer/Sites
MyLaptop:Sites ragman$ mkdir HeroLinks</pre>
<p>Create un nuovo sito sul vostro web server locale e fatelo puntare alla cartella appena creata con una URL del tipo <code>http://herolinks.local</code>.</p>
<h3>Inizializzare il repository</h3>
<p>Inizializzate un nuovo repository Git all&#8217;interno della stessa cartella.</p>
<pre class="console">MyLaptop:Sites ragman$ cd HeroLinks
MyLaptop:HeroLinks ragman$ git init
Initialized empty Git repository in .git/
MyLaptop:HeroLinks ragman$ cat
MyLaptop:HeroLinks ragman$ git add .
MyLaptop:HeroLinks ragman$ git commit -m "HeroLinks app created."</pre>
<h3>Trasferire l&#8217;applicazione su Heroku</h3>
<p>Heroku imposta l&#8217;ambiente Ruby come impostazione predefinita per le nuove applicazioni. Per creare l’applicazione in PHP dobbiamo modificare gli argomenti della riga di comando per utilizzare lo stack chiamato Cedar.</p>
<p>Il comando da usare sarà simile a:</p>
<pre class="console">MyLaptop:HeroLinks ragman$ heroku create HeroLinks --stack cedar
Creating herolinks... done, stack is cedar
http://herolinks.herokuapp.com/ | git@heroku.com:herolinks.git
Git remote heroku added</pre>
<p>Il comando crea l’applicazione sul server di Heroku e ci comunica il suo indirizzo pubblico e il percorso del repository remoto.</p>
<p>Il comando per pubblicare l’applicazione è:</p>
<pre class="console">MyLaptop:HeroLinks ragman$ git push heroku master</pre>
<p>È necessario creare almeno un file nella cartella dell’applicazione o il comando fallisce, io ho creato un file <code>index.php</code> con un messaggio di benvenuto.</p>
<p>Il risultato del comando <code>push</code> sarà simile a:</p>
<pre class="console">Counting objects: 3, done.
Writing objects: 100% (3/3), 253 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
-----&gt; Heroku receiving push
-----&gt; PHP app detected
-----&gt; Bundling Apache v2.2.19
-----&gt; Bundling PHP v5.3.6
-----&gt; Discovering process types
 Procfile declares types -&gt; (none)
 Default types for PHP -&gt; web
-----&gt; Compiled slug size is 21.5MB
-----&gt; Launching... done, v4
 http://herolinks.heroku.com deployed to Heroku
To git@heroku.com:herolinks.git
 * [new branch] master -&gt; master</pre>
<h2>Cominciamo a programmare</h2>
<p>Quest’articolo è focalizzato principalmente su Heroku e Facebook, pertanto non scriverò tutto il codice da zero ma utilizzerò alcuni componenti già pronti:</p>
<ul>
<li>Bootstrap – una libreria CSS creata dai ragazzi di Twitter (per definire lo stile dell&#8217;interfaccia);</li>
<li>Slim – un framework PHP potente e leggero (per il controller principale);</li>
<li>un paio di librerie estratte dal framework CakePHP (per la validazione dell’input);</li>
<li>una semplice classe database creata da me che si appoggia a PDO.</li>
</ul>
<p>Come si può notare dalla struttura della directory l’applicazione è piuttosto semplice.</p>
<p><img class="size-medium wp-image-622 alignnone" title="Herolinks - fig1 - struttura dell'applicazione" src="/files/fig1-188x300.png" alt="" width="188" height="300" /></p>
<p>Un file <code>.htaccess</code> indirizza tutte le richieste allo script `index.php` che contiene tutta la logica di controllo. La directory <code>lib</code> contiene le librerie esterne e la cartella <code>templates</code> contiene i file dell’interfaccia.</p>
<p>La nostra applicazione ha tre pagine: una home page che visualizza tutta la lista dei link condivisi (home.php), una pagina che contiene il form per condividere un nuovo link (new.php) e una pagina che visualizza i risultati della ricerca (search.php).</p>
<h2>Accesso al database</h2>
<p>La piattaforma Heroku crea uno spazio di 5MB sul database condiviso per tutte le applicazioni Ruby. Per le applicazioni PHP la creazione del database non è automatica, dobbiamo crearlo manualmente con il comando:</p>
<pre class="console">MyLaptop:HeroLinks ragman$ heroku addons:add shared-database</pre>
<p>Le applicazioni possono accedere al database utilizzando la variabile d’ambiente <code>DATABASE_URL</code> che contiene la stringa di connessione. È accessibile da PHP come <code>$_ENV["DATABASE_URL"]</code>.</p>
<p>Se acquistate un database dedicato come Heroku Postgres potete usare la console <code>pgsql</code> per amministrarlo. I database condivisi sono devono invece essere gestiti manualmente, ad eccezione dei comandi <code>db:push</code> e <code>db:pull</code> per l’importazione e l’esportazione dei dati.</p>
<p>Non ho installato PostgreSQL sulla mia macchina di sviluppo, quindi per la versione locale dell’applicazione ho utilizzato SQLite che punta a un file nella directory <code>data</code>. Il codice utilizzato per caricare il driver corretto è:</p>
<pre>
<pre class="brush: php; ">
// if $_ENV[&quot;DATABASE_URL&quot;] is empty then the app is not running on Heroku
if (empty($_ENV[&quot;DATABASE_URL&quot;])) {
    $config[&quot;db&quot;][&quot;driver&quot;] = &quot;sqlite&quot;;
    $config[&quot;db&quot;][&quot;url&quot;] = &quot;sqlite://&quot; . realpath(&quot;data/my.db&quot;);
}
else {
    // translate the database URL to a PDO-friendly DSN
    $url = parse_url($_ENV[&quot;DATABASE_URL&quot;]);
    $config[&quot;db&quot;][&quot;driver&quot;] = $url[&quot;scheme&quot;];
    $config[&quot;db&quot;][&quot;url&quot;] = sprintf(
        &quot;pgsql:user=%s;password=%s;host=%s;dbname=%s&quot;,
         $url[&quot;user&quot;], $url[&quot;pass&quot;], $url[&quot;host&quot;],
         trim($url[&quot;path&quot;], &quot;/&quot;));
}
</pre>
</pre>
<p>Come prima cosa imposto il database di default a SQLite, se la variabile <code>$_ENV["DATABASE_URL"]</code> non è impostata vuol dire che sto utilizzando l’ambiente locale. Se invece sono su Heroku devo elaborare la stringa di connessione e convertirla in un formato compatibile con PDO. La stringa di partenza é simile a:</p>
<pre>postgres://username:password@host/database</pre>
<p>e deve essere convertita nel formato</p>
<pre>pgsql:user=username;password=password;host=host;dbname=database</pre>
<h2>Il controller principale</h2>
<p>Il file <code>index.php</code> è il controller principale dell&#8217;applicazione. Dopo aver impostato il database si passa a configurare i dettagli di Facebook, poi si caricano le altre librerie e si crea un nuovo oggetto della classe <code>Slim</code> che è la nostra applicazione.</p>
<pre>
<pre class="brush: php; ">
// Load the core Slim framework...
require_once &quot;lib/Slim/Slim.php&quot;;

// ...add other accessory libraries
require_once &quot;lib/db/db.class.php&quot;;
require_once &quot;lib/cake/sanitize.php&quot;;
require_once &quot;lib/cake/validation.php&quot;;

// and then the Facebook SDK
require_once &quot;lib/facebook/facebook.php&quot;;

// Create a new Slim application
$app = new Slim();
</pre>
</pre>
<p>In questo caso sto creando l&#8217;oggetto Slim con le impostazioni di default, è possibile passare al costruttore un array associativo di parametri, ma per il momento i default ci vanno bene.</p>
<p>Utilizziamo Slim per collegare le URL dell&#8217;applicazione ad altrettante funzioni PHP. Abbiamo 4 URL: <code>/</code> (la home), <code>/new</code>, <code>/search</code> e <code>/install</code>.</p>
<p>Slim consente di mappare ad una URL funzioni diverse per gestire i diversi metodi HTTP oppure una funzione sola che gestisce più di un metodo. In questo caso abbiamo bisogno che la funzione collegata alla URL principale gestisca i metodi <code>GET</code> e <code>POST</code>, perché quando l&#8217;applicazione sarà chiamata da Facebook riceverà dei dati via <code>POST</code>, la famosa <em>signed request</em>. Il codice che ci serve è:</p>
<pre>
<pre class="brush: php; ">
$app-&gt;map(&quot;/&quot;, function () use ($app, $config) {
            // do something
    })-&gt;via(&quot;GET&quot;, &quot;POST&quot;);
</pre>
</pre>
<p>Il metodo <code>map()</code> fa proprio questo, collega una funzione anonima all&#8217;URL principale e specificando che deve essere accessibile se il metodo HTTP utilizzato è <code>GET</code> o <code>POST</code>.</p>
<h2>Installazione dell&#8217;applicazione</h2>
<p>Normalmente cercherei di scrivere un codice di installazione che funzioni in qualsiasi ambiente, ma ci sono delle differenze tra SQLite e PostgreSQL che vanno oltre il raggio d&#8217;azione di questo articolo. Per ovviare a queste differenze l&#8217;installer è abilitato solo sulla copia locale dell&#8217;applicazione, per copiare i dati in remoto utilizzeremo le funzioni di Heroku.</p>
<p>La funzione anonima associate all&#8217;URL <code>/install</code> esegue un controllo sulla variabile <code>$config</code> per determinare l&#8217;ambiente di esecuzione. Se l&#8217;ambiente utilizza il driver SQLite vengono eseguite delle query che creano le tabelle necessarie utilizzando lo standard PDO.</p>
<pre>
<pre class="brush: php; ">
$app-&gt;get(&quot;/install&quot;, function() use ($app) {
    global $config;
    // check driver and perform install only for SQLite/local
    if ($config[&quot;db&quot;][&quot;driver&quot;] == &quot;sqlite&quot;) {
        if ($db = Db::getConnection()) {
            $query = &quot;CREATE TABLE IF NOT EXISTS links (
                id INTEGER PRIMARY KEY,
                url VARCHAR(255),
                title VARCHAR (100),
                description VARCHAR(512),
                username VARCHAR(50),
                useremail VARCHAR(100),
                created DATE DEFAULT (datetime(&#039;now&#039;,&#039;localtime&#039;))
            )&quot;;
            try {
                $stmt = $db-&gt;prepare($query);
                $stmt-&gt;execute();
                $app-&gt;flash(&quot;info&quot;, &quot;Application installed successfully!&quot;);
                $app-&gt;redirect(&quot;/&quot;);
            }
            catch (PDOException $e) {
                $app-&gt;flashNow(&quot;error&quot;, &quot;Unable to install application: &quot; .
                    $e-&gt;getMessage());
            }
        }
        else {
            $app-&gt;flashNow(&quot;error&quot;, &quot;Unable to open DB&quot;);
        }
    }
    else {
        $app-&gt;flashNow(&quot;info&quot;, &quot;Install command is for local/SQLite only, try to run &lt;code&gt;heroku db:push sqlite://data/my.db&lt;/code&gt; instead!&quot;);
    }
    $app-&gt;render(&quot;default.php&quot;, array(&quot;action&quot; =&gt; &quot;install&quot;));
});
</pre>
</pre>
<p>La variabile <code>$db</code> è un oggetto PDO, il metodo statico <code>Db::getConnection()</code> cerca di connettersi al database o restituisce <code>NULL</code> in caso di errore.</p>
<p>Il metodo <code>flash()</code> salva un messaggio testuale nella sessione corrente associato ad un&#8217;etichetta &#8220;info&#8221;. Il messaggio è poi disponibile nella successiva richiesta HTTP (la pagina successiva). Esiste anche un metodo <code>flashNow()</code>; il messaggio salvato da questo metodo è accessibile nella pagina corrente all&#8217;interno della variabile <code>$flash</code>.</p>
<p>Utilizzando delle parole chiave appropriate (error, info, warning, ecc) è possibile fare in modo che il messaggio sia associato agli stili CSS predefiniti da Bootstrap, per esempio:</p>
<pre>
<pre class="brush: php; ">
&lt;?php
if (!empty($flash[&quot;error&quot;])) {
?&gt;
&lt;div class=&quot;alert-message error&quot;&gt;
 &lt;?php echo $flash[&quot;error&quot;] ?&gt;
&lt;/div&gt;
&lt;?php
}?&gt;
</pre>
</pre>
<p>Il metodo <code>render()</code> accetta due parametri:</p>
<ul>
<li>il file PHP (o HTML) che contiene l&#8217;interfaccia,</li>
<li>un array associativo di variabili che sono passati al file chiamato.</li>
</ul>
<p>In questo caso è passata una variabile chiamata <code>action</code> che contiene il valore &#8220;install&#8221;; Il file <code>default.php</code> avrà una variabile corrispondente chiamata <code>$action</code> da utilizzare. I file di interfaccia sono contenuti nella directory <code>templates</code> ma questo valore è personalizzabile utilizzando la configurazione di Slim (vi rimando al manuale per maggiori informazioni). Una volta installato il database in locale si possono usare i comandi di Heroku per importare la struttura (e i dati se ci sono) nell&#8217;applicazione remota.</p>
<pre class="console">MyLaptop:HeroLinks ragman$ heroku db:push sqlite://data/my.db</pre>
<p>Il risultato del comando dovrebbe assomigliare a:</p>
<pre class="console">Loaded Taps v0.3.23
     Warning: Data in the app 'herolinks' will be overwritten and will not be recoverable.
     !    WARNING: Potentially Destructive Action
     !    This command will affect the app: herolinks
     !    To proceed, type "herolinks" or re-run this command with --confirm herolinks</pre>
<p>Bisogna digitare il nome dell&#8217;applicazione e premere invio per confermare l&#8217;importazione.</p>
<h2>Il flusso dell&#8217;applicazione</h2>
<p>Il resto dell&#8217;applicazione è lineare e segue il metodo di programmazione simile a Model-View-Controller, con la differenza che in questo caso non abbiamo un Model.</p>
<p>La homepage recupera i 10 link più recenti dal database utilizzando una query SQL. I risultati sono salvati in un array <code>$links</code> e passati al file di interfaccia (home.php) dal metodo <code>render()</code>.</p>
<pre>
<pre class="brush: php; ">
&lt;?php
$app-&gt;map(&quot;/&quot;, function () use ($app) {
    $pageTitle = &quot;Latest Links&quot;;
    $action = &quot;home&quot;;
    $links = array();
    if ($db = Db::getConnection()) {
        $query = &quot;SELECT * FROM links ORDER BY created DESC LIMIT 10&quot;;
        try {
            foreach ($db-&gt;query($query) as $link) {
                $links[] = $link;
            }
        }
        catch (PDOException $e) {
            $app-&gt;flashNow(&quot;error&quot;, $e-&gt;getMessage());
        }
    }
    else {
        $app-&gt;flashNow(&quot;error&quot;, &quot;Unable to open DB&quot;);
    }
    $app-&gt;render(&quot;home.php&quot;, array(
        &quot;pageTitle&quot; =&gt; $pageTitle,
        &quot;action&quot; =&gt; $action,
        &quot;links&quot; =&gt; $links));
})-&gt;via(&quot;GET&quot;, &quot;POST&quot;);

&lt;?php
if (!empty($links)) {
?&gt;
&lt;h2&gt;Latest links&lt;/h2&gt;
&lt;table class=&quot;linklist zebra-striped&quot; summary=&quot;Latest submitted links&quot;&gt;
 &lt;tr&gt;
  &lt;th&gt;Site&lt;/th&gt;
  &lt;th&gt;Description&lt;/th&gt;
  &lt;th&gt;User&lt;/th&gt;
  &lt;th&gt;Date&lt;/th&gt;
 &lt;/tr&gt;
&lt;?php
    foreach($links as $link){
?&gt;
 &lt;tr&gt;
  &lt;td&gt;&lt;a href=&quot;&lt;?php echo $link[&quot;url&quot;] ?&gt;&quot; rel=&quot;external&quot;&gt;&lt;?php echo $link[&quot;title&quot;] ?&gt;&lt;/a&gt;&lt;/td&gt;
  &lt;td&gt;&lt;?php echo $link[&quot;description&quot;] ?&gt;&lt;/td&gt;
  &lt;td&gt;&lt;?php echo $link[&quot;username&quot;] ?&gt;&lt;/td&gt;
  &lt;td&gt;&lt;?php echo date(&quot;d F Y H:i&quot;, strtotime($link[&quot;created&quot;])) ?&gt;&lt;/td&gt;
 &lt;/tr&gt;
&lt;?php
    }
?&gt;
&lt;/table&gt;
&lt;?php
}
else {
?&gt;
&lt;div class=&quot;alert-message block-message info&quot;&gt;
 &lt;p&gt;Sorry, the link database is empty!&lt;/p&gt;
 &lt;div class=&quot;alert-actions&quot;&gt;&lt;a class=&quot;btn primary&quot; href=&quot;/new&quot; &gt;Add a link now&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;?php
}
</pre>
</pre>
<p>La pagina che aggiunge un nuovo link recupera i dati del form con i metodi <code>request()-&gt;isPost()</code> e <code>request()-&gt;post()</code> di Slim. I dati sono poi ripuliti e convalidati con i metodi delle classi Sanitize e Validation del framework CakePHP.</p>
<pre>
<pre class="brush: php; ">
$app-&gt;map(&quot;/new&quot;, function () use ($app) {
        $pageTitle = &quot;Add new link&quot;;
        $action = &quot;new&quot;;
        $data = array();
        $errors = array();
        if ($app-&gt;request()-&gt;isPost()) {
            $data = $app-&gt;request()-&gt;post();
            $data = Sanitize::clean($data, array(&quot;escape&quot; =&gt; false));
            $valid = Validation::getInstance();
            if (!$valid-&gt;email($data[&quot;useremail&quot;])) {
                $errors[&quot;useremail&quot;] = &quot;Invalid email address&quot;;
            }
            if (!$valid-&gt;notEmpty($data[&quot;username&quot;])) {
                $errors[&quot;username&quot;] = &quot;Please insert your name&quot;;
            }
            if (!$valid-&gt;notEmpty($data[&quot;title&quot;])) {
                $errors[&quot;title&quot;] = &quot;Please insert a title&quot;;
            }
            if (!$valid-&gt;url($data[&quot;url&quot;])) {
                $errors[&quot;url&quot;] = &quot;Invalid or empty URL&quot;;
            }
            if (empty($errors)) {
                if ($db = Db::getConnection()) {
                    $query = &quot;INSERT INTO links (url, title, description, username, useremail) VALUES(:url, :title, :description, :username, :useremail)&quot;;
                    try {
                        $stmt = $db-&gt;prepare($query);
                        $stmt-&gt;bindParam(&quot;:url&quot;, $data[&quot;url&quot;]);
                        $stmt-&gt;bindParam(&quot;:title&quot;, $data[&quot;title&quot;]);
                        $stmt-&gt;bindParam(&quot;:description&quot;, $data[&quot;description&quot;]);
                        $stmt-&gt;bindParam(&quot;:username&quot;, $data[&quot;username&quot;]);
                        $stmt-&gt;bindParam(&quot;:useremail&quot;, $data[&quot;useremail&quot;]);
                        $stmt-&gt;execute();
                        $app-&gt;flash(&quot;info&quot;, &quot;Link added successfully!&quot;);
                        $app-&gt;redirect(&quot;/&quot;);
                    }
                    catch (PDOException $e) {
                        $app-&gt;flashNow(&quot;error&quot;, &quot;Unable to save your URL: &quot; . $e-&gt;getMessage());
                    }
                }
                else {
                    $app-&gt;flashNow(&quot;error&quot;, &quot;Unable to open DB&quot;);
                }
            }
        }
        $app-&gt;render(&quot;new.php&quot;, array(
            &quot;pageTitle&quot; =&gt; $pageTitle,
            &quot;action&quot; =&gt; $action,
            &quot;data&quot; =&gt; $data,
            &quot;errors&quot; =&gt; $errors));
    })-&gt;via(&quot;GET&quot;, &quot;POST&quot;);
</pre>
</pre>
<p>Eventuali errori sono salvati nell&#8217;array <code>$errors</code> che è utilizzato sia dal controller che dalle view (i file di interfaccia). Il controller utilizza <code>$errors</code> per determinare se i dati possono essere salvati nel database e la view per visualizzare i messaggi di errore nei relativi campi del form.</p>
<pre>
<pre class="brush: php; ">
&lt;form action=&quot;&quot; method=&quot;post&quot; accept-charset=&quot;utf-8&quot;&gt;
 &lt;fieldset&gt;
  &lt;div class=&quot;clearfix&lt;?php if (!empty($errors[&quot;url&quot;])) echo &quot; error&quot; ?&gt;&quot;&gt;
   &lt;label for=&quot;url&quot;&gt;Site URL&lt;/label&gt;
   &lt;div class=&quot;input&quot;&gt;
    &lt;input type=&quot;text&quot; size=&quot;30&quot; name=&quot;url&quot; id=&quot;url&quot; class=&quot;xlarge&quot; value=&quot;&lt;?php echo (!empty($data[&quot;url&quot;])) ? $data[&quot;url&quot;] : &quot;&quot;; ?&gt;&quot;&gt;
&lt;?php
$field = &quot;url&quot;;
if (!empty($errors[$field])) {
?&gt;
    &lt;span class=&quot;help-inline&quot;&gt;&lt;?php echo $errors[$field] ?&gt;&lt;/span&gt;
&lt;?php
}
?&gt;
   &lt;/div&gt;
  &lt;/div&gt;
  &lt;!-- Other fields here --&gt;
 &lt;/fieldset&gt;
&lt;/form&gt;
</pre>
</pre>
<p>Per salvare i dati nel database ho utilizzato istruzioni PDO all&#8217;interno di un blocco try-catch. Il metodo <code>flashNow()</code> visualizza eventuali errori PDO (ovviamente questo va evitato se siamo in un ambiente di produzione).</p>
<p>La pagina di ricerca è quasi identica alla homepage, ad eccezione del fatto che prima di eseguire la query viene valutato il termine di ricerca.</p>
<pre>
<pre class="brush: php; ">
$app-&gt;get(&quot;/search(/:key)&quot;, function($key = null) use ($app) {
        $pageTitle = &quot;Link Search&quot;;
        $action = &quot;search&quot;;
        $links = array();
        if ($app-&gt;request()-&gt;isGet()) {
            if (empty($key)) {
                $key = $app-&gt;request()-&gt;get(&quot;key&quot;);
            }
            $key = Sanitize::clean($key, array(&quot;escape&quot; =&gt; false));
        }
        if ($db = Db::getConnection()) {
            $query = &quot;SELECT * FROM links WHERE (title LIKE :key OR url LIKE :key) ORDER BY created DESC&quot;;
            try {
                $stmt = $db-&gt;prepare($query);
                $needle = &quot;%&quot; . $key . &quot;%&quot;;
                $stmt-&gt;bindParam(&quot;:key&quot;, $needle, PDO::PARAM_STR);
                $stmt-&gt;execute();
                while ($link = $stmt-&gt;fetch(PDO::FETCH_ASSOC)) {
                    $links[] = $link;
                }
            }
            catch (PDOException $e) {
                $app-&gt;flashNow(&quot;error&quot;, &quot;Unable to execut search: &quot; . $e-&gt;getMessage());
            }
        }
        else {
            $app-&gt;flashNow(&quot;error&quot;, &quot;Unable to open DB&quot;);
        }
        $app-&gt;render(&quot;search.php&quot;, array(
            &quot;pageTitle&quot; =&gt; $pageTitle,
            &quot;action&quot; =&gt; $action,
            &quot;key&quot; =&gt; $key,
            &quot;links&quot; =&gt; $links));
    });
</pre>
</pre>
<p>La sintassi <code>$app-&gt;get("/search(/:key)", function($key = null)</code> significa che ogni stringa che segue il nome dell&#8217;azione <code>/search</code> è considerata termine di ricerca e salvata nel parametro <code>$key</code> della funzione associata. La variabile è poi &#8220;ripulita&#8221; prima dell&#8217;uso.</p>
<h2>Il collegamento a Facebook</h2>
<p>Fino a qui l&#8217;applicazione funziona bene da sola. Per essere utilizzata dentro Facebook e recuperare i dati dell&#8217;utente abbiamo bisogno di:</p>
<ul>
<li>scaricare il Facebook PHP SDK da GitHub,</li>
<li>registrare l&#8217;applicazione su Facebook a partire dalla pagina sviluppatori.</li>
</ul>
<p>Ho copiato la directory <code>src</code> del SDK nella directory <code>lib</code> dell&#8217;applicazione e l&#8217;ho rinominata <code>facebook</code>.</p>
<p>Per registrare l&#8217;applicazione si Facebook bisogna fornire una serie di dettagli come l&#8217;indirizzo dell&#8217;applicazione (es http://myapp.heroku.com) e il nome utilizzato per il componente (canvas) che ospiterà l&#8217;applicazione all&#8217;interno di Facebook. Se scelgo per esempio &#8220;myapp&#8221; sarà creato un indirizzo https://apps.facebook.com/myapp/ per l&#8217;applicazione.</p>
<p>Una volta registrata l&#8217;applicazione possiamo provvedere a impostare i dettagli di configurazione nel nostro controller `index.php`.</p>
<pre>
<pre class="brush: php; ">
$config[&quot;facebook&quot;][&quot;appId&quot;] = &quot;YOUR_APP_ID&quot;;
$config[&quot;facebook&quot;][&quot;secret&quot;] = &quot;YOUR_APP_SECRET&quot;;
$config[&quot;facebook&quot;][&quot;canvas&quot;] = &quot;your-app-canvas&quot;;
$config[&quot;facebook&quot;][&quot;canvas_url&quot;] = &quot;https://apps.facebook.com/your-app-canvas/&quot;;
</pre>
</pre>
<p>Ci serve anche un altro parametro che è l&#8217;indirizzo della nostra applicazione e deve essere fornito alla funzione di autorizzazione.</p>
<pre>
<pre class="brush: php; ">
$config[&quot;app&quot;][&quot;home&quot;] = &quot;https://your-app.heroku.com&quot;;
</pre>
</pre>
<p>L&#8217;integrazione con Facebook avviene in due sezioni distinte del codice. Nella prima sezione viene creato un nuovo oggetto della classe Facebook e viene assegnato come proprietà dell&#8217;oggetto <code>$app</code> che è la nostra applicazione. Il vantaggio di questa soluzione è che se è possibile accedere all&#8217;applicazione è anche possibile accedere al collegamento con Facebook. In questa sezione impostiamo anche la proprietà <code>facebookCanvas</code> che serve all&#8217;applicazione per capire se si trova all&#8217;interno di Facebook oppure no.</p>
<pre>
<pre class="brush: php; ">
$app = new Slim();
$app-&gt;Facebook = new Facebook($config[&quot;facebook&quot;]);
$app-&gt;facebookUserProfile = null;
$app-&gt;facebookCanvas = isRunningInsideFacebook();
</pre>
</pre>
<p>Il secondo punto di integrazione è la funzione <code>isRunningInsideFacebook()</code> che si occupa di determinare se l&#8217;applicazione è eseguita all&#8217;interno di Facebook; per fare questo controlla la presenza della variabile cifrata <code>signed_request</code> passata da Facebook via <code>POST</code>.</p>
<pre>
<pre class="brush: php; ">
function isRunningInsideFacebook() {
    return !empty($_REQUEST[&quot;signed_request&quot;]);
}
</pre>
</pre>
<p>La funzione <code>facebookInit()</code> si occupa di tutto il resto, come controllare di avere i permessi di accesso. Utilizzando le funzioni del SDK estrae i dati ricevuti, se non esiste un parametro <code>user_id</code> l&#8217;applicazione non è autorizzata quindi deve ridirigere l&#8217;utente verso Facebook per richiedere l&#8217;autorizzazione.</p>
<pre>
<pre class="brush: php; ">
function facebookInit() {
        global $app;
        global $config;
        if ($fbData = $app-&gt;Facebook-&gt;getSignedRequest()) {
            // redirect to Facebook Authorization if the User ID is not in the request
            if (empty($fbData[&quot;user_id&quot;])) {
                $auth_url = &quot;https://www.facebook.com/dialog/oauth?client_id=&quot;
                          . $config[&quot;facebook&quot;][&quot;appId&quot;] . &quot;&amp;amp;amp;redirect_uri=&quot; . urlencode($config[&quot;app&quot;][&quot;home&quot;])
                          . &quot;&amp;amp;amp;scope=email&quot;;
                echo &#039;&lt;script type=&quot;text/javascript&quot;&gt;// &lt;![CDATA[
               top.location.href = &quot;&#039; . $auth_url . &#039;&quot;;
// ]]&gt;&lt;/script&gt;&#039;;
                exit;
            }
        }
        if ($fbAccessToken = $app-&gt;Facebook-&gt;getAccessToken()) {
            // if code is present it was sent by an auth request, so redirect back to Facebook App Page
            if ($code = $app-&gt;request()-&gt;get(&quot;code&quot;)) {
                $app-&gt;redirect($config[&#039;facebook&#039;][&quot;canvas_url&quot;]);
            }
            $user = $app-&gt;Facebook-&gt;getUser();
            if ($user) {
                try {
                    // proceed knowing you have a logged-in user who is authenticated
                    $app-&gt;facebookUserProfile = $app-&gt;Facebook-&gt;api(&quot;/me&quot;);
                    $app-&gt;facebookUserProfile[&quot;logout&quot;] = $app-&gt;Facebook-&gt;getLogoutUrl();
                }
                catch (FacebookApiException $e) {
                    $app-&gt;flashNow(&quot;error&quot;, $e-&gt;getMessage());
                    $user = null;
                }
            }
        }
    }
</pre>
</pre>
<p>Se l&#8217;applicazione è autorizzata riceve un parametro chiamato <code>code</code> che è la chiave d&#8217;accesso temporanea fornita dal servizio OAuth di Facebook. Il servizio reindirizza l&#8217;utente all&#8217;indirizzo esterno dell&#8217;applicazione e il ho scelto di far tornare l&#8217;utente alla versione &#8220;dentro Facebook&#8221;. Se l&#8217;autorizzazione è negata i parametri ricevuti sono differenti, ma per questo articolo sono consapevolmente ignorati.</p>
<p>Il codice quindi recupera i dati dal profilo dell&#8217;utente e li salva nella proprietà <code>$app-&gt;facebookUserProfile</code>.</p>
<p>Ma quando viene eseguito questo codice? Il codice che associa le funzioni PHP collegate alle varie azioni è stato leggermente modificato in:</p>
<pre>
<pre class="brush: php; ">
$app-&gt;map(&quot;/&quot;, &quot;facebookInit&quot;, function () use ($app, $config) {
        // other code here
    })-&gt;via(&quot;GET&quot;, &quot;POST&quot;);
</pre>
</pre>
<p>Nella terminologia di Slim si chiama Middleware. La funzione <code>facebookInit()</code> è chiamata prima di elaborare la URL. Questa funzionalità ci garantisce che ogni pagina ha accesso ai dati di Facebook.</p>
<h2>Conclusioni</h2>
<p>Questo esempio ci mostra cosa possiamo ottenere con Heroku, Facebook e altri componenti gratuiti. Spero che vi sia venuta voglia di approfondire l&#8217;argomento e di creare la vostra prossima applicazione con Heroku. Troverete il codice sorgente a partire da <a href='/files/HeroLinks.zip'>questo link</a>. Happy coding!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vtardia.com/blog/applicazioni-sulla-nuvola-con-heroku-e-facebook-sdk/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dominare WordPress con la linea di comando</title>
		<link>http://www.vtardia.com/blog/mastering-wordpress-with-the-command-line/</link>
		<comments>http://www.vtardia.com/blog/mastering-wordpress-with-the-command-line/#comments</comments>
		<pubDate>Fri, 23 Sep 2011 12:47:55 +0000</pubDate>
		<dc:creator>Ragman</dc:creator>
				<category><![CDATA[Tips & Tricks]]></category>
		<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.vtardia.com/?p=578</guid>
		<description><![CDATA[Qualche volta i classici strumenti di manutenzione di WordPress non sono abbastanza se vogliamo avere un maggiore controllo sulla manutenzione del nostro sito. In questi casi, se il fornitore di hosting ci consente gli accessi via terminale SSH, uno script a linea di comando può essere una soluzione più efficace. Diciamo che abbiamo bisogno di [...]]]></description>
			<content:encoded><![CDATA[<p>Qualche volta i classici strumenti di manutenzione di WordPress non sono abbastanza se vogliamo avere un maggiore controllo sulla manutenzione del nostro sito. In questi casi, se il fornitore di hosting ci consente gli accessi via terminale SSH, uno script a linea di comando può essere una soluzione più efficace.<span id="more-578"></span></p>
<p>Diciamo che abbiamo bisogno di importare o esportare dei dati da un file di backup molto grande, di circa 50.000 articoli e 200.000 categorie e tag, e che ogni oggetto debba essere a sua volta elaborato (es. ripulitura del codice, scaricamento delle immagini, ecc).</p>
<p>Con uno script web possiamo facilmente andare incontro ad alcuni tipici problemi:</p>
<ul>
<li>l'esecuzione dello script dura troppo a lungo e viene terminata dal server</li>
<li>lo script necessita di più memoria di quella fornita dal server</li>
</ul>
<p>Se il vostro problema è di questo tipo, può essere risolto agilmente con uno script a linea di comando. Inoltre, sempre se il vostro fornitore lo consente, potete impostare un vero script di cron anzichè affidarvi alla funzione pseudo-cron di WordPress per gestire gli eventi temporizzati. Ma cominciamo a vedere un po' di codice.</p>
<h2>Passo 1 - Impostiamo il nostro ambiente</h2>
<p>La prima cosa da fare è creare un ambiente in cui possiamo eseguire i nostri script. Una soluzione possibile è la creazione di una directory <code>wp-content/bin</code> in cui ospitare tutti i nostri script.</p>
<p>Il primo e più importante file che andiamo a creare è chiamato <code>cli.php</code>, contiene il codice comune a tutti gli script (una sola istruzione per il momento) e <strong>deve assolutamente essere incluso in tutti gli script</strong>, vediamo perché:</p>
<pre class="brush: php; ">
if (&#039;cli&#039; != php_sapi_name()) exit(&quot;Not this way babe!\n&quot;);
</pre>
<p>Questa istruzione dice al nostro interprete PHP che lo script deve essere eseguito solo ed esclusivamente se lo stiamo chiamando da una console. È possibile aggiungere altre funzioni comuni a questa libreria, ma per il momento questa è la più importante. Ora andiamo a scrivere il nostro primo script che si chiamerà <code>test-posts.php</code> e recupererà la lista degli articoli più recenti.</p>
<h2>Passo 2 - Impostazioni di sicurezza</h2>
<p>Non è un passo obbligatorio, ma <strong>caldamente raccomandato</strong>: possiamo impostare il nostro script in modo che possa essere eseguito solo da alcuni utenti e inoltre possiamo anche impostare una password da passare alla riga di comando.</p>
<p><strong>Importante</strong>: Assicuratevi che i permessi di accesso ai vostri script siano impostati in modo da impedire l'accesso e l'esecuzione ad utenti non autorizzati. Questo dipende da come è impostato il vostro sistema, ma in generale impostando i permessi a <code>600</code> potrà essere eseguito solo dal proprietario con il comando</p>
<pre class="console"><code>$ php -f test-posts.php</code></pre>
<p>Quindi con queste righe di codice possiamo impostare una restrizione a livello utente.</p>
<pre>
<pre class="brush: php; ">
$users = array(&#039;someuser&#039;, &#039;anotheruser&#039;);
$cli_user = exec(&#039;whoami&#039;);
if (!empty($users)) {
    if (!in_array($cli_user, $users)) {
        echo &quot;Your username ({$cli_user}) is not in my list babe!\n&quot;;
        exit(1);
    } // end if
} // end if
</pre>
</pre>
<p>Poi potremmo voler richiedere il passaggio di una chiave segreta alla riga di comando, per esempio:</p>
<pre class="console"><code>$ php -f test-posts.php -- --key=SuperSecretKey</code></pre>
<p>Possiamo ottenere questo con queste istruzioni:</p>
<pre>
<pre class="brush: php; ">
if (!defined(&#039;CLI_SECRET&#039;)) define(&#039;CLI_SECRET&#039;, &#039;SuperSecretKey&#039;);
if (CLI_SECRET !== &#039;&#039;) {

    // Check for arguments
    if ($argc &lt; 2) {
        echo &quot;Invalid arguments: a super secret code is needed to run this script!\n&quot;;
        printf(&quot;Usage: /path/to/php -f %s -- --key=&lt;supersecret&gt;\n&quot;, basename(__FILE__));
        exit(2);
    } // end if

    // Parsing arguments: move the secret key (if present) to $_GET[&#039;key&#039;] var.
    $args = split(&#039;=&#039;, $argv[1]);
    if (&#039;--key&#039; == $args[0]) $_GET[&#039;key&#039;] = $args[1];

        // Do stuff
        if(CLI_SECRET !== $_GET[&quot;key&quot;]){

        echo &quot;Access denied!\n&quot;;
        exit(3);

    } // end if

} // end if
</pre>
</pre>
<h2>Passo 3 - Carichiamo WordPress</h2>
<p>Ora possiamo caricare l'ambiente di WordPress all'interno del nostro script e con il prossimo passo andremo invece a scrivere il nostro codice personalizzato.</p>
<p>Dobbiamo tenere conto che <strong>alcuni plugin potrebbero interferire con questa fase</strong>, in particolare quei plugin che fanno uso di cookie o intestazioni HTTP potrebbero lamentarsi se visualizziamo qualcosa a video prima che il caricamento di WordPress sia terminato.</p>
<p>Con la prossima istruzione ci assicuriamo innanzitutto che i plugin di gestione della cache tipo WPSuperCache vengano disattivati.</p>
<pre>
<pre class="brush: php; ">
$_POST[&#039;wp_cache_status&#039;] = &#039;none&#039;;
</pre>
</pre>
<p>Poi includiamo i file necessari per il caricamento di WordPress (il percorso esatto dipende da dove si trovano i file nella vostra installazione).</p>
<pre>
<pre class="brush: php; ">
$wpLoader = realpath(dirname(__FILE__) . &#039;/../../wp-load.php&#039;);
require_once($wpLoader);
</pre>
</pre>
<p>A questo punto se non ci sono errori possiamo accedere ai dati di WordPress.</p>
<h2>Passo 4 - Accesso e gestione dei dati</h2>
<p>Giunti a questa fase possiamo utilizzare tutte le API fornite da WordPress e dai plugin correntemente attivati. Il codice di esempio qui di seguito recupera l'elenco dei post più recenti:</p>
<pre>
<pre class="brush: php; ">
$posts = get_posts();
foreach ($posts as $post) {
    setup_postdata($post);
    echo &quot; - &quot;;
    the_title();
    echo &quot;\n&quot;;
} // end foreach
</pre>
</pre>
<p>Possiamo eseguire lo script con il comando:</p>
<pre class="console"><code>php -f test-posts.php -- --key=SuperSecretKey</code></pre>
<p>E l'output sarà simile a:</p>
<pre class="console"><code>WordPress successfully loaded!</code>

<code> - Lorem ipsum dolor sit amet</code>
<code> - Consectetur adipisicing elit</code>
<code> - Duis aute irure dolor in reprehenderit</code>
<code> - ...</code>
<code> - Last post of the list</code></pre>
<h2>Un buon punto di partenza</h2>
<p>Utilizzando questo esempio come un template, possiamo fare più o meno tutto quello che vogliamo sul nostro blog. Il limite è come sempre la nostra fantasia.</p>
<p>Vi invito quindi a <a href="/files/wp-content-bin.zip" title="Scarica il codice sorgente degli script">scaricare il codice sorgente</a> degli script e a postare nei commenti le vostre opinioni, domande e suggerimenti.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vtardia.com/blog/mastering-wordpress-with-the-command-line/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Come saranno le eLibrerie?</title>
		<link>http://www.vtardia.com/blog/come-saranno-le-elibrerie/</link>
		<comments>http://www.vtardia.com/blog/come-saranno-le-elibrerie/#comments</comments>
		<pubDate>Mon, 04 Jul 2011 12:49:36 +0000</pubDate>
		<dc:creator>Ragman</dc:creator>
				<category><![CDATA[Libri]]></category>
		<category><![CDATA[ebook]]></category>

		<guid isPermaLink="false">http://www.vtardia.com/?p=541</guid>
		<description><![CDATA[Qualche giorno fa giravo per un centro commerciale e mi sono fermato in libreria. Mi piace girare tra le novità e sfogliare i libri che attirano la mia attenzione. Poi ho pensato: «Ma con tutti questi eBook come si evolveranno le librerie nei prossimi anni?». Gli eBook sono enormemente comodi, sia per i manuali tecnici, [...]]]></description>
			<content:encoded><![CDATA[<p>Qualche giorno fa giravo per un centro commerciale e mi sono fermato in libreria. Mi piace girare tra le novità e sfogliare i libri che attirano la mia attenzione. Poi ho pensato: «Ma con tutti questi eBook come si evolveranno le librerie nei prossimi anni?».<span id="more-541"></span></p>
<p>Gli eBook sono enormemente comodi, sia per i manuali tecnici, di cui mi piace la formula “digital bundle” (PDF + ePub + mobi), sia per i libri classici, quelli da leggere in poltrona o sui treni, che sono sempre più pieni e tirar fuori un libro da leggere è un’impresa.</p>
<p>Però mi piace anche l’ambiente libreria, per la sua atmosfera particolare, un’esperienza molto più bella anche rispetto al miglior negozio di libri virtuale. Allora come si fa a mettere insieme le due cose?</p>
<p>Qui di seguito c’è un’idea che mi è venuta, sotto forma di storiella, magari qualcuno interessato la vede e ci lavora sopra&#8230;</p>
<p>Allora, entro in libreria (Mondadori, Feltrinelli, Giunti o “quella Sottocasa”) e lungo le pareti vedo gli scaffali di libri (di carta) e i poster con le copertine dei nuovi arrivi. In posizione di evidenza ci sono i tavoli con i nuovi arrivi o le offerte speciali (più o meno come ora).</p>
<p>In un angolo c’è un salottino per poter leggere i libri comprati, o sfogliare i cataloghi o alcune riviste. Di fianco alle poltrone del salottino cosa c’è?</p>
<p>La parte “e”: diversi tablet (iPad, Kindle, ecc) a disposizione della clientela, adeguatamente “agganciati alla seggiola”. I clienti, seduti in poltrona, li utilizzano per sfogliare i cataloghi elettronici di libri e riviste, leggere le anteprime, le recensioni, oppure l’ultimo numero di Wired. Ma come si compra?</p>
<p>Alternati ai tavoli con le novità ci sono delle “torrette”, come quelle dei negozi di CD, tutte colorate con le copertine dei libri in uscita. Le torrette sono quadrate e su ogni lato c’è agganciato un tablet che fa girare l’applicazione catalogo della libreria in questione.</p>
<p>Io sono attirato dalla copertina di un libro cartaceo, il nuovo di “scegliete voi chi”. Guardo la copertina, leggo il riassunto, mi piace, e noto che è disponibile anche in formato elettronico.</p>
<p>Vado alla torretta con l’iPad, cerco il libro nel catalogo, ne vedo altri, che mi piacciono, leggo le trame e li aggiungo al carrello elettronico. Quando ho finito stampo il mio carrello su un foglietto, tipo scontrino con un codice a barre e l’elenco dei libri richiesti, non ho ancora pagato niente.</p>
<p><strong>Nota</strong>: si potrebbe essere ancora più “eco-friendly” se al posto dello scontrino ritiro una tessera di plastica con un codice a barre, come quelle dei parcheggi ATM di Milano, per esempio.</p>
<p>Vado alla cassa, porgo lo scontrino del carrello, la commessa passa il codice a barre, pago in contanti (per gli amanti della privacy estrema) o con il bancomat e cosa ottengo?</p>
<p>Vediamo, la consegna potrebbe avvenire:</p>
<ul>
<li>via email: lascio l’indirizzo email alla commessa e mi arriva un’email che contiene il link per scaricare i miei acquisti, oppure</li>
<li>porgo alla commessa la mia chiave USB e lei procede a caricare i libri, oppure</li>
<li>direttamente con il mio tablet personale mi collego alla rete wireless del negozio, inserisco il codice dello scontrino e scarico i libri sul mio lettore, quindi vado al salottino per leggere&#8230;</li>
<li>&#8230;oppure mi collego da casa al sito della libreria, inserisco lo stesso codice e scarico.</li>
</ul>
<p>Cosa vi sembra, può funzionare? Certo ci sono un po’ di dettagli tecnici da sistemare, la sicurezza delle chiavi USB, della rete wireless, però sembra una cosa praticabile.</p>
<p>Unisce la praticità degli eBook con l’esperienza della libreria classica con salottino di lettura. Voi cosa ne pensate? Ne avete già viste?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vtardia.com/blog/come-saranno-le-elibrerie/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Il nuovo logo: the making of</title>
		<link>http://www.vtardia.com/blog/new-logo-the-making-of/</link>
		<comments>http://www.vtardia.com/blog/new-logo-the-making-of/#comments</comments>
		<pubDate>Wed, 22 Jun 2011 16:34:19 +0000</pubDate>
		<dc:creator>Ragman</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[Generale]]></category>

		<guid isPermaLink="false">http://vtardia.local/?p=378</guid>
		<description><![CDATA[Così come il precedente sito non mi rappresentava più, la stessa cosa si può dire per il logo. Me ne serviva uno nuovo e la cosa migliore che mi è venuta in mente è partire da zero come se fossi un nuovo cliente. E questa è la storia. Passo 1: il concept Definire il concept [...]]]></description>
			<content:encoded><![CDATA[<p>Così come il precedente sito non mi rappresentava più, la stessa cosa si può dire per il logo. Me ne serviva uno nuovo e la cosa migliore che mi è venuta in mente è partire da zero come se fossi un nuovo cliente. E questa è la storia.<span id="more-378"></span></p>
<h2>Passo 1: il concept</h2>
<p>Definire il concept del mio logo non è stato per niente semplice, perché avrebbe dovuto rappresentare le mie diverse personalità: designer, sviluppatore, musicista, compositore e professionista. Volevo qualcosa che apparisse al tempo stesso professionale, ma altrettanto fresco.</p>
<p>Poi volevo che il logo includesse anche un simbolo, icona, glifo che potesse essere utilizzato indipendentemente. Infine avrebbe dovuto rendere bene sia nella versione al tratto che in quella con colori ed &#8220;effetti speciali&#8221;.</p>
<h2>Passo 2: la ricerca dei simboli</h2>
<p><a class="fancybox" href="/files/rune_study_web.jpg"><img class="size-medium wp-image-517 alignleft" title="Il quaderno delle ricerche" src="/files/rune_study_web-300x200.jpg" alt="" width="300" height="200" /></a>Sarà il mio passato come Master di Dungeons &amp; Dragons oppure la passione per il fantasy e i misteri, sta di fatto che mi piacciono le rune. Quindi ho fatto una ricerca su alcuni testi per trovare dei simboli runici da usare come punto di partenza. Ne ho trovato uno chiamato <em>Jera</em>, nella sua forma originale così come appare nell&#8217;antico alfabeto chiamato <em>Elder Futhark</em>.</p>
<p>Alcuni dei significati di questa runa sono: raccolto, azione buona, comunità, energia. Nell&#8217;antica arte della divinazione runica, la runa Jera parlava di armonia e cambiamento. Curiosamente in quel periodo di cambiamenti nella mia vita ce ne sono stati parecchi. Infine il colore associato a Jera è il blu, che è anche il mio colore preferito.</p>
<p>Ho fatto qualche esperimento di trasformazione con carta e matita e anche con Illustrator, ma alla fine la runa originale mi piaceva di più e l&#8217;ho trovata rappresentata degnamente nel font open source <a href="http://junicode.sourceforge.net/">Junicode</a>.</p>
<h2>Passo 3: il giusto carattere</h2>
<p>Prima di andare a guardare le solite librerie tipo Adobe o Linotype ho preso l&#8217;abitudine di cercare ispirazione in <a href="http://www.dafont.com/">dafont.com</a>. Ho trovato 20-30 caratteri interessanti e ho cominciato a giocare con Illustrator.</p>
<p>Ho quindi ridotto i candidati a quattro o cinque e chiesto un parere ad alcuni amici, il verdetto è stato&#8230; <a href="http://www.dafont.com/baar-sophia.font">Baar Sophia</a> di <a href="http://www.menschengeist.de/">Lutz Baar</a> e <a href="http://www.dafont.com/petita.font">Petita</a> di <a href="http://manfred-klein.ina-mar.com/">Manfred Klein</a>. Sono due font gratuiti per uso personale, mentre per altri utilizzi gli autori chiedono che sia fatta una donazione ad un ente non-profit come <a href="http://www.doctorswithoutborders.org/">Medici Senza frontiere</a>, fatto.</p>
<h2>Passo 4: disegnare il logo &#8211; ne resterà solo uno</h2>
<p><a class="fancybox" href="/files/logo_sketches_web.jpg"><img class="alignleft size-thumbnail wp-image-522" title="Provini fatti a mano" src="/files/logo_sketches_web-150x150.jpg" alt="" width="150" height="150" /></a>Ho cominciato qualche ciclo di disegna-pausa-rivedi e anche in questo caso ho prodotto i soliti quattro o cinque candidati. Li ho fatti vedere ai soliti amici e, sorpresa! Eravamo tutti attratti dallo stesso. Aggiudicato!</p>
<p style="text-align: center;">&nbsp;</p>
<h2>Passo 5: la scelta dei colori</h2>
<p><a class="fancybox" href="/files/color_tests_web.jpg"><img class="alignleft size-medium wp-image-526" title="Esperimenti di colore" src="/files/color_tests_web-300x200.jpg" alt="" width="300" height="200" /></a>Avevo già deciso di utilizzare una tonalità di blu come colore principale ma non volevo che sembrasse troppo &#8220;corporate&#8221;. Ho ripescato una foto fatta diversi anni fa con dei blu interessanti, ne ho campionati un po&#8217; e ho sperimentato diverse varianti con l&#8217;applicazione <em>myPantone</em> e la guida colore <em>Pantone Goe™ </em>fino a che non ho trovato quello giusto. E poi?</p>
<p>In quel periodo stavo leggendo <em><a title="A Practical Guide to Designing for the Web by MARK BOULTON" href="http://fivesimplesteps.com/books/practical-guide-designing-for-the-web">Designing for the Web</a></em> di Mark Boulton e ho trovato un suggerimento sull&#8217;accoppiata blu e lime&#8230; perché no? Ho trovato una tonalità interessante di lime sulla guida colore e ho aggiunto un candidato all&#8217;elenco dei loghi, che alla fine è diventato il mio preferito. Avevo trovato il mio logo!</p>
<h2>Ultimo passo: guida all&#8217;uso</h2>
<p><a class="fancybox" href="/files/cheat_sheet_web.jpg"><img class="alignleft size-medium wp-image-534" title="Mini guida di stile" src="/files/cheat_sheet_web-300x200.jpg" alt="" width="300" height="200" /></a>Avevo un logo, dei colori &#8220;ufficiali&#8221; per il mio brand personale, perché non mettere tutto insieme in una bella mini-guida? Fatta, stampata e messa bene in vista a disposizione come riferimento per gli usi futuri.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vtardia.com/blog/new-logo-the-making-of/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Il silenzio degli indecenti (per la serie &#8220;dove c@**0 eri finito?&#8221;)</title>
		<link>http://www.vtardia.com/blog/how-and-why-of-a-long-silence/</link>
		<comments>http://www.vtardia.com/blog/how-and-why-of-a-long-silence/#comments</comments>
		<pubDate>Fri, 17 Jun 2011 09:08:24 +0000</pubDate>
		<dc:creator>Ragman</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[Generale]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://vtardia.local/?p=372</guid>
		<description><![CDATA[Come ogni blog dedicato al web design è quasi scontato che i primi articoli di un nuovo corso trattino, molto egocentricamente, del riallineamento del sito stesso. Nel mio caso c&#8217;è stato anche un lungo periodo in cui la home page è stata presidiata dagli odiati &#8220;lavori in corso&#8221;. Ho imparato qualcosa: usare i plugin! Quando [...]]]></description>
			<content:encoded><![CDATA[<p>Come ogni blog dedicato al web design è quasi scontato che i primi articoli di un nuovo corso trattino, molto egocentricamente, del riallineamento del sito stesso. Nel mio caso c&#8217;è stato anche un lungo periodo in cui la home page è stata presidiata dagli odiati &#8220;lavori in corso&#8221;.<span id="more-372"></span></p>
<h2>Ho imparato qualcosa: usare i plugin!</h2>
<p>Quando ho pubblicato il sito, anni fa, WordPress era alla versione 1.5 e non era così facilmente integrabile alle mie necessità, principalmente il supporto bilingue e qualche altra cosina. Io però ero più giovane, avevo molto più tempo libero, quindi ho integrato quello che mi serviva direttamente nei sorgenti, grosso errore!</p>
<p>Anche a tenere traccia delle modifiche, dopo qualche tempo gestire gli aggiornamenti è diventato pesante, con due effetti particolarmente negativi:</p>
<ul>
<li>non riuscire ad utilizzare le novità delle nuove versioni di WordPress,</li>
<li>avere un sito potenzialmente bucabile dal primo sfigato di passaggio.</li>
</ul>
<p>Ho quindi preferito chiuderlo per un po&#8217; e concentrarmi sui social network; nel frattempo avrei fatto tesoro dell&#8217;esperienza accumulata lavorando sul WordPress di altri con necessità più umane. E anche aspettando una versione più matura di WordPress&#8230;</p>
<h2>&#8230;ed eccomi di nuovo qui</h2>
<p>Ho imparato la lezione e ho costruito un sito <a title="Basic, il theme framework semplice" href="/resources/wptheme-basic/">intorno ad un &#8220;theme framework&#8221;</a> (parola sconosciuta fino a qualche anno fa) risultato delle buone abitudini acquisite in questi anni. Compreso nel pacchetto c&#8217;è un plugin di &#8220;addons&#8221; personalizzati e un nuovo campo di battaglia dove sperimentare. Buon giorno a tutti!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vtardia.com/blog/how-and-why-of-a-long-silence/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WYMEditor: editor WYSIWYG interessante</title>
		<link>http://www.vtardia.com/blog/wymeditor-editor-wysiwyg-interessante/</link>
		<comments>http://www.vtardia.com/blog/wymeditor-editor-wysiwyg-interessante/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 14:55:58 +0000</pubDate>
		<dc:creator>Ragman</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[Generale]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.vtardia.com/?p=65</guid>
		<description><![CDATA[Chi mi conosce sa che non sono amante degli editor WYSIWYG nelle applicazioni web, preferisco piuttosto la soluzione Markdown. Recentemente però un cliente lo ha richiesto espressamente per un CMS fatto su misura, quindi ho dovuto cercarne uno che girasse bene in accoppiata con jQuery/jQuery UI. Ho trovato WYMEditor: veloce, facile da installare, facile da [...]]]></description>
			<content:encoded><![CDATA[<p>Chi mi conosce sa che non sono amante degli editor WYSIWYG nelle applicazioni web, preferisco piuttosto la soluzione <a href="http://daringfireball.net/projects/markdown/">Markdown</a>.</p>
<p>Recentemente però un cliente lo ha richiesto espressamente per un CMS fatto su misura, quindi ho dovuto cercarne uno che girasse bene in accoppiata con  jQuery/jQuery UI.</p>
<p>Ho trovato <a href="http://www.wymeditor.org/">WYMEditor</a>: veloce, facile da installare, facile da usare e facile da personalizzare. Per ora è la mia scelta, voi cosa ne pensate?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vtardia.com/blog/wymeditor-editor-wysiwyg-interessante/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Social Network: la guida del Garante</title>
		<link>http://www.vtardia.com/blog/social-network-la-guida-del-garante/</link>
		<comments>http://www.vtardia.com/blog/social-network-la-guida-del-garante/#comments</comments>
		<pubDate>Thu, 28 May 2009 09:57:55 +0000</pubDate>
		<dc:creator>Ragman</dc:creator>
				<category><![CDATA[Privacy]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.vtardia.com/?p=64</guid>
		<description><![CDATA[Il Garante della privacy ha da poco pubblicato la sua guida per la tutela dei dati sui social network. Personalmente sono soddisfatto di come è stata impostata e realizzata. Consiglio a tutti la lettura dell’opuscolo che potete scaricare dal sito ufficiale. Buona lettura!]]></description>
			<content:encoded><![CDATA[<p><img class=" alignleft" src="http://www.garanteprivacy.it/ifs/files/garante_root/Immagini/OpuscoloSocialNetwork2009-80x80.jpg" alt="Copertina dell'opuscolo" width="80" height="80" /></p>
<p>Il Garante della privacy ha da poco pubblicato la sua guida per la tutela dei dati sui social network.</p>
<p>Personalmente sono soddisfatto di come è stata impostata e realizzata. Consiglio a tutti la lettura dell’opuscolo che potete <a href="http://www.garanteprivacy.it/garante/doc.jsp?ID=1614258">scaricare dal sito ufficiale</a>.</p>
<p>Buona lettura!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vtardia.com/blog/social-network-la-guida-del-garante/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Vuoi difendere la privacy? Usa il cervello!</title>
		<link>http://www.vtardia.com/blog/difendi-la-privaci-usa-il-cervello-2/</link>
		<comments>http://www.vtardia.com/blog/difendi-la-privaci-usa-il-cervello-2/#comments</comments>
		<pubDate>Fri, 24 Apr 2009 21:16:54 +0000</pubDate>
		<dc:creator>Ragman</dc:creator>
				<category><![CDATA[Privacy]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.vtardia.com/?p=63</guid>
		<description><![CDATA[Si parla tanto, in rete e in televisione di come diverse entità  maligne chiamate social network, capeggiate dal famigerato Facebook, fanno a gara per accaparrarsi i nostri dati personali e invadere la nostra privacy. La cosa ha fatto preoccupare i garanti della privacy di tutto il mondo che hanno pensato di prendere dei provvedimenti. Tremo [...]]]></description>
			<content:encoded><![CDATA[<p>Si parla tanto, in rete e in televisione di come diverse entità  maligne chiamate social network, capeggiate dal famigerato Facebook, fanno a gara per accaparrarsi i nostri dati personali e invadere la nostra privacy.</p>
<p>La cosa ha fatto preoccupare i garanti della privacy di tutto il mondo che hanno pensato di prendere dei provvedimenti. Tremo al solo pensiero di cosa possa uscire dal loro cilindro&#8230;</p>
<p>In realtà  la tecnologia definitiva per difendere i fatti nostri ce l&#8217;abbiamo &#8220;built-in&#8221; fin dalla nascita (tanto per citare S.J.) e si chiama cervello.<span id="more-63"></span></p>
<p>È un hardware molto evoluto e può essere esteso e aggiornato con diversi plugin, primo fra tutti il buon senso.</p>
<p>Il buon senso dovrebbe dirci quando vale la pena condividere certe informazioni e quando invece farne a meno. In generale ci sono casi in cui è soggettivo, altri in cui drizzare le antenne e riflettere sulle possibili conseguenze.</p>
<p>Per esempio: pago un servizio aggiuntivo al mio provider per non pubblicare il mio indirizzo di casa sui record di registrazione dei miei domini. Perché quindi dovrei comunicarlo ad un pinco pallino qualunque che mi promette un fantastico eBook gratuito su come aumentare i visitatori del mio blog? O una suoneria per cellulare, uno sfondo per il computer o qualche altra cosa che magari posso reperire con 10 minuti di Google senza comunicare niente a nessuno?</p>
<p>Già quando sono obbligato a fornire l&#8217;indirizzo email per scaricare qualcosa mi girano. Se mi interessano le informazioni che puoi darmi te lo do io spontaneamente.</p>
<p>Dal nostro lato di utenti dovemmo essere più selettivi e attenti a come gestiamo la nostra vita online. Nella vita reale i foglietti si possono stracciare e le cose dette si possono dimenticare, ma sul web rimangono.</p>
<p>Non è necessario rinunciare a tutto, ma addestrare il buon senso e sviluppare delle buone abitudini che ci aiutino a vivere meglio. Come ad esempio chiedere il permesso prima di pubblicare la foto di qualcuno o evitare di pubblicare foto e filmati che ritraggono noi o i nostri amici in situazioni &#8220;discutibili&#8221;.</p>
<p>Non è escluso che il nostro capufficio o un nostro cliente o potenziale cliente possano &#8220;casualmente&#8221; venirne in possesso&#8230;</p>
<p>Nel caso particolare di Facebook sicuramente possono esserci delle questioni tecniche alla base della <a href="http://punto-informatico.it/2602790/PI/Commenti/niente-privacy-benvenuti-facebook.aspx">mancata eliminazione di alcuni dati degli utenti</a>, d&#8217;altra parte il sito e i servizi si sono evoluti molto velocemente ed è normale che ci sia qualche bug e confido che ci metteranno una pezza il più presto possibile.</p>
<p>Dal lato dei garanti credo che sia meglio puntare sull&#8217;educazione invece che sulla repressione. E soprattutto controllare che chi gestisce i dati rispetti le leggi in materia e non ne faccia un uso troppo &#8220;disinvolto&#8221;.</p>
<p>Diciamoci la verità , se c&#8217;è qualche programmatore in ascolto: possibile che non vi sia mai capitato di sviluppare un&#8217;applicazione che raccoglie dati dagli utenti per un servizio qualsiasi e di leggere nelle specifiche che i dati degli utenti che si disiscrivono al servizio XYZ non vanno cancellati ma vanno solamente segnalati come inattivi perchè potrebbero sempre servire in futuro? E per cosa se non hai il permesso di usarli?</p>
<p>Se ne potrebbe parlare molto più a lungo, ma la chiudo qui. Quel che volevo dire è che ci si può iscrivere a tutti i social network, chat, community &amp; c della rete, basta avere voglia e tempo. Il bello della rete e che puoi trovare e fare veramente di tutto, ma con un cervello funzionante e attento ti diverti di più&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vtardia.com/blog/difendi-la-privaci-usa-il-cervello-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress: manutenzione straordinaria</title>
		<link>http://www.vtardia.com/blog/wordpress-manutenzione-straordinaria/</link>
		<comments>http://www.vtardia.com/blog/wordpress-manutenzione-straordinaria/#comments</comments>
		<pubDate>Thu, 13 Nov 2008 14:45:27 +0000</pubDate>
		<dc:creator>Ragman</dc:creator>
				<category><![CDATA[Tips & Tricks]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://www.vtardia.com/?p=61</guid>
		<description><![CDATA[In questi giorni ho avuto la necessità  di rimuovere in massa un numero notevole di articoli da un&#8217;installazione di WordPress e di doverlo fare &#8220;sporcandomi le mani&#8221; all&#8217;interno del database, dato che per qualche motivo il pannello di amministrazione non voleva saperne di funzionare. Condivido qui di seguito la soluzione che ho trovato in caso [...]]]></description>
			<content:encoded><![CDATA[<p>In questi giorni ho avuto la necessità  di rimuovere in massa un numero notevole di articoli da un&#8217;installazione di WordPress e di doverlo fare &#8220;sporcandomi le mani&#8221; all&#8217;interno del database, dato che per qualche motivo il pannello di amministrazione non voleva saperne di funzionare. Condivido qui di seguito la soluzione che ho trovato in caso servisse a qualcuno, ma anche nel caso in cui qualche collega conosca una soluzione migliore per il futuro.<span id="more-61"></span></p>
<h3>Situazione iniziale</h3>
<p><strong>Obiettivo</strong>: cancellare da un&#8217;installazione di WordPress 2.6.3 tutti i post appartenenti alla categoria &#8216;Musica&#8217; o ad una delle sue sotto-categorie.</p>
<p><strong>Problema</strong>: il pannello di amministrazione causa diversi errori anche dopo avere disabilitato tutti i plugin, ma non c&#8217;è il tempo necessario per andare a caccia della causa.</p>
<p><strong>Nota</strong>: i parametri relativi all&#8217;installazione specifica di WordPress non sono quelli esposti in questo esempio. Per comodità  assumerò &#8216;Musica&#8217; come categoria base, al cui ID nel database assegno il valore arbitrario “100”, utilizzando il prefisso di default “wp_” per le tabelle del database.</p>
<h3>Premessa tecnica: gestione delle tassonomie in WordPress</h3>
<p>WordPress gestisce le categorie e i tag utilizzando 3 tabelle:</p>
<dl>
<dt><code>wp_terms</code></dt>
<dd>Contiene i nomi di categorie e tag tutti insieme.</dd>
<dt><code>wp_term_taxonomy</code></dt>
<dd>Contiene i dettagli sui termini, cioè se un termine è un nome di categoria<br />
(category), un tag applicato a un post (post_tag), una categoria di link<br />
(link_category), ecc e il collegamento con il suo genitore (parent).<br /> Il campo <code>term_taxonomy_id</code> è la chiave primaria della tabella ed è usato come chiave esterna nella tabella <code>wp_term_relationships</code>.</dd>
<dt><code>wp_term_relationships</code></dt>
<dd>Contiene le relazioni tra i termini (<code>term_taxonomy_id</code>) e gli oggetti associati (<code>object_id</code>), post o link.</dd>
</dl>
<h3>Passo 1: troviamo tutti i termini collegati alla categoria madre</h3>
<p>Nella tabella <code>wp_terms</code> il termine “Musica” ha term_id=100. Per avere una lista dei termini associati la query da eseguire è:</p>
<p>[code lang="sql" light="true"]SELECT * FROM wp_term_taxonomy WHERE term_id = 100 OR parent = 100[/code]</p>
<p>Per utilizzarla nel passo successivo però ci serve solo la chiave, quindi eseguiremo:</p>
<p>[code lang="sql" light="true"]SELECT term_taxonomy_id FROM wp_term_taxonomy WHERE term_id =100 OR parent =100[/code]</p>
<h3>Passo 2: selezioniamo gli ID dei post che ci interessano</h3>
<p>Il campo che collega le tabelle <code>wp_term_relationships</code> e <code>wp_term_taxonomy</code> è <code>term_taxonomy_id</code>, quindi ho usato 2 query annidate per avere tutti i dati in un passaggio solo:</p>
<pre class="brush: sql; ">
SELECT object_id
FROM &amp;lt;code&amp;gt;wp_term_relationships&amp;lt;/code&amp;gt;
WHERE &amp;lt;code&amp;gt;term_taxonomy_id&amp;lt;/code&amp;gt;
IN (

	SELECT term_taxonomy_id
	FROM &amp;lt;code&amp;gt;wp_term_taxonomy&amp;lt;/code&amp;gt;
	WHERE term_id =100
	OR parent =100
)
</pre>
<p>Questa query recupera gli ID di tutti i post appartenenti alle categorie interessate e sarà  utilizzata nel prossimo passo.</p>
<h3>Passo 3: applichiamo il risultato</h3>
<p>Per selezionare i post che mi interessano interrogo la tabella <code>wp_posts</code> inserendo le due query ricavate in precedenza nella condizione <code>WHERE</code>.</p>
<pre class="brush: sql; ">
SELECT *
FROM wp_posts
WHERE ID
IN (

	SELECT object_id
	FROM wp_term_relationships
	WHERE term_taxonomy_id
	IN (

		SELECT term_taxonomy_id
		FROM wp_term_taxonomy
		WHERE term_id =100
		OR parent =100
	)
)
</pre>
<p>Sostituendo <code>DELETE</code> al primo <code>SELECT *</code> cancello i post selezionati in precedenza, ma è sempre meglio <strong>controllare prima i dati</strong>!</p>
<h3>Passo 4: pulizia</h3>
<p>Una volta cancellati i post bisogna eliminare anche i loro riferimenti rimasti nella tabella `wp_term_relationships, che ci sono stati utili, ma ora non servono più.</p>
<p>Eseguirò quindi la query composta del punto 2 sostituendo <code>DELETE</code> al primo <code>SELECT *</code>.</p>
<p>E questo è tutto, ora mi posso dedicare con calma a capire perchè il pannello di amministrazione non funziona, ma questa è un’altra storia <img src='http://www.vtardia.com/site/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.vtardia.com/blog/wordpress-manutenzione-straordinaria/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Promemoria per il prossimo presidente</title>
		<link>http://www.vtardia.com/blog/promemoria-per-il-prossimo-presidente/</link>
		<comments>http://www.vtardia.com/blog/promemoria-per-il-prossimo-presidente/#comments</comments>
		<pubDate>Thu, 04 Sep 2008 13:01:13 +0000</pubDate>
		<dc:creator>Ragman</dc:creator>
				<category><![CDATA[Generale]]></category>

		<guid isPermaLink="false">http://www.vtardia.com/blog/promemoria-per-il-prossimo-presidente/</guid>
		<description><![CDATA[Ho ricevuto da poco nella mia mailbox la versione italiana del numero di agosto di Crypto Gram, la newsletter dell&#8217;esperto di sicurezza Bruce Schneider. Particolarmente interessanti sono i consigli di Schneider per il prossimo presidente degli Stati Uniti (chiunque sarà ), tant&#8217;è che ne consiglio la lettura anche ai nostri rappresentanti, nella versione curata da [...]]]></description>
			<content:encoded><![CDATA[<p>Ho ricevuto da poco nella mia mailbox la versione italiana del numero di agosto di <a href="http://www.schneier.com/crypto-gram.html">Crypto Gram</a>, la newsletter dell&#8217;esperto di sicurezza <a href="http://www.schneier.com/">Bruce Schneider</a>.</p>
<p>Particolarmente interessanti sono i consigli di Schneider per il prossimo presidente degli Stati Uniti (chiunque sarà ), tant&#8217;è che <a href="http://www.communicationvalley.it/cryptogram.php">ne consiglio la lettura</a> anche ai nostri rappresentanti, nella versione curata da <a href="http://www.communicationvalley.it/">Communication Valley</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vtardia.com/blog/promemoria-per-il-prossimo-presidente/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

