TYPO3 API  SVNRelease
class.tx_em_tools.php
Go to the documentation of this file.
00001 <?php
00002 /* **************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) webservices.nl
00006 *  (c) 2006-2010 Karsten Dambekalns <karsten@typo3.org>
00007 *  All rights reserved
00008 *
00009 *  This script is part of the TYPO3 project. The TYPO3 project is
00010 *  free software; you can redistribute it and/or modify
00011 *  it under the terms of the GNU General Public License as published by
00012 *  the Free Software Foundation; either version 2 of the License, or
00013 *  (at your option) any later version.
00014 *
00015 *  The GNU General Public License can be found at
00016 *  http://www.gnu.org/copyleft/gpl.html.
00017 *  A copy is found in the textfile GPL.txt and important notices to the license
00018 *  from the author is found in LICENSE.txt distributed with these scripts.
00019 *
00020 *
00021 *  This script is distributed in the hope that it will be useful,
00022 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00023 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024 *  GNU General Public License for more details.
00025 *
00026 *  This copyright notice MUST APPEAR in all copies of the script!
00027 ***************************************************************/
00028 /**
00029  * class.tx_em_tools.php
00030  *
00031  * $Id: class.tx_em_tools.php 2084 2010-03-22 01:46:37Z steffenk $
00032  */
00033 
00034 /**
00035  * Static tools for extension manager
00036  * Some of them should be moved later to t3lib static libraries
00037  *
00038  */
00039 final class tx_em_Tools {
00040 
00041     /**
00042      * Keeps default categories.
00043      *
00044      * @var  array
00045      */
00046     protected static $defaultCategories = array(
00047         'be' => 0,
00048         'module' => 1,
00049         'fe' => 2,
00050         'plugin' => 3,
00051         'misc' => 4,
00052         'services' => 5,
00053         'templates' => 6,
00054         'doc' => 8,
00055         'example' => 9,
00056     );
00057     /**
00058      * Keeps default states.
00059      *
00060      * @var  array
00061      */
00062     protected static $defaultStates = array(
00063         'alpha' => 0,
00064         'beta' => 1,
00065         'stable' => 2,
00066         'experimental' => 3,
00067         'test' => 4,
00068         'obsolete' => 5,
00069         'excludeFromUpdates' => 6,
00070         'n/a' => 999,
00071     );
00072 
00073     /**
00074      * Colors for states
00075      *
00076      * @var array
00077      */
00078     protected static $stateColors = array(
00079         'alpha' => '#d12438',
00080         'beta' => '#97b17e',
00081         'stable' => '#3bb65c',
00082         'experimental' => '#007eba',
00083         'test' => '#979797',
00084         'obsolete' => '#000000',
00085         'excludeFromUpdates' => '#cf7307'
00086     );
00087 
00088     /**
00089      * Gets the stateColor array
00090      *
00091      * @static
00092      * @return array
00093      */
00094     public static function getStateColors() {
00095         return self::$stateColors;
00096     }
00097 
00098     /**
00099      * Unzips a zip file in the given path.
00100      *
00101      * Uses unzip binary if available, otherwise a pure PHP unzip is used.
00102      *
00103      * @param string $file      Full path to zip file
00104      * @param string $path      Path to change to before extracting
00105      * @return boolean  True on success, false in failure
00106      */
00107     public static function unzip($file, $path) {
00108         if (strlen($GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'])) {
00109             chdir($path);
00110             $cmd = $GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'] . ' -o ' . escapeshellarg($file);
00111             t3lib_utility_Command::exec($cmd, $list, $ret);
00112             return ($ret === 0);
00113         } else {
00114                 // we use a pure PHP unzip
00115             $unzip = t3lib_div::makeInstance('tx_em_Tools_Unzip', $file);
00116             $ret = $unzip->extract(array('add_path' => $path));
00117             return (is_array($ret));
00118         }
00119     }
00120 
00121 
00122     /**
00123      * Refreshes the global extension list
00124      *
00125      * @return void
00126      */
00127     public static function refreshGlobalExtList() {
00128         global $TYPO3_LOADED_EXT;
00129 
00130         $TYPO3_LOADED_EXT = t3lib_extMgm::typo3_loadExtensions();
00131         if ($TYPO3_LOADED_EXT['_CACHEFILE']) {
00132             require(PATH_typo3conf . $TYPO3_LOADED_EXT['_CACHEFILE'] . '_ext_localconf.php');
00133         }
00134         return;
00135 
00136         $GLOBALS['TYPO3_LOADED_EXT'] = t3lib_extMgm::typo3_loadExtensions();
00137         if ($TYPO3_LOADED_EXT['_CACHEFILE']) {
00138             require(PATH_typo3conf . $TYPO3_LOADED_EXT['_CACHEFILE'] . '_ext_localconf.php');
00139         } else {
00140             $temp_TYPO3_LOADED_EXT = $TYPO3_LOADED_EXT;
00141             foreach ($temp_TYPO3_LOADED_EXT as $_EXTKEY => $temp_lEDat) {
00142                 if (is_array($temp_lEDat) && $temp_lEDat['ext_localconf.php']) {
00143                     $_EXTCONF = $GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][$_EXTKEY];
00144                     require($temp_lEDat['ext_localconf.php']);
00145                 }
00146             }
00147         }
00148     }
00149 
00150     /**
00151      * Set category array entries for extension
00152      *
00153      * @param   array       Category index array
00154      * @param   array       Part of list array for extension.
00155      * @param   string      Extension key
00156      * @return  array       Modified category index array
00157      */
00158     public static function setCat(&$cat, $listArrayPart, $extKey) {
00159 
00160             // Getting extension title:
00161         $extTitle = $listArrayPart['EM_CONF']['title'];
00162 
00163             // Category index:
00164         $index = $listArrayPart['EM_CONF']['category'];
00165         $cat['cat'][$index][$extKey] = $extTitle;
00166 
00167             // Author index:
00168         $index = $listArrayPart['EM_CONF']['author'] . ($listArrayPart['EM_CONF']['author_company'] ? ', ' . $listArrayPart['EM_CONF']['author_company'] : '');
00169         $cat['author_company'][$index][$extKey] = $extTitle;
00170 
00171             // State index:
00172         $index = $listArrayPart['EM_CONF']['state'];
00173         $cat['state'][$index][$extKey] = $extTitle;
00174 
00175             // Type index:
00176         $index = $listArrayPart['type'];
00177         $cat['type'][$index][$extKey] = $extTitle;
00178 
00179             // Return categories:
00180         return $cat;
00181     }
00182 
00183     /**
00184      * Returns upload folder for extension
00185      *
00186      * @param   string      Extension key
00187      * @return  string      Upload folder for extension
00188      */
00189     public static function uploadFolder($extKey) {
00190         return 'uploads/tx_' . str_replace('_', '', $extKey) . '/';
00191     }
00192 
00193 
00194     /**
00195      * Returns image tag for "uninstall"
00196      *
00197      * @return  string      <img> tag
00198      */
00199     public static function removeButton() {
00200         return t3lib_iconWorks::getSpriteIcon('actions-system-extension-uninstall', array('title' => $GLOBALS['LANG']->getLL('ext_details_remove_ext')));
00201     }
00202 
00203     /**
00204      * Returns image for "install"
00205      *
00206      * @return  string      <img> tag
00207      */
00208     public static function installButton() {
00209         return t3lib_iconWorks::getSpriteIcon('actions-system-extension-install', array('title' => $GLOBALS['LANG']->getLL('helperFunction_install_extension')));
00210     }
00211 
00212     /**
00213      * Warning (<img> + text string) message about the impossibility to import extensions (both local and global locations are disabled...)
00214      *
00215      * @return  string      <img> + text string.
00216      */
00217     public static function noImportMsg() {
00218         return t3lib_iconWorks::getSpriteIcon('status-dialog-warning') .
00219                '<strong>' . $GLOBALS['LANG']->getLL('helperFunction_import_not_possible') . '</strong>';
00220     }
00221 
00222 
00223     /**
00224      * Fixes an old style ext_emconf.php array by adding constraints if needed and removing deprecated keys
00225      *
00226      * @param   array       $emConf
00227      * @return  array
00228      */
00229     public static function fixEMCONF($emConf) {
00230         if (!isset($emConf['constraints']) || !isset($emConf['constraints']['depends']) || !isset($emConf['constraints']['conflicts']) || !isset($emConf['constraints']['suggests'])) {
00231             if (!isset($emConf['constraints']) || !isset($emConf['constraints']['depends'])) {
00232                 $emConf['constraints']['depends'] = self::stringToDep($emConf['dependencies']);
00233                 if (strlen($emConf['PHP_version'])) {
00234                     $versionRange = self::splitVersionRange($emConf['PHP_version']);
00235                     if (version_compare($versionRange[0], '3.0.0', '<')) {
00236                         $versionRange[0] = '3.0.0';
00237                     }
00238                     if (version_compare($versionRange[1], '3.0.0', '<')) {
00239                         $versionRange[1] = '0.0.0';
00240                     }
00241                     $emConf['constraints']['depends']['php'] = implode('-', $versionRange);
00242                 }
00243                 if (strlen($emConf['TYPO3_version'])) {
00244                     $versionRange = self::splitVersionRange($emConf['TYPO3_version']);
00245                     if (version_compare($versionRange[0], '3.5.0', '<')) {
00246                         $versionRange[0] = '3.5.0';
00247                     }
00248                     if (version_compare($versionRange[1], '3.5.0', '<')) {
00249                         $versionRange[1] = '0.0.0';
00250                     }
00251                     $emConf['constraints']['depends']['typo3'] = implode('-', $versionRange);
00252                 }
00253             }
00254             if (!isset($emConf['constraints']) || !isset($emConf['constraints']['conflicts'])) {
00255                 $emConf['constraints']['conflicts'] = self::stringToDep($emConf['conflicts']);
00256             }
00257             if (!isset($emConf['constraints']) || !isset($emConf['constraints']['suggests'])) {
00258                 $emConf['constraints']['suggests'] = array();
00259             }
00260         } elseif (isset($emConf['constraints']) && isset($emConf['dependencies'])) {
00261             $emConf['suggests'] = isset($emConf['suggests']) ? $emConf['suggests'] : array();
00262             $emConf['dependencies'] = self::depToString($emConf['constraints']);
00263             $emConf['conflicts'] = self::depToString($emConf['constraints'], 'conflicts');
00264         }
00265 
00266             // sanity check for version numbers, intentionally only checks php and typo3
00267         if (isset($emConf['constraints']['depends']) && isset($emConf['constraints']['depends']['php'])) {
00268             $versionRange = self::splitVersionRange($emConf['constraints']['depends']['php']);
00269             if (version_compare($versionRange[0], '3.0.0', '<')) {
00270                 $versionRange[0] = '3.0.0';
00271             }
00272             if (version_compare($versionRange[1], '3.0.0', '<')) {
00273                 $versionRange[1] = '0.0.0';
00274             }
00275             $emConf['constraints']['depends']['php'] = implode('-', $versionRange);
00276         }
00277         if (isset($emConf['constraints']['depends']) && isset($emConf['constraints']['depends']['typo3'])) {
00278             $versionRange = self::splitVersionRange($emConf['constraints']['depends']['typo3']);
00279             if (version_compare($versionRange[0], '3.5.0', '<')) {
00280                 $versionRange[0] = '3.5.0';
00281             }
00282             if (version_compare($versionRange[1], '3.5.0', '<')) {
00283                 $versionRange[1] = '0.0.0';
00284             }
00285             $emConf['constraints']['depends']['typo3'] = implode('-', $versionRange);
00286         }
00287 
00288         unset($emConf['private']);
00289         unset($emConf['download_password']);
00290         unset($emConf['TYPO3_version']);
00291         unset($emConf['PHP_version']);
00292 
00293         return $emConf;
00294     }
00295 
00296 
00297     /**
00298      * Returns the $EM_CONF array from an extensions ext_emconf.php file
00299      *
00300      * @param   string      Absolute path to EMCONF file.
00301      * @param   string      Extension key.
00302      * @return  array       EMconf array values.
00303      */
00304     public static function includeEMCONF($path, $_EXTKEY) {
00305         $EM_CONF = NULL;
00306         @include($path);
00307         if (is_array($EM_CONF[$_EXTKEY])) {
00308             return self::fixEMCONF($EM_CONF[$_EXTKEY]);
00309         }
00310         return FALSE;
00311     }
00312 
00313 
00314     /**
00315      * Extracts the directories in the $files array
00316      *
00317      * @param   array       Array of files / directories
00318      * @return  array       Array of directories from the input array.
00319      */
00320     public static function extractDirsFromFileList($files) {
00321         $dirs = array();
00322 
00323         if (is_array($files)) {
00324                 // Traverse files / directories array:
00325             foreach ($files as $file) {
00326                 if (substr($file, -1) == '/') {
00327                     $dirs[$file] = $file;
00328                 } else {
00329                     $pI = pathinfo($file);
00330                     if (strcmp($pI['dirname'], '') && strcmp($pI['dirname'], '.')) {
00331                         $dirs[$pI['dirname'] . '/'] = $pI['dirname'] . '/';
00332                     }
00333                 }
00334             }
00335         }
00336         return $dirs;
00337     }
00338 
00339     /**
00340      * Splits a version range into an array.
00341      *
00342      * If a single version number is given, it is considered a minimum value.
00343      * If a dash is found, the numbers left and right are considered as minimum and maximum. Empty values are allowed.
00344      *
00345      * @param   string      $ver A string with a version range.
00346      * @return  array
00347      */
00348     public static function splitVersionRange($ver) {
00349         $versionRange = array();
00350         if (strstr($ver, '-')) {
00351             $versionRange = explode('-', $ver, 2);
00352         } else {
00353             $versionRange[0] = $ver;
00354             $versionRange[1] = '';
00355         }
00356 
00357         if (!$versionRange[0]) {
00358             $versionRange[0] = '0.0.0';
00359         }
00360         if (!$versionRange[1]) {
00361             $versionRange[1] = '0.0.0';
00362         }
00363 
00364         return $versionRange;
00365     }
00366 
00367     /**
00368      * Checks whether the passed dependency is TER2-style (array) and returns a single string for displaying the dependencies.
00369      *
00370      * It leaves out all version numbers and the "php" and "typo3" dependencies, as they are implicit and of no interest without the version number.
00371      *
00372      * @param   mixed       $dep Either a string or an array listing dependencies.
00373      * @param   string      $type The dependency type to list if $dep is an array
00374      * @return  string      A simple dependency list for display
00375      */
00376     public static function depToString($dep, $type = 'depends') {
00377         if (is_array($dep)) {
00378             unset($dep[$type]['php']);
00379             unset($dep[$type]['typo3']);
00380             $s = (count($dep[$type])) ? implode(',', array_keys($dep[$type])) : '';
00381             return $s;
00382         }
00383         return '';
00384     }
00385 
00386     /**
00387      * Checks whether the passed dependency is TER-style (string) or TER2-style (array) and returns a single string for displaying the dependencies.
00388      *
00389      * It leaves out all version numbers and the "php" and "typo3" dependencies, as they are implicit and of no interest without the version number.
00390      *
00391      * @param   mixed       $dep Either a string or an array listing dependencies.
00392      * @param   string      $type The dependency type to list if $dep is an array
00393      * @return  string      A simple dependency list for display
00394      */
00395     public static function stringToDep($dep) {
00396         $constraint = array();
00397         if (is_string($dep) && strlen($dep)) {
00398             $dep = explode(',', $dep);
00399             foreach ($dep as $v) {
00400                 $constraint[$v] = '';
00401             }
00402         }
00403         return $constraint;
00404     }
00405 
00406 
00407     /**
00408      * Returns version information
00409      *
00410      * @param   string      Version code, x.x.x
00411      * @param   string      part: "", "int", "main", "sub", "dev"
00412      * @return  string
00413      * @see renderVersion()
00414      */
00415     public static function makeVersion($v, $mode) {
00416         $vDat = self::renderVersion($v);
00417         return $vDat['version_' . $mode];
00418     }
00419 
00420     /**
00421      * Parses the version number x.x.x and returns an array with the various parts.
00422      *
00423      * @param   string      Version code, x.x.x
00424      * @param   string      Increase version part: "main", "sub", "dev"
00425      * @return  string
00426      */
00427     public static function renderVersion($v, $raise = '') {
00428         $parts = t3lib_div::intExplode('.', $v . '..');
00429         $parts[0] = t3lib_div::intInRange($parts[0], 0, 999);
00430         $parts[1] = t3lib_div::intInRange($parts[1], 0, 999);
00431         $parts[2] = t3lib_div::intInRange($parts[2], 0, 999);
00432 
00433         switch ((string) $raise) {
00434             case 'main':
00435                 $parts[0]++;
00436                 $parts[1] = 0;
00437                 $parts[2] = 0;
00438                 break;
00439             case 'sub':
00440                 $parts[1]++;
00441                 $parts[2] = 0;
00442                 break;
00443             case 'dev':
00444                 $parts[2]++;
00445                 break;
00446         }
00447 
00448         $res = array();
00449         $res['version'] = $parts[0] . '.' . $parts[1] . '.' . $parts[2];
00450         $res['version_int'] = intval($parts[0] * 1000000 + $parts[1] * 1000 + $parts[2]);
00451         $res['version_main'] = $parts[0];
00452         $res['version_sub'] = $parts[1];
00453         $res['version_dev'] = $parts[2];
00454 
00455         return $res;
00456     }
00457 
00458     /**
00459      * Render version from intVersion
00460      *
00461      * @static
00462      * @param  int  $intVersion
00463      * @return string version
00464      */
00465     public static function versionFromInt($intVersion) {
00466         $versionString = str_pad($intVersion, 9, '0', STR_PAD_LEFT);
00467         $parts = array(
00468             substr($versionString, 0, 3),
00469             substr($versionString, 3, 3),
00470             substr($versionString, 6, 3)
00471         );
00472         return intval($parts[0]) . '.' . intval($parts[1]) . '.' . intval($parts[2]);
00473     }
00474 
00475     /**
00476      * Evaluates differences in version numbers with three parts, x.x.x. Returns true if $v1 is greater than $v2
00477      *
00478      * @param   string      Version number 1
00479      * @param   string      Version number 2
00480      * @param   integer     Tolerance factor. For instance, set to 1000 to ignore difference in dev-version (third part)
00481      * @return  boolean     True if version 1 is greater than version 2
00482      */
00483     public static function versionDifference($v1, $v2, $div = 1) {
00484         return floor(self::makeVersion($v1, 'int') / $div) > floor(self::makeVersion($v2, 'int') / $div);
00485     }
00486 
00487 
00488     /**
00489      * Returns true if the $str is found as the first part of a string in $array
00490      *
00491      * @param   string      String to test with.
00492      * @param   array       Input array
00493      * @param   boolean     If set, the test is case insensitive
00494      * @return  boolean     True if found.
00495      */
00496     public static function first_in_array($str, $array, $caseInsensitive = FALSE) {
00497         if ($caseInsensitive) {
00498             $str = strtolower($str);
00499         }
00500         if (is_array($array)) {
00501             foreach ($array as $cl) {
00502                 if ($caseInsensitive) {
00503                     $cl = strtolower($cl);
00504                 }
00505                 if (t3lib_div::isFirstPartOfStr($cl, $str)) {
00506                     return TRUE;
00507                 }
00508             }
00509         }
00510         return FALSE;
00511     }
00512 
00513     /**
00514      * Compares two arrays with MD5-hash values for analysis of which files has changed.
00515      *
00516      * @param   array       Current values
00517      * @param   array       Past values
00518      * @return  array       Affected files
00519      */
00520     public static function findMD5ArrayDiff($current, $past) {
00521         if (!is_array($current)) {
00522             $current = array();
00523         }
00524         if (!is_array($past)) {
00525             $past = array();
00526         }
00527         $filesInCommon = array_intersect($current, $past);
00528         $diff1 = array_keys(array_diff($past, $filesInCommon));
00529         $diff2 = array_keys(array_diff($current, $filesInCommon));
00530         $affectedFiles = array_unique(array_merge($diff1, $diff2));
00531         return $affectedFiles;
00532     }
00533 
00534     /**
00535      * Returns title and style attribute for mouseover help text.
00536      *
00537      * @param   string      Help text.
00538      * @return  string      title="" attribute prepended with a single space
00539      */
00540     public static function labelInfo($str) {
00541         return ' title="' . htmlspecialchars($str) . '" style="cursor:help;"';
00542     }
00543 
00544 
00545     /**
00546      * Returns the absolute path where the extension $extKey is installed (based on 'type' (SGL))
00547      *
00548      * @param   string      Extension key
00549      * @param   string      Install scope type: L, G, S
00550      * @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.
00551      */
00552     public static function getExtPath($extKey, $type, $returnWithoutExtKey = FALSE) {
00553         $typePath = self::typePath($type);
00554 
00555         if ($typePath) {
00556             $path = $typePath . ($returnWithoutExtKey ? '' : $extKey . '/');
00557             return $path; # @is_dir($path) ? $path : '';
00558         } else {
00559             return '';
00560         }
00561     }
00562 
00563     /**
00564      * Get type of extension (G,S,L) from extension path
00565      *
00566      * @param string $path
00567      */
00568     public static function getExtTypeFromPath($path) {
00569         if (strpos($path, TYPO3_mainDir . 'sysext/') !== FALSE) {
00570             return 'S';
00571         } elseif (strpos($path, TYPO3_mainDir . 'ext/') !== FALSE) {
00572             return 'G';
00573         } elseif (strpos($path, 'typo3conf/ext/') !== FALSE) {
00574             return 'L';
00575         }
00576     }
00577 
00578     /**
00579      * Get path from type
00580      *
00581      * @param string $type S/G/L
00582      */
00583     public static function typePath($type) {
00584         if ($type === 'S') {
00585             return PATH_typo3 . 'sysext/';
00586         } elseif ($type === 'G') {
00587             return PATH_typo3 . 'ext/';
00588         } elseif ($type === 'L') {
00589             return PATH_typo3conf . 'ext/';
00590         }
00591     }
00592 
00593     /**
00594      * Get relative path from type
00595      *
00596      * @param string $type S/G/L
00597      */
00598     public static function typeRelPath($type) {
00599         if ($type === 'S') {
00600             return 'sysext/';
00601         } elseif ($type === 'G') {
00602             return 'ext/';
00603         } elseif ($type === 'L') {
00604             return '../typo3conf/ext/';
00605         }
00606     }
00607 
00608     /**
00609      * Get backpath from type
00610      *
00611      * @param string $type S/G/L
00612      */
00613     public static function typeBackPath($type) {
00614         if ($type === 'L') {
00615             return '../../../../' . TYPO3_mainDir;
00616         } else {
00617             return '../../../';
00618         }
00619     }
00620 
00621     /**
00622      * Reads locallang file into array (for possible include in header)
00623      *
00624      * @param $file
00625      * @return array
00626      * @deprecated  since TYPO3 4.5.1, will be removed in TYPO3 4.7 - use pageRenderer->addInlineLanguageLabelFile() instead
00627      */
00628     public static function getArrayFromLocallang($file, $key = 'default') {
00629         $content = t3lib_div::getURL($file);
00630         $array = t3lib_div::xml2array($content);
00631 
00632         return $array['data'][$key];
00633     }
00634 
00635     /**
00636      * Include a locallang file and return the $LOCAL_LANG array serialized.
00637      *
00638      * @param   string      Absolute path to locallang file to include.
00639      * @param   string      Old content of a locallang file (keeping the header content)
00640      * @return  array       Array with header/content as key 0/1
00641      * @see makeUploadarray()
00642      */
00643     public static function getSerializedLocalLang($file, $content) {
00644         $LOCAL_LANG = NULL;
00645         $returnParts = explode('$LOCAL_LANG', $content, 2);
00646 
00647         include($file);
00648         if (is_array($LOCAL_LANG)) {
00649             $returnParts[1] = serialize($LOCAL_LANG);
00650             return $returnParts;
00651         } else {
00652             return array();
00653         }
00654     }
00655 
00656 
00657     /**
00658      * Enter description here...
00659      *
00660      * @param   unknown_type        $array
00661      * @param   unknown_type        $lines
00662      * @param   unknown_type        $level
00663      * @return  unknown
00664      */
00665     public static function arrayToCode($array, $level = 0) {
00666         $lines = 'array(' . LF;
00667         $level++;
00668         foreach ($array as $k => $v) {
00669             if (strlen($k) && is_array($v)) {
00670                 $lines .= str_repeat(TAB, $level) . "'" . $k . "' => " . self::arrayToCode($v, $level);
00671             } elseif (strlen($k)) {
00672                 $lines .= str_repeat(TAB, $level) . "'" . $k . "' => " . (t3lib_div::testInt($v) ? intval($v) : "'" . t3lib_div::slashJS(trim($v), 1) . "'") . ',' . LF;
00673             }
00674         }
00675 
00676         $lines .= str_repeat(TAB, $level - 1) . ')' . ($level - 1 == 0 ? '' : ',' . LF);
00677         return $lines;
00678     }
00679 
00680 
00681     /**
00682      * Traverse the array of installed extensions keys and arranges extensions in the priority order they should be in
00683      *
00684      * @param   array       Array of extension keys as values
00685      * @param   array       Extension information array
00686      * @return  array       Modified array of extention keys as values
00687      * @see addExtToList()
00688      */
00689     public static function managesPriorities($listArr, $instExtInfo) {
00690 
00691             // Initialize:
00692         $levels = array(
00693             'top' => array(),
00694             'middle' => array(),
00695             'bottom' => array(),
00696         );
00697 
00698             // Traverse list of extensions:
00699         foreach ($listArr as $ext) {
00700             $prio = trim($instExtInfo[$ext]['EM_CONF']['priority']);
00701             switch ((string) $prio) {
00702                 case 'top':
00703                 case 'bottom':
00704                     $levels[$prio][] = $ext;
00705                     break;
00706                 default:
00707                     $levels['middle'][] = $ext;
00708                     break;
00709             }
00710         }
00711         return array_merge(
00712             $levels['top'],
00713             $levels['middle'],
00714             $levels['bottom']
00715         );
00716     }
00717 
00718 
00719     /**
00720      * Returns either array with all default categories or index/title
00721      * of a category entry.
00722      *
00723      * @access  public
00724      * @param   mixed   $cat  category title or category index
00725      * @return  mixed
00726      */
00727     public static function getDefaultCategory($cat = NULL) {
00728         if (is_null($cat)) {
00729             return self::$defaultCategories;
00730         } else {
00731             if (is_string($cat)) {
00732                     // default category
00733                 $catIndex = 4;
00734                 if (array_key_exists(strtolower($cat), self::$defaultCategories)) {
00735                     $catIndex = self::$defaultCategories[strtolower($cat)];
00736                 }
00737                 return $catIndex;
00738             } else {
00739                 if (is_int($cat) && $cat >= 0) {
00740                     $catTitle = array_search($cat, self::$defaultCategories);
00741                         // default category
00742                     if (!$catTitle) {
00743                         $catTitle = 'misc';
00744                     }
00745                     return $catTitle;
00746                 }
00747             }
00748         }
00749     }
00750 
00751     /**
00752      * Returns either array with all default states or index/title
00753      * of a state entry.
00754      *
00755      * @access  public
00756      * @param   mixed   $state  state title or state index
00757      * @return  mixed
00758      */
00759     public static function getDefaultState($state = NULL) {
00760         if (is_null($state)) {
00761             return self::$defaultStates;
00762         } else {
00763             if (is_string($state)) {
00764                     // default state
00765                 $stateIndex = 999;
00766                 if (array_key_exists(strtolower($state), self::$defaultStates)) {
00767                     $stateIndex = self::$defaultStates[strtolower($state)];
00768                 }
00769                 return $stateIndex;
00770             } else {
00771                 if (is_int($state) && $state >= 0) {
00772                     $stateTitle = array_search($state, self::$defaultStates);
00773                         // default state
00774                     if (!$stateTitle) {
00775                         $stateTitle = 'n/a';
00776                     }
00777                     return $stateTitle;
00778                 }
00779             }
00780         }
00781     }
00782 
00783     /**
00784      * Extension States
00785      * Content must be redundant with the same internal variable as in class.tx_extrep.php!
00786      *
00787      * @static
00788      * @return array
00789      */
00790     public static function getStates() {
00791         return array(
00792             'alpha' => $GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:state_alpha'),
00793             'beta' => $GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:state_beta'),
00794             'stable' => $GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:state_stable'),
00795             'experimental' => $GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:state_experimental'),
00796             'test' => $GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:state_test'),
00797             'obsolete' => $GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:state_obsolete'),
00798             'excludeFromUpdates' => $GLOBALS['LANG']->sL('LLL:EXT:em/language/locallang.xml:state_exclude_from_updates')
00799         );
00800     }
00801 
00802     /**
00803      * Reports back if installation in a certain scope is possible.
00804      *
00805      * @param   string      Scope: G, L, S
00806      * @param   string      Extension lock-type (eg. "L" or "G")
00807      * @return  boolean     True if installation is allowed.
00808      */
00809     public static function importAsType($type, $lockType = '') {
00810         switch ($type) {
00811             case 'G':
00812                 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall'] && (!$lockType || !strcmp($lockType, $type));
00813             break;
00814             case 'L':
00815                 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall'] && (!$lockType || !strcmp($lockType, $type));
00816             break;
00817             case 'S':
00818                 return isset($GLOBALS['TYPO3_CONF_VARS']['EXT']['allowSystemInstall']) && $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowSystemInstall'];
00819             break;
00820             default:
00821                 return FALSE;
00822         }
00823     }
00824 
00825     /**
00826      * Returns true if extensions in scope, $type, can be deleted (or installed for that sake)
00827      *
00828      * @param   string      Scope: "G" or "L"
00829      * @return  boolean     True if possible.
00830      */
00831     public static function deleteAsType($type) {
00832         switch ($type) {
00833             case 'G':
00834                 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall'];
00835             break;
00836             case 'L':
00837                 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall'];
00838             break;
00839             default:
00840                 return FALSE;
00841         }
00842     }
00843 
00844 
00845     /**
00846      * Creates directories in $extDirPath
00847      *
00848      * @param   array       Array of directories to create relative to extDirPath, eg. "blabla", "blabla/blabla" etc...
00849      * @param   string      Absolute path to directory.
00850      * @return  mixed       Returns false on success or an error string
00851      */
00852     public static function createDirsInPath($dirs, $extDirPath) {
00853         if (is_array($dirs)) {
00854             foreach ($dirs as $dir) {
00855                 $error = t3lib_div::mkdir_deep($extDirPath, $dir);
00856                 if ($error) {
00857                     return $error;
00858                 }
00859             }
00860         }
00861 
00862         return FALSE;
00863     }
00864 
00865     /**
00866      * Analyses the php-scripts of an available extension on server
00867      *
00868      * @param   string      Absolute path to extension
00869      * @param   string      Prefix for tables/classes.
00870      * @param   string      Extension key
00871      * @return  array       Information array.
00872      * @see makeDetailedExtensionAnalysis()
00873      */
00874     public static function getClassIndexLocallangFiles($absPath, $table_class_prefix, $extKey) {
00875         $excludeForPackaging = $GLOBALS['TYPO3_CONF_VARS']['EXT']['excludeForPackaging'];
00876         $filesInside = t3lib_div::removePrefixPathFromList(t3lib_div::getAllFilesAndFoldersInPath(array(), $absPath, 'php,inc', 0, 99, $excludeForPackaging), $absPath);
00877         $out = array();
00878         $reg = array();
00879 
00880         foreach ($filesInside as $fileName) {
00881             if (substr($fileName, 0, 4) != 'ext_' && substr($fileName, 0, 6) != 'tests/') { // ignore supposed-to-be unit tests as well
00882                 $baseName = basename($fileName);
00883                 if (substr($baseName, 0, 9) == 'locallang' && substr($baseName, -4) == '.php') {
00884                     $out['locallang'][] = $fileName;
00885                 } elseif ($baseName != 'conf.php') {
00886                     if (filesize($absPath . $fileName) < 500 * 1024) {
00887                         $fContent = t3lib_div::getUrl($absPath . $fileName);
00888                         unset($reg);
00889                         if (preg_match('/\n[[:space:]]*class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/', $fContent, $reg)) {
00890 
00891                                 // Find classes:
00892                             $lines = explode(LF, $fContent);
00893                             foreach ($lines as $l) {
00894                                 $line = trim($l);
00895                                 unset($reg);
00896                                 if (preg_match('/^class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/', $line, $reg)) {
00897                                     $out['classes'][] = $reg[1];
00898                                     $out['files'][$fileName]['classes'][] = $reg[1];
00899                                     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])) {
00900                                         $out['NSerrors']['classname'][] = $reg[1];
00901                                     } else {
00902                                         $out['NSok']['classname'][] = $reg[1];
00903                                     }
00904                                 }
00905                             }
00906                                 // If class file prefixed 'class.'....
00907                             if (substr($baseName, 0, 6) == 'class.') {
00908                                 $fI = pathinfo($baseName);
00909                                 $testName = substr($baseName, 6, -(1 + strlen($fI['extension'])));
00910                                 if ($testName !== 'ext_update' && substr($testName, 0, 3) != 'ux_' && !t3lib_div::isFirstPartOfStr($testName, $table_class_prefix) && strcmp(substr($table_class_prefix, 0, -1), $testName)) {
00911                                     $out['NSerrors']['classfilename'][] = $baseName;
00912                                 } else {
00913                                     $out['NSok']['classfilename'][] = $baseName;
00914                                     if (is_array($out['files'][$fileName]['classes']) && tx_em_Tools::first_in_array($testName, $out['files'][$fileName]['classes'], 1)) {
00915                                         $out['msg'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_class_ok'),
00916                                                                 $fileName, $testName
00917                                         );
00918                                     } else {
00919                                         $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_class_not_ok'),
00920                                                                    $fileName, $testName
00921                                         );
00922                                     }
00923                                 }
00924                             }
00925                                 // Check for proper XCLASS definition
00926                                 // Match $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS'] with single or doublequotes
00927                             $XclassSearch = '\$TYPO3_CONF_VARS\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]';
00928                             $XclassParts = preg_split('/if \(defined\([\'"]TYPO3_MODE[\'"]\)(.*)' . $XclassSearch . '/', $fContent, 2);
00929                             if (count($XclassParts) !== 2) {
00930                                     // Match $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS'] with single or doublequotes
00931                                 $XclassSearch = '\$GLOBALS\[[\'"]TYPO3_CONF_VARS[\'"]\]\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]';
00932                                 $XclassParts = preg_split('/if \(defined\([\'"]TYPO3_MODE[\'"]\)(.*)' . $XclassSearch . '/', $fContent, 2);
00933                             }
00934 
00935                             if (count($XclassParts) == 2) {
00936                                 unset($reg);
00937                                 preg_match('/^\[[\'"]([[:alnum:]_\/\.]*)[\'"]\]/', $XclassParts[1], $reg);
00938                                 if ($reg[1]) {
00939                                     $cmpF = 'ext/' . $extKey . '/' . $fileName;
00940                                     if (!strcmp($reg[1], $cmpF)) {
00941                                         if (preg_match('/_once[[:space:]]*\(' . $XclassSearch . '\[[\'"]' . preg_quote($cmpF, '/') . '[\'"]\]\);/', $XclassParts[1])) {
00942                                             $out['msg'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_ok'), $fileName);
00943                                         } else {
00944                                             $out['errors'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_no_include');
00945                                         }
00946                                     } else {
00947                                         $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_incorrect'),
00948                                                                    $reg[1], $cmpF
00949                                         );
00950                                     }
00951                                 } else {
00952                                     $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_xclass_filename'), $fileName);
00953                                 }
00954                             } elseif (!tx_em_Tools::first_in_array('ux_', $out['files'][$fileName]['classes'])) {
00955                                     // No Xclass definition required if classname starts with 'ux_'
00956                                 $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_xclass_found'), $fileName);
00957                             }
00958                         }
00959                     }
00960                 }
00961             }
00962         }
00963         return $out;
00964     }
00965 
00966     /**
00967      * Write new TYPO3_MOD_PATH to "conf.php" file.
00968      *
00969      * @param   string      Absolute path to a "conf.php" file of the backend module which we want to write back to.
00970      * @param   string      Install scope type: L, G, S
00971      * @param   string      Relative path for the module folder in extension
00972      * @return  string      Returns message about the status.
00973      * @see modConfFileAnalysis()
00974      */
00975     public static function writeTYPO3_MOD_PATH($confFilePath, $type, $mP) {
00976         $lines = explode(LF, t3lib_div::getUrl($confFilePath));
00977         $confFileInfo = array();
00978         $confFileInfo['lines'] = $lines;
00979         $reg = array();
00980 
00981         $flag_M = 0;
00982         $flag_B = 0;
00983         $flag_Dispatch = 0;
00984 
00985         foreach ($lines as $k => $l) {
00986             $line = trim($l);
00987 
00988             unset($reg);
00989             if (preg_match('/^define[[:space:]]*\([[:space:]]*["\']TYPO3_MOD_PATH["\'][[:space:]]*,[[:space:]]*["\']([[:alnum:]_\/\.]+)["\'][[:space:]]*\)[[:space:]]*;/', $line, $reg)) {
00990                 $lines[$k] = str_replace($reg[0], 'define(\'TYPO3_MOD_PATH\', \'' . self::typeRelPath($type) . $mP . '\');', $lines[$k]);
00991                 $flag_M = $k + 1;
00992             }
00993 
00994             unset($reg);
00995             if (preg_match('/^\$BACK_PATH[[:space:]]*=[[:space:]]*["\']([[:alnum:]_\/\.]+)["\'][[:space:]]*;/', $line, $reg)) {
00996                 $lines[$k] = str_replace($reg[0], '$BACK_PATH=\'' . self::typeBackPath($type) . '\';', $lines[$k]);
00997                 $flag_B = $k + 1;
00998             }
00999 
01000                 // Check if this module uses new API (see http://bugs.typo3.org/view.php?id=5278)
01001                 // where TYPO3_MOD_PATH and BACK_PATH are not required
01002             unset($reg);
01003             if (preg_match('/^\$MCONF\[["\']script["\']\][[:space:]]*=[[:space:]]*["\']_DISPATCH["\'][[:space:]]*;/', $line, $reg)) {
01004                 $flag_Dispatch = $k + 1;
01005             }
01006 
01007         }
01008 
01009         if ($flag_B && $flag_M) {
01010             t3lib_div::writeFile($confFilePath, implode(LF, $lines));
01011             return sprintf($GLOBALS['LANG']->getLL('writeModPath_ok'),
01012                            substr($confFilePath, strlen(PATH_site)));
01013         } elseif ($flag_Dispatch) {
01014             return sprintf(
01015                 $GLOBALS['LANG']->getLL('writeModPath_notRequired'),
01016                 substr($confFilePath, strlen(PATH_site))
01017             );
01018         } else {
01019             return self::rfw(
01020                 sprintf($GLOBALS['LANG']->getLL('writeModPath_error'),
01021                         $confFilePath)
01022             );
01023         }
01024     }
01025 
01026     /**
01027      * Sends content of file for download
01028      *
01029      * @static
01030      * @param  $path
01031      * @return void
01032      */
01033     public static function sendFile($path) {
01034         $path = t3lib_div::resolveBackPath(PATH_site . $path);
01035 
01036         if (is_file($path) && is_readable($path) && t3lib_div::isAllowedAbsPath($path)) {
01037             header('Content-Type: application/octet-stream');
01038             header('Content-Disposition: attachment; filename=' . basename($path));
01039             readfile($path);
01040             exit;
01041         }
01042     }
01043 
01044     /**
01045      * Rename a file / folder
01046      * @static
01047      * @param  $file
01048      * @param  $newName
01049      * @return bool
01050      */
01051     public static function renameFile($file, $newName) {
01052         if($file[0] == '/') {
01053             $file = substr($file, 1);
01054         }
01055         if($newName[0] == '/') {
01056             $newName = substr($newName, 1);
01057         }
01058 
01059         $file = t3lib_div::resolveBackPath(PATH_site . $file);
01060         $newName = t3lib_div::resolveBackPath(PATH_site . $newName);
01061         if (is_writable($file) && t3lib_div::isAllowedAbsPath($file) && t3lib_div::isAllowedAbsPath($newName)) {
01062             return rename($file, $newName);
01063         }
01064 
01065         return false;
01066     }
01067 
01068 
01069     /**
01070      * Creates a new file
01071      *
01072      * Returns an array with
01073      * 0: boolean success
01074      * 1: string absolute path of written file/folder
01075      * 2: error code
01076      *
01077      * The error code returns
01078      * 0: no error
01079      * -1: not writable
01080      * -2: not allowed path
01081      * -3: already exists
01082      * -4: not able to create
01083      *
01084      * @static
01085      * @param  $folder
01086      * @param  $file
01087      * @param  $isFolder
01088      * @return array
01089      */
01090     public static function createNewFile($folder, $file, $isFolder) {
01091         $success = FALSE;
01092         $error = 0;
01093 
01094         if (substr($folder, -1) !== '/') {
01095             $folder .= '/';
01096         }
01097 
01098 
01099         $newFile = t3lib_div::resolveBackPath(PATH_site . $folder . $file);
01100 
01101         if (!is_writable(dirname($newFile))) {
01102             $error = -1;
01103         } elseif (!t3lib_div::isAllowedAbsPath($newFile)) {
01104             $error = -2;
01105         } elseif (file_exists($newFile)) {
01106             $error = -3;
01107         } else {
01108             if ($isFolder) {
01109                 $success = t3lib_div::mkdir($newFile);
01110             } else {
01111                 $success = t3lib_div::writeFile($newFile, '');
01112             }
01113 
01114             if (!$success) {
01115                 $error = -4;
01116             }
01117         }
01118 
01119         return array(
01120             $success,
01121             $newFile,
01122             $error
01123         );
01124     }
01125 
01126 
01127     /**
01128      * Wrapping input string in a link tag with link to email address
01129      *
01130      * @param   string      Input string, being wrapped in <a> tags
01131      * @param   string      Email address for use in link.
01132      * @return  string      Output
01133      */
01134     public static function wrapEmail($str, $email) {
01135         if ($email) {
01136             $str = '<a href="mailto:' . htmlspecialchars($email) . '">' . htmlspecialchars($str) . '</a>';
01137         }
01138         return $str;
01139     }
01140 
01141     /**
01142      * red-fontwrap. Returns the string wrapped in a <span>-tag defining the color to be red
01143      *
01144      * @param   string      Input string
01145      * @return  string      Output string
01146      */
01147     public static function rfw($string) {
01148         return '<span class="typo3-red">' . $string . '</span>';
01149     }
01150 
01151     /**
01152      * dimmed-fontwrap. Returns the string wrapped in a <span>-tag defining the color to be gray/dimmed
01153      *
01154      * @param   string      Input string
01155      * @return  string      Output string
01156      */
01157     public static function dfw($string) {
01158         return '<span class="typo3-dimmed">' . $string . '</span>';
01159     }
01160 }
01161 
01162 ?>