dolibarr 24.0.0-beta
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-2026 MDW <mdeweerd@users.noreply.github.com>
4 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
26// @phan-file-suppress PhanPluginPHPDocInWrongComment
27
32{
36 public $db;
37
41 public $error = '';
42
46 public $feed_version;
47
51 private $_format = '';
55 private $_urlRSS;
59 private $_language;
63 private $_generator;
67 private $_copyright;
71 private $_lastbuilddate;
75 private $_imageurl;
79 private $_link;
83 private $_title;
87 private $_description;
91 private $_lastfetchdate; // Last successful fetch
95 private $_rssarray = array();
96
100 private $current_namespace;
101
105 public $items = array();
109 public $current_item = array();
113 public $channel = array();
117 public $textinput = array();
121 public $image = array();
122
126 private $initem;
130 private $intextinput;
134 private $incontent;
138 private $inimage;
142 private $inchannel;
143
147 public $stack = array(); // parser stack
151 private $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright');
152
153
159 public function __construct($db)
160 {
161 $this->db = $db;
162 }
163
169 public function getFormat()
170 {
171 return $this->_format;
172 }
173
179 public function getUrlRss()
180 {
181 return $this->_urlRSS;
182 }
188 public function getLanguage()
189 {
190 return $this->_language;
191 }
197 public function getGenerator()
198 {
199 return $this->_generator;
200 }
206 public function getCopyright()
207 {
208 return $this->_copyright;
209 }
215 public function getLastBuildDate()
216 {
217 return $this->_lastbuilddate;
218 }
224 public function getImageUrl()
225 {
226 return $this->_imageurl;
227 }
233 public function getLink()
234 {
235 return $this->_link;
236 }
242 public function getTitle()
243 {
244 return $this->_title;
245 }
251 public function getDescription()
252 {
253 return $this->_description;
254 }
260 public function getLastFetchDate()
261 {
262 return $this->_lastfetchdate;
263 }
269 public function getItems()
270 {
271 return $this->_rssarray;
272 }
273
283 public function parser($urlRSS, $maxNb = 0, $cachedelay = 60, $cachedir = '')
284 {
285 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
286 include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
287
288 $rss = '';
289 $str = ''; // This will contain content of feed
290
291 // Check parameters
292 if (!dol_is_url($urlRSS)) {
293 $this->error = "ErrorBadUrl";
294 return -1;
295 }
296
297 $this->_urlRSS = $urlRSS;
298 $newpathofdestfile = $cachedir.'/'.dol_hash($this->_urlRSS, '3'); // Force md5 hash (does not contain special chars)
299 $newmask = '0644';
300
301 //dol_syslog("RssParser::parser parse url=".$urlRSS." => cache file=".$newpathofdestfile);
302 $nowgmt = dol_now();
303
304 // Search into cache
305 $foundintocache = 0;
306 if ($cachedelay > 0 && $cachedir) {
307 $filedate = dol_filemtime($newpathofdestfile);
308 if ($filedate >= ($nowgmt - $cachedelay)) {
309 //dol_syslog("RssParser::parser cache file ".$newpathofdestfile." is not older than now - cachedelay (".$nowgmt." - ".$cachedelay.") so we use it.");
310 $foundintocache = 1;
311
312 $this->_lastfetchdate = $filedate;
313 } else {
314 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.");
315 }
316 }
317
318 // Load file into $str
319 if ($foundintocache) { // Cache file found and is not too old
320 $str = file_get_contents($newpathofdestfile);
321 } else {
322 try {
323 $result = getURLContent($this->_urlRSS, 'GET', '', 1, array(), array('http', 'https'), 0);
324
325 if (!empty($result['content'])) {
326 $str = $result['content'];
327 } elseif (!empty($result['curl_error_msg'])) {
328 $this->error = 'Error retrieving URL '.$this->_urlRSS.' - '.$result['curl_error_msg'];
329 return -1;
330 }
331 } catch (Exception $e) {
332 $this->error = 'Error retrieving URL '.$this->_urlRSS.' - '.$e->getMessage();
333 return -2;
334 }
335 }
336
337 if ($str !== false) {
338 // Convert $str into xml
339 if (getDolGlobalString('EXTERNALRSS_USE_SIMPLEXML')) {
340 //print 'xx'.LIBXML_NOCDATA;
341 libxml_use_internal_errors(false);
342 if (LIBXML_VERSION < 20900) {
343 // Avoid load of external entities (security problem).
344 // Required only if LIBXML_VERSION < 20900
345 // @phan-suppress-next-line PhanDeprecatedFunctionInternal
346 libxml_disable_entity_loader(true);
347 }
348
349 $rss = simplexml_load_string($str, "SimpleXMLElement", LIBXML_NOCDATA);
350 } else {
351 if (!function_exists('xml_parser_create')) {
352 $this->error = 'Function xml_parser_create are not supported by your PHP';
353 return -1;
354 }
355
356 try {
357 // @phan-suppress-next-line PhanTypeMismatchArgumentInternalProbablyReal
358 $xmlparser = xml_parser_create(null);
359
360 xml_parser_set_option($xmlparser, XML_OPTION_CASE_FOLDING, 0);
361 xml_parser_set_option($xmlparser, XML_OPTION_SKIP_WHITE, 1);
362 xml_parser_set_option($xmlparser, XML_OPTION_TARGET_ENCODING, "UTF-8");
363 //xml_set_external_entity_ref_handler($xmlparser, 'extEntHandler'); // Seems to have no effect even when function extEntHandler exists.
364
365 if (!is_resource($xmlparser) && !is_object($xmlparser)) {
366 $this->error = "ErrorFailedToCreateParser";
367 return -1;
368 }
369
370 // @phan-suppress-next-line PhanDeprecatedFunctionInternal
371 xml_set_object($xmlparser, $this);
372 // @phan-suppress-next-line PhanUndeclaredFunctionInCallable
373 xml_set_element_handler($xmlparser, 'feed_start_element', 'feed_end_element'); // @phpstan-ignore-line
374 // @phan-suppress-next-line PhanUndeclaredFunctionInCallable
375 xml_set_character_data_handler($xmlparser, 'feed_cdata'); // @phpstan-ignore-line
376
377 $status = xml_parse($xmlparser, $str, false);
378
379 xml_parser_free($xmlparser);
380
381 $rss = $this;
382 //var_dump($status.' '.$rss->_format);exit;
383 } catch (Exception $e) {
384 $rss = null;
385 }
386 }
387 }
388
389 // If $rss loaded
390 if ($rss) {
391 // Save file into cache
392 if (empty($foundintocache) && $cachedir) {
393 dol_syslog(get_class($this)."::parser cache file ".$newpathofdestfile." is saved onto disk.");
394 if (!dol_is_dir($cachedir)) {
395 dol_mkdir($cachedir);
396 }
397 $fp = fopen($newpathofdestfile, 'w');
398 if ($fp) {
399 fwrite($fp, $str);
400 fclose($fp);
401 dolChmod($newpathofdestfile);
402
403 $this->_lastfetchdate = $nowgmt;
404 } else {
405 print 'Error, failed to open file '.$newpathofdestfile.' for write';
406 }
407 }
408
409 unset($str); // Free memory
410
411 if (empty($rss->_format)) { // If format not detected automatically
412 $rss->_format = 'rss';
413 if (empty($rss->channel)) {
414 $rss->_format = 'atom';
415 }
416 }
417
418 $items = array();
419
420 // Save description entries
421 if ($rss->_format == 'rss') {
422 //var_dump($rss);
423 if (getDolGlobalString('EXTERNALRSS_USE_SIMPLEXML')) {
424 if (!empty($rss->channel->language)) {
425 $this->_language = sanitizeVal((string) $rss->channel->language);
426 }
427 if (!empty($rss->channel->generator)) {
428 $this->_generator = sanitizeVal((string) $rss->channel->generator);
429 }
430 if (!empty($rss->channel->copyright)) {
431 $this->_copyright = sanitizeVal((string) $rss->channel->copyright);
432 }
433 if (!empty($rss->channel->lastbuilddate)) {
434 $this->_lastbuilddate = sanitizeVal((string) $rss->channel->lastbuilddate);
435 }
436 if (!empty($rss->channel->image->url[0])) {
437 $this->_imageurl = sanitizeVal((string) $rss->channel->image->url[0]);
438 }
439 if (!empty($rss->channel->link)) {
440 $this->_link = sanitizeVal((string) $rss->channel->link);
441 }
442 if (!empty($rss->channel->title)) {
443 $this->_title = sanitizeVal((string) $rss->channel->title);
444 }
445 if (!empty($rss->channel->description)) {
446 $this->_description = sanitizeVal((string) $rss->channel->description);
447 }
448 } else {
449 //var_dump($rss->channel);
450 if (!empty($rss->channel['language'])) {
451 $this->_language = sanitizeVal((string) $rss->channel['language']);
452 }
453 if (!empty($rss->channel['generator'])) {
454 $this->_generator = sanitizeVal((string) $rss->channel['generator']);
455 }
456 if (!empty($rss->channel['copyright'])) {
457 $this->_copyright = sanitizeVal((string) $rss->channel['copyright']);
458 }
459 if (!empty($rss->channel['lastbuilddate'])) {
460 $this->_lastbuilddate = sanitizeVal((string) $rss->channel['lastbuilddate']);
461 }
462 if (!empty($rss->image['url'])) {
463 $this->_imageurl = sanitizeVal((string) $rss->image['url']);
464 }
465 if (!empty($rss->channel['link'])) {
466 $this->_link = sanitizeVal((string) $rss->channel['link']);
467 }
468 if (!empty($rss->channel['title'])) {
469 $this->_title = sanitizeVal((string) $rss->channel['title']);
470 }
471 if (!empty($rss->channel['description'])) {
472 $this->_description = sanitizeVal((string) $rss->channel['description']);
473 }
474 }
475
476 if (getDolGlobalString('EXTERNALRSS_USE_SIMPLEXML')) {
477 $items = $rss->channel->item; // With simplexml
478 } else {
479 $items = $rss->items; // With xmlparse
480 }
481 //var_dump($items);exit;
482 } elseif ($rss->_format == 'atom') {
483 //var_dump($rss);
484 if (getDolGlobalString('EXTERNALRSS_USE_SIMPLEXML')) {
485 if (!empty($rss->generator)) {
486 $this->_generator = sanitizeVal((string) $rss->generator);
487 }
488 if (!empty($rss->lastbuilddate)) {
489 $this->_lastbuilddate = sanitizeVal((string) $rss->modified);
490 }
491 if (!empty($rss->link->href)) {
492 $this->_link = sanitizeVal((string) $rss->link->href);
493 }
494 if (!empty($rss->title)) {
495 $this->_title = sanitizeVal((string) $rss->title);
496 }
497 if (!empty($rss->description)) {
498 $this->_description = sanitizeVal((string) $rss->description);
499 }
500 } else {
501 //if (!empty($rss->channel['rss_language'])) $this->_language = (string) $rss->channel['rss_language'];
502 if (!empty($rss->channel['generator'])) {
503 $this->_generator = sanitizeVal((string) $rss->channel['generator']);
504 }
505 //if (!empty($rss->channel['rss_copyright'])) $this->_copyright = (string) $rss->channel['rss_copyright'];
506 if (!empty($rss->channel['modified'])) {
507 $this->_lastbuilddate = sanitizeVal((string) $rss->channel['modified']);
508 }
509 //if (!empty($rss->image['rss_url'])) $this->_imageurl = (string) $rss->image['rss_url'];
510 if (!empty($rss->channel['link'])) {
511 $this->_link = sanitizeVal((string) $rss->channel['link']);
512 }
513 if (!empty($rss->channel['title'])) {
514 $this->_title = sanitizeVal((string) $rss->channel['title']);
515 }
516 //if (!empty($rss->channel['rss_description'])) $this->_description = (string) $rss->channel['rss_description'];
517
518 if (!empty($rss->channel)) {
519 $this->_imageurl = sanitizeVal($this->getAtomImageUrl($rss->channel));
520 }
521 }
522 if (getDolGlobalString('EXTERNALRSS_USE_SIMPLEXML')) {
523 $tmprss = xml2php($rss);
524 $items = $tmprss['entry'];
525 } else {
526 // With simplexml
527 $items = $rss->items; // With xmlparse
528 }
529 //var_dump($items);exit;
530 }
531
532 $i = 0;
533
534 // Loop on each record
535 if (is_array($items)) {
536 foreach ($items as $item) {
537 //var_dump($item);exit;
538 if ($rss->_format == 'rss') {
539 if (getDolGlobalString('EXTERNALRSS_USE_SIMPLEXML')) {
540 $itemLink = sanitizeVal((string) $item->link);
541 $itemTitle = sanitizeVal((string) $item->title);
542 $itemDescription = sanitizeVal((string) $item->description);
543 $itemPubDate = sanitizeVal((string) $item->pubDate);
544 $itemId = '';
545 $itemAuthor = '';
546 } else {
547 $itemLink = sanitizeVal((string) $item['link']);
548 $itemTitle = sanitizeVal((string) $item['title']);
549 $itemDescription = sanitizeVal((string) $item['description']);
550 $itemPubDate = sanitizeVal((string) $item['pubdate']);
551 $itemId = sanitizeVal((string) $item['guid']);
552 $itemAuthor = sanitizeVal((string) ($item['author'] ?? ''));
553 }
554
555 // Loop on each category
556 $itemCategory = array();
557 if (!empty($item->category) && is_array($item->category)) {
558 foreach ($item->category as $cat) {
559 $itemCategory[] = (string) $cat;
560 }
561 }
562 } elseif ($rss->_format == 'atom') {
563 $itemLink = (isset($item['link']) ? sanitizeVal((string) $item['link']) : '');
564 $itemTitle = sanitizeVal((string) $item['title']);
565 $itemDescription = sanitizeVal($this->getAtomItemDescription($item));
566 $itemPubDate = sanitizeVal((string) $item['created']);
567 $itemId = sanitizeVal((string) $item['id']);
568 $itemAuthor = sanitizeVal((string) ($item['author'] ? $item['author'] : $item['author_name']));
569 $itemCategory = array();
570 } else {
571 $itemLink = '';
572 $itemTitle = '';
573 $itemDescription = '';
574 $itemPubDate = '';
575 $itemId = '';
576 $itemAuthor = '';
577 $itemCategory = array();
578 print 'ErrorBadFeedFormat';
579 }
580
581 // Add record to result array
582 $this->_rssarray[$i] = array(
583 'link' => $itemLink,
584 'title' => $itemTitle,
585 'description' => $itemDescription,
586 'pubDate' => $itemPubDate,
587 'category' => $itemCategory,
588 'id' => $itemId,
589 'author' => $itemAuthor
590 );
591 //var_dump($this->_rssarray);
592
593 $i++;
594
595 if ($i > $maxNb) {
596 break; // We get all records we want
597 }
598 }
599 }
600
601 return 1;
602 } else {
603 $this->error = 'ErrorFailedToLoadRSSFile';
604 return -1;
605 }
606 }
607
608
609
610 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
619 public function feed_start_element($p, $element, $attrs)
620 {
621 // phpcs:enable
622 $el = $element = strtolower($element);
623 $attrs = array_change_key_case($attrs, CASE_LOWER);
624
625 // check for a namespace, and split if found
626 $ns = false;
627 if (strpos($element, ':')) {
628 list($ns, $el) = explode(':', $element, 2);
629 }
630 if ($ns and $ns != 'rdf') {
631 $this->current_namespace = $ns;
632 }
633
634 // if feed type isn't set, then this is first element of feed identify feed from root element
635 if (empty($this->_format)) {
636 if ($el == 'rdf') {
637 $this->_format = 'rss';
638 $this->feed_version = '1.0';
639 } elseif ($el == 'rss') {
640 $this->_format = 'rss';
641 $this->feed_version = $attrs['version'];
642 } elseif ($el == 'feed') {
643 $this->_format = 'atom';
644 $this->feed_version = $attrs['version'];
645 $this->inchannel = true;
646 }
647 return;
648 }
649
650 if ($el == 'channel') {
651 $this->inchannel = true;
652 } elseif ($el == 'item' || $el == 'entry') {
653 $this->initem = true;
654 if (isset($attrs['rdf:about'])) {
655 $this->current_item['about'] = $attrs['rdf:about'];
656 }
657 } elseif ($this->_format == 'rss' && $this->current_namespace == '' && $el == 'textinput') {
658 // if we're in the default namespace of an RSS feed,
659 // record textinput or image fields
660 $this->intextinput = true;
661 } elseif ($this->_format == 'rss' && $this->current_namespace == '' && $el == 'image') {
662 $this->inimage = true;
663 } elseif ($this->_format == 'atom' && in_array($el, $this->_CONTENT_CONSTRUCTS)) {
664 // handle atom content constructs
665 // avoid clashing w/ RSS mod_content
666 if ($el == 'content') {
667 $el = 'atom_content';
668 }
669
670 $this->incontent = $el;
671 } elseif ($this->_format == 'atom' && $this->incontent) {
672 // if inside an Atom content construct (e.g. content or summary) field treat tags as text
673 // if tags are inlined, then flatten
674 $attrs_str = implode(' ', array_map('rss_map_attrs', array_keys($attrs), array_values($attrs)));
675
676 $this->append_content("<$element $attrs_str>");
677
678 array_unshift($this->stack, $el);
679 } elseif ($this->_format == 'atom' && $el == 'link') {
680 // Atom support many links per containing element.
681 // Magpie treats link elements of type rel='alternate'
682 // as being equivalent to RSS's simple link element.
683 if (isset($attrs['rel']) && $attrs['rel'] == 'alternate') {
684 $link_el = 'link';
685 } elseif (!isset($attrs['rel'])) {
686 $link_el = 'link';
687 } else {
688 $link_el = 'link_'.$attrs['rel'];
689 }
690
691 $this->append($link_el, $attrs['href']);
692 } else {
693 // set stack[0] to current element
694 array_unshift($this->stack, $el);
695 }
696 }
697
698
699 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
707 public function feed_cdata($p, $text)
708 {
709 // phpcs:enable
710 if ($this->_format == 'atom' and $this->incontent) {
711 $this->append_content($text);
712 } else {
713 $current_el = implode('_', array_reverse($this->stack));
714 $this->append($current_el, $text);
715 }
716 }
717
718 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
726 public function feed_end_element($p, $el)
727 {
728 // phpcs:enable
729 $el = strtolower($el);
730
731 if ($el == 'item' or $el == 'entry') {
732 $this->items[] = $this->current_item;
733 $this->current_item = array();
734 $this->initem = false;
735 } elseif ($this->_format == 'rss' and $this->current_namespace == '' and $el == 'textinput') {
736 $this->intextinput = false;
737 } elseif ($this->_format == 'rss' and $this->current_namespace == '' and $el == 'image') {
738 $this->inimage = false;
739 } elseif ($this->_format == 'atom' and in_array($el, $this->_CONTENT_CONSTRUCTS)) {
740 $this->incontent = false;
741 } elseif ($el == 'channel' or $el == 'feed') {
742 $this->inchannel = false;
743 } elseif ($this->_format == 'atom' and $this->incontent) {
744 // balance tags properly
745 // note: i don't think this is actually necessary
746 if ($this->stack[0] == $el) {
747 $this->append_content("</$el>");
748 } else {
749 $this->append_content("<$el />");
750 }
751
752 array_shift($this->stack);
753 } else {
754 array_shift($this->stack);
755 }
756
757 $this->current_namespace = false;
758 }
759
760
768 public function concat(&$str1, $str2 = "")
769 {
770 if (!isset($str1)) {
771 $str1 = "";
772 }
773 $str1 .= $str2;
774 return $str1;
775 }
776
777 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
784 public function append_content($text)
785 {
786 // phpcs:enable
787 if (!empty($this->initem)) {
788 $this->concat($this->current_item[$this->incontent], $text);
789 } elseif (!empty($this->inchannel)) {
790 $this->concat($this->channel[$this->incontent], $text);
791 }
792 }
793
801 public function append($el, $text)
802 {
803 if (!$el) {
804 return;
805 }
806 if (!empty($this->current_namespace)) {
807 if (!empty($this->initem)) {
808 $this->concat($this->current_item[$this->current_namespace][$el], $text);
809 } elseif (!empty($this->inchannel)) {
810 $this->concat($this->channel[$this->current_namespace][$el], $text);
811 } elseif (!empty($this->intextinput)) {
812 $this->concat($this->textinput[$this->current_namespace][$el], $text);
813 } elseif (!empty($this->inimage)) {
814 $this->concat($this->image[$this->current_namespace][$el], $text);
815 }
816 } else {
817 if (!empty($this->initem)) {
818 // @phpstan-ignore-next-line argument.type
819 $this->concat($this->current_item[$el], $text); // @phan-suppress-current-line PhanTypeMismatchArgument
820 } elseif (!empty($this->intextinput)) {
821 // @phpstan-ignore-next-line argument.type
822 $this->concat($this->textinput[$el], $text); // @phan-suppress-current-line PhanTypeMismatchArgument
823 } elseif (!empty($this->inimage)) {
824 // @phpstan-ignore-next-line argument.type
825 $this->concat($this->image[$el], $text); // @phan-suppress-current-line PhanTypeMismatchArgument
826 } elseif (!empty($this->inchannel)) {
827 $this->concat($this->channel[$el], $text);
828 }
829 }
830 }
831
839 private function getAtomItemDescription(array $item, $maxlength = 500)
840 {
841 $result = "";
842
843 if (isset($item['summary'])) {
844 $result = $item['summary'];
845 } elseif (isset($item['atom_content'])) {
846 $result = $item['atom_content'];
847 }
848
849 // remove all HTML elements that can possible break the maximum size of a tooltip,
850 // like headings, image, video etc. and allow only simple style elements
851 $result = strip_tags($result, "<br><p><ul><ol><li>");
852
853 $result = str_replace("\n", "", $result);
854
855 if (strlen($result) > $maxlength) {
856 $result = substr($result, 0, $maxlength);
857 $result .= "...";
858 }
859
860 return $result;
861 }
862
869 private function getAtomImageUrl(array $feed)
870 {
871 if (isset($feed['icon'])) {
872 return $feed['logo'];
873 }
874
875 if (isset($feed['icon'])) {
876 return $feed['logo'];
877 }
878
879 if (isset($feed['webfeeds:logo'])) {
880 return $feed['webfeeds:logo'];
881 }
882
883 if (isset($feed['webfeeds:icon'])) {
884 return $feed['webfeeds:icon'];
885 }
886
887 if (isset($feed['webfeeds:wordmark'])) {
888 return $feed['webfeeds:wordmark'];
889 }
890
891 return "";
892 }
893}
894
902function rss_map_attrs($k, $v)
903{
904 return "$k=\"$v\"";
905}
906
913function xml2php($xml)
914{
915 $threads = 0;
916 $tab = false;
917 $array = array();
918 foreach ($xml->children() as $key => $value) {
919 '@phan-var-force SimpleXMLElement $value';
920 $child = xml2php($value);
921
922 //To deal with the attributes
923 foreach ($value->attributes() as $ak => $av) {
924 $child[$ak] = (string) $av;
925 }
926
927 //Let see if the new child is not in the array
928 if ($tab === false && array_key_exists($key, $array)) {
929 //If this element is already in the array we will create an indexed array
930 $tmp = $array[$key];
931 $array[$key] = null;
932 $array[$key][] = $tmp;
933 $array[$key][] = $child;
934 $tab = true;
935 } elseif ($tab === true) {
936 //Add an element in an existing array
937 $array[$key][] = $child;
938 } else {
939 //Add a simple element
940 $array[$key] = $child;
941 }
942
943 $threads++;
944 }
945
946
947 if ($threads == 0) {
948 return (string) $xml;
949 }
950
951 return $array;
952}
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.
dol_now($mode='gmt')
Return date for now.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalString($key, $default='')
Return a 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, $timeoutconnect=0, $timeoutresponse=0, $otherCurlOptions=array(), $morelogsuffix='')
Function to get a content from an URL (use proxy if proxy defined).
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
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, $mode=0)
Returns a hash (non reversible encryption) of a string.