[BUGFIX] Remote extensions aren't displayed
[Packages/TYPO3.CMS.git] / typo3 / sysext / extensionmanager / Classes / Utility / Parser / ExtensionXmlPushParser.php
1 <?php
2 namespace TYPO3\CMS\Extensionmanager\Utility\Parser;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010 Marcus Krause <marcus#exp2010@t3sec.info>
8 * Steffen Kamper <info@sk-typo3.de>
9 * All rights reserved
10 *
11 * This script is part of the TYPO3 project. The TYPO3 project is
12 * free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Module: Extension manager - Extension.xml push-parser
29 */
30 /**
31 * Parser for TYPO3's extension.xml file.
32 *
33 * Depends on PHP ext/xml which should be available
34 * with PHP 4+. This is the parser used in TYPO3
35 * Core <= 4.3 (without the "collect all data in one
36 * array" behaviour).
37 * Notice: ext/xml has proven to be buggy with entities.
38 * Use at least PHP 5.2.9+ and libxml2 2.7.3+!
39 *
40 * @author Marcus Krause <marcus#exp2010@t3sec.info>
41 * @author Steffen Kamper <info@sk-typo3.de>
42 * @since 2010-02-10
43 * @package TYPO3
44 * @subpackage EM
45 */
46 class ExtensionXmlPushParser extends \TYPO3\CMS\Extensionmanager\Utility\Parser\ExtensionXmlAbstractParser implements \SplSubject {
47
48 /**
49 * Keeps current element to process.
50 *
51 * @var string
52 */
53 protected $element = NULL;
54
55 /**
56 * Keeps list of attached observers.
57 *
58 * @var SplObserver[]
59 */
60 protected $observers = array();
61
62 /**
63 * Class constructor.
64 */
65 public function __construct() {
66 $this->requiredPhpExtensions = 'xml';
67 if ($this->isAvailable()) {
68 $this->objXml = xml_parser_create();
69 xml_set_object($this->objXml, $this);
70 }
71 }
72
73 /**
74 * Method parses an extensions.xml file.
75 *
76 * @param string $file GZIP stream resource
77 * @return void
78 * @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException in case of parse errors
79 */
80 public function parseXml($file) {
81 if (!is_resource($this->objXml)) {
82 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException('Unable to create XML parser.', 1342640663);
83 }
84 // keep original character case of XML document
85 xml_parser_set_option($this->objXml, XML_OPTION_CASE_FOLDING, FALSE);
86 xml_parser_set_option($this->objXml, XML_OPTION_SKIP_WHITE, FALSE);
87 xml_parser_set_option($this->objXml, XML_OPTION_TARGET_ENCODING, 'utf-8');
88 xml_set_element_handler($this->objXml, 'startElement', 'endElement');
89 xml_set_character_data_handler($this->objXml, 'characterData');
90 if (!($fp = fopen($file, 'r'))) {
91 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(sprintf('Unable to open file resource %s.', htmlspecialchars($file)), 1342640689);
92 }
93 while ($data = fread($fp, 4096)) {
94 if (!xml_parse($this->objXml, $data, feof($fp))) {
95 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)), 1342640703);
96 }
97 }
98 xml_parser_free($this->objXml);
99 }
100
101 /**
102 * Method is invoked when parser accesses start tag of an element.
103 *
104 * @param resource $parser parser resource
105 * @param string $elementName element name at parser's current position
106 * @param array $attrs array of an element's attributes if available
107 * @return void
108 */
109 protected function startElement($parser, $elementName, $attrs) {
110 switch ($elementName) {
111 case 'extension':
112 $this->extensionKey = $attrs['extensionkey'];
113 break;
114 case 'version':
115 $this->version = $attrs['version'];
116 break;
117 default:
118 $this->element = $elementName;
119 }
120 }
121
122 /**
123 * Method is invoked when parser accesses end tag of an element.
124 *
125 * @param resource $parser parser resource
126 * @param string $elementName: element name at parser's current position
127 * @return void
128 */
129 protected function endElement($parser, $elementName) {
130 switch ($elementName) {
131 case 'extension':
132 $this->resetProperties(TRUE);
133 break;
134 case 'version':
135 $this->notify();
136 $this->resetProperties();
137 break;
138 default:
139 $this->element = NULL;
140 }
141 }
142
143 /**
144 * Method is invoked when parser accesses any character other than elements.
145 *
146 * @param resource $parser: parser resource
147 * @param string $data: an element's value
148 * @return void
149 */
150 protected function characterData($parser, $data) {
151 if (isset($this->element)) {
152 switch ($this->element) {
153 case 'downloadcounter':
154 // downloadcounter could be a child node of
155 // extension or version
156 if ($this->version == NULL) {
157 $this->extensionDownloadCounter = $data;
158 } else {
159 $this->versionDownloadCounter = $data;
160 }
161 break;
162 case 'title':
163 $this->title = $data;
164 break;
165 case 'description':
166 $this->description = $data;
167 break;
168 case 'state':
169 $this->state = $data;
170 break;
171 case 'reviewstate':
172 $this->reviewstate = $data;
173 break;
174 case 'category':
175 $this->category = $data;
176 break;
177 case 'lastuploaddate':
178 $this->lastuploaddate = $data;
179 break;
180 case 'uploadcomment':
181 $this->uploadcomment = $data;
182 break;
183 case 'dependencies':
184 $this->dependencies = $this->convertDependencies($data);
185 break;
186 case 'authorname':
187 $this->authorname = $data;
188 break;
189 case 'authoremail':
190 $this->authoremail = $data;
191 break;
192 case 'authorcompany':
193 $this->authorcompany = $data;
194 break;
195 case 'ownerusername':
196 $this->ownerusername = $data;
197 break;
198 case 't3xfilemd5':
199 $this->t3xfilemd5 = $data;
200 break;
201 }
202 }
203 }
204
205 /**
206 * Method attaches an observer.
207 *
208 * @param SplObserver $observer: an observer to attach
209 * @return void
210 */
211 public function attach(\SplObserver $observer) {
212 $this->observers[] = $observer;
213 }
214
215 /**
216 * Method detaches an attached observer
217 *
218 * @param SplObserver $observer: an observer to detach
219 * @return void
220 */
221 public function detach(\SplObserver $observer) {
222 $key = array_search($observer, $this->observers, TRUE);
223 if (!($key === FALSE)) {
224 unset($this->observers[$key]);
225 }
226 }
227
228 /**
229 * Method notifies attached observers.
230 *
231 * @return void
232 */
233 public function notify() {
234 foreach ($this->observers as $observer) {
235 $observer->update($this);
236 }
237 }
238
239 }
240
241
242 ?>