Creare un lettore di Feed RSS in Flex 3
di Fabio Biondi
L’RSS è un formato ormai diffusissimo per la condivisione di informazioni, utilizzato soprattutto in blog e portali. I siti web che sfruttano questo standard mettono a disposizione i propri contenuti ad un qualunque sviluppatore, che potrà utilizzarli nella propria applicazione o sito web per presentarli in modo totalmente differente rispetto all’originale. In questo tutorial utilizzeremo Flex 3 per creare un lettore RSS utile a leggere i contenuti del nostro portale FlexGala e, a fine articolo, modificheremo leggermente il codice per realizzare un RSS Reader generico che funzioni con qualunque sito. Focalizzeremo l’attenzione principalmente sulle funzionalità relative all’acquisizione dei dati e sul problema di sicurezza relativo all’accesso dei dati da un dominio esterno, utilizzando un proxy PHP per risolvere il problema, tralasciando tutto ciò che concerne l’interfaccia grafica e i componenti base di flex che saranno invece commentati passo-passo all’interno del codice in modo da rendere comunque comprensibile l’articolo anche agli utenti meno esperti.
IL FORMATO RSS
In sostanza l’RSS è rappresentato da un file XML che segue determinati standard ed è quindi possibile creare degli script generici che funzionino correttamente in svariate situazioni e che leggano i contenuti da un qualunque sito.
Di seguito un estratto di un feed RSS disponibile su FlexGala:
<?xml version=”1.0”?> <!-- Generated on Sun, 27 Apr 2008 17:13:32 +0000 --> <rss version=”2.0”> <channel> <title>Le news di Augitaly.com</title> <link>http://www.augitaly.com</link> <description>News dal mondo di Flex 2</description> <language>it</language> <webMaster>webmaster@augitaly.com</webMaster> <generator>PHP RSS Feed Generator</generator> <item> <title>Ridurre il peso del file SWF rimuovendo le classi non usate con getQualifiedClassName()</title> <description><![CDATA[Il tema dell’ottimizzazione tocca davvero questo [...]]]></description> <link>http://www.augitaly.com/flexgala/index.php?cmd=newsreader&id=243</link> <pubDate>Thu, 24 Apr 2008 00:10:10 +0000</pubDate> </item> [... altri nodi ‘item] </channel> </rss>
Maggiori informazioni sul formato RSS sono reperibili su Wikipedia:
http://it.wikipedia.org/wiki/Really_simple_syndication
Per il parsing del file XML, ovvero l’interpretazione dei dati acquisiti, sfrutteremo il component HTTPService e lo standard E4X, ma non affronteremo in dettaglio l’argomento perchè già ampiamente trattato in diversi articoli dei nostri portali.
L’RSS READER di FLEXGALA
Di seguito descriviamo le funzionalità della prima applicazione che andremo a realizzare, ovvero il lettore di contenuti del portale FlexGala:
- Utilizzando il componente COMBOBOX faremo in modo che l’utente possa selezionare uno dei quattro feed RSS presenti FlexGala: news, articoli, video tutorials e gli articoli da altre fonti.
- Sulla sinistra sfrutteremo un componente LIST per visualizzare l’elenco degli articoli di un determinato feed
- Sulla destra, all’interno di una TEXTAREA, presenteremo l’abstract dell’articolo selezionato
- Infine, utilizzeremo un componente BUTTON per aprire la pagina dell’articolo completo disponibile sul sito ufficiale.
Il risultato finale sarà simile a quello dell'immagine 1
RSS READER GENERICO
La seconda applicazione sarà identica alla precedente ma, al posto del menu a tendina con un elenco preimpostato di siti, daremo la possibilità all’utente di digitare un qualunque feed RSS. (Immagine 2)
DOWNLOAD SORGENTI e DEMO APPLICAZIONI
Il download dei codici sorgenti Flex e PHP può essere effettuato al seguente URL:
http://www.fabiobiondi.com/_augiltaly/UM/5_rss/RSSReader.zip
Le demo funzionanti delle applicazioni sono invece disponibili ai seguente indirizzi:
1) http://www.fabiobiondi.com/_augiltaly/UM/5_rss/RSSReader.html
2) http://www.fabiobiondi.com/_augiltaly/UM/5_rss/RSSReader2.html
FLASH PLAYER 9 e PROBLEMI DI SICUREZZA: UTILIZZIAMO UN PROXY
Prima di analizzare il codice è necessario capire le nuove modalità di sicurezza del Flash Player 9.
Un’applicazione realizzata in Flex, posizionata sul proprio dominio web, non può accedere direttamente ai dati disponibili in un dominio web remoto, differente da quello in cui si sono posizionati gli swf. Ogni qualvolta si tenta di accedere a contenuti esterni si riceveranno dei messaggi di errore/sicurezza e sarà quindi impossibile accedere ai dati di cui si ha bisogno.
TIP: Questo non accade mentre si sviluppa l’applicazione in ambiente Flex Builder, ma avviene solo quando si posizionano i files on-line.
Le soluzioni più utilizzate per risolvere questo tipo di problema sono le tre seguenti:
1) utilizzare un file cross-domain: ovvero posizionando un file xml, formattato in modo appropriato affinché il Flash Player lo interpreti correttamente, nella root del webserver remoto che mette a disposizione i dati. In questo file si specificherà l’elenco dei domini ai quali si concede il permesso di accedere ai dati. Ad esempio, se il dominio dove metteremo l’applicazione si chiama dominio.com e quello remoto si chiamata dominioRSS.com, nella root di quest’ultimo dovremo mettere il file cross-domain.xml strutturato come segue:
<?xml version=”1.0”?> <!DOCTYPE cross-domain-policy SYSTEM “http://www.adobe.com/xml/dtds/cross-domain-policy.dtd”> <cross-domain-policy> <allow-access-from domain=”dominio.com” /> </cross-domain-policy>
Questa soluzione molto spesso non è praticabile perchè non abbiamo la possibilità di posizionare i file nei domini remoti, visto che probabilmente non saranno di nostra proprietà.
2) La soluzione al nostro problema è rappresentata invece dall’utilizzo di un file PROXY, ovvero un file che faccia da ponte tra il sito remoto e il Flash Player.
In sostanza, la nostra applicazione invece di chiamare direttamente l’URL remoto del feed RSS invocherà un file server side presente nel nostro dominio, che si occuperà di chiamare a sua volta il feed RSS e di passare i dati a Flex. Questo file può essere creato con un qualunque linguaggio server side e, nel nostro caso, utilizzeremo PHP. Potete trovare maggiori informazioni sull’utilizzo di un proxy e il relativo codice sorgente anche in ColdFusion, ASP e JAVA al seguente URL:
http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_16520&slice...
Lo script PHP è comunque molto semplice e serve semplicemente a leggere un url remoto e a passare a Flex i relativi contenuti della pagina invocata.
<?php readfile($_REQUEST[“url”]); ?>
Da Flex, chiameremo quindi questo file, passando come parametro l’url del feed RSS da visualizzare, bypassando il problema di sicurezza del Flash Player 9.
EXPERT TIP:
Affinchè il file PROXY PHP funzioni correttamente è necessario che nelle impostazioni del file PHP.ini del proprio hosting sia abilitata l’opzione allow_url_fopen , spesso ad OFF per evitare inclusioni remote di malware e mpack. Inoltre, dalla versione 5.2.x di PHP, potrebbe essere necessario abilitare la proprietà allow_url_include.
Se posizionate il file proxy php sul vostro hosting, provate ad avviare il file dal vostro browser e ricevete un errore simile al seguente, è probabile che dobbiate modificare le variabili che abbiamo appena menzionato:
Warning: readfile() [function.readfile]: URL file-access is disabled in the server configuration in /var/www/web121/html/_tutorial/augitaly/usermatter/6_flexrssreader/proxy.php on line 11
Warning: readfile(http://www.augitaly.com/flexgala/rss.php?t=n) [function.readfile]: failed to open stream: no suitable wrapper could be found in /var/www/web121/html/_tutorial/augitaly/usermatter/6_flexrssreader/proxy.php on line 11
3) Un’alternativa a quanto indicato nei punti 1) e 2) è l’utilizzo dei LiveCycle Data Service, un software server side prodotto da Adobe per estendere le capacità di Flex, che tra le varie funzionalità permette di creare applicazioni che effettuano richieste remote che non soffrono del problema di sicurezza menzionato, ma questo è un argomento che non tratteremo in questo articolo.
Di seguito il codice della prima applicazione commentato passo-passo:
<?xml version=”1.0” encoding=”utf-8”?> <mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute” creationComplete=”loadXMLData(urlArray[0].data)”> <mx:Script> <![CDATA[ import mx.events.* import mx.rpc.events.ResultEvent; // PATH del PROXY PHP // --> DEBUG (da usare in locale quando effettuate i test da Flex. // IMPORTANTE: Cambiare l’URL in base al path del proprio webserver) private const pathProxy:String = “http://localhost/Web/_FLEX3/RSSReader/src/php/proxy.php?url=”; // VERSIONE FINALE (on-Line) // Commentare la riga precedente e decommentare la seguente //private const pathProxy:String = “php/proxy.php?url=”; /* CARICAMENTO RSS Questa funzione viene chiamata sia quando l’applicazione è avviata la prima volta (tramite l’evento ‘creationComplete’), passando come parametro il primo elemento dell’array degli URL, sia ogni qualvolta viene selezionato un nuovo feed dal ComboBox */ public function loadXMLData(url:String):void { // Impostiamo l’URL del file da caricare rssRPC.url= url; // Inviamo la richiesta HTTPService rssRPC.send(); } /* CARICAMENTO DATI AVVENUTO CON SUCCESSO */ private function defaultData(event:ResultEvent):void { // Visualizzione Abstract del primo articolo viewAbstract(0) // Evidenziazione della prima voce del componente LIST posts_list.selectedIndex = 0; } /* VISUALIZZAZIONE dell’ABSTRACT */ private function viewAbstract(idxNews:uint):void { // Visualizziamo l’abstract dell’articolo sfruttando lo standard E4X // per navigare all’interno dell’oggetto XMLListCollection e per recuperare // il valore del nodo ‘description’ post_details.htmlText = articoliXML[idxNews].description; } /* APERTURA URL dell’ARTICOLO COMPLETO */ private function openURL(event:MouseEvent):void { // L’indice dell’articolo selezionato viene acquisito dal component LIST var articoloSelezionato:uint = posts_list.selectedIndex; // Recuperiamo il ‘link’ dell’articolo completo sfruttando lo standard E4X // per navigare all’interno dell’oggetto XMLListCollection var linkNews:String = articoliXML[articoloSelezionato].link; // Apriamo il link in una nuova pagina var adobeURL:URLRequest = new URLRequest(linkNews); navigateToURL(adobeURL, “_blank”); } ]]> </mx:Script> <!-- ARRAY contenente gli URL del COMBOBOX --> <mx:ArrayCollection id=”urlArray”> <mx:Array id=”myArray”> <mx:Object label=”News” data=”{pathProxy + ‘http://www.augitaly.com/flexgala/rss.php?t=n’}”/> <mx:Object label=”Layout” data=”{pathProxy + ‘http://www.augitaly.com/flexgala/rss.php?t=l’}”/> <mx:Object label=”Video tutorials” data=”{pathProxy + ‘http://www.augitaly.com/flexgala/rss.php?t=v’}”/> <mx:Object label=”Articoli da altre fonti” data=”{pathProxy + ‘http://del.icio.us/rss/FlexGala’}”/> </mx:Array> </mx:ArrayCollection> <!-- Il componente HTTPService permette di caricare dati da un URL. La proprietà resultFormat indica in quale modalità interpretare i dati (E4X). L’E4X è una novità di AS3 che permette di navigare all’interno dei nodi XML in modo agevole. Non appena i dati saranno acquisiti verrà invocato l’evento ‘result’. In questo tutorial non abbiamo gestito il caso in cui la richiesta fallisca ma è possibile utilizzare l’apposito evento ‘fault’ --> <mx:HTTPService id=”rssRPC” resultFormat=”e4x” result=”defaultData(event)” /> <!-- - Conserviamo nella variabile ‘articoliXML’ l’elenco degli articoli (item) - Utilizziamo la classe XMLListCollection perchè permette di sfruttare le potenzialità E4X disponibili dalla versione 3.0 di Actionscript. --> <mx:XMLListCollection id=”articoliXML” source=”{rssRPC.lastResult.channel.item}” /> <mx:VBox x=”10” y=”0” height=”227” width=”250”> <!-- COMBOBOX con l’ELENCO dei FEED RSS di FlexGala: - Acquisiamo gli URL attraverso l’array ‘urlArray’ definito in precedenza - Ad ogni selezione carichiamo i nuovi dati chiamando la funzione ‘loadXMLData’ e passando come parametro l’url selezionato --> <mx:ComboBox width=”100%” id=”combo_list” dataProvider=”{urlArray}” change=”loadXMLData(urlArray[event.currentTarget.selectedIndex].data)” /> <!-- VISUALIZZAZIONE ELENCO ARTICOLI - Il dataProvider utilizzato per reperire l’elenco degli articoli è popolato automaticamente ad ogni nuova chiamata grazie al BINDING. - Ad ogni selezione viene invocato l’evento ‘change’ e visualizziamo il relativo abstract --> <mx:List width=”100%” height=”100%” id=”posts_list” dataProvider=”{articoliXML}” change=”viewAbstract(event.currentTarget.selectedIndex)” labelField=”title” /> </mx:VBox> <!-- TEXTAREA per la VISUALIZZAZIONE dell’ABSTRACT --> <mx:TextArea id=”post_details” x=”268” y=”29” width=”312” height=”198”/> <!-- IL PUlSANTE PER APRIRE IL LINK DELL’ARTICOLO COMPLETO SUL SITO UFFICIALE --> <mx:Button x=”149” y=”235” label=”Dettaglio news” click=”openURL(event)”/> </mx:Application>
Di seguito il codice della seconda applicazione commentato passo-passo:
<?xml version=”1.0” encoding=”utf-8”?> <mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute”> <mx:Script> <![CDATA[ import mx.controls.Alert; import mx.events.* import mx.rpc.events.ResultEvent; import mx.rpc.events.FaultEvent; // PATH PROXY PHP // --> DEBUG private const pathProxy:String = “http://localhost/Web/_FLEX3/RSSReader/src/php/proxy.php?url=”; // VERSIONE FINALE (on-Line) //private const pathProxy:String = “php/proxy.php?url=”; [Bindable] public var dp:XMLList; private function openCustomRSS(url:String):void { rssRPC.url= pathProxy + url; rssRPC.send(); } // Caricamento RSS Avvenuto con successo private function defaultData(event:ResultEvent):void { // Visualizzazione del titolo del Feed RSS title_txt.text = event.currentTarget.lastResult.channel.title; // Lista dei nodi dp = event.currentTarget.lastResult.channel.item // Visualizziamo il primo post della lista viewAbstract(0) // Visualizziamo il primo elemento della lista posts_list.selectedIndex = 0; } // In caso di URL inesistente private function faultData(event:FaultEvent):void { Alert.show(“URL non disponibile”); } // Visualizziamo l’abstract private function viewAbstract(idxNews:uint):void { try { post_details.htmlText = String(dp[idxNews].description); } catch(e:*){} } /* APERTURA URL dell’ARTICOLO COMPLETO */ private function openURL(event:MouseEvent):void { var linkNews:String = dp[posts_list.selectedIndex].link; var adobeURL:URLRequest = new URLRequest(linkNews); navigateToURL(adobeURL, “_blank”); } ]]> </mx:Script> <mx:HTTPService id=”rssRPC” resultFormat=”e4x” result=”defaultData(event)” fault=”faultData(event)” /> <mx:ApplicationControlBar x=”0” y=”0” dock=”true” height=”44”> <mx:Label text=”Indirizzo RSS:”/> <mx:TextInput id=”testoInput” width=”380”/> <mx:Button label=”Leggi RSS” click=”openCustomRSS(testoInput.text)”/> </mx:ApplicationControlBar> <mx:Label id=”title_txt” x=”10” y=”13” width=”570”/> <mx:VBox x=”10” y=”39” height=”199” width=”250”> <mx:List width=”100%” height=”100%” id=”posts_list” dataProvider=”{dp}” change=”viewAbstract(event.currentTarget.selectedIndex)” labelField=”title” /> </mx:VBox> <mx:TextArea id=”post_details” x=”268” y=”39” width=”312” height=”198”/> <mx:Button x=”149” y=”246” label=”Dettaglio news” click=”openURL(event)”/> </mx:Application>
______________________________________________________________
Fabio Biondi
info@fabiobiondi.com
Adobe Flash/Flex Developer dal 2002, realizza siti web dinamici e rich internet application. Ottenuta nel 2004 la certificazione Flash Developer, dal 2007 è Adobe Flash Certified Instructor. Inoltre sviluppa e coordina progetti che fanno uso delle più recenti tecnologie Adobe complementari a Flash, come Flex, FlashLite, Air e Flash Media Server. Membro fondatore dell’Adobe UserGroup (AUG) Actionscript.it, ora fa parte dell’AUG Augitaly.com. Attualmente lavora presso la Web agency Fishouse di Castelfranco Veneto (TV).


