2 /***************************************************************
5 * (c) 1999-2009 Kasper Skaarhoj (kasperYYYY@typo3.com)
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
28 * Super Admin class has functions for the administration of multiple TYPO3 sites in folders
29 * See 'misc/superadmin.php' for details on how to use!
32 * Revised for TYPO3 3.6 February/2004 by Kasper Skaarhoj
35 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
38 * [CLASS/FUNCTION INDEX of SCRIPT]
40 * 120: function debug($p1,$p2='')
43 * 134: class t3lib_superadmin
45 * SECTION: Initialize stuff
46 * 180: function t3lib_superadmin()
47 * 192: function init($parentDirs)
49 * SECTION: Main functions
50 * 215: function defaultSet()
51 * 271: function make()
53 * SECTION: Output preparation
54 * 376: function setMenuItem($code,$label)
55 * 390: function error($str)
56 * 401: function headerParentDir($str)
57 * 412: function headerSiteDir($str)
59 * SECTION: Collection information
60 * 444: function initProcess()
61 * 482: function processSiteDir($path,$dir)
62 * 524: function includeLocalconf($localconf)
63 * 554: function connectToDatabase($siteInfo)
64 * 576: function getDBInfo($key)
66 * SECTION: Content: Installation Overview
67 * 626: function makeTable()
69 * SECTION: Content: Local extensions
70 * 729: function localExtensions()
71 * 902: function getExtensionInfo($path,$extKey,$k)
72 * 956: function getAllFilesAndFoldersInPath($fileArr,$extPath,$extList='',$regDirs=0)
73 * 978: function findMostRecent($fileArr,$extPath)
74 * 996: function removePrefixPathFromList($fileArr,$extPath)
76 * SECTION: Content: Other
77 * 1033: function singleSite($exp)
78 * 1064: function loginLog($DB)
79 * 1102: function log_getDetails($text,$data)
80 * 1116: function rmCachedFiles($exp)
81 * 1149: function menuContent($exp)
82 * 1221: function makeAdminLogin()
83 * 1295: function changeAdminPasswordsForm()
84 * 1330: function setNewPasswords()
87 * (This index is automatically created/updated by the extension "extdeveval")
99 // *******************************
100 // Set error reporting
101 // *******************************
102 if (defined('E_DEPRECATED')) {
103 error_reporting(E_ALL ^ E_NOTICE ^ E_DEPRECATED
);
105 error_reporting(E_ALL ^ E_NOTICE
);
108 define('TYPO3_mainDir', 'typo3/'); // This is the directory of the backend administration for the sites of this TYPO3 installation.
112 $path_t3lib = './typo3_src/t3lib/';
113 include_once($path_t3lib.'class.t3lib_div.php');
114 include_once($path_t3lib.'class.t3lib_db.php');
115 $TYPO3_DB = t3lib_div
::makeInstance('t3lib_DB');
119 * Debug function. Substitute since no config_default.php file is included anywhere
121 * @param mixed Debug var
122 * @param string Header string
125 function debug($p1,$p2='') {
126 t3lib_div
::debug($p1,$p2);
132 * Super Admin class has functions for the administration of multiple TYPO3 sites in folders
133 * NOTICE: Only compliant with single MySQL database usage per installation!
135 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
139 class t3lib_superadmin
{
142 var $targetWindow = 'superAdminWindow';
143 var $targetWindowAdmin = 'superAdminWindowAdmin';
144 var $targetWindowInstall = 'superAdminWindowInstall';
145 var $scriptName = 'superadmin.php';
148 var $show; // "menu", "all", "admin", "info", "rmTempCached", "localext"
149 var $type; // "phpinfo", "page" - default renders a frameset
150 var $exp; // Additional parameter, typically a md5-hash pointing to an installation of TYPO3
153 var $parentDirs = array(); // Configured directories to search
154 var $globalSiteInfo = array(); // Array with information about found TYPO3 installations
156 var $currentUrl = '';
157 var $mapDBtoKey = array();
158 var $collectAdminPasswords = array();
159 var $changeAdminPasswords = array();
160 var $collectInstallPasswords = array();
163 var $full = 0; // If set, the full information array per site is printed.
165 var $noCVS = 0; // See tools/em/index.php....
174 /**********************************
178 **********************************/
181 * Constructor, setting GP vars
185 function t3lib_superadmin() {
186 $this->show
= t3lib_div
::_GP('show');
187 $this->type
= t3lib_div
::_GP('type');
188 $this->exp
= t3lib_div
::_GP('exp');
192 * Initialize with configuration - from the 'superadmin.php' script. See misc/superadmin.php for example.
194 * @param array Numerical array with arrays having two keys, 'dir' and 'url' where 'dir' is the absolute path to a directory with TYPO3 installations inside.
197 function init($parentDirs) {
198 $this->parentDirs
= $parentDirs;
208 /**************************
212 **************************/
215 * Main function, creating HTML content; frameset, menu, content frames.
216 * Outputs the full HTML to browser.
220 function defaultSet() {
222 // Creating content based on "type" variable:
223 switch($this->type
) {
230 PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
231 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
234 <style type
="text/css">
235 .redclass
{color
: red
;}
236 P
{font
-family
: Verdana
, Arial
, Helvetica
, sans
-serif
; font
-size
: 11px
}
237 BODY
{font
-family
: Verdana
, Arial
, Helvetica
, sans
-serif
; font
-size
: 10px
}
238 H1
{font
-family
: Verdana
, Arial
, Helvetica
, sans
-serif
; font
-size
: 20px
; color
: #000066;}
239 H2
{font
-family
: Verdana
, Arial
, Helvetica
, sans
-serif
; font
-size
: 17px
; color
: #000066;}
240 H3
{font
-family
: Verdana
, Arial
, Helvetica
, sans
-serif
; font
-size
: 14px
; color
: #000066;}
241 H4
{font
-family
: Verdana
, Arial
, Helvetica
, sans
-serif
; font
-size
: 11px
; color
: maroon
;}
242 TD
{font
-family
: Verdana
, Arial
, Helvetica
, sans
-serif
; font
-size
: 10px
}
244 <title
>TYPO3 Super Admin
</title
>
256 <!DOCTYPE HTML
PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
259 <title
>TYPO3 Super Admin
</title
>
261 <frameset cols
="250,*">
262 <frame name
="TSAmenu" src
="superadmin.php?type=page&show=menu" marginwidth
="10" marginheight
="10" scrolling
="auto" frameborder
="0">
263 <frame name
="TSApage" src
="superadmin.php?type=page" marginwidth
="10" marginheight
="10" scrolling
="auto" frameborder
="0">
272 * Main function, creating page content.
274 * @return string HTML content.
280 // Creating information about the sites found:
281 $content = $this->initProcess();
284 switch($this->show
) {
287 $lines[]=$this->setMenuItem('info','INFO');
288 $lines[]=$this->setMenuItem('update','UPDATE');
290 $lines[]='<a href="'.htmlspecialchars($this->scriptName
.'?type=page').'" target="TSApage">Default</a>';
291 $lines[]='<a href="'.htmlspecialchars($this->scriptName
.'?type=page&show=all').'" target="TSApage">All details</a>';
292 $lines[]='<a href="'.htmlspecialchars($this->scriptName
.'?type=page&show=admin').'" target="TSApage">Admin logins</a>';
293 $lines[]='<a href="'.htmlspecialchars($this->scriptName
.'?type=phpinfo').'" target="TSApage">phpinfo()</a>';
294 $lines[]='<a href="'.htmlspecialchars($this->scriptName
.'?type=page&show=localext').'" target="TSApage">Local extensions</a>';
296 $content = implode('<br />',$lines);
298 $content.=$this->menuContent($this->exp
);
299 $retVal = '<h2 align="center">TYPO3<br />Super Admin</h2>'.$content;
303 <h1>All details:</h1>
305 '.$this->makeTable().'
307 <h1>Details per site:</h1>
311 $content = $this->setNewPasswords();
314 <h1>Admin options:</h1>
316 <h2>Admin logins:</h2>
317 '.$this->makeAdminLogin().'
320 <h2>TBE Admin Passwords:</h2>
321 '.t3lib_div
::view_array($this->collectAdminPasswords
).'
324 <h2>Install Tool Passwords:</h2>
325 '.t3lib_div
::view_array($this->collectInstallPasswords
).'
328 <h2>Change TBE Admin Passwords:</h2>
329 '.$this->changeAdminPasswordsForm().'
334 <h1>Single site details</h1>
335 '.$this->singleSite($this->exp
).
340 <h1>Removing temp_CACHED_*.php files</h1>
341 '.$this->rmCachedFiles($this->exp
).
346 <h1>Local Extensions Found:</h1>
347 '.$this->localExtensions().
352 <h1>Default info:</h1>'.
368 /********************************
372 *******************************/
375 * Creates menu item from input.
377 * @param string Value for "&exp" parameter
378 * @param string The label
379 * @return string Wrapped value
381 function setMenuItem($code,$label) {
382 $out = '<a href="'.htmlspecialchars($this->scriptName
.'?type=page&show=menu&exp='.$code).'" target="TSAmenu">'.htmlspecialchars($label).'</a>';
383 if ($code==$this->exp
) {
384 $out = '<span style="color:red;">>></span>'.$out;
390 * Wrap string in red span tag (for errors)
392 * @param string Input string
393 * @return string Output string
395 function error($str) {
396 $out = '<span style="color:red; font-size: 14px; font-weight: bold;">'.htmlspecialchars($str).'</span>';
401 * Wraps input string in <h2>
403 * @param string Input string
404 * @return string Output string, wrapped in <h2>
406 function headerParentDir($str) {
407 $out = '<h2>'.htmlspecialchars($str).'</h2>';
412 * Wraps input string in <h3>
414 * @param string Input string
415 * @return string Output string, wrapped in <h3>
417 function headerSiteDir($str) {
418 $out = '<h3>'.htmlspecialchars($str).'</h3>';
438 /********************************
440 * Collection information
442 *******************************/
445 * Traverses the parent dirs, collecting the list of TYPO3 installations into $this->globalSiteInfo
447 * @return string HTML content (The default view seen when starting the superadmin.php script)
449 function initProcess() {
452 foreach($this->parentDirs
as $k => $v) {
453 $dir = rtrim($v['dir'], '/');
454 $baseUrl=rtrim($v['url'], '/');
455 $content.='<br /><br /><br />';
456 $content.=$this->headerParentDir($dir);
458 $in_dirs = t3lib_div
::get_dirs($dir);
462 while(list($k,$v)=each($in_dirs)) {
463 if (substr($v,0,9)!='typo3_src') {
464 $this->currentUrl
= $baseUrl.'/'.$v;
465 $content.= $this->headerSiteDir($v);
466 $content.= $this->processSiteDir($dir.'/'.$v,$dir);
470 $content.=$this->error('"'.$dir.'" was not a directory!');
478 * Creating information array for a specific TYPO3 installation
479 * Information about site is stored in ->globalSiteInfo array
481 * @param string Absolute path to installation (PATH_site)
482 * @param string Directory of main directory (level under PATH_site)
483 * @return string HTML content with information about the site.
487 function processSiteDir($path,$dir) {
488 if (@is_dir
($path)) {
489 $localconf = $path.'/typo3conf/localconf.php';
490 if (@is_file
($localconf)) {
491 $key = md5($localconf);
492 $this->includeLocalconf($localconf);
494 $this->mapDBtoKey
[$this->globalSiteInfo
[$key]['siteInfo']['TYPO3_db']] = $key;
495 $this->globalSiteInfo
[$key]['siteInfo']['MAIN_DIR'] = $dir;
496 $this->globalSiteInfo
[$key]['siteInfo']['SA_PATH'] = $path;
497 $this->globalSiteInfo
[$key]['siteInfo']['URL'] = $this->currentUrl
.'/';
498 $this->globalSiteInfo
[$key]['siteInfo']['ADMIN_URL'] = $this->currentUrl
.'/'.TYPO3_mainDir
;
499 $this->globalSiteInfo
[$key]['siteInfo']['INSTALL_URL'] = $this->currentUrl
.'/'.TYPO3_mainDir
.'install/';
501 // Connect to database:
502 $conMsg = $this->connectToDatabase($this->globalSiteInfo
[$key]['siteInfo']);
504 $this->getDBInfo($key);
512 $out.=t3lib_div
::view_array($this->globalSiteInfo
[$key]);
514 $out.=t3lib_div
::view_array($this->globalSiteInfo
[$key]['siteInfo']);
516 } else $out = $this->error($localconf.' is not a file!');
517 } else $out = $this->error($path.' is not a directory!');
522 * Includes "localconf" of a TYPO3 installation an loads $this->globalSiteInfo with this information.
524 * @param string Absolute path to localconf.php file to include.
525 * @return array Array with information about the site.
527 * @see processSiteDir()
529 function includeLocalconf($localconf) {
530 $TYPO3_CONF_VARS = array();
532 $typo_db_username = '';
533 $typo_db_password = '';
539 $siteInfo['sitename'] = $TYPO3_CONF_VARS['SYS']['sitename'];
540 $siteInfo['TYPO3_db'] = $typo_db;
541 $siteInfo['TYPO3_db_username'] = $typo_db_username;
542 $siteInfo['TYPO3_db_password'] = $typo_db_password;
543 $siteInfo['TYPO3_db_host'] = $typo_db_host;
544 $siteInfo['installToolPassword'] = $TYPO3_CONF_VARS['BE']['installToolPassword'];
545 $siteInfo['warningEmailAddress'] = $TYPO3_CONF_VARS['BE']['warning_email_addr'];
546 $siteInfo['warningMode'] = $TYPO3_CONF_VARS['BE']['warning_mode'];
548 $this->globalSiteInfo
[md5($localconf)] = array('siteInfo'=>$siteInfo,'TYPO3_CONF_VARS'=>$TYPO3_CONF_VARS);
553 * Connects to a MySQL database with the TYPO3 db host/username/password and database as found in the localconf.php file!
554 * This is NOT compatible with DBAL and connection will obviously just fail with an error message if it turns out that the _DEFAULT handler of a site is not in a MySQL database
556 * @param array $siteInfo array, containing username/password/host/database values.
557 * @return string Array message if any
559 function connectToDatabase($siteInfo) {
560 if (@mysql_pconnect
($siteInfo['TYPO3_db_host'], $siteInfo['TYPO3_db_username'], $siteInfo['TYPO3_db_password'])) {
561 if (!$siteInfo['TYPO3_db']) {
562 return $this->error('No database selected');
563 } elseif (!mysql_select_db($siteInfo['TYPO3_db'])) {
564 return $this->error('Cannot connect to the current database, "'.$siteInfo['TYPO3_db'].'"');
567 return $this->error('The current username, password or host was not accepted when the connection to the database was attempted to be established!');
573 * Get database information, assuming standard tables like "be_users"
574 * Adding the information to ->globalSiteInfo
576 * @param string Key for site in ->globalSiteInfo
579 * @see processSiteDir()
581 function getDBInfo($key) {
582 $DB = $this->globalSiteInfo
[$key]['siteInfo']['TYPO3_db'];
585 $query = $GLOBALS['TYPO3_DB']->SELECTquery('count(*)', 'be_users', 'admin=0 AND deleted=0');
586 $res = mysql($DB, $query);
587 $row = mysql_fetch_row($res);
588 $this->globalSiteInfo
[$key]['siteInfo']['BE_USERS_NONADMIN'] = $row[0];
591 $query = $GLOBALS['TYPO3_DB']->SELECTquery('count(*)', 'be_users', 'admin!=0 AND deleted=0');
592 $res = mysql($DB, $query);
593 $row = mysql_fetch_row($res);
594 $this->globalSiteInfo
[$key]['siteInfo']['BE_USERS_ADMIN'] = $row[0];
596 // Select Admin users
597 $query = $GLOBALS['TYPO3_DB']->SELECTquery('uid,username,password,email,realName,disable', 'be_users', 'admin!=0 AND deleted=0');
598 $res = mysql($DB, $query);
599 while($row = mysql_fetch_assoc($res)) {
600 $this->globalSiteInfo
[$key]['siteInfo']['ADMINS'][] = $row;
620 /******************************
622 * Content: Installation Overview
624 ******************************/
627 * Creates big table with information about all installations in ->globalSiteInfo
629 * @return string HTML table
631 function makeTable() {
637 $info[] = 'Database:';
638 $info[] = 'Username';
639 $info[] = 'Password';
641 $info[] = 'Links (new win)';
642 $info[] = '#Users NA/A';
643 $info[] = 'Admin be_users Info';
644 $info[] = 'Install Tool Password';
645 $info[] = 'Warning email address';
648 <tr bgcolor="#eeeeee">
649 <td nowrap="nowrap" valign="top">'.implode('</td>
650 <td nowrap="nowrap" valign="top">',$info).'</td>
653 // Traverse globalSiteInfo for each site:
654 foreach($this->globalSiteInfo
as $k => $all) {
657 // Sitename and Database details:
658 $info[] = htmlspecialchars($all['siteInfo']['sitename']);
659 $info[] = '<span style="color:#666666;">'.htmlspecialchars($all['siteInfo']['MAIN_DIR']).'</span>'.htmlspecialchars(substr($all['siteInfo']['SA_PATH'],strlen($all['siteInfo']['MAIN_DIR'])));
660 $info[] = htmlspecialchars($all['siteInfo']['TYPO3_db']);
661 $info[] = htmlspecialchars($all['siteInfo']['TYPO3_db_username']);
662 $info[] = htmlspecialchars($all['siteInfo']['TYPO3_db_password']);
663 $info[] = htmlspecialchars($all['siteInfo']['TYPO3_db_host']);
666 $info[] = '<a href="'.htmlspecialchars($all['siteInfo']['URL']).'" target="'.$this->targetWindow
.'">Site</a>'.
667 ' / <a href="'.htmlspecialchars($all['siteInfo']['ADMIN_URL']).'" target="'.$this->targetWindowAdmin
.'">Admin</a>'.
668 ' / <a href="'.htmlspecialchars($all['siteInfo']['INSTALL_URL']).'" target="'.$this->targetWindowInstall
.'">Install</a>';
669 $info[] = htmlspecialchars($all['siteInfo']['BE_USERS_NONADMIN'].'/'.$all['siteInfo']['BE_USERS_ADMIN']);
672 if (is_array($all['siteInfo']['ADMINS'])) {
674 foreach($all['siteInfo']['ADMINS'] as $vArr) {
675 $lines[] = htmlspecialchars($vArr['password'].' - '.$vArr['username'].' ('.$vArr['realName'].', '.$vArr['email'].')');
676 $this->collectAdminPasswords
[$vArr['password']][] = array(
677 'path' => $all['siteInfo']['SA_PATH'],
678 'site' => $all['siteInfo']['sitename'],
679 'database' => $all['siteInfo']['TYPO3_db'],
680 'user' => $vArr['username'],
681 'name_email' => $vArr['realName'].', '.$vArr['email']
683 $this->changeAdminPasswords
[$vArr['password']][] = $all['siteInfo']['TYPO3_db'].':'.$vArr['uid'].':'.$vArr['username'];
685 $info[] = implode('<br />',$lines);
687 $info[] = $this->error('No DB connection!');
690 $info[] = htmlspecialchars($all['siteInfo']['installToolPassword']);
691 $this->collectInstallPasswords
[$all['siteInfo']['installToolPassword']][] = $all['siteInfo']['SA_PATH'].' - '.$all['siteInfo']['sitename'].' - ('.$all['siteInfo']['TYPO3_db'].')';
693 $info[] = htmlspecialchars($all['siteInfo']['warningEmailAddress']);
694 $info[] = htmlspecialchars($all['siteInfo']['warningMode']);
699 <td nowrap="nowrap" valign="top">'.implode('</td>
700 <td nowrap="nowrap" valign="top">',$info).'</td>
704 // Compile / return table finally:
705 $table = '<table border="1" cellpadding="1" cellspacing="1">'.implode('',$mainArrRows).'</table>';
722 /******************************
724 * Content: Local extensions
726 ******************************/
729 * Based on the globalSiteInfo array, this prints information about local extensions for each site.
730 * In particular version number and most recent mod-time is interesting!
732 * @return string HTML
734 function localExtensions() {
735 $this->extensionInfoArray
=array();
737 // Traverse $this->globalSiteInfo for local extensions:
738 foreach($this->globalSiteInfo
as $k => $all) {
739 if ($all['siteInfo']['SA_PATH']) {
740 $extDir = $all['siteInfo']['SA_PATH'].'/typo3conf/ext/';
741 if (@is_dir
($extDir)) {
742 $this->extensionInfoArray
['site'][$k] = array();
744 // Get extensions in local directory
745 $extensions=t3lib_div
::get_dirs($extDir);
746 if (is_array($extensions)) {
747 foreach($extensions as $extKey) {
748 // Getting and setting information for extension:
749 $eInfo = $this->getExtensionInfo($extDir,$extKey,$k);
750 $this->extensionInfoArray
['site'][$k][$extKey] = $eInfo;
751 $this->extensionInfoArray
['ext'][$extKey][$k] = $eInfo;
761 <tr bgcolor="#ccccee" style="font-weight:bold;">
762 <td>Extension key</td>
767 <td><span title="If M, then there is a manual.">M</span></td>
768 <td>Last mod. time</td>
769 <td>Hash off all file mod. times:</td>
770 <td>TYPO3 ver. req.</td>
771 <td>CGL compliance</td>
776 if (is_array($this->extensionInfoArray
['ext'])) {
777 $extensionKeysCollect=array();
779 ksort($this->extensionInfoArray
['ext']);
780 reset($this->extensionInfoArray
['ext']);
786 foreach($this->extensionInfoArray
['ext'] as $extKey => $instances) {
789 // Find most recent mtime of the options:
791 while(list($k,$eInfo)=each($instances)) {
792 $mtimes[] = $eInfo['mtime'];
795 $maxMtime = max($mtimes);
798 // So, traverse all sites with the extension present:
799 foreach($instances as $k => $eInfo) {
800 // Set background color if mtime matches
801 if ($maxMtime==$eInfo['mtime']) {
802 $this->extensionInfoArray
['site'][$k][$extKey]['_highlight']=1;
803 $bgCol = $eInfo['dirtype']=='link' ?
' bgcolor="#ffcccc"' : ' bgcolor="#eeeeee"';
805 $bgCol = ' style="color: #999999; font-style: italic;"';
809 $type = substr($extKey,0,5)!='user_' ?
'reg' : 'user';
810 if ($type=='reg') $extensionKeysCollect[] = $extKey;
812 if (!is_array($eInfo)) {
816 '.(!$c?
'<td rowspan="'.count($instances).'">'.htmlspecialchars($extKey).'</td>':'').'
817 <td nowrap="nowrap" bgcolor="#ccddcc">'.htmlspecialchars($this->globalSiteInfo
[$k]['siteInfo']['SA_PATH']).'</td>
818 <td nowrap="nowrap" bgcolor="#ccddcc" colspan="8"><em>'.htmlspecialchars($eInfo).'</em></td>
825 '.(!$c?
'<td rowspan="'.count($instances).'">'.htmlspecialchars($extKey).'</td>':'').'
826 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($this->globalSiteInfo
[$k]['siteInfo']['SA_PATH']).'</td>
827 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($eInfo['title']).'</td>
828 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($eInfo['version']).'</td>
829 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($eInfo['numberfiles']).'</td>
830 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($eInfo['manual']?
'M':'-').'</td>
831 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($eInfo['mtime']?
date('d-m-y H:i:s',$eInfo['mtime']):'').'</td>
832 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($eInfo['mtime_hash']).'</td>
834 <td'.$bgCol.'>'.htmlspecialchars($eInfo['TYPO3_version']).'</td>
835 <td'.$bgCol.'><img src="clear.gif" width="150" height="1" alt="" /><br />'.htmlspecialchars($eInfo['CGLcompliance'].($eInfo['CGLcompliance_note'] ?
' - '.$eInfo['CGLcompliance_note'] : '')).'</td>
843 // Extensions with registered extension keys:
845 <h3>Registered extensions:</h3>
846 <table border="1">'.$headerRow.implode('',$rows['reg']).'</table>';
848 // List of those extension keys in a form field:
849 $extensionKeysCollect = array_unique($extensionKeysCollect);
850 asort($extensionKeysCollect);
851 $out.='<form action=""><textarea cols="80" rows="10">'.implode(chr(10),$extensionKeysCollect).'</textarea></form>';
853 // USER extension (prefixed "user_")
855 <h3>User extensions:</h3>
856 <table border="1">'.$headerRow.implode('',$rows['user']).'</table>';
860 if (is_array($this->extensionInfoArray
['site'])) {
862 foreach($this->extensionInfoArray
['site'] as $k => $extensions) {
864 // So, traverse all sites with the extension present:
866 foreach($extensions as $extKey => $eInfo) {
868 // Set background color if mtime matches
869 if ($eInfo['_highlight']) {
870 $bgCol = $eInfo['dirtype']=='link' ?
' bgcolor="#ffcccc"' : ' bgcolor="#eeeeee"';
872 $bgCol = ' style="color: #999999; font-style: italic;"';
878 '.(!$c?
'<td rowspan="'.count($extensions).'">'.htmlspecialchars($this->globalSiteInfo
[$k]['siteInfo']['SA_PATH']).'</td>':'').'
879 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($extKey).'</td>
880 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($eInfo['title']).'</td>
881 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($eInfo['version']).'</td>
882 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($eInfo['numberfiles']).'</td>
883 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($eInfo['mtime']?
date('d-m-y H:i:s',$eInfo['mtime']):'').'</td>
884 <td nowrap="nowrap"'.$bgCol.'>'.htmlspecialchars($eInfo['mtime_hash']).'</td>
892 <table border="1">'.implode('',$rows).'</table>';
900 * Gets information for an extension, eg. version and most-recently-edited-script
902 * @param string Path to local extension folder
903 * @param string Extension key
904 * @param string Key to globalSiteInformation array
905 * @return array Information array (unless an error occured)
907 function getExtensionInfo($path,$extKey,$k) {
908 $file = $path.$extKey.'/ext_emconf.php';
909 if (@is_file
($file)) {
916 $eInfo['title'] = $EM_CONF[$extKey]['title'];
917 $eInfo['version'] = $EM_CONF[$extKey]['version'];
918 $eInfo['CGLcompliance'] = $EM_CONF[$extKey]['CGLcompliance'];
919 $eInfo['CGLcompliance_note'] = $EM_CONF[$extKey]['CGLcompliance_note'];
920 $eInfo['TYPO3_version'] = $EM_CONF[$extKey]['TYPO3_version'];
921 $filesHash = unserialize($EM_CONF[$extKey]['_md5_values_when_last_written']);
923 if (!is_array($filesHash) ||
count($filesHash)<500) {
925 // Get all files list (may take LOONG time):
926 $extPath = $path.$extKey.'/';
928 $fileArr = $this->removePrefixPathFromList($this->getAllFilesAndFoldersInPath($fileArr,$extPath),$extPath);
930 if (!is_array($fileArr)) {
931 debug(array($fileArr,$extKey,$extPath,$this->getAllFilesAndFoldersInPath(array(),$extPath)),'ERROR');
935 $eInfo['numberfiles'] = count($fileArr);
936 $eInfo['dirtype'] = filetype($path.$extKey);
938 // Most recent modification:
939 $eInfo['mtime_files'] = $this->findMostRecent($fileArr,$extPath);
940 if (count($eInfo['mtime_files'])) $eInfo['mtime'] = max($eInfo['mtime_files']);
941 $eInfo['mtime_hash'] = md5(implode(',',$eInfo['mtime_files']));
943 $eInfo['mtime_hash'] = 'No calculation done, too many files in extension: '.count($filesHash);
946 $eInfo['manual'] = @is_file
($path.$extKey.'/doc/manual.sxw');
949 } else return 'ERROR: No emconf.php file: '.$file;
953 * Recursively gather all files and folders of extension path.
955 * @param array Array of files to which new files are added
956 * @param string Path to look up files in
957 * @param string List of file extensions to include. Blank = all
958 * @param boolean If set, directories are included as well.
959 * @return array $fileArr with new entries added.
961 function getAllFilesAndFoldersInPath($fileArr,$extPath,$extList='',$regDirs=0) {
962 if ($regDirs) $fileArr[] = $extPath;
963 $fileArr = array_merge($fileArr,t3lib_div
::getFilesInDir($extPath,$extList,1,1));
965 $dirs = t3lib_div
::get_dirs($extPath);
966 if (is_array($dirs)) {
967 foreach($dirs as $subdirs) {
968 if ($subdirs && (strcmp($subdirs,'CVS') ||
!$this->noCVS
)) {
969 $fileArr = $this->getAllFilesAndFoldersInPath($fileArr,$extPath.$subdirs.'/',$extList,$regDirs);
977 * Creates an array with modification times of all files in $fileArr
979 * @param array Files in extension (rel path)
980 * @param string Abs path prefix for files.
981 * @return array Array with modification times of files (filenames are keys)
983 function findMostRecent($fileArr,$extPath) {
984 $mtimeArray = array();
985 foreach($fileArr as $fN) {
986 if ($fN!='ext_emconf.php') {
987 $mtime = filemtime($extPath.$fN);
988 $mtimeArray[$fN] = $mtime;
995 * Removes the absolute part of all files/folders in fileArr
997 * @param array File array
998 * @param string Prefix to remove
999 * @return array Modified file array (or error string)
1001 function removePrefixPathFromList($fileArr,$extPath) {
1003 while(list($k,$absFileRef)=each($fileArr)) {
1004 if(t3lib_div
::isFirstPartOfStr($absFileRef,$extPath)) {
1005 $fileArr[$k]=substr($absFileRef,strlen($extPath));
1006 } else return 'ERROR: One or more of the files was NOT prefixed with the prefix-path!';
1026 /******************************
1030 ******************************/
1033 * Shows detailed information for a single installation of TYPO3
1035 * @param string KEY pointing to installation
1036 * @return string HTML content
1038 function singleSite($exp) {
1039 $all = $this->globalSiteInfo
[$exp];
1041 // General information:
1043 <h2>'.htmlspecialchars($all['siteInfo']['sitename'].' (DB: '.$all['siteInfo']['TYPO3_db']).')</h2>
1046 <h3>Main details:</h3>
1048 LINKS: <a href="'.htmlspecialchars($all['siteInfo']['URL']).'" target="'.$this->targetWindow
.'">Site</a> / <a href="'.htmlspecialchars($all['siteInfo']['ADMIN_URL']).'" target="'.$this->targetWindowAdmin
.'">Admin</a> / <a href="'.htmlspecialchars($all['siteInfo']['INSTALL_URL']).'" target="'.$this->targetWindowInstall
.'">Install</a>
1051 // Add all information in globalSiteInfo array:
1052 $content.= t3lib_div
::view_array($all);
1056 <h3>Login-Log for last month:</h3>';
1057 $content.= $this->loginLog($all['siteInfo']['TYPO3_db']);
1064 * Get last-login log for database.
1066 * @param string Database
1067 * @return string HTML
1069 function loginLog($DB) {
1071 //1=login, 2=logout, 3=failed login (+ errorcode 3), 4=failure_warning_email sent
1072 $query = $GLOBALS['TYPO3_DB']->SELECTquery(
1073 'sys_log.*, be_users.username AS username, be_users.admin AS admin',
1075 'be_users.uid=sys_log.userid AND sys_log.type=255 AND sys_log.tstamp > ' . ($GLOBALS['EXEC_TIME'] - (60 * 60 * 24 * 30)),
1077 'sys_log.tstamp DESC'
1079 $res = mysql($DB,$query);
1084 while($row = mysql_fetch_assoc($res)) {
1085 $day = date('d-m-Y',$row['tstamp']);
1086 if ($dayRef!=$day) {
1088 <h4>'.$day.':</h4>';
1091 $theLine = date('H:i',$row['tstamp']).': '.str_pad(substr($row['username'],0,10),10).' '.$this->log_getDetails($row['details'],unserialize($row['log_data']));
1092 $theLine = htmlspecialchars($theLine);
1093 $lines[]= $row['admin'] ?
'<span class="redclass">'.$theLine.'</span>' : $theLine;
1097 return '<pre>'.implode(chr(10),$lines).'</pre>';
1101 * Compile log details into template string
1103 * @param string Log message (template)
1104 * @param array Data array to insert in log message
1105 * @return string Log details.
1107 function log_getDetails($text,$data) {
1108 // $code is used later on to substitute errormessages with language-corrected values...
1109 if (is_array($data)) {
1110 return sprintf($text, $data[0],$data[1],$data[2],$data[3],$data[4]);
1111 } else return $text;
1116 * Removing temp_CACHED files for installation
1118 * @param string KEY pointing to installation
1119 * @return string HTML content
1121 function rmCachedFiles($exp) {
1122 $all = $this->globalSiteInfo
[$exp];
1124 <h2>'.htmlspecialchars($all['siteInfo']['sitename'].' (DB: '.$all['siteInfo']['TYPO3_db']).')</h2>
1126 <h3>typo3conf/temp_CACHED_* files:</h3>';
1128 $path = $all['siteInfo']['SA_PATH'].'/typo3conf/';
1129 if (@is_dir
($path)) {
1130 $filesInDir = t3lib_div
::getFilesInDir($path,'php',1);
1132 foreach($filesInDir as $kk => $vv) {
1133 if (t3lib_div
::isFirstPartOfStr(basename($vv),'temp_CACHED_')) {
1134 if (strstr(basename($vv),'ext_localconf.php') ||
strstr(basename($vv),'ext_tables.php')) {
1135 $content.='REMOVED: '.$vv.'<br />';
1137 if (file_exists($vv)) $content.= $this->error('ERROR: File still exists, so could not be removed anyways!').'<br />';
1142 $content.= $this->error('ERROR: '.$path.' was not a directory!');
1149 * Menu for either update/information, showing links for each installation found
1151 * @param string Action key "update" or "info"
1152 * @return string HTML output.
1154 function menuContent($exp) {
1161 foreach($this->globalSiteInfo
as $k => $all) {
1163 // Setting section header, if needed.
1164 if ($head!=$all['siteInfo']['MAIN_DIR']) {
1166 <h4 style="white-space: nowrap;">'.htmlspecialchars(t3lib_div
::fixed_lgd_cs($all['siteInfo']['MAIN_DIR'],-18)).'</h4>';
1167 $head = $all['siteInfo']['MAIN_DIR']; // Set new head...
1175 $label = $all['siteInfo']['sitename'] ?
$all['siteInfo']['sitename'] : '(DB: '.$all['siteInfo']['TYPO3_db'].')';
1178 <b>'.htmlspecialchars($label).'</b> ('.htmlspecialchars(substr($all['siteInfo']['SA_PATH'],strlen($all['siteInfo']['MAIN_DIR'])+
1)).')<br />';
1180 // To avoid "visited links" display on next hit:
1181 $tempVal='&_someUniqueValue=' . $GLOBALS['EXEC_TIME'];
1183 // Add links for update:
1184 $url = $this->scriptName
.'?type=page&show=rmTempCached&exp='.$k.$tempVal;
1185 $lines[] = '<span style="white-space: nowrap;"><a href="'.htmlspecialchars($url).'" target="TSApage">Remove temp_CACHED files</a></span>';
1187 $url = $all['siteInfo']['INSTALL_URL'].'index.php?TYPO3_INSTALL[type]=database&TYPO3_INSTALL[database_type]=import|CURRENT_STATIC'."&presetWholeTable=1".$tempVal.'#bottom';
1188 $lines[] = '<span style="white-space: nowrap;"><a href="'.htmlspecialchars($url).'" target="TSApage">CURRENT_STATIC</a></span>';
1190 $url = $all['siteInfo']['INSTALL_URL'].'index.php?TYPO3_INSTALL[type]=database&TYPO3_INSTALL[database_type]=cmpFile|CURRENT_TABLES'.$tempVal.'#bottom';
1191 $lines[] = '<span style="white-space: nowrap;"><a href="'.htmlspecialchars($url).'" target="TSApage">CURRENT_TABLES</a></span>';
1194 $url = $all['siteInfo']['INSTALL_URL'].'index.php?TYPO3_INSTALL[type]=database&TYPO3_INSTALL[database_type]=cache|'.
1195 "&PRESET[database_clearcache][cache_pages]=1".
1196 '&PRESET[database_clearcache][cache_pagesection]=1'.
1197 "&PRESET[database_clearcache][cache_hash]=1".
1200 $lines[] = '<span style="white-space: nowrap;"><a href="'.htmlspecialchars($url).'" target="TSApage">Clear cache</a></span>';
1203 $url = $all['siteInfo']['ADMIN_URL'].'index.php';
1204 $lines[] = '<span style="white-space: nowrap;"><a href="'.htmlspecialchars($url).'" target="'.$this->targetWindowAdmin
.'">Admin -></a></span>';
1208 $label = $all['siteInfo']['sitename'] ?
$all['siteInfo']['sitename'] : '(DB: '.$all['siteInfo']['TYPO3_db'].')';
1210 $url = $this->scriptName
.'?type=page&show=info&exp='.$k;
1211 $lines[] = '<span style="white-space: nowrap;"><a href="'.htmlspecialchars($url).'" target="TSApage">'.htmlspecialchars($label).'</a> ('.htmlspecialchars(substr($all['siteInfo']['SA_PATH'],strlen($all['siteInfo']['MAIN_DIR'])+
1)).'/)</span>';
1217 return implode('<br />',$lines).'<br />';
1222 * Create list of admin logins.
1224 * @return string HTML table
1226 function makeAdminLogin() {
1232 // Traverse installations found:
1233 foreach($this->globalSiteInfo
as $k => $all) {
1235 // Setting section header, if needed.
1236 if ($head!=$all['siteInfo']['MAIN_DIR']) {
1239 <td colspan="2"><br />
1240 <h4>'.htmlspecialchars($all['siteInfo']['MAIN_DIR']).'</h4>
1243 $head = $all['siteInfo']['MAIN_DIR'];
1247 $label = $all['siteInfo']['sitename'] ?
$all['siteInfo']['sitename'] : '(DB: '.$all['siteInfo']['TYPO3_db'].')';
1248 $unique = md5(microtime());
1253 if (is_array($all['siteInfo']['ADMINS'])) {
1255 foreach($all['siteInfo']['ADMINS'] as $vArr) {
1256 $chalVal = md5($vArr['username'].':'.$vArr['password'].':'.$unique);
1257 $opts[] = '<option value="'.$chalVal.'">'.htmlspecialchars($vArr['username'].($vArr['disable']?
' [DISABLED]':'')).'</option>';
1258 if (!$defUName) { $defUName = $vArr['username']; }
1261 if (count($opts)>1) {
1263 <select name="userident" onchange="document[\''.$k.'\'].username.value=this.options[this.selectedIndex].text;">
1270 ('.$defUName.')<br />
1271 <input type="hidden" name="userident" value="'.$chalVal.'" />';
1275 <form name="'.$k.'" action="'.$all['siteInfo']['ADMIN_URL'].'index.php" target="EXTERnalWindow" method="post">
1276 <input type="submit" name="submit" value="Login" />
1277 <input type="hidden" name="username" value="'.$defUName.'" />
1278 <input type="hidden" name="challenge" value="'.$unique.'" />
1279 <input type="hidden" name="redirect_url" value="" />
1280 <input type="hidden" name="login_status" value="login" />
1281 '.trim($userident).'
1286 <td><strong>'.htmlspecialchars($label).'</strong></td>
1287 <td nowrap="nowrap">'.trim($form).'</td>
1291 // Return login table:
1292 return '<table border="1" cellpadding="5" cellspacing="1">'.implode('',$lines).'</table>';
1296 * For for changing admin passwords
1298 * @return string Form content.
1300 function changeAdminPasswordsForm() {
1303 foreach($this->changeAdminPasswords
as $k => $p) {
1307 foreach($p as $kk => $pp) {
1308 $content.= '<span style="white-space: nowrap;">';
1309 $content.= '<input type="checkbox" name="SETFIELDS[]" value="'.$pp.'" /> '.$pp.' - ';
1310 $content.= htmlspecialchars(implode(' - ',$this->collectAdminPasswords
[$k][$kk]));
1311 $content.= '</span><br />';
1315 $content.='New password: <input type="text" name="NEWPASS" /><br />';
1316 $content.='New password (md5): <input type="text" name="NEWPASS_md5" /><br />
1317 (This overrules any plain password above!)
1320 <form action="'.htmlspecialchars($this->scriptName
.'?type=page&show=admin').'" method="post">
1322 <input type="submit" name="Set" />
1330 * Setting new passwords
1332 * @return string Status
1333 * @see changeAdminPasswordsForm()
1335 function setNewPasswords() {
1336 $whichFields = t3lib_div
::_POST('SETFIELDS');
1337 $pass = trim(t3lib_div
::_POST('NEWPASS'));
1338 $passMD5 = t3lib_div
::_POST('NEWPASS_md5');
1341 if (($pass ||
$passMD5) && is_array($whichFields)) {
1342 $pass = $passMD5 ?
$passMD5 : md5($pass);
1344 foreach($whichFields as $values) {
1345 $parts = explode(':',$values);
1346 if (count($parts)>2) {
1347 $key = $this->mapDBtoKey
[$parts[0]];
1348 if ($key && isset($this->globalSiteInfo
[$key]['siteInfo'])) {
1349 $error = $this->connectToDatabase($this->globalSiteInfo
[$key]['siteInfo']);
1351 $DB = $this->globalSiteInfo
[$key]['siteInfo']['TYPO3_db'];
1352 $content.='<h3>Updating '.$DB.':</h3>';
1354 $query = $GLOBALS['TYPO3_DB']->UPDATEquery(
1356 'uid='.intval($parts[1]).' AND username="'.addslashes($parts[2]).'" AND admin!=0',
1357 array('password' => $pass)
1358 ); // username/admin are added to security. But they are certainly redundant!!
1361 $content.= 'Affected rows: '.mysql_affected_rows().'<br /><hr />';
1369 $this->initProcess();
1374 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['t3lib/class.t3lib_superadmin.php']) {
1375 include_once($TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['t3lib/class.t3lib_superadmin.php']);