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