7e2214fc7243f8675933e3eba1010b3219c68e31
[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 * Reads locallang file into array (for possible include in header)
566 *
567 * @param $file
568 */
569 public function getArrayFromLocallang($file, $key = 'default') {
570 $content = t3lib_div::getURL($file);
571 $array = t3lib_div::xml2array($content);
572 return $array['data'][$key];
573
574 }
575
576 /**
577 * Include a locallang file and return the $LOCAL_LANG array serialized.
578 *
579 * @param string Absolute path to locallang file to include.
580 * @param string Old content of a locallang file (keeping the header content)
581 * @return array Array with header/content as key 0/1
582 * @see makeUploadarray()
583 */
584 function getSerializedLocalLang($file, $content) {
585 $LOCAL_LANG = NULL;
586 $returnParts = explode('$LOCAL_LANG', $content, 2);
587
588 include($file);
589 if (is_array($LOCAL_LANG)) {
590 $returnParts[1] = serialize($LOCAL_LANG);
591 return $returnParts;
592 } else {
593 return array();
594 }
595 }
596
597
598 /**
599 * Enter description here...
600 *
601 * @param unknown_type $array
602 * @param unknown_type $lines
603 * @param unknown_type $level
604 * @return unknown
605 */
606 function arrayToCode($array, $level = 0) {
607 $lines = 'array(' . LF;
608 $level++;
609 foreach ($array as $k => $v) {
610 if (strlen($k) && is_array($v)) {
611 $lines .= str_repeat(TAB, $level) . "'" . $k . "' => " . self::arrayToCode($v, $level);
612 } elseif (strlen($k)) {
613 $lines .= str_repeat(TAB, $level) . "'" . $k . "' => " . (t3lib_div::testInt($v) ? intval($v) : "'" . t3lib_div::slashJS(trim($v), 1) . "'") . ',' . LF;
614 }
615 }
616
617 $lines .= str_repeat(TAB, $level - 1) . ')' . ($level - 1 == 0 ? '' : ',' . LF);
618 return $lines;
619 }
620
621
622 /**
623 * Traverse the array of installed extensions keys and arranges extensions in the priority order they should be in
624 *
625 * @param array Array of extension keys as values
626 * @param array Extension information array
627 * @return array Modified array of extention keys as values
628 * @see addExtToList()
629 */
630 function managesPriorities($listArr, $instExtInfo) {
631
632 // Initialize:
633 $levels = array(
634 'top' => array(),
635 'middle' => array(),
636 'bottom' => array(),
637 );
638
639 // Traverse list of extensions:
640 foreach ($listArr as $ext) {
641 $prio = trim($instExtInfo[$ext]['EM_CONF']['priority']);
642 switch ((string) $prio) {
643 case 'top':
644 case 'bottom':
645 $levels[$prio][] = $ext;
646 break;
647 default:
648 $levels['middle'][] = $ext;
649 break;
650 }
651 }
652 return array_merge(
653 $levels['top'],
654 $levels['middle'],
655 $levels['bottom']
656 );
657 }
658
659
660 /**
661 * Returns either array with all default categories or index/title
662 * of a category entry.
663 *
664 * @access public
665 * @param mixed $cat category title or category index
666 * @return mixed
667 */
668 static public function getDefaultCategory($cat = NULL) {
669 if (is_null($cat)) {
670 return self::$defaultCategories;
671 } else {
672 if (is_string($cat)) {
673 // default category
674 $catIndex = 4;
675 if (array_key_exists(strtolower($cat), self::$defaultCategories)) {
676 $catIndex = self::$defaultCategories[strtolower($cat)];
677 }
678 return $catIndex;
679 } else {
680 if (is_int($cat) && $cat >= 0) {
681 $catTitle = array_search($cat, self::$defaultCategories);
682 // default category
683 if (!$catTitle) {
684 $catTitle = 'misc';
685 }
686 return $catTitle;
687 }
688 }
689 }
690 }
691
692 /**
693 * Returns either array with all default states or index/title
694 * of a state entry.
695 *
696 * @access public
697 * @param mixed $state state title or state index
698 * @return mixed
699 */
700 static public function getDefaultState($state = NULL) {
701 if (is_null($state)) {
702 return self::$defaultStates;
703 } else {
704 if (is_string($state)) {
705 // default state
706 $stateIndex = 999;
707 if (array_key_exists(strtolower($state), self::$defaultStates)) {
708 $stateIndex = self::$defaultStates[strtolower($state)];
709 }
710 return $stateIndex;
711 } else {
712 if (is_int($state) && $state >= 0) {
713 $stateTitle = array_search($state, self::$defaultStates);
714 // default state
715 if (!$stateTitle) {
716 $stateTitle = 'n/a';
717 }
718 return $stateTitle;
719 }
720 }
721 }
722 }
723
724 /**
725 * Reports back if installation in a certain scope is possible.
726 *
727 * @param string Scope: G, L, S
728 * @param string Extension lock-type (eg. "L" or "G")
729 * @return boolean True if installation is allowed.
730 */
731 function importAsType($type, $lockType = '') {
732 switch ($type) {
733 case 'G':
734 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall'] && (!$lockType || !strcmp($lockType, $type));
735 break;
736 case 'L':
737 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall'] && (!$lockType || !strcmp($lockType, $type));
738 break;
739 case 'S':
740 return $this->systemInstall;
741 break;
742 default:
743 return false;
744 }
745 }
746
747 /**
748 * Returns true if extensions in scope, $type, can be deleted (or installed for that sake)
749 *
750 * @param string Scope: "G" or "L"
751 * @return boolean True if possible.
752 */
753 function deleteAsType($type) {
754 switch ($type) {
755 case 'G':
756 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall'];
757 break;
758 case 'L':
759 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall'];
760 break;
761 default:
762 return false;
763 }
764 }
765
766
767 /**
768 * Creates directories in $extDirPath
769 *
770 * @param array Array of directories to create relative to extDirPath, eg. "blabla", "blabla/blabla" etc...
771 * @param string Absolute path to directory.
772 * @return mixed Returns false on success or an error string
773 */
774 function createDirsInPath($dirs, $extDirPath) {
775 if (is_array($dirs)) {
776 foreach ($dirs as $dir) {
777 $error = t3lib_div::mkdir_deep($extDirPath, $dir);
778 if ($error) {
779 return $error;
780 }
781 }
782 }
783
784 return false;
785 }
786
787 /**
788 * Analyses the php-scripts of an available extension on server
789 *
790 * @param string Absolute path to extension
791 * @param string Prefix for tables/classes.
792 * @param string Extension key
793 * @return array Information array.
794 * @see makeDetailedExtensionAnalysis()
795 */
796 function getClassIndexLocallangFiles($absPath, $table_class_prefix, $extKey) {
797 $filesInside = t3lib_div::removePrefixPathFromList(t3lib_div::getAllFilesAndFoldersInPath(array(), $absPath, 'php,inc', 0, 99, $this->excludeForPackaging), $absPath);
798 $out = array();
799 $reg = array();
800
801 foreach ($filesInside as $fileName) {
802 if (substr($fileName, 0, 4) != 'ext_' && substr($fileName, 0, 6) != 'tests/') { // ignore supposed-to-be unit tests as well
803 $baseName = basename($fileName);
804 if (substr($baseName, 0, 9) == 'locallang' && substr($baseName, -4) == '.php') {
805 $out['locallang'][] = $fileName;
806 } elseif ($baseName != 'conf.php') {
807 if (filesize($absPath . $fileName) < 500 * 1024) {
808 $fContent = t3lib_div::getUrl($absPath . $fileName);
809 unset($reg);
810 if (preg_match('/\n[[:space:]]*class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/', $fContent, $reg)) {
811
812 // Find classes:
813 $lines = explode(LF, $fContent);
814 foreach ($lines as $l) {
815 $line = trim($l);
816 unset($reg);
817 if (preg_match('/^class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/', $line, $reg)) {
818 $out['classes'][] = $reg[1];
819 $out['files'][$fileName]['classes'][] = $reg[1];
820 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])) {
821 $out['NSerrors']['classname'][] = $reg[1];
822 } else {
823 $out['NSok']['classname'][] = $reg[1];
824 }
825 }
826 }
827 // If class file prefixed 'class.'....
828 if (substr($baseName, 0, 6) == 'class.') {
829 $fI = pathinfo($baseName);
830 $testName = substr($baseName, 6, -(1 + strlen($fI['extension'])));
831 if ($testName!=='ext_update' && substr($testName, 0, 3) != 'ux_' && !t3lib_div::isFirstPartOfStr($testName, $table_class_prefix) && strcmp(substr($table_class_prefix, 0, -1), $testName)) {
832 $out['NSerrors']['classfilename'][] = $baseName;
833 } else {
834 $out['NSok']['classfilename'][] = $baseName;
835 if (is_array($out['files'][$fileName]['classes']) && tx_em_Tools::first_in_array($testName, $out['files'][$fileName]['classes'], 1)) {
836 $out['msg'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_class_ok'),
837 $fileName, $testName
838 );
839 } else {
840 $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_class_not_ok'),
841 $fileName, $testName
842 );
843 }
844 }
845 }
846 // Check for proper XCLASS definition
847 // Match $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS'] with single or doublequotes
848 $XclassSearch = '\$TYPO3_CONF_VARS\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]';
849 $XclassParts = preg_split('/if \(defined\([\'"]TYPO3_MODE[\'"]\) && ' . $XclassSearch . '/', $fContent, 2);
850 if (count($XclassParts) !== 2) {
851 // Match $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS'] with single or doublequotes
852 $XclassSearch = '\$GLOBALS\[[\'"]TYPO3_CONF_VARS[\'"]\]\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]';
853 $XclassParts = preg_split('/if \(defined\([\'"]TYPO3_MODE[\'"]\) && ' . $XclassSearch . '/', $fContent, 2);
854 }
855 if (count($XclassParts) == 2) {
856 unset($reg);
857 preg_match('/^\[[\'"]([[:alnum:]_\/\.]*)[\'"]\]/', $XclassParts[1], $reg);
858 if ($reg[1]) {
859 $cmpF = 'ext/' . $extKey . '/' . $fileName;
860 if (!strcmp($reg[1], $cmpF)) {
861 if (preg_match('/_once[[:space:]]*\(' . $XclassSearch . '\[[\'"]' . preg_quote($cmpF, '/') . '[\'"]\]\);/', $XclassParts[1])) {
862 $out['msg'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_ok'), $fileName);
863 } else {
864 $out['errors'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_no_include');
865 }
866 } else {
867 $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_incorrect'),
868 $reg[1], $cmpF
869 );
870 }
871 } else {
872 $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_xclass_filename'), $fileName);
873 }
874 } elseif (!tx_em_Tools::first_in_array('ux_', $out['files'][$fileName]['classes'])) {
875 // No Xclass definition required if classname starts with 'ux_'
876 $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_xclass_found'), $fileName);
877 }
878 }
879 }
880 }
881 }
882 }
883 return $out;
884 }
885
886 /**
887 * Write new TYPO3_MOD_PATH to "conf.php" file.
888 *
889 * @param string Absolute path to a "conf.php" file of the backend module which we want to write back to.
890 * @param string Install scope type: L, G, S
891 * @param string Relative path for the module folder in extension
892 * @return string Returns message about the status.
893 * @see modConfFileAnalysis()
894 */
895 function writeTYPO3_MOD_PATH($confFilePath, $type, $mP) {
896 $lines = explode(LF, t3lib_div::getUrl($confFilePath));
897 $confFileInfo = array();
898 $confFileInfo['lines'] = $lines;
899 $reg = array();
900
901 $flag_M = 0;
902 $flag_B = 0;
903 $flag_Dispatch = 0;
904
905 foreach ($lines as $k => $l) {
906 $line = trim($l);
907
908 unset($reg);
909 if (preg_match('/^define[[:space:]]*\([[:space:]]*["\']TYPO3_MOD_PATH["\'][[:space:]]*,[[:space:]]*["\']([[:alnum:]_\/\.]+)["\'][[:space:]]*\)[[:space:]]*;/', $line, $reg)) {
910 $lines[$k] = str_replace($reg[0], 'define(\'TYPO3_MOD_PATH\', \'' . self::typeRelPath($type) . $mP . '\');', $lines[$k]);
911 $flag_M = $k + 1;
912 }
913
914 unset($reg);
915 if (preg_match('/^\$BACK_PATH[[:space:]]*=[[:space:]]*["\']([[:alnum:]_\/\.]+)["\'][[:space:]]*;/', $line, $reg)) {
916 $lines[$k] = str_replace($reg[0], '$BACK_PATH=\'' . self::typeRelPath($type) . '\';', $lines[$k]);
917 $flag_B = $k + 1;
918 }
919
920 // Check if this module uses new API (see http://bugs.typo3.org/view.php?id=5278)
921 // where TYPO3_MOD_PATH and BACK_PATH are not required
922 unset($reg);
923 if (preg_match('/^\$MCONF\[["\']script["\']\][[:space:]]*=[[:space:]]*["\']_DISPATCH["\'][[:space:]]*;/', $line, $reg)) {
924 $flag_Dispatch = $k + 1;
925 }
926
927 }
928
929 if ($flag_B && $flag_M) {
930 t3lib_div::writeFile($confFilePath, implode(LF, $lines));
931 return sprintf($GLOBALS['LANG']->getLL('writeModPath_ok'),
932 substr($confFilePath, strlen(PATH_site)));
933 } elseif ($flag_Dispatch) {
934 return sprintf(
935 $GLOBALS['LANG']->getLL('writeModPath_notRequired'),
936 substr($confFilePath, strlen(PATH_site))
937 );
938 } else {
939 return $GLOBALS["TBE_TEMPLATE"]->rfw(
940 sprintf($GLOBALS['LANG']->getLL('writeModPath_error'),
941 $confFilePath)
942 );
943 }
944 }
945
946 /**
947 * Wrapping input string in a link tag with link to email address
948 *
949 * @param string Input string, being wrapped in <a> tags
950 * @param string Email address for use in link.
951 * @return string Output
952 */
953 function wrapEmail($str, $email) {
954 if ($email) {
955 $str = '<a href="mailto:' . htmlspecialchars($email) . '">' . htmlspecialchars($str) . '</a>';
956 }
957 return $str;
958 }
959
960 /**
961 * red-fontwrap. Returns the string wrapped in a <span>-tag defining the color to be red
962 *
963 * @param string Input string
964 * @return string Output string
965 */
966 function rfw($string) {
967 return '<span class="typo3-red">' . $string . '</span>';
968 }
969
970 /**
971 * dimmed-fontwrap. Returns the string wrapped in a <span>-tag defining the color to be gray/dimmed
972 *
973 * @param string Input string
974 * @return string Output string
975 */
976 function dfw($string) {
977 return '<span class="typo3-dimmed">' . $string . '</span>';
978 }
979 }
980
981 ?>