Follow-up to #16495: corrected the backpath for imported modules (files)
[Packages/TYPO3.CMS.git] / typo3 / sysext / em / classes / tools / class.tx_em_tools.php
1 <?php
2 /* **************************************************************
3 * Copyright notice
4 *
5 * (c) webservices.nl
6 * (c) 2006-2010 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 * class.tx_em_tools.php
30 *
31 * $Id: class.tx_em_tools.php 2084 2010-03-22 01:46:37Z steffenk $
32 */
33
34 /**
35 * Static tools for extension manager
36 * Some of them should be moved later to t3lib static libraries
37 *
38 */
39 final class tx_em_Tools {
40
41 /**
42 * Keeps default categories.
43 *
44 * @var array
45 */
46 static protected $defaultCategories = array('be' => 0,
47 'module' => 1,
48 'fe' => 2,
49 'plugin' => 3,
50 'misc' => 4,
51 'services' => 5,
52 'templates' => 6,
53 'example' => 9,
54 'doc' => 8,
55 );
56 /**
57 * Keeps default states.
58 *
59 * @var array
60 */
61 static protected $defaultStates = array('alpha' => 0,
62 'beta' => 1,
63 'stable' => 2,
64 'experimental' => 3,
65 'test' => 4,
66 'obsolete' => 5,
67 'excludeFromUpdates' => 6,
68 'n/a' => 999,
69 );
70
71 /**
72 * Unzips a zip file in the given path.
73 *
74 * Uses unzip binary if available, otherwise a pure PHP unzip is used.
75 *
76 * @param string $file Full path to zip file
77 * @param string $path Path to change to before extracting
78 * @return boolean True on success, false in failure
79 */
80 public function unzip($file, $path) {
81 if (strlen($GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'])) {
82 chdir($path);
83 $cmd = $GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'] . ' -o ' . escapeshellarg($file);
84 exec($cmd, $list, $ret);
85 return ($ret === 0);
86 } else {
87 // we use a pure PHP unzip
88 $unzip = t3lib_div::makeInstance('tx_em_Tools_Unzip', $file);
89 $ret = $unzip->extract(array('add_path' => $path));
90 return (is_array($ret));
91 }
92 }
93
94
95 /**
96 * Refreshes the global extension list
97 *
98 * @return void
99 */
100 function refreshGlobalExtList() {
101 global $TYPO3_LOADED_EXT;
102
103 $TYPO3_LOADED_EXT = t3lib_extMgm::typo3_loadExtensions();
104 if ($TYPO3_LOADED_EXT['_CACHEFILE']) {
105 require(PATH_typo3conf . $TYPO3_LOADED_EXT['_CACHEFILE'] . '_ext_localconf.php');
106 }
107 return;
108
109 $GLOBALS['TYPO3_LOADED_EXT'] = t3lib_extMgm::typo3_loadExtensions();
110 if ($TYPO3_LOADED_EXT['_CACHEFILE']) {
111 require(PATH_typo3conf . $TYPO3_LOADED_EXT['_CACHEFILE'] . '_ext_localconf.php');
112 } else {
113 $temp_TYPO3_LOADED_EXT = $TYPO3_LOADED_EXT;
114 foreach ($temp_TYPO3_LOADED_EXT as $_EXTKEY => $temp_lEDat) {
115 if (is_array($temp_lEDat) && $temp_lEDat['ext_localconf.php']) {
116 $_EXTCONF = $GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][$_EXTKEY];
117 require($temp_lEDat['ext_localconf.php']);
118 }
119 }
120 }
121 }
122
123 /**
124 * Set category array entries for extension
125 *
126 * @param array Category index array
127 * @param array Part of list array for extension.
128 * @param string Extension key
129 * @return array Modified category index array
130 */
131 public function setCat(&$cat, $listArrayPart, $extKey) {
132
133 // Getting extension title:
134 $extTitle = $listArrayPart['EM_CONF']['title'];
135
136 // Category index:
137 $index = $listArrayPart['EM_CONF']['category'];
138 $cat['cat'][$index][$extKey] = $extTitle;
139
140 // Author index:
141 $index = $listArrayPart['EM_CONF']['author'] . ($listArrayPart['EM_CONF']['author_company'] ? ', ' . $listArrayPart['EM_CONF']['author_company'] : '');
142 $cat['author_company'][$index][$extKey] = $extTitle;
143
144 // State index:
145 $index = $listArrayPart['EM_CONF']['state'];
146 $cat['state'][$index][$extKey] = $extTitle;
147
148 // Type index:
149 $index = $listArrayPart['type'];
150 $cat['type'][$index][$extKey] = $extTitle;
151
152 // Return categories:
153 return $cat;
154 }
155
156 /**
157 * Returns upload folder for extension
158 *
159 * @param string Extension key
160 * @return string Upload folder for extension
161 */
162 public function uploadFolder($extKey) {
163 return 'uploads/tx_' . str_replace('_', '', $extKey) . '/';
164 }
165
166
167 /**
168 * Returns image tag for "uninstall"
169 *
170 * @return string <img> tag
171 */
172 public function removeButton() {
173 return t3lib_iconWorks::getSpriteIcon('actions-system-extension-uninstall', array('title' => $GLOBALS['LANG']->getLL('ext_details_remove_ext')));
174 }
175
176 /**
177 * Returns image for "install"
178 *
179 * @return string <img> tag
180 */
181 public function installButton() {
182 return t3lib_iconWorks::getSpriteIcon('actions-system-extension-install', array('title' => $GLOBALS['LANG']->getLL('helperFunction_install_extension')));
183 }
184
185 /**
186 * Warning (<img> + text string) message about the impossibility to import extensions (both local and global locations are disabled...)
187 *
188 * @return string <img> + text string.
189 */
190 public function noImportMsg() {
191 return t3lib_iconWorks::getSpriteIcon('status-dialog-warning') .
192 '<strong>' . $GLOBALS['LANG']->getLL('helperFunction_import_not_possible') . '</strong>';
193 }
194
195
196 /**
197 * Fixes an old style ext_emconf.php array by adding constraints if needed and removing deprecated keys
198 *
199 * @param array $emConf
200 * @return array
201 */
202 public function fixEMCONF($emConf) {
203 if (!isset($emConf['constraints']) || !isset($emConf['constraints']['depends']) || !isset($emConf['constraints']['conflicts']) || !isset($emConf['constraints']['suggests'])) {
204 if (!isset($emConf['constraints']) || !isset($emConf['constraints']['depends'])) {
205 $emConf['constraints']['depends'] = self::stringToDep($emConf['dependencies']);
206 if (strlen($emConf['PHP_version'])) {
207 $versionRange = self::splitVersionRange($emConf['PHP_version']);
208 if (version_compare($versionRange[0], '3.0.0', '<')) {
209 $versionRange[0] = '3.0.0';
210 }
211 if (version_compare($versionRange[1], '3.0.0', '<')) {
212 $versionRange[1] = '0.0.0';
213 }
214 $emConf['constraints']['depends']['php'] = implode('-', $versionRange);
215 }
216 if (strlen($emConf['TYPO3_version'])) {
217 $versionRange = self::splitVersionRange($emConf['TYPO3_version']);
218 if (version_compare($versionRange[0], '3.5.0', '<')) {
219 $versionRange[0] = '3.5.0';
220 }
221 if (version_compare($versionRange[1], '3.5.0', '<')) {
222 $versionRange[1] = '0.0.0';
223 }
224 $emConf['constraints']['depends']['typo3'] = implode('-', $versionRange);
225 }
226 }
227 if (!isset($emConf['constraints']) || !isset($emConf['constraints']['conflicts'])) {
228 $emConf['constraints']['conflicts'] = self::stringToDep($emConf['conflicts']);
229 }
230 if (!isset($emConf['constraints']) || !isset($emConf['constraints']['suggests'])) {
231 $emConf['constraints']['suggests'] = array();
232 }
233 } elseif (isset($emConf['constraints']) && isset($emConf['dependencies'])) {
234 $emConf['suggests'] = isset($emConf['suggests']) ? $emConf['suggests'] : array();
235 $emConf['dependencies'] = self::depToString($emConf['constraints']);
236 $emConf['conflicts'] = self::depToString($emConf['constraints'], 'conflicts');
237 }
238
239 // sanity check for version numbers, intentionally only checks php and typo3
240 if (isset($emConf['constraints']['depends']) && isset($emConf['constraints']['depends']['php'])) {
241 $versionRange = self::splitVersionRange($emConf['constraints']['depends']['php']);
242 if (version_compare($versionRange[0], '3.0.0', '<')) {
243 $versionRange[0] = '3.0.0';
244 }
245 if (version_compare($versionRange[1], '3.0.0', '<')) {
246 $versionRange[1] = '0.0.0';
247 }
248 $emConf['constraints']['depends']['php'] = implode('-', $versionRange);
249 }
250 if (isset($emConf['constraints']['depends']) && isset($emConf['constraints']['depends']['typo3'])) {
251 $versionRange = self::splitVersionRange($emConf['constraints']['depends']['typo3']);
252 if (version_compare($versionRange[0], '3.5.0', '<')) {
253 $versionRange[0] = '3.5.0';
254 }
255 if (version_compare($versionRange[1], '3.5.0', '<')) {
256 $versionRange[1] = '0.0.0';
257 }
258 $emConf['constraints']['depends']['typo3'] = implode('-', $versionRange);
259 }
260
261 unset($emConf['private']);
262 unset($emConf['download_password']);
263 unset($emConf['TYPO3_version']);
264 unset($emConf['PHP_version']);
265
266 return $emConf;
267 }
268
269
270 /**
271 * Returns the $EM_CONF array from an extensions ext_emconf.php file
272 *
273 * @param string Absolute path to EMCONF file.
274 * @param string Extension key.
275 * @return array EMconf array values.
276 */
277 public function includeEMCONF($path, $_EXTKEY) {
278 $EM_CONF = NULL;
279 @include($path);
280 if (is_array($EM_CONF[$_EXTKEY])) {
281 return self::fixEMCONF($EM_CONF[$_EXTKEY]);
282 }
283 return false;
284 }
285
286
287 /**
288 * Extracts the directories in the $files array
289 *
290 * @param array Array of files / directories
291 * @return array Array of directories from the input array.
292 */
293 function extractDirsFromFileList($files) {
294 $dirs = array();
295
296 if (is_array($files)) {
297 // Traverse files / directories array:
298 foreach ($files as $file) {
299 if (substr($file, -1) == '/') {
300 $dirs[$file] = $file;
301 } else {
302 $pI = pathinfo($file);
303 if (strcmp($pI['dirname'], '') && strcmp($pI['dirname'], '.')) {
304 $dirs[$pI['dirname'] . '/'] = $pI['dirname'] . '/';
305 }
306 }
307 }
308 }
309 return $dirs;
310 }
311
312 /**
313 * Splits a version range into an array.
314 *
315 * If a single version number is given, it is considered a minimum value.
316 * If a dash is found, the numbers left and right are considered as minimum and maximum. Empty values are allowed.
317 *
318 * @param string $ver A string with a version range.
319 * @return array
320 */
321 public function splitVersionRange($ver) {
322 $versionRange = array();
323 if (strstr($ver, '-')) {
324 $versionRange = explode('-', $ver, 2);
325 } else {
326 $versionRange[0] = $ver;
327 $versionRange[1] = '';
328 }
329
330 if (!$versionRange[0]) {
331 $versionRange[0] = '0.0.0';
332 }
333 if (!$versionRange[1]) {
334 $versionRange[1] = '0.0.0';
335 }
336
337 return $versionRange;
338 }
339
340 /**
341 * Checks whether the passed dependency is TER2-style (array) and returns a single string for displaying the dependencies.
342 *
343 * It leaves out all version numbers and the "php" and "typo3" dependencies, as they are implicit and of no interest without the version number.
344 *
345 * @param mixed $dep Either a string or an array listing dependencies.
346 * @param string $type The dependency type to list if $dep is an array
347 * @return string A simple dependency list for display
348 */
349 public function depToString($dep, $type = 'depends') {
350 if (is_array($dep)) {
351 unset($dep[$type]['php']);
352 unset($dep[$type]['typo3']);
353 $s = (count($dep[$type])) ? implode(',', array_keys($dep[$type])) : '';
354 return $s;
355 }
356 return '';
357 }
358
359 /**
360 * Checks whether the passed dependency is TER-style (string) or TER2-style (array) and returns a single string for displaying the dependencies.
361 *
362 * It leaves out all version numbers and the "php" and "typo3" dependencies, as they are implicit and of no interest without the version number.
363 *
364 * @param mixed $dep Either a string or an array listing dependencies.
365 * @param string $type The dependency type to list if $dep is an array
366 * @return string A simple dependency list for display
367 */
368 public function stringToDep($dep) {
369 $constraint = array();
370 if (is_string($dep) && strlen($dep)) {
371 $dep = explode(',', $dep);
372 foreach ($dep as $v) {
373 $constraint[$v] = '';
374 }
375 }
376 return $constraint;
377 }
378
379
380 /**
381 * Returns version information
382 *
383 * @param string Version code, x.x.x
384 * @param string part: "", "int", "main", "sub", "dev"
385 * @return string
386 * @see renderVersion()
387 */
388 public function makeVersion($v, $mode) {
389 $vDat = self::renderVersion($v);
390 return $vDat['version_' . $mode];
391 }
392
393 /**
394 * Parses the version number x.x.x and returns an array with the various parts.
395 *
396 * @param string Version code, x.x.x
397 * @param string Increase version part: "main", "sub", "dev"
398 * @return string
399 */
400 public function renderVersion($v, $raise = '') {
401 $parts = t3lib_div::intExplode('.', $v . '..');
402 $parts[0] = t3lib_div::intInRange($parts[0], 0, 999);
403 $parts[1] = t3lib_div::intInRange($parts[1], 0, 999);
404 $parts[2] = t3lib_div::intInRange($parts[2], 0, 999);
405
406 switch ((string) $raise) {
407 case 'main':
408 $parts[0]++;
409 $parts[1] = 0;
410 $parts[2] = 0;
411 break;
412 case 'sub':
413 $parts[1]++;
414 $parts[2] = 0;
415 break;
416 case 'dev':
417 $parts[2]++;
418 break;
419 }
420
421 $res = array();
422 $res['version'] = $parts[0] . '.' . $parts[1] . '.' . $parts[2];
423 $res['version_int'] = intval($parts[0] * 1000000 + $parts[1] * 1000 + $parts[2]);
424 $res['version_main'] = $parts[0];
425 $res['version_sub'] = $parts[1];
426 $res['version_dev'] = $parts[2];
427
428 return $res;
429 }
430
431 /**
432 * Evaluates differences in version numbers with three parts, x.x.x. Returns true if $v1 is greater than $v2
433 *
434 * @param string Version number 1
435 * @param string Version number 2
436 * @param integer Tolerance factor. For instance, set to 1000 to ignore difference in dev-version (third part)
437 * @return boolean True if version 1 is greater than version 2
438 */
439 public function versionDifference($v1, $v2, $div = 1) {
440 return floor(self::makeVersion($v1, 'int') / $div) > floor(self::makeVersion($v2, 'int') / $div);
441 }
442
443
444 /**
445 * Returns true if the $str is found as the first part of a string in $array
446 *
447 * @param string String to test with.
448 * @param array Input array
449 * @param boolean If set, the test is case insensitive
450 * @return boolean True if found.
451 */
452 public function first_in_array($str, $array, $caseInsensitive = FALSE) {
453 if ($caseInsensitive) {
454 $str = strtolower($str);
455 }
456 if (is_array($array)) {
457 foreach ($array as $cl) {
458 if ($caseInsensitive) {
459 $cl = strtolower($cl);
460 }
461 if (t3lib_div::isFirstPartOfStr($cl, $str)) {
462 return true;
463 }
464 }
465 }
466 return false;
467 }
468
469 /**
470 * Compares two arrays with MD5-hash values for analysis of which files has changed.
471 *
472 * @param array Current values
473 * @param array Past values
474 * @return array Affected files
475 */
476 function findMD5ArrayDiff($current, $past) {
477 if (!is_array($current)) {
478 $current = array();
479 }
480 if (!is_array($past)) {
481 $past = array();
482 }
483 $filesInCommon = array_intersect($current, $past);
484 $diff1 = array_keys(array_diff($past, $filesInCommon));
485 $diff2 = array_keys(array_diff($current, $filesInCommon));
486 $affectedFiles = array_unique(array_merge($diff1, $diff2));
487 return $affectedFiles;
488 }
489
490 /**
491 * Returns title and style attribute for mouseover help text.
492 *
493 * @param string Help text.
494 * @return string title="" attribute prepended with a single space
495 */
496 public function labelInfo($str) {
497 return ' title="' . htmlspecialchars($str) . '" style="cursor:help;"';
498 }
499
500
501 /**
502 * Returns the absolute path where the extension $extKey is installed (based on 'type' (SGL))
503 *
504 * @param string Extension key
505 * @param string Install scope type: L, G, S
506 * @return string Returns the absolute path to the install scope given by input $type variable. It is checked if the path is a directory. Slash is appended.
507 */
508 public function getExtPath($extKey, $type, $returnWithoutExtKey = FALSE) {
509 $typePath = self::typePath($type);
510
511 if ($typePath) {
512 $path = $typePath . ($returnWithoutExtKey ? '' : $extKey . '/');
513 return $path; # @is_dir($path) ? $path : '';
514 } else {
515 return '';
516 }
517 }
518
519 /**
520 * Get type of extension (G,S,L) from extension path
521 *
522 * @param string $path
523 */
524 public function getExtTypeFromPath($path) {
525 if (strpos($path, TYPO3_mainDir . 'sysext/') !== false) {
526 return 'S';
527 } elseif (strpos($path, TYPO3_mainDir . 'ext/') !== false) {
528 return 'G';
529 } elseif (strpos($path, 'typo3conf/ext/') !== false) {
530 return 'L';
531 }
532 }
533
534 /**
535 * Get path from type
536 *
537 * @param string $type S/G/L
538 */
539 public function typePath($type) {
540 if ($type === 'S') {
541 return PATH_typo3 . 'sysext/';
542 } elseif ($type === 'G') {
543 return PATH_typo3 . 'ext/';
544 } elseif ($type === 'L') {
545 return PATH_typo3conf . 'ext/';
546 }
547 }
548
549 /**
550 * Get relative path from type
551 *
552 * @param string $type S/G/L
553 */
554 public function typeRelPath($type) {
555 if ($type === 'S') {
556 return 'sysext/';
557 } elseif ($type === 'G') {
558 return 'ext/';
559 } elseif ($type === 'L') {
560 return '../typo3conf/ext/';
561 }
562 }
563
564 /**
565 * Get backpath from type
566 *
567 * @param string $type S/G/L
568 */
569 public function typeBackPath($type) {
570 if ($type === 'L') {
571 return '../../../../' . TYPO3_mainDir;
572 } else {
573 return '../../../';
574 }
575 }
576
577 /**
578 * Reads locallang file into array (for possible include in header)
579 *
580 * @param $file
581 */
582 public function getArrayFromLocallang($file, $key = 'default') {
583 $content = t3lib_div::getURL($file);
584 $array = t3lib_div::xml2array($content);
585 return $array['data'][$key];
586
587 }
588
589 /**
590 * Include a locallang file and return the $LOCAL_LANG array serialized.
591 *
592 * @param string Absolute path to locallang file to include.
593 * @param string Old content of a locallang file (keeping the header content)
594 * @return array Array with header/content as key 0/1
595 * @see makeUploadarray()
596 */
597 function getSerializedLocalLang($file, $content) {
598 $LOCAL_LANG = NULL;
599 $returnParts = explode('$LOCAL_LANG', $content, 2);
600
601 include($file);
602 if (is_array($LOCAL_LANG)) {
603 $returnParts[1] = serialize($LOCAL_LANG);
604 return $returnParts;
605 } else {
606 return array();
607 }
608 }
609
610
611 /**
612 * Enter description here...
613 *
614 * @param unknown_type $array
615 * @param unknown_type $lines
616 * @param unknown_type $level
617 * @return unknown
618 */
619 function arrayToCode($array, $level = 0) {
620 $lines = 'array(' . LF;
621 $level++;
622 foreach ($array as $k => $v) {
623 if (strlen($k) && is_array($v)) {
624 $lines .= str_repeat(TAB, $level) . "'" . $k . "' => " . self::arrayToCode($v, $level);
625 } elseif (strlen($k)) {
626 $lines .= str_repeat(TAB, $level) . "'" . $k . "' => " . (t3lib_div::testInt($v) ? intval($v) : "'" . t3lib_div::slashJS(trim($v), 1) . "'") . ',' . LF;
627 }
628 }
629
630 $lines .= str_repeat(TAB, $level - 1) . ')' . ($level - 1 == 0 ? '' : ',' . LF);
631 return $lines;
632 }
633
634
635 /**
636 * Traverse the array of installed extensions keys and arranges extensions in the priority order they should be in
637 *
638 * @param array Array of extension keys as values
639 * @param array Extension information array
640 * @return array Modified array of extention keys as values
641 * @see addExtToList()
642 */
643 function managesPriorities($listArr, $instExtInfo) {
644
645 // Initialize:
646 $levels = array(
647 'top' => array(),
648 'middle' => array(),
649 'bottom' => array(),
650 );
651
652 // Traverse list of extensions:
653 foreach ($listArr as $ext) {
654 $prio = trim($instExtInfo[$ext]['EM_CONF']['priority']);
655 switch ((string) $prio) {
656 case 'top':
657 case 'bottom':
658 $levels[$prio][] = $ext;
659 break;
660 default:
661 $levels['middle'][] = $ext;
662 break;
663 }
664 }
665 return array_merge(
666 $levels['top'],
667 $levels['middle'],
668 $levels['bottom']
669 );
670 }
671
672
673 /**
674 * Returns either array with all default categories or index/title
675 * of a category entry.
676 *
677 * @access public
678 * @param mixed $cat category title or category index
679 * @return mixed
680 */
681 static public function getDefaultCategory($cat = NULL) {
682 if (is_null($cat)) {
683 return self::$defaultCategories;
684 } else {
685 if (is_string($cat)) {
686 // default category
687 $catIndex = 4;
688 if (array_key_exists(strtolower($cat), self::$defaultCategories)) {
689 $catIndex = self::$defaultCategories[strtolower($cat)];
690 }
691 return $catIndex;
692 } else {
693 if (is_int($cat) && $cat >= 0) {
694 $catTitle = array_search($cat, self::$defaultCategories);
695 // default category
696 if (!$catTitle) {
697 $catTitle = 'misc';
698 }
699 return $catTitle;
700 }
701 }
702 }
703 }
704
705 /**
706 * Returns either array with all default states or index/title
707 * of a state entry.
708 *
709 * @access public
710 * @param mixed $state state title or state index
711 * @return mixed
712 */
713 static public function getDefaultState($state = NULL) {
714 if (is_null($state)) {
715 return self::$defaultStates;
716 } else {
717 if (is_string($state)) {
718 // default state
719 $stateIndex = 999;
720 if (array_key_exists(strtolower($state), self::$defaultStates)) {
721 $stateIndex = self::$defaultStates[strtolower($state)];
722 }
723 return $stateIndex;
724 } else {
725 if (is_int($state) && $state >= 0) {
726 $stateTitle = array_search($state, self::$defaultStates);
727 // default state
728 if (!$stateTitle) {
729 $stateTitle = 'n/a';
730 }
731 return $stateTitle;
732 }
733 }
734 }
735 }
736
737 /**
738 * Reports back if installation in a certain scope is possible.
739 *
740 * @param string Scope: G, L, S
741 * @param string Extension lock-type (eg. "L" or "G")
742 * @return boolean True if installation is allowed.
743 */
744 function importAsType($type, $lockType = '') {
745 switch ($type) {
746 case 'G':
747 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall'] && (!$lockType || !strcmp($lockType, $type));
748 break;
749 case 'L':
750 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall'] && (!$lockType || !strcmp($lockType, $type));
751 break;
752 case 'S':
753 return $this->systemInstall;
754 break;
755 default:
756 return false;
757 }
758 }
759
760 /**
761 * Returns true if extensions in scope, $type, can be deleted (or installed for that sake)
762 *
763 * @param string Scope: "G" or "L"
764 * @return boolean True if possible.
765 */
766 function deleteAsType($type) {
767 switch ($type) {
768 case 'G':
769 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall'];
770 break;
771 case 'L':
772 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall'];
773 break;
774 default:
775 return false;
776 }
777 }
778
779
780 /**
781 * Creates directories in $extDirPath
782 *
783 * @param array Array of directories to create relative to extDirPath, eg. "blabla", "blabla/blabla" etc...
784 * @param string Absolute path to directory.
785 * @return mixed Returns false on success or an error string
786 */
787 function createDirsInPath($dirs, $extDirPath) {
788 if (is_array($dirs)) {
789 foreach ($dirs as $dir) {
790 $error = t3lib_div::mkdir_deep($extDirPath, $dir);
791 if ($error) {
792 return $error;
793 }
794 }
795 }
796
797 return false;
798 }
799
800 /**
801 * Analyses the php-scripts of an available extension on server
802 *
803 * @param string Absolute path to extension
804 * @param string Prefix for tables/classes.
805 * @param string Extension key
806 * @return array Information array.
807 * @see makeDetailedExtensionAnalysis()
808 */
809 function getClassIndexLocallangFiles($absPath, $table_class_prefix, $extKey) {
810 $filesInside = t3lib_div::removePrefixPathFromList(t3lib_div::getAllFilesAndFoldersInPath(array(), $absPath, 'php,inc', 0, 99, $this->excludeForPackaging), $absPath);
811 $out = array();
812 $reg = array();
813
814 foreach ($filesInside as $fileName) {
815 if (substr($fileName, 0, 4) != 'ext_' && substr($fileName, 0, 6) != 'tests/') { // ignore supposed-to-be unit tests as well
816 $baseName = basename($fileName);
817 if (substr($baseName, 0, 9) == 'locallang' && substr($baseName, -4) == '.php') {
818 $out['locallang'][] = $fileName;
819 } elseif ($baseName != 'conf.php') {
820 if (filesize($absPath . $fileName) < 500 * 1024) {
821 $fContent = t3lib_div::getUrl($absPath . $fileName);
822 unset($reg);
823 if (preg_match('/\n[[:space:]]*class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/', $fContent, $reg)) {
824
825 // Find classes:
826 $lines = explode(LF, $fContent);
827 foreach ($lines as $l) {
828 $line = trim($l);
829 unset($reg);
830 if (preg_match('/^class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/', $line, $reg)) {
831 $out['classes'][] = $reg[1];
832 $out['files'][$fileName]['classes'][] = $reg[1];
833 if ($reg[1]!=='ext_update' && substr($reg[1], 0, 3) != 'ux_' && !t3lib_div::isFirstPartOfStr($reg[1], $table_class_prefix) && strcmp(substr($table_class_prefix, 0, -1), $reg[1])) {
834 $out['NSerrors']['classname'][] = $reg[1];
835 } else {
836 $out['NSok']['classname'][] = $reg[1];
837 }
838 }
839 }
840 // If class file prefixed 'class.'....
841 if (substr($baseName, 0, 6) == 'class.') {
842 $fI = pathinfo($baseName);
843 $testName = substr($baseName, 6, -(1 + strlen($fI['extension'])));
844 if ($testName!=='ext_update' && substr($testName, 0, 3) != 'ux_' && !t3lib_div::isFirstPartOfStr($testName, $table_class_prefix) && strcmp(substr($table_class_prefix, 0, -1), $testName)) {
845 $out['NSerrors']['classfilename'][] = $baseName;
846 } else {
847 $out['NSok']['classfilename'][] = $baseName;
848 if (is_array($out['files'][$fileName]['classes']) && tx_em_Tools::first_in_array($testName, $out['files'][$fileName]['classes'], 1)) {
849 $out['msg'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_class_ok'),
850 $fileName, $testName
851 );
852 } else {
853 $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_class_not_ok'),
854 $fileName, $testName
855 );
856 }
857 }
858 }
859 // Check for proper XCLASS definition
860 // Match $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS'] with single or doublequotes
861 $XclassSearch = '\$TYPO3_CONF_VARS\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]';
862 $XclassParts = preg_split('/if \(defined\([\'"]TYPO3_MODE[\'"]\) && ' . $XclassSearch . '/', $fContent, 2);
863 if (count($XclassParts) !== 2) {
864 // Match $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS'] with single or doublequotes
865 $XclassSearch = '\$GLOBALS\[[\'"]TYPO3_CONF_VARS[\'"]\]\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]';
866 $XclassParts = preg_split('/if \(defined\([\'"]TYPO3_MODE[\'"]\) && ' . $XclassSearch . '/', $fContent, 2);
867 }
868 if (count($XclassParts) == 2) {
869 unset($reg);
870 preg_match('/^\[[\'"]([[:alnum:]_\/\.]*)[\'"]\]/', $XclassParts[1], $reg);
871 if ($reg[1]) {
872 $cmpF = 'ext/' . $extKey . '/' . $fileName;
873 if (!strcmp($reg[1], $cmpF)) {
874 if (preg_match('/_once[[:space:]]*\(' . $XclassSearch . '\[[\'"]' . preg_quote($cmpF, '/') . '[\'"]\]\);/', $XclassParts[1])) {
875 $out['msg'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_ok'), $fileName);
876 } else {
877 $out['errors'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_no_include');
878 }
879 } else {
880 $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_incorrect'),
881 $reg[1], $cmpF
882 );
883 }
884 } else {
885 $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_xclass_filename'), $fileName);
886 }
887 } elseif (!tx_em_Tools::first_in_array('ux_', $out['files'][$fileName]['classes'])) {
888 // No Xclass definition required if classname starts with 'ux_'
889 $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_xclass_found'), $fileName);
890 }
891 }
892 }
893 }
894 }
895 }
896 return $out;
897 }
898
899 /**
900 * Write new TYPO3_MOD_PATH to "conf.php" file.
901 *
902 * @param string Absolute path to a "conf.php" file of the backend module which we want to write back to.
903 * @param string Install scope type: L, G, S
904 * @param string Relative path for the module folder in extension
905 * @return string Returns message about the status.
906 * @see modConfFileAnalysis()
907 */
908 function writeTYPO3_MOD_PATH($confFilePath, $type, $mP) {
909 $lines = explode(LF, t3lib_div::getUrl($confFilePath));
910 $confFileInfo = array();
911 $confFileInfo['lines'] = $lines;
912 $reg = array();
913
914 $flag_M = 0;
915 $flag_B = 0;
916 $flag_Dispatch = 0;
917
918 foreach ($lines as $k => $l) {
919 $line = trim($l);
920
921 unset($reg);
922 if (preg_match('/^define[[:space:]]*\([[:space:]]*["\']TYPO3_MOD_PATH["\'][[:space:]]*,[[:space:]]*["\']([[:alnum:]_\/\.]+)["\'][[:space:]]*\)[[:space:]]*;/', $line, $reg)) {
923 $lines[$k] = str_replace($reg[0], 'define(\'TYPO3_MOD_PATH\', \'' . self::typeRelPath($type) . $mP . '\');', $lines[$k]);
924 $flag_M = $k + 1;
925 }
926
927 unset($reg);
928 if (preg_match('/^\$BACK_PATH[[:space:]]*=[[:space:]]*["\']([[:alnum:]_\/\.]+)["\'][[:space:]]*;/', $line, $reg)) {
929 $lines[$k] = str_replace($reg[0], '$BACK_PATH=\'' . self::typeBackPath($type) . '\';', $lines[$k]);
930 $flag_B = $k + 1;
931 }
932
933 // Check if this module uses new API (see http://bugs.typo3.org/view.php?id=5278)
934 // where TYPO3_MOD_PATH and BACK_PATH are not required
935 unset($reg);
936 if (preg_match('/^\$MCONF\[["\']script["\']\][[:space:]]*=[[:space:]]*["\']_DISPATCH["\'][[:space:]]*;/', $line, $reg)) {
937 $flag_Dispatch = $k + 1;
938 }
939
940 }
941
942 if ($flag_B && $flag_M) {
943 t3lib_div::writeFile($confFilePath, implode(LF, $lines));
944 return sprintf($GLOBALS['LANG']->getLL('writeModPath_ok'),
945 substr($confFilePath, strlen(PATH_site)));
946 } elseif ($flag_Dispatch) {
947 return sprintf(
948 $GLOBALS['LANG']->getLL('writeModPath_notRequired'),
949 substr($confFilePath, strlen(PATH_site))
950 );
951 } else {
952 return $GLOBALS["TBE_TEMPLATE"]->rfw(
953 sprintf($GLOBALS['LANG']->getLL('writeModPath_error'),
954 $confFilePath)
955 );
956 }
957 }
958
959 /**
960 * Wrapping input string in a link tag with link to email address
961 *
962 * @param string Input string, being wrapped in <a> tags
963 * @param string Email address for use in link.
964 * @return string Output
965 */
966 function wrapEmail($str, $email) {
967 if ($email) {
968 $str = '<a href="mailto:' . htmlspecialchars($email) . '">' . htmlspecialchars($str) . '</a>';
969 }
970 return $str;
971 }
972
973 /**
974 * red-fontwrap. Returns the string wrapped in a <span>-tag defining the color to be red
975 *
976 * @param string Input string
977 * @return string Output string
978 */
979 function rfw($string) {
980 return '<span class="typo3-red">' . $string . '</span>';
981 }
982
983 /**
984 * dimmed-fontwrap. Returns the string wrapped in a <span>-tag defining the color to be gray/dimmed
985 *
986 * @param string Input string
987 * @return string Output string
988 */
989 function dfw($string) {
990 return '<span class="typo3-dimmed">' . $string . '</span>';
991 }
992 }
993
994 ?>