Creare un lettore di Feed RSS in Flex 3

Immagini

Immagine 1 Immagine 2

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:

  1. <?xml version=”1.0”?>
  2. <!-- Generated on Sun, 27 Apr 2008 17:13:32 +0000 -->
  3. <rss version=”2.0”>
  4. <channel>
  5. <title>Le news di Augitaly.com</title>
  6. <link>http://www.augitaly.com</link>
  7. <description>News dal mondo di Flex 2</description>
  8. <language>it</language>
  9. <webMaster>webmaster@augitaly.com</webMaster>
  10. <generator>PHP RSS Feed Generator</generator>
  11. <item>
  12. <title>Ridurre il peso del file SWF rimuovendo le classi non usate con getQualifiedClassName()</title>
  13. <description><![CDATA[Il tema dell’ottimizzazione tocca davvero questo [...]]]></description>
  14. <link>http://www.augitaly.com/flexgala/index.php?cmd=newsreader&amp;id=243</link>
  15. <pubDate>Thu, 24 Apr 2008 00:10:10 +0000</pubDate>
  16. </item>
  17.  
  18. [... altri nodi ‘item]
  19. </channel>
  20. </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:

  1. <?xml version=”1.0”?>
  2. <!DOCTYPE cross-domain-policy SYSTEM “http://www.adobe.com/xml/dtds/cross-domain-policy.dtd”>
  3. <cross-domain-policy>
  4. <allow-access-from domain=”dominio.com” />
  5. </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.

  1. <?php
  2. readfile($_REQUEST[“url”]);
  3. ?>

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:

  1. <?xml version=”1.0” encoding=”utf-8”?>
  2. <mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”
  3. layout=”absolute”
  4. creationComplete=”loadXMLData(urlArray[0].data)”>
  5.  
  6. <mx:Script>
  7. <![CDATA[
  8. import mx.events.*
  9. import mx.rpc.events.ResultEvent;
  10.  
  11. // PATH del PROXY PHP
  12. // --> DEBUG (da usare in locale quando effettuate i test da Flex.
  13. // IMPORTANTE: Cambiare l’URL in base al path del proprio webserver)
  14. private const pathProxy:String = “http://localhost/Web/_FLEX3/RSSReader/src/php/proxy.php?url=”;
  15.  
  16. // VERSIONE FINALE (on-Line)
  17. // Commentare la riga precedente e decommentare la seguente
  18. //private const pathProxy:String = “php/proxy.php?url=”;
  19. /*
  20. CARICAMENTO RSS
  21. Questa funzione viene chiamata sia quando l’applicazione
  22. è avviata la prima volta (tramite l’evento ‘creationComplete’),
  23. passando come parametro il primo elemento dell’array degli URL,
  24. sia ogni qualvolta viene selezionato un nuovo feed dal ComboBox
  25. */
  26. public function loadXMLData(url:String):void
  27. {
  28.  
  29. // Impostiamo l’URL del file da caricare
  30. rssRPC.url= url;
  31.  
  32. // Inviamo la richiesta HTTPService
  33. rssRPC.send();
  34. }
  35.  
  36. /*
  37. CARICAMENTO DATI AVVENUTO CON SUCCESSO
  38. */
  39. private function defaultData(event:ResultEvent):void
  40. {
  41.  
  42. // Visualizzione Abstract del primo articolo
  43. viewAbstract(0)
  44.  
  45. // Evidenziazione della prima voce del componente LIST
  46. posts_list.selectedIndex = 0;
  47. }
  48.  
  49.  
  50. /*
  51. VISUALIZZAZIONE dell’ABSTRACT
  52. */
  53. private function viewAbstract(idxNews:uint):void
  54. {
  55. // Visualizziamo l’abstract dell’articolo sfruttando lo standard E4X
  56. // per navigare all’interno dell’oggetto XMLListCollection e per recuperare
  57. // il valore del nodo ‘description’
  58. post_details.htmlText = articoliXML[idxNews].description;
  59. }
  60.  
  61.  
  62. /*
  63. APERTURA URL dell’ARTICOLO COMPLETO
  64. */
  65. private function openURL(event:MouseEvent):void
  66. {
  67. // L’indice dell’articolo selezionato viene acquisito dal component LIST
  68. var articoloSelezionato:uint = posts_list.selectedIndex;
  69.  
  70. // Recuperiamo il ‘link’ dell’articolo completo sfruttando lo standard E4X
  71. // per navigare all’interno dell’oggetto XMLListCollection
  72. var linkNews:String = articoliXML[articoloSelezionato].link;
  73.  
  74. // Apriamo il link in una nuova pagina
  75. var adobeURL:URLRequest = new URLRequest(linkNews);
  76. navigateToURL(adobeURL, “_blank”);
  77. }
  78.  
  79. ]]>
  80. </mx:Script>
  81.  
  82. <!--
  83. ARRAY contenente gli URL del COMBOBOX
  84. -->
  85. <mx:ArrayCollection id=”urlArray”>
  86. <mx:Array id=”myArray”>
  87. <mx:Object label=”News” data=”{pathProxy + ‘http://www.augitaly.com/flexgala/rss.php?t=n’}”/>
  88. <mx:Object label=”Layout” data=”{pathProxy + ‘http://www.augitaly.com/flexgala/rss.php?t=l’}”/>
  89. <mx:Object label=”Video tutorials” data=”{pathProxy + ‘http://www.augitaly.com/flexgala/rss.php?t=v’}”/>
  90. <mx:Object label=”Articoli da altre fonti” data=”{pathProxy + ‘http://del.icio.us/rss/FlexGala’}”/>
  91. </mx:Array>
  92. </mx:ArrayCollection>
  93.  
  94.  
  95. <!--
  96. Il componente HTTPService permette di caricare dati da un URL.
  97. La proprietà resultFormat indica in quale modalità interpretare i dati (E4X).
  98. L’E4X è una novità di AS3 che permette di navigare all’interno dei nodi XML in modo agevole.
  99. Non appena i dati saranno acquisiti verrà invocato l’evento ‘result’.
  100. In questo tutorial non abbiamo gestito il caso in cui la richiesta fallisca
  101. ma è possibile utilizzare l’apposito evento ‘fault’
  102. -->
  103. <mx:HTTPService id=”rssRPC”
  104. resultFormat=”e4x”
  105. result=”defaultData(event)”
  106. />
  107.  
  108. <!--
  109. - Conserviamo nella variabile ‘articoliXML’ l’elenco degli articoli (item)
  110. - Utilizziamo la classe XMLListCollection perchè permette di sfruttare
  111. le potenzialità E4X disponibili dalla versione 3.0 di Actionscript.
  112. -->
  113. <mx:XMLListCollection id=”articoliXML”
  114. source=”{rssRPC.lastResult.channel.item}” />
  115.  
  116.  
  117. <mx:VBox x=”10” y=”0” height=”227” width=”250”>
  118.  
  119. <!--
  120. COMBOBOX con l’ELENCO dei FEED RSS di FlexGala:
  121. - Acquisiamo gli URL attraverso l’array ‘urlArray’ definito in precedenza
  122. - Ad ogni selezione carichiamo i nuovi dati chiamando la funzione ‘loadXMLData’
  123. e passando come parametro l’url selezionato
  124. -->
  125. <mx:ComboBox width=”100%” id=”combo_list”
  126. dataProvider=”{urlArray}”
  127. change=”loadXMLData(urlArray[event.currentTarget.selectedIndex].data)”
  128. />
  129.  
  130. <!--
  131. VISUALIZZAZIONE ELENCO ARTICOLI
  132. - Il dataProvider utilizzato per reperire l’elenco degli articoli
  133. è popolato automaticamente ad ogni nuova chiamata grazie al BINDING.
  134. - Ad ogni selezione viene invocato l’evento ‘change’ e visualizziamo il
  135. relativo abstract
  136.  
  137. -->
  138. <mx:List width=”100%” height=”100%” id=”posts_list”
  139. dataProvider=”{articoliXML}”
  140. change=”viewAbstract(event.currentTarget.selectedIndex)”
  141. labelField=”title”
  142. />
  143.  
  144. </mx:VBox>
  145.  
  146. <!--
  147. TEXTAREA per la VISUALIZZAZIONE dell’ABSTRACT
  148. -->
  149. <mx:TextArea id=”post_details” x=”268” y=”29” width=”312” height=”198”/>
  150.  
  151. <!--
  152. IL PUlSANTE PER APRIRE IL LINK DELL’ARTICOLO COMPLETO SUL SITO UFFICIALE
  153. -->
  154. <mx:Button x=”149” y=”235” label=”Dettaglio news”
  155. click=”openURL(event)”/>
  156.  
  157. </mx:Application>

Di seguito il codice della seconda applicazione commentato passo-passo:

  1. <?xml version=”1.0” encoding=”utf-8”?>
  2. <mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”
  3. layout=”absolute”>
  4.  
  5. <mx:Script>
  6. <![CDATA[
  7. import mx.controls.Alert;
  8. import mx.events.*
  9. import mx.rpc.events.ResultEvent;
  10. import mx.rpc.events.FaultEvent;
  11.  
  12. // PATH PROXY PHP
  13. // --> DEBUG
  14. private const pathProxy:String = “http://localhost/Web/_FLEX3/RSSReader/src/php/proxy.php?url=”;
  15.  
  16. // VERSIONE FINALE (on-Line)
  17. //private const pathProxy:String = “php/proxy.php?url=”;
  18.  
  19.  
  20. [Bindable]
  21. public var dp:XMLList;
  22.  
  23. private function openCustomRSS(url:String):void
  24. {
  25. rssRPC.url= pathProxy + url;
  26. rssRPC.send();
  27. }
  28.  
  29. // Caricamento RSS Avvenuto con successo
  30. private function defaultData(event:ResultEvent):void
  31. {
  32. // Visualizzazione del titolo del Feed RSS
  33. title_txt.text = event.currentTarget.lastResult.channel.title;
  34.  
  35. // Lista dei nodi
  36. dp = event.currentTarget.lastResult.channel.item
  37.  
  38. // Visualizziamo il primo post della lista
  39. viewAbstract(0)
  40.  
  41. // Visualizziamo il primo elemento della lista
  42. posts_list.selectedIndex = 0;
  43. }
  44.  
  45.  
  46. // In caso di URL inesistente
  47. private function faultData(event:FaultEvent):void
  48. {
  49. Alert.show(“URL non disponibile”);
  50. }
  51.  
  52. // Visualizziamo l’abstract
  53. private function viewAbstract(idxNews:uint):void
  54. {
  55. try
  56. {
  57. post_details.htmlText = String(dp[idxNews].description);
  58. }
  59. catch(e:*){}
  60. }
  61.  
  62. /*
  63. APERTURA URL dell’ARTICOLO COMPLETO
  64. */
  65. private function openURL(event:MouseEvent):void
  66. {
  67. var linkNews:String = dp[posts_list.selectedIndex].link;
  68. var adobeURL:URLRequest = new URLRequest(linkNews);
  69. navigateToURL(adobeURL, “_blank”);
  70. }
  71. ]]>
  72. </mx:Script>
  73.  
  74. <mx:HTTPService id=”rssRPC”
  75. resultFormat=”e4x”
  76. result=”defaultData(event)”
  77. fault=”faultData(event)”
  78.  
  79. />
  80.  
  81. <mx:ApplicationControlBar x=”0” y=”0” dock=”true” height=”44”>
  82. <mx:Label text=”Indirizzo RSS:”/>
  83. <mx:TextInput id=”testoInput” width=”380”/>
  84. <mx:Button label=”Leggi RSS”
  85. click=”openCustomRSS(testoInput.text)”/>
  86. </mx:ApplicationControlBar>
  87.  
  88. <mx:Label id=”title_txt” x=”10” y=”13” width=”570”/>
  89.  
  90. <mx:VBox x=”10” y=”39” height=”199” width=”250”>
  91. <mx:List width=”100%” height=”100%” id=”posts_list”
  92. dataProvider=”{dp}”
  93. change=”viewAbstract(event.currentTarget.selectedIndex)”
  94. labelField=”title”
  95. />
  96.  
  97. </mx:VBox>
  98.  
  99. <mx:TextArea id=”post_details” x=”268” y=”39” width=”312” height=”198”/>
  100.  
  101. <mx:Button x=”149” y=”246” label=”Dettaglio news”
  102. click=”openURL(event)”/>
  103.  
  104.  
  105. </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).