Cleanup: Updated copyright comments
[Packages/TYPO3.CMS.git] / typo3 / sysext / em / classes / connection / class.tx_em_connection_ter.php
1 <?php
2 /* **************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
6 * (c) 2006-2011 Karsten Dambekalns <karsten@typo3.org>
7 * All rights reserved
8 *
9 * This script is part of the TYPO3 project. The TYPO3 project is
10 * free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
17 * A copy is found in the textfile GPL.txt and important notices to the license
18 * from the author is found in LICENSE.txt distributed with these scripts.
19 *
20 *
21 * This script is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * This copyright notice MUST APPEAR in all copies of the script!
27 ***************************************************************/
28
29
30 /**
31 * TER2 connection handling class for the TYPO3 Extension Manager.
32 *
33 * It contains methods for downloading and uploading extensions and related code
34 *
35 * @author Karsten Dambekalns <karsten@typo3.org>
36 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
37 * @package TYPO3
38 * @subpackage EM
39 */
40 class tx_em_Connection_Ter {
41 var $wsdlURL;
42
43 /**
44 * Extension manager module
45 *
46 * @var SC_mod_tools_em_index
47 */
48 var $emObj;
49
50 public function __construct($emObj) {
51 $this->emObj = $emObj;
52 }
53
54 /**
55 * Fetches an extension from the given mirror
56 *
57 * @param string $extKey Extension Key
58 * @param string $version Version to install
59 * @param string $expectedMD5 Expected MD5 hash of extension file
60 * @param string $mirrorURL URL of mirror to use
61 * @return mixed T3X data (array) or error message (string)
62 */
63 function fetchExtension($extKey, $version, $expectedMD5, $mirrorURL) {
64 $extPath = t3lib_div::strtolower($extKey);
65 $mirrorURL .= $extPath{0} . '/' . $extPath{1} . '/' . $extPath . '_' . $version . '.t3x';
66 $t3x = t3lib_div::getURL($mirrorURL, 0, array(TYPO3_user_agent));
67 $MD5 = md5($t3x);
68
69 if ($t3x === FALSE) {
70 return 'The T3X file could not be fetched. Possible reasons: network problems, allow_url_fopen is off, curl is not enabled in Install tool.';
71 }
72
73 if ($MD5 == $expectedMD5) {
74 // Fetch and return:
75 return $this->decodeExchangeData($t3x);
76 } else {
77 return 'Error: MD5 hash of downloaded file not as expected:<br />' . $MD5 . ' != ' . $expectedMD5;
78 }
79 }
80
81 /**
82 * Fetches an extensions l10n file from the given mirror
83 *
84 * @param string $extKey Extension Key
85 * @param string $lang The language code of the translation to fetch
86 * @param string $mirrorURL URL of mirror to use
87 * @return mixed Array containing l10n data or error message (string)
88 */
89 function fetchTranslation($extKey, $lang, $mirrorURL) {
90 $extPath = t3lib_div::strtolower($extKey);
91 $mirrorURL .= $extPath{0} . '/' . $extPath{1} . '/' . $extPath . '-l10n/' . $extPath . '-l10n-' . $lang . '.zip';
92 $l10n = t3lib_div::getURL($mirrorURL, 0, array(TYPO3_user_agent));
93
94 if ($l10n !== false) {
95 return array($l10n);
96 } else {
97 return 'Error: Translation could not be fetched.';
98 }
99 }
100
101 /**
102 * Install translations for all selected languages for an extension
103 *
104 * @param string $extKey The extension key to install the translations for
105 * @param string $lang Language code of translation to fetch
106 * @param string $mirrorURL Mirror URL to fetch data from
107 * @return mixed true on success, error string on fauilure
108 */
109 function updateTranslation($extKey, $lang, $mirrorURL) {
110 $l10n = $this->fetchTranslation($extKey, $lang, $mirrorURL);
111 if (is_array($l10n)) {
112 $file = PATH_site . 'typo3temp/' . $extKey . '-l10n-' . $lang . '.zip';
113 $path = 'l10n/' . $lang . '/';
114 if (!is_dir(PATH_typo3conf . $path)) {
115 t3lib_div::mkdir_deep(PATH_typo3conf, $path);
116 }
117 t3lib_div::writeFile($file, $l10n[0]);
118 if (tx_em_Tools::unzip($file, PATH_typo3conf . $path)) {
119 return TRUE;
120 }
121 }
122 return FALSE;
123 }
124
125 /**
126 * Fetches extension l10n status from the given mirror
127 *
128 * @param string $extKey Extension Key
129 * @param string $mirrorURL URL of mirror to use
130 * @return mixed Array containing l10n status data or FALSE if no status could be fetched
131 */
132 function fetchTranslationStatus($extKey, $mirrorURL) {
133 $extPath = t3lib_div::strtolower($extKey);
134 $mirrorURL .= $extPath{0} . '/' . $extPath{1} . '/' . $extPath . '-l10n/' . $extPath . '-l10n.xml';
135 $remote = t3lib_div::getURL($mirrorURL, 0, array(TYPO3_user_agent));
136
137 if ($remote !== false) {
138 $parsed = $this->emObj->xmlHandler->parseL10nXML($remote);
139 return $parsed['languagePackIndex'];
140 }
141
142 return FALSE;
143 }
144
145 /**
146 * Decode server data
147 * This is information like the extension list, extension information etc., return data after uploads (new em_conf)
148 *
149 * @param string Data stream from remove server
150 * @return mixed On success, returns an array with data array and stats array as key 0 and 1. Otherwise returns error string
151 * @see fetchServerData(), processRepositoryReturnData()
152 */
153 function decodeServerData($externalData) {
154 $parts = explode(':', $externalData, 4);
155 $dat = base64_decode($parts[2]);
156 // compare hashes ignoring any leading whitespace. See bug #0000365.
157 if (ltrim($parts[0]) == md5($dat)) {
158 if ($parts[1] == 'gzcompress') {
159 if (function_exists('gzuncompress')) {
160 $dat = gzuncompress($dat);
161 } else {
162 return 'Decoding Error: No decompressor available for compressed content. gzuncompress() function is not available!';
163 }
164 }
165 $listArr = unserialize($dat);
166
167 if (is_array($listArr)) {
168 return $listArr;
169 } else {
170 return 'Error: Unserialized information was not an array - strange!';
171 }
172 } else {
173 return 'Error: MD5 hashes in T3X data did not match!';
174 }
175 }
176
177 /**
178 * Decodes extension upload array.
179 * This kind of data is when an extension is uploaded to TER
180 *
181 * @param string Data stream
182 * @return mixed Array with result on success, otherwise an error string.
183 */
184 function decodeExchangeData($str) {
185 $parts = explode(':', $str, 3);
186 if ($parts[1] == 'gzcompress') {
187 if (function_exists('gzuncompress')) {
188 $parts[2] = gzuncompress($parts[2]);
189 } else {
190 return 'Decoding Error: No decompressor available for compressed content. gzcompress()/gzuncompress() functions are not available!';
191 }
192 }
193 if (md5($parts[2]) == $parts[0]) {
194 $output = unserialize($parts[2]);
195 if (is_array($output)) {
196 return array($output, '');
197 } else {
198 return 'Error: Content could not be unserialized to an array. Strange (since MD5 hashes match!)';
199 }
200 } else {
201 return 'Error: MD5 mismatch. Maybe the extension file was downloaded and saved as a text file by the browser and thereby corrupted!? (Always select "All" filetype when saving extensions)';
202 }
203 }
204
205
206 /**
207 * Encodes extension upload array
208 *
209 * @param array Array containing extension
210 * @return string Content stream
211 */
212 function makeUploadDataFromarray($uploadArray) {
213 if (is_array($uploadArray)) {
214 $serialized = serialize($uploadArray);
215 $md5 = md5($serialized);
216
217 $content = $md5 . ':';
218 $content .= 'gzcompress:';
219 $content .= gzcompress($serialized);
220 }
221 return $content;
222 }
223
224 /**
225 * Upload extension to ter
226 * @param $em
227 * @return
228 */
229 function uploadToTER($em) {
230 $uArr = $this->emObj->extensionDetails->makeUploadarray($em['extKey'], $em['extInfo']);
231 if (!is_array($uArr)) {
232 return $uArr;
233 }
234
235 // Render new version number:
236 $newVersionBase = $em['extInfo']['EM_CONF']['version'];
237 switch ((string) $em['upload']['mode']) {
238 case 'new_dev':
239 $cmd = 'dev';
240 break;
241 case 'new_sub':
242 $cmd = 'sub';
243 break;
244 case 'new_main':
245 $cmd = 'main';
246 break;
247 case 'custom':
248 $newVersionBase = $em['upload']['version'];
249 case 'latest':
250 default:
251 $cmd = '';
252 break;
253 }
254 $versionArr = tx_em_Tools::renderVersion($newVersionBase, $cmd);
255 $em['version'] = $versionArr['version'];
256
257 // Create dependency / conflict information:
258 $dependenciesArr = array();
259 $extKeysArr = $uArr['EM_CONF']['constraints']['depends'];
260
261 if (is_array($extKeysArr)) {
262 foreach ($extKeysArr as $extKey => $version) {
263 if (strlen($extKey)) {
264 $dependenciesArr[] = array(
265 'kind' => 'depends',
266 'extensionKey' => utf8_encode($extKey),
267 'versionRange' => utf8_encode($version),
268 );
269 }
270 }
271 }
272
273 $extKeysArr = $uArr['EM_CONF']['constraints']['conflicts'];
274 if (is_array($extKeysArr)) {
275 foreach ($extKeysArr as $extKey => $version) {
276 if (strlen($extKey)) {
277 $dependenciesArr[] = array(
278 'kind' => 'conflicts',
279 'extensionKey' => utf8_encode($extKey),
280 'versionRange' => utf8_encode($version),
281 );
282 }
283 }
284 }
285 // FIXME: This part must be removed, when the problem is solved on the TER-Server #5919
286 if (count($dependenciesArr) == 1) {
287 $dependenciesArr[] = array(
288 'kind' => 'depends',
289 'extensionKey' => '',
290 'versionRange' => '',
291 );
292 }
293 // END for Bug #5919
294
295 // Compile data for SOAP call:
296 $accountData = array(
297 'username' => $em['user']['fe_u'],
298 'password' => $em['user']['fe_p']
299 );
300 $extensionData = array(
301 'extensionKey' => utf8_encode($em['extKey']),
302 'version' => utf8_encode($em['version']),
303 'metaData' => array(
304 'title' => utf8_encode($uArr['EM_CONF']['title']),
305 'description' => utf8_encode($uArr['EM_CONF']['description']),
306 'category' => utf8_encode($uArr['EM_CONF']['category']),
307 'state' => utf8_encode($uArr['EM_CONF']['state']),
308 'authorName' => utf8_encode($uArr['EM_CONF']['author']),
309 'authorEmail' => utf8_encode($uArr['EM_CONF']['author_email']),
310 'authorCompany' => utf8_encode($uArr['EM_CONF']['author_company']),
311 ),
312 'technicalData' => array(
313 'dependencies' => $dependenciesArr,
314 'loadOrder' => utf8_encode($uArr['EM_CONF']['loadOrder']),
315 'uploadFolder' => (boolean) intval($uArr['EM_CONF']['uploadfolder']),
316 'createDirs' => utf8_encode($uArr['EM_CONF']['createDirs']),
317 'shy' => (boolean) intval($uArr['EM_CONF']['shy']),
318 'modules' => utf8_encode($uArr['EM_CONF']['module']),
319 'modifyTables' => utf8_encode($uArr['EM_CONF']['modify_tables']),
320 'priority' => utf8_encode($uArr['EM_CONF']['priority']),
321 'clearCacheOnLoad' => (boolean) intval($uArr['EM_CONF']['clearCacheOnLoad']),
322 'lockType' => utf8_encode($uArr['EM_CONF']['lockType']),
323 ),
324 'infoData' => array(
325 'codeLines' => intval($uArr['misc']['codelines']),
326 'codeBytes' => intval($uArr['misc']['codebytes']),
327 'codingGuidelinesCompliance' => utf8_encode($uArr['EM_CONF']['CGLcompliance']),
328 'codingGuidelinesComplianceNotes' => utf8_encode($uArr['EM_CONF']['CGLcompliance_note']),
329 'uploadComment' => utf8_encode($em['upload']['comment']),
330 'techInfo' => $uArr['techInfo'],
331 ),
332 );
333
334 $filesData = array();
335 foreach ($uArr['FILES'] as $filename => $infoArr) {
336 $filesData[] = array(
337 'name' => utf8_encode($infoArr['name']),
338 'size' => intval($infoArr['size']),
339 'modificationTime' => intval($infoArr['mtime']),
340 'isExecutable' => intval($infoArr['is_executable']),
341 'content' => $infoArr['content'],
342 'contentMD5' => $infoArr['content_md5'],
343 );
344 }
345
346 $soap = t3lib_div::makeInstance('tx_em_Connection_Soap');
347 $soap->init(array('wsdl' => $this->wsdlURL, 'soapoptions' => array('trace' => 1, 'exceptions' => 0)));
348 $response = $soap->call(
349 'uploadExtension',
350 array(
351 'accountData' => $accountData,
352 'extensionData' => $extensionData,
353 'filesData' => $filesData
354 )
355 );
356
357 if ($response === FALSE) {
358 switch (TRUE) {
359 case is_string($soap->error):
360 return $soap->error;
361 break;
362 default:
363 return $soap->error->faultstring;
364 }
365 }
366
367 return $response;
368 }
369 }
370
371 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/sysext/em/classes/connection/class.tx_em_connection_ter.php'])) {
372 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/sysext/em/classes/connection/class.tx_em_connection_ter.php']);
373 }
374 ?>