Index: t3lib/class.t3lib_extmgm.php =================================================================== --- t3lib/class.t3lib_extmgm.php (révision 9198) +++ t3lib/class.t3lib_extmgm.php (copie de travail) @@ -231,6 +231,184 @@ } /** + * Gets the information array for an extension, eg. version and most-recently-edited-script + * The following keys are added : + * 'manual' tells if the extension has a manual file. + * 'filesHash' gives an array containing the md5 checksums of the files and the file names + * @param string Extension key + * @return array / string Information array if successfull + * error text if an error occured + */ + static public function getExtensionInfo($extkey) { + + if (!is_string($extkey) || empty($extkey)) { + throw new InvalidArgumentException('Extension key must be a non-empty string.'); + } + if (!self::isLoaded($extkey)) { + return 'Error: Extension ' . $extkey . ' has not been installed. (t3lib_extMgm::getExtensionInfo)'; + } + + $result = ''; + $path = self::extPath($extkey); + $file = $path . '/ext_emconf.php'; + if (@is_file($file)) { + $_EXTKEY = $extkey; + $EM_CONF = array(); + include($file); + + $info = array(); + // types of the keys of the extension information array: t ... text, a ... array + $keyTypeArray = array ('title' => 't', 'author' => 't', 'author_email' => 't', + 'author_company' => 't', 'version' => 't', 'CGLcompliance' => 't', + 'CGLcompliance_note' => 't', 'excludeXCLASScheck' => 'a', + '_md5_values_when_last_written' => 't', 'TYPO3_version' => 't' + ); + // copy info from emconf: + foreach ($keyTypeArray as $key => $type) { + if ( + isset($EM_CONF[$extkey][$key]) + && ($type == 't' || is_array($EM_CONF[$extkey][$key])) + ) { + $info[$key] = $EM_CONF[$extkey][$key]; + } + } + + if (is_array($EM_CONF[$extkey]['constraints']) && is_array($EM_CONF[$extkey]['constraints']['depends'])) { + $info['TYPO3_version'] = $EM_CONF[$extkey]['constraints']['depends']['typo3']; + } + $info['filesHash'] = unserialize($EM_CONF[$key]['_md5_values_when_last_written']); + $info['manual'] = @is_file($path . '/doc/manual.sxw'); + $result = $info; + } else { + $result = 'ERROR: No emconf.php file: ' . $file; + } + return $result; + } + + /** * Clears the extension key map. * * @return void Index: typo3/sysext/em/mod1/class.em_index.php =================================================================== --- typo3/sysext/em/mod1/class.em_index.php (révision 9198) +++ typo3/sysext/em/mod1/class.em_index.php (copie de travail) @@ -4299,7 +4300,107 @@ return $infoArray; } + /** + * Analyses a singe php-script of an available extension on server + * + * @param string Absolute path to extension + * @param string relative filename with relative path inside of extension + * @param string basename of relative filename + * @param string Prefix for tables/classes. + * @param string Extension key + * @param array extension Information array + * @param array return Information or Error array. + * @see makeDetailedExtensionAnalysis() + */ + public function getClassIndexFile($absPath, $fileName, $baseName, $table_class_prefix, $extKey, $extInfo, &$out) { + $reg = array(); + $matchCount = 0; + $fContent = ''; + + if (filesize($absPath . $fileName) < 500 * 1024) { + $fContent = t3lib_div::getUrl($absPath . $fileName); + unset($reg); + $matchCount = preg_match('/\n[[:space:]]*class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/', $fContent, $reg); + } + + if ($matchCount) { + + // Find classes: + $lines = explode(LF,$fContent); + foreach($lines as $l) { + $line = trim($l); + unset($reg); + if (preg_match('/^class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/',$line,$reg)) { + $out['classes'][] = $reg[1]; + $out['files'][$fileName]['classes'][] = $reg[1]; + 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])) { + $out['NSerrors']['classname'][] = $reg[1]; + } else $out['NSok']['classname'][] = $reg[1]; + } + } + // If class file prefixed 'class.'.... + if (substr($baseName,0,6) == 'class.') { + $fI = pathinfo($baseName); + $testName = substr($baseName, 6, -(1+strlen($fI['extension']))); + if ($testName !== 'ext_update' && substr($testName, 0, 3) != 'ux_' && !t3lib_div::isFirstPartOfStr($testName, $table_class_prefix) && strcmp(substr($table_class_prefix, 0, -1),$testName)) { + $out['NSerrors']['classfilename'][] = $baseName; + } else { + $out['NSok']['classfilename'][] = $baseName; + if (is_array($out['files'][$fileName]['classes']) && $this->first_in_array($testName,$out['files'][$fileName]['classes'], 1)) { + $out['msg'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_class_ok'), + $fileName, $testName + ); + } else $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_class_not_ok'), + $fileName, $testName + ); + } + } + + // Check for proper XCLASS definition + // Match $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS'] with single or doublequotes + $XclassSearch = '\$TYPO3_CONF_VARS\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]'; + $XclassParts = preg_split('/if \(defined\([\'"]TYPO3_MODE[\'"]\) && ' . $XclassSearch . '/', $fContent, 2); + + if (count($XclassParts) !== 2) { + // Match $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS'] with single or doublequotes + $XclassSearch = '\$GLOBALS\[[\'"]TYPO3_CONF_VARS[\'"]\]\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]'; + $XclassParts = preg_split('/if \(defined\([\'"]TYPO3_MODE[\'"]\) && ' . $XclassSearch . '/', $fContent, 2); + } + if (count($XclassParts)==2) { + unset($reg); + preg_match('/^\[[\'"]([[:alnum:]_\/\.]*)[\'"]\]/', $XclassParts[1], $reg); + if ($reg[1]) { + $cmpF = 'ext/' . $extKey . '/' . $fileName; + if (!strcmp($reg[1],$cmpF)) { + if (preg_match('/_once[[:space:]]*\(' . $XclassSearch . '\[[\'"]' . preg_quote($cmpF, '/') . '[\'"]\]\);/', $XclassParts[1])) { + $out['msg'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_ok'), $fileName); + } else $out['errors'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_no_include'); + } else $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_incorrect'), + $reg[1], $cmpF + ); + } else $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_xclass_filename'), $fileName); + } elseif (!$this->first_in_array('ux_', $out['files'][$fileName]['classes'])) { + $bDoCheck = TRUE; + if (isset($extInfo['excludeXCLASScheck']) && is_array($extInfo['excludeXCLASScheck'])) { + foreach ($extInfo['excludeXCLASScheck'] as $pattern) { + $pattern = str_replace('*', '.*', $pattern); + if (preg_match('`' . $pattern . '`', $fileName)) { + $bDoCheck = FALSE; + break; + } + } + } + if ($bDoCheck) { + // No Xclass definition required if classname starts with 'ux_' + $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_xclass_found'), $fileName); + } + } + } + } + + + /** * Analyses the php-scripts of an available extension on server * * @param string Absolute path to extension @@ -4311,7 +4412,7 @@ function getClassIndexLocallangFiles($absPath,$table_class_prefix,$extKey) { $filesInside = t3lib_div::removePrefixPathFromList(t3lib_div::getAllFilesAndFoldersInPath(array(),$absPath,'php,inc',0,99,$this->excludeForPackaging),$absPath); $out = array(); - $reg = array(); + $extInfo = t3lib_extMgm::getExtensionInfo($extKey); foreach($filesInside as $fileName) { if (substr($fileName,0,4)!='ext_' && substr($fileName,0,6)!='tests/') { // ignore supposed-to-be unit tests as well @@ -4319,70 +4420,15 @@ if (substr($baseName,0,9)=='locallang' && substr($baseName,-4)=='.php') { $out['locallang'][] = $fileName; } elseif ($baseName!='conf.php') { - if (filesize($absPath.$fileName)<500*1024) { - $fContent = t3lib_div::getUrl($absPath.$fileName); - unset($reg); - if (preg_match('/\n[[:space:]]*class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/',$fContent,$reg)) { - - // Find classes: - $lines = explode(LF,$fContent); - foreach($lines as $l) { - $line = trim($l); - unset($reg); - if (preg_match('/^class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/',$line,$reg)) { - $out['classes'][] = $reg[1]; - $out['files'][$fileName]['classes'][] = $reg[1]; - 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])) { - $out['NSerrors']['classname'][] = $reg[1]; - } else $out['NSok']['classname'][] = $reg[1]; - } - } - // If class file prefixed 'class.'.... - if (substr($baseName,0,6)=='class.') { - $fI = pathinfo($baseName); - $testName=substr($baseName,6,-(1+strlen($fI['extension']))); - if ($testName!=='ext_update' && substr($testName,0,3)!='ux_' && !t3lib_div::isFirstPartOfStr($testName,$table_class_prefix) && strcmp(substr($table_class_prefix,0,-1),$testName)) { - $out['NSerrors']['classfilename'][] = $baseName; - } else { - $out['NSok']['classfilename'][] = $baseName; - if (is_array($out['files'][$fileName]['classes']) && $this->first_in_array($testName,$out['files'][$fileName]['classes'],1)) { - $out['msg'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_class_ok'), - $fileName, $testName - ); - } else $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_class_not_ok'), - $fileName, $testName - ); - } - } - - // Check for proper XCLASS definition - // Match $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS'] with single or doublequotes - $XclassSearch = '\$TYPO3_CONF_VARS\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]'; - $XclassParts = preg_split('/if \(defined\([\'"]TYPO3_MODE[\'"]\) && ' . $XclassSearch . '/', $fContent, 2); - if (count($XclassParts) !== 2) { - // Match $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS'] with single or doublequotes - $XclassSearch = '\$GLOBALS\[[\'"]TYPO3_CONF_VARS[\'"]\]\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]'; - $XclassParts = preg_split('/if \(defined\([\'"]TYPO3_MODE[\'"]\) && ' . $XclassSearch . '/', $fContent, 2); - } - if (count($XclassParts)==2) { - unset($reg); - preg_match('/^\[[\'"]([[:alnum:]_\/\.]*)[\'"]\]/',$XclassParts[1],$reg); - if ($reg[1]) { - $cmpF = 'ext/'.$extKey.'/'.$fileName; - if (!strcmp($reg[1],$cmpF)) { - if (preg_match('/_once[[:space:]]*\(' . $XclassSearch . '\[[\'"]' . preg_quote($cmpF, '/') . '[\'"]\]\);/', $XclassParts[1])) { - $out['msg'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_ok'), $fileName); - } else $out['errors'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_no_include'); - } else $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_incorrect'), - $reg[1], $cmpF - ); - } else $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_xclass_filename'), $fileName); - } elseif (!$this->first_in_array('ux_', $out['files'][$fileName]['classes'])) { - // No Xclass definition required if classname starts with 'ux_' - $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_xclass_found'), $fileName); - } - } - } + $this->getClassIndexFile( + $absPath, + $fileName, + $baseName, + $table_class_prefix, + $extKey, + $extInfo, + $out + ); } } }