[SECURITY] XML entity expansion
[Packages/TYPO3.CMS.git] / typo3 / sysext / extensionmanager / Classes / Utility / Parser / MirrorXmlPushParser.php
1 <?php
2 namespace TYPO3\CMS\Extensionmanager\Utility\Parser;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * Parser for TYPO3's mirrors.xml file.
19 *
20 * Depends on PHP ext/xml which should be available
21 * with PHP 4+. This is the parser used in TYPO3
22 * Core <= 4.3 (without the "collect all data in one
23 * array" behaviour).
24 * Notice: ext/xml has proven to be buggy with entities.
25 * Use at least PHP 5.2.9+ and libxml2 2.7.3+!
26 * @since 2010-11-17
27 */
28 class MirrorXmlPushParser extends AbstractMirrorXmlParser
29 {
30 /**
31 * @var string
32 */
33 protected $element;
34
35 /**
36 * Class constructor.
37 */
38 public function __construct()
39 {
40 $this->requiredPhpExtensions = 'xml';
41 }
42
43 /**
44 * Create required parser
45 *
46 * @return void
47 */
48 protected function createParser()
49 {
50 $this->objXml = xml_parser_create();
51 xml_set_object($this->objXml, $this);
52 }
53
54 /**
55 * Method parses a mirror.xml file.
56 *
57 * @param string $file GZIP stream resource
58 * @return void
59 * @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException in case of XML parser errors
60 */
61 public function parseXml($file)
62 {
63 $this->createParser();
64 if (!is_resource($this->objXml)) {
65 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException('Unable to create XML parser.', 1342641009);
66 }
67 // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
68 $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
69 // keep original character case of XML document
70 xml_parser_set_option($this->objXml, XML_OPTION_CASE_FOLDING, false);
71 xml_parser_set_option($this->objXml, XML_OPTION_SKIP_WHITE, false);
72 xml_parser_set_option($this->objXml, XML_OPTION_TARGET_ENCODING, 'utf-8');
73 xml_set_element_handler($this->objXml, 'startElement', 'endElement');
74 xml_set_character_data_handler($this->objXml, 'characterData');
75 if (!($fp = fopen($file, 'r'))) {
76 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(sprintf('Unable to open file resource %s.', $file), 1342641010);
77 }
78 while ($data = fread($fp, 4096)) {
79 if (!xml_parse($this->objXml, $data, feof($fp))) {
80 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(sprintf('XML error %s in line %u of file resource %s.', xml_error_string(xml_get_error_code($this->objXml)), xml_get_current_line_number($this->objXml), $file), 1342641011);
81 }
82 }
83 libxml_disable_entity_loader($previousValueOfEntityLoader);
84 xml_parser_free($this->objXml);
85 }
86
87 /**
88 * Method is invoked when parser accesses start tag of an element.
89 *
90 * @param resource $parser parser resource
91 * @param string $elementName element name at parser's current position
92 * @param array $attrs array of an element's attributes if available
93 * @return void
94 */
95 protected function startElement($parser, $elementName, $attrs)
96 {
97 switch ($elementName) {
98 default:
99 $this->element = $elementName;
100 }
101 }
102
103 /**
104 * Method is invoked when parser accesses end tag of an element.
105 * Although the first parameter seems unused, it needs to be there for
106 * adherence to the API of xml_set_element_handler
107 *
108 * @see xml_set_element_handler
109 * @param resource $parser parser resource
110 * @param string $elementName element name at parser's current position
111 * @return void
112 */
113 protected function endElement($parser, $elementName)
114 {
115 switch ($elementName) {
116 case 'mirror':
117 $this->notify();
118 $this->resetProperties();
119 break;
120 default:
121 $this->element = null;
122 }
123 }
124
125 /**
126 * Method is invoked when parser accesses any character other than elements.
127 * Although the first parameter seems unused, it needs to be there for
128 * adherence to the API of xml_set_character_data_handler
129 *
130 * @see xml_set_character_data_handler
131 * @param resource $parser parser resource
132 * @param string $data an element's value
133 * @return void
134 */
135 protected function characterData($parser, $data)
136 {
137 if (isset($this->element)) {
138 switch ($this->element) {
139 case 'title':
140 $this->title = $data;
141 break;
142 case 'host':
143 $this->host = $data;
144 break;
145 case 'path':
146 $this->path = $data;
147 break;
148 case 'country':
149 $this->country = $data;
150 break;
151 case 'name':
152 $this->sponsorname = $data;
153 break;
154 case 'link':
155 $this->sponsorlink = $data;
156 break;
157 case 'logo':
158 $this->sponsorlogo = $data;
159 break;
160 default:
161 // Do nothing
162 }
163 }
164 }
165 }