[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 * Parser for TYPO3's mirrors.xml file.
18 *
19 * Depends on PHP ext/xml which should be available
20 * with PHP 4+. This is the parser used in TYPO3
21 * Core <= 4.3 (without the "collect all data in one
22 * array" behaviour).
23 * Notice: ext/xml has proven to be buggy with entities.
24 * Use at least PHP 5.2.9+ and libxml2 2.7.3+!
25 *
26 * @author Marcus Krause <marcus#exp2010@t3sec.info>
27 * @author Steffen Kamper <info@sk-typo3.de>
28 * @since 2010-11-17
29 */
30 class MirrorXmlPushParser extends AbstractMirrorXmlParser {
31
32 /**
33 * @var string
34 */
35 protected $element;
36
37 /**
38 * Class constructor.
39 */
40 public function __construct() {
41 $this->requiredPhpExtensions = 'xml';
42 }
43
44 /**
45 * Create required parser
46 *
47 * @return void
48 */
49 protected function createParser() {
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 $this->createParser();
63 if (!is_resource($this->objXml)) {
64 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException('Unable to create XML parser.', 1342641009);
65 }
66 // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
67 $previousValueOfEntityLoader = libxml_disable_entity_loader(TRUE);
68 // keep original character case of XML document
69 xml_parser_set_option($this->objXml, XML_OPTION_CASE_FOLDING, FALSE);
70 xml_parser_set_option($this->objXml, XML_OPTION_SKIP_WHITE, FALSE);
71 xml_parser_set_option($this->objXml, XML_OPTION_TARGET_ENCODING, 'utf-8');
72 xml_set_element_handler($this->objXml, 'startElement', 'endElement');
73 xml_set_character_data_handler($this->objXml, 'characterData');
74 if (!($fp = fopen($file, 'r'))) {
75 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(sprintf('Unable to open file resource %s.', htmlspecialchars($file)), 1342641010);
76 }
77 while ($data = fread($fp, 4096)) {
78 if (!xml_parse($this->objXml, $data, feof($fp))) {
79 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), htmlspecialchars($file)), 1342641011);
80 }
81 }
82 libxml_disable_entity_loader($previousValueOfEntityLoader);
83 xml_parser_free($this->objXml);
84 }
85
86 /**
87 * Method is invoked when parser accesses start tag of an element.
88 *
89 * @param resource $parser parser resource
90 * @param string $elementName element name at parser's current position
91 * @param array $attrs array of an element's attributes if available
92 * @return void
93 */
94 protected function startElement($parser, $elementName, $attrs) {
95 switch ($elementName) {
96 default:
97 $this->element = $elementName;
98 }
99 }
100
101 /**
102 * Method is invoked when parser accesses end tag of an element.
103 * Although the first parameter seems unused, it needs to be there for
104 * adherence to the API of xml_set_element_handler
105 *
106 * @see xml_set_element_handler
107 * @param resource $parser parser resource
108 * @param string $elementName element name at parser's current position
109 * @return void
110 */
111 protected function endElement($parser, $elementName) {
112 switch ($elementName) {
113 case 'mirror':
114 $this->notify();
115 $this->resetProperties();
116 break;
117 default:
118 $this->element = NULL;
119 }
120 }
121
122 /**
123 * Method is invoked when parser accesses any character other than elements.
124 * Although the first parameter seems unused, it needs to be there for
125 * adherence to the API of xml_set_character_data_handler
126 *
127 * @see xml_set_character_data_handler
128 * @param resource $parser parser resource
129 * @param string $data an element's value
130 * @return void
131 */
132 protected function characterData($parser, $data) {
133 if (isset($this->element)) {
134 switch ($this->element) {
135 case 'title':
136 $this->title = $data;
137 break;
138 case 'host':
139 $this->host = $data;
140 break;
141 case 'path':
142 $this->path = $data;
143 break;
144 case 'country':
145 $this->country = $data;
146 break;
147 case 'name':
148 $this->sponsorname = $data;
149 break;
150 case 'link':
151 $this->sponsorlink = $data;
152 break;
153 case 'logo':
154 $this->sponsorlogo = $data;
155 break;
156 default:
157 // Do nothing
158 }
159 }
160 }
161 }