From a934b9e23d99473b610bfab79aecff4604e9d265 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 26 Aug 2011 19:09:02 +0000 Subject: [PATCH] New: Enhance error management and support Atom feeds in rss module. --- htdocs/admin/external_rss.php | 9 +- htdocs/core/class/rssparser.class.php | 151 +++++++++++++++++++++----- htdocs/langs/ca_ES/admin.lang | 1 + htdocs/langs/en_US/admin.lang | 1 + htdocs/langs/en_US/boxes.lang | 8 +- htdocs/langs/en_US/errors.lang | 1 + htdocs/langs/es_ES/admin.lang | 1 + htdocs/langs/fr_FR/admin.lang | 1 + htdocs/langs/fr_FR/errors.lang | 1 + htdocs/langs/ru_RU/boxes.lang | 42 +++---- htdocs/lib/files.lib.php | 23 +++- 11 files changed, 184 insertions(+), 55 deletions(-) diff --git a/htdocs/admin/external_rss.php b/htdocs/admin/external_rss.php index 8f8813033ce..bcab1f64283 100644 --- a/htdocs/admin/external_rss.php +++ b/htdocs/admin/external_rss.php @@ -24,7 +24,7 @@ * \file htdocs/admin/external_rss.php * \ingroup external_rss * \brief Page to setupe module ExternalRss - * \version $Id: external_rss.php,v 1.49 2011/08/17 13:44:16 eldy Exp $ + * \version $Id: external_rss.php,v 1.50 2011/08/26 19:09:03 eldy Exp $ */ require("../main.inc.php"); @@ -286,7 +286,10 @@ if ($resql) } else { - print ''.$langs->trans("Offline").''; + print ''.$langs->trans("Offline"); + $langs->load("errors"); + if ($rssparser->error) print ' - '.$langs->trans($rssparser->error); + print ''; } print ""; print ""; @@ -320,5 +323,5 @@ else $db->close(); -llxFooter('$Date: 2011/08/17 13:44:16 $ - $Revision: 1.49 $'); +llxFooter('$Date: 2011/08/26 19:09:03 $ - $Revision: 1.50 $'); ?> diff --git a/htdocs/core/class/rssparser.class.php b/htdocs/core/class/rssparser.class.php index 1b018b5073d..4a8277f52bf 100755 --- a/htdocs/core/class/rssparser.class.php +++ b/htdocs/core/class/rssparser.class.php @@ -19,7 +19,7 @@ * \file htdocs/core/class/rssparser.class.php * \ingroup core * \brief File of class to parse rss feeds - * \version $Id: rssparser.class.php,v 1.1 2011/08/17 13:44:13 eldy Exp $ + * \version $Id: rssparser.class.php,v 1.3 2011/08/26 19:09:02 eldy Exp $ */ class RssParser { @@ -75,8 +75,15 @@ class RssParser { include_once(DOL_DOCUMENT_ROOT.'/lib/files.lib.php'); + // Check parameters + if (! dol_is_url($urlRSS)) + { + $this->error="ErrorBadUrl"; + return -1; + } + $this->_urlRSS = $urlRSS; - $newpathofdestfile=$cachedir.'/'.md5($this->_urlRSS); + $newpathofdestfile=$cachedir.'/'.md5($this->_urlRSS); $newmask=octdec('0644'); //dol_syslog("RssPArser::parser parse url=".$urlRSS." => cache file=".$newpathofdestfile); @@ -109,7 +116,14 @@ class RssParser else { try { - $rss = @simplexml_load_file($this->_urlRSS); + ini_set("user_agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"); + ini_set("max_execution_time", 10); + if (! empty($conf->global->MAIN_SIMPLEXMLLOAD_DEBUG)) $rss = simplexml_load_file($this->_urlRSS); + else + { + //libxml_use_internal_errors(false); + $rss = @simplexml_load_file($this->_urlRSS); + } } catch (Exception $e) { print 'Error retrieving URL '.$this->urlRSS.' - '.$e->getMessage(); @@ -119,6 +133,8 @@ class RssParser // If $rss loaded if ($rss) { + $items=array(); + // Save file into cache if (empty($foundintocache) && $cachedir) { @@ -133,33 +149,60 @@ class RssParser $this->_lastfetchdate=$nowgmt; } - // Save description entries - if (!empty($rss->channel->language)) $this->_language = (string) $rss->channel->language; - if (!empty($rss->channel->generator)) $this->_generator = (string) $rss->channel->generator; - if (!empty($rss->channel->copyright)) $this->_copyright = (string) $rss->channel->copyright; - if (!empty($rss->channel->lastbuilddate)) $this->_lastbuilddate = (string) $rss->channel->lastbuilddate; - if (!empty($rss->channel->image->url[0])) $this->_imageurl = (string) $rss->channel->image->url[0]; - if (!empty($rss->channel->link)) $this->_link = (string) $rss->channel->link; - if (!empty($rss->channel->title)) $this->_title = (string) $rss->channel->title; - if (!empty($rss->channel->description)) $this->_description = (string) $rss->channel->description; - // TODO imageurl + $rss->_format='rss'; + if (empty($rss->channel)) $rss->_format='atom'; + + // Save description entries + if ($rss->_format == 'rss') + { + if (!empty($rss->channel->language)) $this->_language = (string) $rss->channel->language; + if (!empty($rss->channel->generator)) $this->_generator = (string) $rss->channel->generator; + if (!empty($rss->channel->copyright)) $this->_copyright = (string) $rss->channel->copyright; + if (!empty($rss->channel->lastbuilddate)) $this->_lastbuilddate = (string) $rss->channel->lastbuilddate; + if (!empty($rss->channel->image->url[0])) $this->_imageurl = (string) $rss->channel->image->url[0]; + if (!empty($rss->channel->link)) $this->_link = (string) $rss->channel->link; + if (!empty($rss->channel->title)) $this->_title = (string) $rss->channel->title; + if (!empty($rss->channel->description)) $this->_description = (string) $rss->channel->description; + $items=$rss->channel->item; + } + else if ($rss->_format == 'atom') + { + if (!empty($rss->generator)) $this->_generator = (string) $rss->generator; + if (!empty($rss->lastbuilddate)) $this->_lastbuilddate = (string) $rss->modified; + if (!empty($rss->link->href)) $this->_link = (string) $rss->link->href; + if (!empty($rss->title)) $this->_title = (string) $rss->title; + if (!empty($rss->description)) $this->_description = (string) $rss->description; + $tmprss=xml2php($rss); + $items=$tmprss['entry']; + } $i = 0; - // Loop on each record - foreach($rss->channel->item as $item) + foreach($items as $item) { - $itemLink = (string) $item->link; - $itemTitle = (string) $item->title; - $itemDescription = (string) $item->description; - $itemPubDate = (string) $item->pubDate; + if ($rss->_format == 'rss') + { + $itemLink = (string) $item->link; + $itemTitle = (string) $item->title; + $itemDescription = (string) $item->description; + $itemPubDate = (string) $item->pubDate; + $itemId = ''; - // Loop on each category - $itemCategory=array(); - foreach ($item->category as $cat) - { - $itemCategory[] = (string) $cat; - } + // Loop on each category + $itemCategory=array(); + foreach ($item->category as $cat) + { + $itemCategory[] = (string) $cat; + } + } + else if ($rss->_format == 'atom') + { + $itemLink = (string) $item['link']['href']; + $itemTitle = (string) $item['title']; + $itemDescription = (string) $item['summary']; + $itemPubDate = (string) $item['created']; + $itemId = (string) $item['id']; + } // Add record to result array $this->_rssarray[$i] = array( @@ -167,7 +210,8 @@ class RssParser 'title'=>$itemTitle, 'description'=>$itemDescription, 'pubDate'=>$itemPubDate, - 'category'=>$itemCategory); + 'category'=>$itemCategory, + 'id'=>$itemId); $i++; @@ -184,4 +228,59 @@ class RssParser } } + + +/** + * Function to convert an XML object into an array + */ +function xml2php($xml) +{ + $fils = 0; + $tab = false; + $array = array(); + foreach($xml->children() as $key => $value) + { + $child = xml2php($value); + + //To deal with the attributes + foreach($value->attributes() as $ak=>$av) + { + $child[$ak] = (string)$av; + + } + + //Let see if the new child is not in the array + if($tab==false && in_array($key,array_keys($array))) + { + //If this element is already in the array we will create an indexed array + $tmp = $array[$key]; + $array[$key] = NULL; + $array[$key][] = $tmp; + $array[$key][] = $child; + $tab = true; + } + elseif($tab == true) + { + //Add an element in an existing array + $array[$key][] = $child; + } + else + { + //Add a simple element + $array[$key] = $child; + } + + $fils++; + } + + + if($fils==0) + { + return (string)$xml; + } + + return $array; + +} + ?> \ No newline at end of file diff --git a/htdocs/langs/ca_ES/admin.lang b/htdocs/langs/ca_ES/admin.lang index 6429299f7b5..db8fd9d034b 100644 --- a/htdocs/langs/ca_ES/admin.lang +++ b/htdocs/langs/ca_ES/admin.lang @@ -883,6 +883,7 @@ DocumentModelOdt=Generació des dels documents amb format OpenDocument (Arxiu .O WatermarkOnDraft=Marca d'aigua en els documents esborrany CompanyIdProfChecker=Id Professional únic MustBeUnique=Ha de ser únic? +Miscellanous=Miscel·lània ##### Webcal setup ##### WebCalSetup=Configuració d'enllaç amb el calendari webcalendar WebCalSyncro=Integrar els esdeveniments Dolibarr a webcalendar diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index c86ffb54295..b056b135e06 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -877,6 +877,7 @@ DocumentModelOdt=Generate documents from OpenDocuments templates (.ODT files for WatermarkOnDraft=Watermark on draft document CompanyIdProfChecker=Professional Id unique MustBeUnique=Must be unique ? +Miscellanous=Miscellanous ##### Webcal setup ##### WebCalSetup=Webcalendar link setup WebCalSyncro=Add Dolibarr events to WebCalendar diff --git a/htdocs/langs/en_US/boxes.lang b/htdocs/langs/en_US/boxes.lang index 9c28211732b..e60083b6258 100644 --- a/htdocs/langs/en_US/boxes.lang +++ b/htdocs/langs/en_US/boxes.lang @@ -15,14 +15,14 @@ BoxLastCustomerOrders=Last customer orders BoxLastBooks=Last books BoxLastActions=Last actions BoxLastContracts=Last contracts -BoxLastContacts=Derniers contacts/adresses +BoxLastContacts=Last contacts/addresses BoxLastMembers=Last members BoxCurrentAccounts=Current accounts balance BoxSalesTurnover=Sales turnover BoxTotalUnpaidCustomerBills=Total unpaid customer's invoices BoxTotalUnpaidSuppliersBills=Total unpaid supplier's invoices BoxTitleLastBooks=Last %s recorded books -BoxTitleNbOfCustomers=Nombre de client +BoxTitleNbOfCustomers=Number of clients BoxTitleLastRssInfos=Last %s news from %s BoxTitleLastProducts=Last %s modified products/services BoxTitleLastCustomerOrders=Last %s modified customer orders @@ -44,11 +44,11 @@ BoxTitleCurrentAccounts=Current account's balances BoxTitleSalesTurnover=Sales turnover BoxTitleTotalUnpaidCustomerBills=Unpaid customer's invoices BoxTitleTotalUnpaidSuppliersBills=Unpaid supplier's invoices -BoxTitleLastModifiedContacts=Last %s modified contacts/addresses +BoxTitleLastModifiedContacts=Last %s modified contacts/addresses BoxMyLastBookmarks=My last %s bookmarks FailedToRefreshDataInfoNotUpToDate=Failed to refresh RSS flux. Last successfull refresh date: %s LastRefreshDate=Last refresh date -NoRecordedBookmarks=No bookmarks defined. +NoRecordedBookmarks=No bookmarks defined. ClickToAdd=Click here to add. NoRecordedCustomers=No recorded customers NoRecordedContacts=No recorded contacts diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang index f57f175d2c3..1eaa3cae301 100644 --- a/htdocs/langs/en_US/errors.lang +++ b/htdocs/langs/en_US/errors.lang @@ -86,3 +86,4 @@ ErrorProductWithRefNotExist=Product with reference '%s' don't exist ErrorDeleteNotPossibleLineIsConsolidated=Delete not possible because record is linked to a bank transation that is conciliated ErrorProdIdAlreadyExist=%s is assigned to another third ErrorFailedToSendPassword=Failed to send password +ErrorFailedToLoadRSSFile=Fails to get RSS feed. Try to add constant MAIN_SIMPLEXMLLOAD_DEBUG if error messages does not provide enough information. \ No newline at end of file diff --git a/htdocs/langs/es_ES/admin.lang b/htdocs/langs/es_ES/admin.lang index a87a0a8bccb..a81320bceeb 100644 --- a/htdocs/langs/es_ES/admin.lang +++ b/htdocs/langs/es_ES/admin.lang @@ -883,6 +883,7 @@ DocumentModelOdt=Generación desde los documentos OpenDocument (Archivo .ODT Ope WatermarkOnDraft=Marca de agua en los documentos borrador CompanyIdProfChecker=Id Profesional único MustBeUnique=¿Debe ser único? +Miscellanous=Miscelánea ##### Webcal setup ##### WebCalSetup=Configuración de enlace con el calendario Webcalendar WebCalSyncro=Integrar los eventos Dolibarr en WebCalendar diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index 42b184565c2..77f3ee56575 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -885,6 +885,7 @@ DocumentModelOdt=Genération depuis des modèles OpenDocument (Fichier .ODT Open WatermarkOnDraft=Filigrane sur les documents brouillons CompanyIdProfChecker=Id professionel unique MustBeUnique=Doit être unique ? +Miscellanous=Miscellanous ##### Webcal setup ##### WebCalSetup= Configuration du lien vers le calendrier Webcalendar WebCalSyncro= Intégrer les événements Dolibarr dans WebCalendar diff --git a/htdocs/langs/fr_FR/errors.lang b/htdocs/langs/fr_FR/errors.lang index a1c97e82c2b..69c9e2b5e9c 100644 --- a/htdocs/langs/fr_FR/errors.lang +++ b/htdocs/langs/fr_FR/errors.lang @@ -87,3 +87,4 @@ ErrorProductWithRefNotExist=La référence produit '%s' n'existe pas ErrorDeleteNotPossibleLineIsConsolidated=Suppression impossible car l'enregistrement porte sur au moins une transaction bancaire rapprochée ErrorProdIdAlreadyExist=%s est attribué à un autre tiers ErrorFailedToSendPassword=Échec de l'envoi du mot de passe +ErrorFailedToLoadRSSFile=Echec de la récupération du flux RSS. Ajouter la constante MAIN_SIMPLEXMLLOAD_DEBUG si le message d'erreur n'est pas assez explicite. \ No newline at end of file diff --git a/htdocs/langs/ru_RU/boxes.lang b/htdocs/langs/ru_RU/boxes.lang index c3d52b9528f..644c87a76eb 100644 --- a/htdocs/langs/ru_RU/boxes.lang +++ b/htdocs/langs/ru_RU/boxes.lang @@ -10,12 +10,12 @@ // Reference language: en_US CHARSET=UTF-8 BoxLastRssInfos=Информация RSS -BoxLastProducts=Последние %s товаров / услуг -BoxLastProductsInContract=Последние %s проданных товаров / услуг +BoxLastProducts=Последние %s товары / услуги +BoxLastProductsInContract=Последние %s проданные товары / услуги BoxLastSupplierBills=Последние счета-фактуры поставщиков BoxLastCustomerBills=Последние счета-фактуры покупателям BoxLastProposals=Последние коммерческие предложения -BoxLastProspects=Последние измененные потенциальные покупатели +BoxLastProspects=Последние измененные потенциальные клиенты BoxLastCustomers=Последние измененные покупатели BoxLastCustomerOrders=Последние заказы покупателей BoxLastSuppliers=Последние измененные поставщики @@ -26,8 +26,8 @@ BoxSalesTurnover=Оборот по продажам BoxTitleLastBooks=Последние %s зарегистрированных сделок BoxTitleNbOfCustomers=Кол-во покупателей BoxTitleLastRssInfos=Последние новости %s из %s -BoxTitleLastProducts=Последние %s измененных товаров / услуг -BoxTitleLastCustomerOrders=Последние %s измененных заказов покупателей +BoxTitleLastProducts=Последние %s измененные товары / услуги +BoxTitleLastCustomerOrders=Последние %s измененные заказы покупателей BoxTitleLastSuppliers=Последние %s зарегистрированных поставщиков BoxTitleLastCustomers=Последние %s зарегистрированных покупателей BoxTitleLastCustomersOrProspects=Последние %s зарегистрированных покупателей и потенциальных клиентов @@ -48,20 +48,10 @@ NoRecordedOrders=Нет зарегистрированных заказы пок NoRecordedProposals=Нет зарегистрированных предложений NoRecordedInvoices=Нет зарегистрированных счетов-фактур покупателям NoRecordedSupplierInvoices=Нет зарегистрированных счетов-фактур поставщиков -// Date 2009-01-19 21:30:52 -// STOP - Lines generated via parser - -// START - Lines generated via autotranslator.php tool (2009-08-13 21:14:36). -// Reference language: en_US LastRefreshDate=Дата последнего обновления NoRecordedProducts=Нет зарегистрированных товаров / услуг NoRecordedProspects=Нет зарегистрированных потенциальных клиентов NoContractedProducts=Нет законтрактованных товаров / услуг -// STOP - Lines generated via autotranslator.php tool (2009-08-13 21:14:36). - - -// START - Lines generated via autotranslator.php tool (2009-08-19 20:18:27). -// Reference language: en_US BoxOldestUnpaidCustomerBills=Самые старые неоплаченные счета-фактуры покупателям BoxOldestUnpaidSupplierBills=Самые старые неоплаченные счета-фактуры поставщиков BoxTotalUnpaidCustomerBills=Общая сумма неоплаченных счетов-фактур покупателям @@ -72,11 +62,21 @@ BoxTitleTotalUnpaidCustomerBills=Неоплаченные счета-факту BoxTitleTotalUnpaidSuppliersBills=Неоплаченные счета-фактуры поставщиков NoUnpaidCustomerBills=Нет неоплаченных счетов-фактур покупателям NoUnpaidSupplierBills=Нет неоплаченных счетов-фактур поставщиков -// STOP - Lines generated via autotranslator.php tool (2009-08-19 20:18:27). - -// START - Lines generated via autotranslator.php tool (2010-09-04 01:33:40). -// Reference language: en_US -> ru_RU BoxTitleLastModifiedSuppliers=Последнее %s измененных поставщиков -BoxTitleLastModifiedCustomers=Последнее %s измененных клиентов +BoxTitleLastModifiedCustomers=Последнее %s измененных покупателей BoxTitleLastModifiedProspects=Последнее %s измененных потенциальных клиентов -// STOP - Lines generated via autotranslator.php tool (2010-09-04 01:56:40). +BoxLastContracts=Последние договоры +BoxLastContacts=Последние контакты / адреса +BoxLastMembers=Последнее участники +BoxTitleLastModifiedCustomers=Последние %s измененных покупателей +BoxTitleLastModifiedProspects=Последние %s измененных потенциальных клиентов +BoxTitleLastProductsInContract=Последние %s товаров / услуг в договорах +BoxTitleLastModifiedMembers=Последние %s измененных участников +BoxTitleLastModifiedContacts=Последние %s измененных контактов / адресов +NoRecordedContacts=Нет введенных контактов +BoxTitleLastContracts=Последние %s договоров +BoxTitleLastModifiedDonations=Последние %s измененных пожертвований +BoxTitleLastModifiedExpenses=Последние %s измененных расходов +NoModifiedSupplierBills=Нет введенных счетов-фактур поставщиков +NoRecordedContracts=Нет введенных договоров +// STOP - Lines generated via autotranslator.php tool (2011-08-25 22:47:13). diff --git a/htdocs/lib/files.lib.php b/htdocs/lib/files.lib.php index 312cece614e..7df39b03ea3 100644 --- a/htdocs/lib/files.lib.php +++ b/htdocs/lib/files.lib.php @@ -19,7 +19,7 @@ /** * \file htdocs/lib/files.lib.php * \brief Library for file managing functions - * \version $Id: files.lib.php,v 1.71 2011/07/31 23:25:43 eldy Exp $ + * \version $Id: files.lib.php,v 1.72 2011/08/26 17:59:14 eldy Exp $ */ /** @@ -186,6 +186,7 @@ function dol_compare_file($a, $b) /** * Return mime type of a file + * * @param file Filename we looking for MIME type * @param default Default mime type if extension not found in known list * @param mode 0=Return full mime, 1=otherwise short mime string, 2=image for mime type, 3=source language @@ -295,6 +296,7 @@ function dol_mimetype($file,$default='application/octet-stream',$mode=0) /** * Test if filename is a directory + * * @param folder Name of folder * @return boolean True if it's a directory, False if not found */ @@ -307,6 +309,7 @@ function dol_is_dir($folder) /** * Return if path is a file + * * @param $pathoffile * @return boolean True or false */ @@ -316,8 +319,26 @@ function dol_is_file($pathoffile) return is_file($newpathoffile); } +/** + * Return if path is an URL + * + * @param $url + * @return boolean True or false + */ +function dol_is_url($url) +{ + $tmpprot=array('file','http','ftp','zlib','data','ssh2','ogg','expect'); + foreach($tmpprot as $prot) + { + if (preg_match('/^'.$prot.':/i',$url)) return true; + } + return false; +} + + /** * Test if a folder is empty + * * @param folder Name of folder * @return boolean True if dir is empty or non-existing, False if it contains files */