dolibarr 20.0.0
rssparser.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2011-2012 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
25// @phan-file-suppress PhanPluginPHPDocInWrongComment
26
31{
35 public $db;
36
40 public $error = '';
41
42 public $feed_version;
43
44 private $_format = '';
45 private $_urlRSS;
46 private $_language;
47 private $_generator;
48 private $_copyright;
49 private $_lastbuilddate;
50 private $_imageurl;
51 private $_link;
52 private $_title;
53 private $_description;
54 private $_lastfetchdate; // Last successful fetch
55 private $_rssarray = array();
56
57 private $current_namespace;
58 public $items = array();
59 public $current_item = array();
60 public $channel = array();
61 public $textinput = array();
62 public $image = array();
63
64 private $initem;
65 private $intextinput;
66 private $incontent;
67 private $inimage;
68 private $inchannel;
69
70 // For parsing with xmlparser
71 public $stack = array(); // parser stack
72 private $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright');
73
74
80 public function __construct($db)
81 {
82 $this->db = $db;
83 }
84
90 public function getFormat()
91 {
92 return $this->_format;
93 }
94
100 public function getUrlRss()
101 {
102 return $this->_urlRSS;
103 }
109 public function getLanguage()
110 {
111 return $this->_language;
112 }
118 public function getGenerator()
119 {
120 return $this->_generator;
121 }
127 public function getCopyright()
128 {
129 return $this->_copyright;
130 }
136 public function getLastBuildDate()
137 {
138 return $this->_lastbuilddate;
139 }
145 public function getImageUrl()
146 {
147 return $this->_imageurl;
148 }
154 public function getLink()
155 {
156 return $this->_link;
157 }
163 public function getTitle()
164 {
165 return $this->_title;
166 }
172 public function getDescription()
173 {
174 return $this->_description;
175 }
181 public function getLastFetchDate()
182 {
183 return $this->_lastfetchdate;
184 }
190 public function getItems()
191 {
192 return $this->_rssarray;
193 }
194
204 public function parser($urlRSS, $maxNb = 0, $cachedelay = 60, $cachedir = '')
205 {
206 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
207 include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
208
209 $rss = '';
210 $str = ''; // This will contain content of feed
211
212 // Check parameters
213 if (!dol_is_url($urlRSS)) {
214 $this->error = "ErrorBadUrl";
215 return -1;
216 }
217
218 $this->_urlRSS = $urlRSS;
219 $newpathofdestfile = $cachedir.'/'.dol_hash($this->_urlRSS, 3); // Force md5 hash (does not contain special chars)
220 $newmask = '0644';
221
222 //dol_syslog("RssParser::parser parse url=".$urlRSS." => cache file=".$newpathofdestfile);
223 $nowgmt = dol_now();
224
225 // Search into cache
226 $foundintocache = 0;
227 if ($cachedelay > 0 && $cachedir) {
228 $filedate = dol_filemtime($newpathofdestfile);
229 if ($filedate >= ($nowgmt - $cachedelay)) {
230 //dol_syslog("RssParser::parser cache file ".$newpathofdestfile." is not older than now - cachedelay (".$nowgmt." - ".$cachedelay.") so we use it.");
231 $foundintocache = 1;
232
233 $this->_lastfetchdate = $filedate;
234 } else {
235 dol_syslog(get_class($this)."::parser cache file ".$newpathofdestfile." is not found or older than now - cachedelay (".$nowgmt." - ".$cachedelay.") so we can't use it.");
236 }
237 }
238
239 // Load file into $str
240 if ($foundintocache) { // Cache file found and is not too old
241 $str = file_get_contents($newpathofdestfile);
242 } else {
243 try {
244 $result = getURLContent($this->_urlRSS, 'GET', '', 1, array(), array('http', 'https'), 0);
245
246 if (!empty($result['content'])) {
247 $str = $result['content'];
248 } elseif (!empty($result['curl_error_msg'])) {
249 $this->error = 'Error retrieving URL '.$this->_urlRSS.' - '.$result['curl_error_msg'];
250 return -1;
251 }
252 } catch (Exception $e) {
253 $this->error = 'Error retrieving URL '.$this->_urlRSS.' - '.$e->getMessage();
254 return -2;
255 }
256 }
257
258 if ($str !== false) {
259 // Convert $str into xml
260 if (getDolGlobalString('EXTERNALRSS_USE_SIMPLEXML')) {
261 //print 'xx'.LIBXML_NOCDATA;
262 libxml_use_internal_errors(false);
263 if (LIBXML_VERSION < 20900) {
264 // Avoid load of external entities (security problem).
265 // Required only if LIBXML_VERSION < 20900
266 // @phan-suppress-next-line PhanDeprecatedFunctionInternal
267 libxml_disable_entity_loader(true);
268 }
269
270 $rss = simplexml_load_string($str, "SimpleXMLElement", LIBXML_NOCDATA);
271 } else {
272 if (!function_exists('xml_parser_create')) {
273 $this->error = 'Function xml_parser_create are not supported by your PHP';
274 return -1;
275 }
276
277 try {
278 // @phan-suppress-next-line PhanTypeMismatchArgumentInternalProbablyReal
279 $xmlparser = xml_parser_create(null);
280
281 xml_parser_set_option($xmlparser, XML_OPTION_CASE_FOLDING, 0);
282 xml_parser_set_option($xmlparser, XML_OPTION_SKIP_WHITE, 1);
283 xml_parser_set_option($xmlparser, XML_OPTION_TARGET_ENCODING, "UTF-8");
284 //xml_set_external_entity_ref_handler($xmlparser, 'extEntHandler'); // Seems to have no effect even when function extEntHandler exists.
285
286 if (!is_resource($xmlparser) && !is_object($xmlparser)) {
287 $this->error = "ErrorFailedToCreateParser";
288 return -1;
289 }
290
291 xml_set_object($xmlparser, $this);
292 // @phan-suppress-next-line PhanUndeclaredFunctionInCallable
293 xml_set_element_handler($xmlparser, 'feed_start_element', 'feed_end_element');
294 // @phan-suppress-next-line PhanUndeclaredFunctionInCallable
295 xml_set_character_data_handler($xmlparser, 'feed_cdata');
296
297 $status = xml_parse($xmlparser, $str, false);
298
299 xml_parser_free($xmlparser);
300
301 $rss = $this;
302 //var_dump($status.' '.$rss->_format);exit;
303 } catch (Exception $e) {
304 $rss = null;
305 }
306 }
307 }
308
309 // If $rss loaded
310 if ($rss) {
311 // Save file into cache
312 if (empty($foundintocache) && $cachedir) {
313 dol_syslog(get_class($this)."::parser cache file ".$newpathofdestfile." is saved onto disk.");
314 if (!dol_is_dir($cachedir)) {
315 dol_mkdir($cachedir);
316 }
317 $fp = fopen($newpathofdestfile, 'w');
318 if ($fp) {
319 fwrite($fp, $str);
320 fclose($fp);
321 dolChmod($newpathofdestfile);
322
323 $this->_lastfetchdate = $nowgmt;
324 } else {
325 print 'Error, failed to open file '.$newpathofdestfile.' for write';
326 }
327 }
328
329 unset($str); // Free memory
330
331 if (empty($rss->_format)) { // If format not detected automatically
332 $rss->_format = 'rss';
333 if (empty($rss->channel)) {
334 $rss->_format = 'atom';
335 }
336 }
337
338 $items = array();
339
340 // Save description entries
341 if ($rss->_format == 'rss') {
342 //var_dump($rss);
343 if (getDolGlobalString('EXTERNALRSS_USE_SIMPLEXML')) {
344 if (!empty($rss->channel->language)) {
345 $this->_language = sanitizeVal((string) $rss->channel->language);
346 }
347 if (!empty($rss->channel->generator)) {
348 $this->_generator = sanitizeVal((string) $rss->channel->generator);
349 }
350 if (!empty($rss->channel->copyright)) {
351 $this->_copyright = sanitizeVal((string) $rss->channel->copyright);
352 }
353 if (!empty($rss->channel->lastbuilddate)) {
354 $this->_lastbuilddate = sanitizeVal((string) $rss->channel->lastbuilddate);
355 }
356 if (!empty($rss->channel->image->url[0])) {
357 $this->_imageurl = sanitizeVal((string) $rss->channel->image->url[0]);
358 }
359 if (!empty($rss->channel->link)) {
360 $this->_link = sanitizeVal((string) $rss->channel->link);
361 }
362 if (!empty($rss->channel->title)) {
363 $this->_title = sanitizeVal((string) $rss->channel->title);
364 }
365 if (!empty($rss->channel->description)) {
366 $this->_description = sanitizeVal((string) $rss->channel->description);
367 }
368 } else {
369 //var_dump($rss->channel);
370 if (!empty($rss->channel['language'])) {
371 $this->_language = sanitizeVal((string) $rss->channel['language']);
372 }
373 if (!empty($rss->channel['generator'])) {
374 $this->_generator = sanitizeVal((string) $rss->channel['generator']);
375 }
376 if (!empty($rss->channel['copyright'])) {
377 $this->_copyright = sanitizeVal((string) $rss->channel['copyright']);
378 }
379 if (!empty($rss->channel['lastbuilddate'])) {
380 $this->_lastbuilddate = sanitizeVal((string) $rss->channel['lastbuilddate']);
381 }
382 if (!empty($rss->image['url'])) {
383 $this->_imageurl = sanitizeVal((string) $rss->image['url']);
384 }
385 if (!empty($rss->channel['link'])) {
386 $this->_link = sanitizeVal((string) $rss->channel['link']);
387 }
388 if (!empty($rss->channel['title'])) {
389 $this->_title = sanitizeVal((string) $rss->channel['title']);
390 }
391 if (!empty($rss->channel['description'])) {
392 $this->_description = sanitizeVal((string) $rss->channel['description']);
393 }
394 }
395
396 if (getDolGlobalString('EXTERNALRSS_USE_SIMPLEXML')) {
397 $items = $rss->channel->item; // With simplexml
398 } else {
399 $items = $rss->items; // With xmlparse
400 }
401 //var_dump($items);exit;
402 } elseif ($rss->_format == 'atom') {
403 //var_dump($rss);
404 if (getDolGlobalString('EXTERNALRSS_USE_SIMPLEXML')) {
405 if (!empty($rss->generator)) {
406 $this->_generator = sanitizeVal((string) $rss->generator);
407 }
408 if (!empty($rss->lastbuilddate)) {
409 $this->_lastbuilddate = sanitizeVal((string) $rss->modified);
410 }
411 if (!empty($rss->link->href)) {
412 $this->_link = sanitizeVal((string) $rss->link->href);
413 }
414 if (!empty($rss->title)) {
415 $this->_title = sanitizeVal((string) $rss->title);
416 }
417 if (!empty($rss->description)) {
418 $this->_description = sanitizeVal((string) $rss->description);
419 }
420 } else {
421 //if (!empty($rss->channel['rss_language'])) $this->_language = (string) $rss->channel['rss_language'];
422 if (!empty($rss->channel['generator'])) {
423 $this->_generator = sanitizeVal((string) $rss->channel['generator']);
424 }
425 //if (!empty($rss->channel['rss_copyright'])) $this->_copyright = (string) $rss->channel['rss_copyright'];
426 if (!empty($rss->channel['modified'])) {
427 $this->_lastbuilddate = sanitizeVal((string) $rss->channel['modified']);
428 }
429 //if (!empty($rss->image['rss_url'])) $this->_imageurl = (string) $rss->image['rss_url'];
430 if (!empty($rss->channel['link'])) {
431 $this->_link = sanitizeVal((string) $rss->channel['link']);
432 }
433 if (!empty($rss->channel['title'])) {
434 $this->_title = sanitizeVal((string) $rss->channel['title']);
435 }
436 //if (!empty($rss->channel['rss_description'])) $this->_description = (string) $rss->channel['rss_description'];
437
438 if (!empty($rss->channel)) {
439 $this->_imageurl = sanitizeVal($this->getAtomImageUrl($rss->channel));
440 }
441 }
442 if (getDolGlobalString('EXTERNALRSS_USE_SIMPLEXML')) {
443 $tmprss = xml2php($rss);
444 $items = $tmprss['entry'];
445 } else {
446 // With simplexml
447 $items = $rss->items; // With xmlparse
448 }
449 //var_dump($items);exit;
450 }
451
452 $i = 0;
453
454 // Loop on each record
455 if (is_array($items)) {
456 foreach ($items as $item) {
457 //var_dump($item);exit;
458 if ($rss->_format == 'rss') {
459 if (getDolGlobalString('EXTERNALRSS_USE_SIMPLEXML')) {
460 $itemLink = sanitizeVal((string) $item->link);
461 $itemTitle = sanitizeVal((string) $item->title);
462 $itemDescription = sanitizeVal((string) $item->description);
463 $itemPubDate = sanitizeVal((string) $item->pubDate);
464 $itemId = '';
465 $itemAuthor = '';
466 } else {
467 $itemLink = sanitizeVal((string) $item['link']);
468 $itemTitle = sanitizeVal((string) $item['title']);
469 $itemDescription = sanitizeVal((string) $item['description']);
470 $itemPubDate = sanitizeVal((string) $item['pubdate']);
471 $itemId = sanitizeVal((string) $item['guid']);
472 $itemAuthor = sanitizeVal((string) ($item['author'] ?? ''));
473 }
474
475 // Loop on each category
476 $itemCategory = array();
477 if (!empty($item->category) && is_array($item->category)) {
478 foreach ($item->category as $cat) {
479 $itemCategory[] = (string) $cat;
480 }
481 }
482 } elseif ($rss->_format == 'atom') {
483 $itemLink = (isset($item['link']) ? sanitizeVal((string) $item['link']) : '');
484 $itemTitle = sanitizeVal((string) $item['title']);
485 $itemDescription = sanitizeVal($this->getAtomItemDescription($item));
486 $itemPubDate = sanitizeVal((string) $item['created']);
487 $itemId = sanitizeVal((string) $item['id']);
488 $itemAuthor = sanitizeVal((string) ($item['author'] ? $item['author'] : $item['author_name']));
489 $itemCategory = array();
490 } else {
491 $itemLink = '';
492 $itemTitle = '';
493 $itemDescription = '';
494 $itemPubDate = '';
495 $itemId = '';
496 $itemAuthor = '';
497 $itemCategory = array();
498 print 'ErrorBadFeedFormat';
499 }
500
501 // Add record to result array
502 $this->_rssarray[$i] = array(
503 'link' => $itemLink,
504 'title' => $itemTitle,
505 'description' => $itemDescription,
506 'pubDate' => $itemPubDate,
507 'category' => $itemCategory,
508 'id' => $itemId,
509 'author' => $itemAuthor
510 );
511 //var_dump($this->_rssarray);
512
513 $i++;
514
515 if ($i > $maxNb) {
516 break; // We get all records we want
517 }
518 }
519 }
520
521 return 1;
522 } else {
523 $this->error = 'ErrorFailedToLoadRSSFile';
524 return -1;
525 }
526 }
527
528
529
530 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
539 public function feed_start_element($p, $element, $attrs)
540 {
541 // phpcs:enable
542 $el = $element = strtolower($element);
543 $attrs = array_change_key_case($attrs, CASE_LOWER);
544
545 // check for a namespace, and split if found
546 $ns = false;
547 if (strpos($element, ':')) {
548 list($ns, $el) = explode(':', $element, 2);
549 }
550 if ($ns and $ns != 'rdf') {
551 $this->current_namespace = $ns;
552 }
553
554 // if feed type isn't set, then this is first element of feed identify feed from root element
555 if (empty($this->_format)) {
556 if ($el == 'rdf') {
557 $this->_format = 'rss';
558 $this->feed_version = '1.0';
559 } elseif ($el == 'rss') {
560 $this->_format = 'rss';
561 $this->feed_version = $attrs['version'];
562 } elseif ($el == 'feed') {
563 $this->_format = 'atom';
564 $this->feed_version = $attrs['version'];
565 $this->inchannel = true;
566 }
567 return;
568 }
569
570 if ($el == 'channel') {
571 $this->inchannel = true;
572 } elseif ($el == 'item' || $el == 'entry') {
573 $this->initem = true;
574 if (isset($attrs['rdf:about'])) {
575 $this->current_item['about'] = $attrs['rdf:about'];
576 }
577 } elseif ($this->_format == 'rss' && $this->current_namespace == '' && $el == 'textinput') {
578 // if we're in the default namespace of an RSS feed,
579 // record textinput or image fields
580 $this->intextinput = true;
581 } elseif ($this->_format == 'rss' && $this->current_namespace == '' && $el == 'image') {
582 $this->inimage = true;
583 } elseif ($this->_format == 'atom' && in_array($el, $this->_CONTENT_CONSTRUCTS)) {
584 // handle atom content constructs
585 // avoid clashing w/ RSS mod_content
586 if ($el == 'content') {
587 $el = 'atom_content';
588 }
589
590 $this->incontent = $el;
591 } elseif ($this->_format == 'atom' && $this->incontent) {
592 // if inside an Atom content construct (e.g. content or summary) field treat tags as text
593 // if tags are inlined, then flatten
594 $attrs_str = implode(' ', array_map('rss_map_attrs', array_keys($attrs), array_values($attrs)));
595
596 $this->append_content("<$element $attrs_str>");
597
598 array_unshift($this->stack, $el);
599 } elseif ($this->_format == 'atom' && $el == 'link') {
600 // Atom support many links per containing element.
601 // Magpie treats link elements of type rel='alternate'
602 // as being equivalent to RSS's simple link element.
603 if (isset($attrs['rel']) && $attrs['rel'] == 'alternate') {
604 $link_el = 'link';
605 } elseif (!isset($attrs['rel'])) {
606 $link_el = 'link';
607 } else {
608 $link_el = 'link_'.$attrs['rel'];
609 }
610
611 $this->append($link_el, $attrs['href']);
612 } else {
613 // set stack[0] to current element
614 array_unshift($this->stack, $el);
615 }
616 }
617
618
619 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
627 public function feed_cdata($p, $text)
628 {
629 // phpcs:enable
630 if ($this->_format == 'atom' and $this->incontent) {
631 $this->append_content($text);
632 } else {
633 $current_el = implode('_', array_reverse($this->stack));
634 $this->append($current_el, $text);
635 }
636 }
637
638 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
646 public function feed_end_element($p, $el)
647 {
648 // phpcs:enable
649 $el = strtolower($el);
650
651 if ($el == 'item' or $el == 'entry') {
652 $this->items[] = $this->current_item;
653 $this->current_item = array();
654 $this->initem = false;
655 } elseif ($this->_format == 'rss' and $this->current_namespace == '' and $el == 'textinput') {
656 $this->intextinput = false;
657 } elseif ($this->_format == 'rss' and $this->current_namespace == '' and $el == 'image') {
658 $this->inimage = false;
659 } elseif ($this->_format == 'atom' and in_array($el, $this->_CONTENT_CONSTRUCTS)) {
660 $this->incontent = false;
661 } elseif ($el == 'channel' or $el == 'feed') {
662 $this->inchannel = false;
663 } elseif ($this->_format == 'atom' and $this->incontent) {
664 // balance tags properly
665 // note: i don't think this is actually necessary
666 if ($this->stack[0] == $el) {
667 $this->append_content("</$el>");
668 } else {
669 $this->append_content("<$el />");
670 }
671
672 array_shift($this->stack);
673 } else {
674 array_shift($this->stack);
675 }
676
677 $this->current_namespace = false;
678 }
679
680
688 public function concat(&$str1, $str2 = "")
689 {
690 if (!isset($str1)) {
691 $str1 = "";
692 }
693 $str1 .= $str2;
694 return $str1;
695 }
696
697 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
704 public function append_content($text)
705 {
706 // phpcs:enable
707 if (!empty($this->initem)) {
708 $this->concat($this->current_item[$this->incontent], $text);
709 } elseif (!empty($this->inchannel)) {
710 $this->concat($this->channel[$this->incontent], $text);
711 }
712 }
713
721 public function append($el, $text)
722 {
723 if (!$el) {
724 return;
725 }
726 if (!empty($this->current_namespace)) {
727 if (!empty($this->initem)) {
728 $this->concat($this->current_item[$this->current_namespace][$el], $text);
729 } elseif (!empty($this->inchannel)) {
730 $this->concat($this->channel[$this->current_namespace][$el], $text);
731 } elseif (!empty($this->intextinput)) {
732 $this->concat($this->textinput[$this->current_namespace][$el], $text);
733 } elseif (!empty($this->inimage)) {
734 $this->concat($this->image[$this->current_namespace][$el], $text);
735 }
736 } else {
737 if (!empty($this->initem)) {
738 $this->concat($this->current_item[$el], $text);
739 } elseif (!empty($this->intextinput)) {
740 $this->concat($this->textinput[$el], $text);
741 } elseif (!empty($this->inimage)) {
742 $this->concat($this->image[$el], $text);
743 } elseif (!empty($this->inchannel)) {
744 $this->concat($this->channel[$el], $text);
745 }
746 }
747 }
748
756 private function getAtomItemDescription(array $item, $maxlength = 500)
757 {
758 $result = "";
759
760 if (isset($item['summary'])) {
761 $result = $item['summary'];
762 } elseif (isset($item['atom_content'])) {
763 $result = $item['atom_content'];
764 }
765
766 // remove all HTML elements that can possible break the maximum size of a tooltip,
767 // like headings, image, video etc. and allow only simple style elements
768 $result = strip_tags($result, "<br><p><ul><ol><li>");
769
770 $result = str_replace("\n", "", $result);
771
772 if (strlen($result) > $maxlength) {
773 $result = substr($result, 0, $maxlength);
774 $result .= "...";
775 }
776
777 return $result;
778 }
779
786 private function getAtomImageUrl(array $feed)
787 {
788 if (isset($feed['icon'])) {
789 return $feed['logo'];
790 }
791
792 if (isset($feed['icon'])) {
793 return $feed['logo'];
794 }
795
796 if (isset($feed['webfeeds:logo'])) {
797 return $feed['webfeeds:logo'];
798 }
799
800 if (isset($feed['webfeeds:icon'])) {
801 return $feed['webfeeds:icon'];
802 }
803
804 if (isset($feed['webfeeds:wordmark'])) {
805 return $feed['webfeeds:wordmark'];
806 }
807
808 return "";
809 }
810}
811
812/*
813 * A method for the xml_set_external_entity_ref_handler()
814 *
815 * @param XMLParser $parser
816 * @param string $ent
817 * @param string|false $base
818 * @param string $sysID
819 * @param string|false $pubID
820 * @return bool
821function extEntHandler($parser, $ent, $base, $sysID, $pubID) {
822 print 'extEntHandler ran';
823 return true;
824}
825*/
826
834function rss_map_attrs($k, $v)
835{
836 return "$k=\"$v\"";
837}
838
845function xml2php($xml)
846{
847 $threads = 0;
848 $tab = false;
849 $array = array();
850 foreach ($xml->children() as $key => $value) {
851 $child = xml2php($value);
852
853 //To deal with the attributes
854 foreach ($value->attributes() as $ak => $av) {
855 $child[$ak] = (string) $av;
856 }
857
858 //Let see if the new child is not in the array
859 if ($tab === false && in_array($key, array_keys($array))) {
860 //If this element is already in the array we will create an indexed array
861 $tmp = $array[$key];
862 $array[$key] = null;
863 $array[$key][] = $tmp;
864 $array[$key][] = $child;
865 $tab = true;
866 } elseif ($tab === true) {
867 //Add an element in an existing array
868 $array[$key][] = $child;
869 } else {
870 //Add a simple element
871 $array[$key] = $child;
872 }
873
874 $threads++;
875 }
876
877
878 if ($threads == 0) {
879 return (string) $xml;
880 }
881
882 return $array;
883}
Class to parse RSS files.
feed_start_element($p, $element, $attrs)
Triggered when opened tag is found.
getAtomItemDescription(array $item, $maxlength=500)
Return a description/summary for one item from a ATOM feed.
concat(&$str1, $str2="")
To concat 2 strings with no warning if an operand is not defined.
getImageUrl()
getImageUrl
feed_end_element($p, $el)
Triggered when closed tag is found.
__construct($db)
Constructor.
getLanguage()
getLanguage
getTitle()
getTitle
getLastBuildDate()
getLastBuildDate
getItems()
getItems
getLink()
getLink
getGenerator()
getGenerator
getCopyright()
getCopyright
feed_cdata($p, $text)
Triggered when CDATA is found.
getLastFetchDate()
getLastFetchDate
getUrlRss()
getUrlRss
parser($urlRSS, $maxNb=0, $cachedelay=60, $cachedir='')
Parse rss URL.
append_content($text)
Enter description here ...
append($el, $text)
smart append - field and namespace aware
getDescription()
getDescription
getFormat()
getFormat
getAtomImageUrl(array $feed)
Return a URL to a image of the given ATOM feed.
dol_is_url($uri)
Return if path is an URI (the name of the method is misleading).
dol_filemtime($pathoffile)
Return time of a file.
dol_is_dir($folder)
Test if filename is a directory.
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
getURLContent($url, $postorget='GET', $param='', $followlocation=1, $addheaders=array(), $allowedschemes=array('http', 'https'), $localurl=0, $ssl_verifypeer=-1)
Function to get a content from an URL (use proxy if proxy defined).
xml2php($xml)
Function to convert an XML object into an array.
rss_map_attrs($k, $v)
Function to convert an XML object into an array.
dol_hash($chain, $type='0', $nosalt=0)
Returns a hash (non reversible encryption) of a string.