Commit 906e375adc1c044d5488563a74af1fd46275b57d

Authored by kevin_fourie
1 parent 5bd874c3

Merged in from DEV trunk...

KTS-3016
""
Implemented.

Committed By: Conrad Vermeulen
Reviewed By: Megan Watson

git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/STABLE/trunk@8019 c91229c3-7414-0410-bfa2-8a42b809f60b
lib/util/support.inc.php 0 → 100644
  1 +<?php
  2 +
  3 +/**
  4 + * $Id:$
  5 + *
  6 + * KnowledgeTree Open Source Edition
  7 + * Document Management Made Simple
  8 + * Copyright (C) 2004 - 2008 The Jam Warehouse Software (Pty) Limited
  9 + *
  10 + * This program is free software; you can redistribute it and/or modify it under
  11 + * the terms of the GNU General Public License version 3 as published by the
  12 + * Free Software Foundation.
  13 + *
  14 + * This program is distributed in the hope that it will be useful, but WITHOUT
  15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  17 + * details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21 + *
  22 + * You can contact The Jam Warehouse Software (Pty) Limited, Unit 1, Tramber Place,
  23 + * Blake Street, Observatory, 7925 South Africa. or email info@knowledgetree.com.
  24 + *
  25 + * The interactive user interfaces in modified source and object code versions
  26 + * of this program must display Appropriate Legal Notices, as required under
  27 + * Section 5 of the GNU General Public License version 3.
  28 + *
  29 + * In accordance with Section 7(b) of the GNU General Public License version 3,
  30 + * these Appropriate Legal Notices must retain the display of the "Powered by
  31 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  32 + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
  33 + * must display the words "Powered by KnowledgeTree" and retain the original
  34 + * copyright notice.
  35 + * Contributor( s): ______________________________________
  36 + *
  37 + */
  38 +
  39 +
  40 +/**
  41 + * TODO: refactor into seperate comparison object
  42 + *
  43 + */
  44 +class MD5SourceTree
  45 +{
  46 + private $rootDir;
  47 + private $logFilename;
  48 + private $logFile;
  49 + private $numDirectories;
  50 + private $numFiles;
  51 + private $comparisonFailure;
  52 + private $exclusions;
  53 +
  54 + public function __construct($exclusions = array())
  55 + {
  56 + $this->numDirectories = 0;
  57 + $this->numFiles = 0;
  58 + $this->exclusions = $exclusions;
  59 + }
  60 +
  61 + /**
  62 + * Helper function to traverse the directories. Called initially by scan()
  63 + *
  64 + * @param string $dir
  65 + */
  66 + private function _scan($dir)
  67 + {
  68 + if (is_dir($dir))
  69 + {
  70 + if ($dh = opendir($dir))
  71 + {
  72 + while (($filename = readdir($dh)) !== false)
  73 + {
  74 + if (substr($filename,0,1) == '.')
  75 + {
  76 + continue;
  77 + }
  78 +
  79 + $path = $dir . '/' . $filename;
  80 + if (is_dir($path))
  81 + {
  82 + $this->numDirectories++;
  83 + $this->_scan($path);
  84 + }
  85 + else
  86 + {
  87 + $this->numFiles++;
  88 + if (is_readable($path))
  89 + {
  90 + $md5 = md5_file($path);
  91 + fwrite($this->logFile, "$md5:$path\n");
  92 + }
  93 + }
  94 + }
  95 + closedir($dh);
  96 + }
  97 + }
  98 + }
  99 +
  100 + /**
  101 + * This does the scan of the directory.
  102 + *
  103 + * @param string $rootDir
  104 + * @param string $reportFile
  105 + */
  106 + public function scan($rootDir, $reportFile)
  107 + {
  108 + $this->rootDir = $rootDir;
  109 + $this->logFilename = $reportFile;
  110 + $this->logFile = fopen($reportFile,'wt');
  111 + $this->_scan($rootDir);
  112 + fclose($this->logFile);
  113 + }
  114 +
  115 +
  116 + /**
  117 + * Used by the compare function, to load a md5 file
  118 + *
  119 + * @param string $path
  120 + * @return array
  121 + */
  122 + private function _loadDirectory($path)
  123 + {
  124 + $dirs = array();
  125 + $numFiles = 0;
  126 + $numDirectories = 0;
  127 + $fp = fopen($path, 'rt');
  128 + while (!feof($fp))
  129 + {
  130 + $line = fgets($fp, 10240);
  131 + list($md5, $path) = explode(':',$line);
  132 + $dirname = dirname($path);
  133 + $filename = basename($path);
  134 + $numFiles++;
  135 + $dirs[$dirname][$filename] = $md5;
  136 + }
  137 + fclose($fp);
  138 + return array('numFiles'=>$numFiles, 'numDirectories'=>$numDirectories, 'dirs'=>$dirs);
  139 + }
  140 +
  141 + /**
  142 + * Internal function used to compare two md5 directory structures.
  143 + *
  144 + * @param array $prev
  145 + * @param array $cur
  146 + * @param string $msg
  147 + */
  148 + private function _compare($prev, $cur, $msg)
  149 + {
  150 + foreach($prev['dirs'] as $prevDir=>$prevDirFiles)
  151 + {
  152 + if (!array_key_exists($prevDir, $cur['dirs']))
  153 + {
  154 + print "$msg: $prevDir does not exist in target.\n";
  155 + }
  156 + else
  157 + {
  158 + foreach($prevDirFiles as $prevFilename=>$prevMD5)
  159 + {
  160 + if (!array_key_exists($prevFilename, $cur['dirs'][$prevDir]))
  161 + {
  162 + $prevFilename = substr($prevFilename,0,-1);
  163 + print "$msg: $prevFilename does not exist in $prevDir.\n";
  164 + }
  165 + else
  166 + {
  167 + if (in_array($prevDir . '/' . $prevFilename, $this->comparisonFailure))
  168 + {
  169 + continue;
  170 + }
  171 +
  172 + $newMD5 = $cur['dirs'][$prevDir][$prevFilename];
  173 + if ($prevMD5 != $newMD5)
  174 + {
  175 + $this->comparisonFailure[] = $prevDir . '/' . $prevFilename;
  176 + $prevFilename = substr($prevFilename,0,-1);
  177 + print "$msg: $prevFilename does not match md5; $prevMD5 != $newMD5.\n";
  178 + }
  179 + }
  180 + }
  181 + }
  182 + }
  183 + }
  184 +
  185 + /**
  186 + * Compare to md5 report files
  187 + *
  188 + * @param string $reportA
  189 + * @param string $reportB
  190 + */
  191 + public function compare($reportA, $reportB)
  192 + {
  193 + if (is_null($reportB))
  194 + {
  195 + $reportB = $this->logFilename;
  196 + }
  197 + $this->comparisonFailure = array();
  198 + $prev = $this->_loadDirectory($reportA);
  199 + $cur = $this->_loadDirectory($reportB);
  200 +
  201 + if ($prev['numDirectories'] != $cur['numDirectories'])
  202 + {
  203 + print "Folder count mismatch!\n";
  204 + }
  205 +
  206 + if ($prev['numFiles'] != $cur['numFiles'])
  207 + {
  208 + print "File count mismatch!\n";
  209 + }
  210 +
  211 + $this->_compare($prev, $cur,'>');
  212 + $this->_compare($cur,$prev,'<');
  213 + }
  214 +}
  215 +
  216 +class SupportUtil
  217 +{
  218 + private $path;
  219 + private $innodb;
  220 + private $noninnodb;
  221 +
  222 + /**
  223 + * Constructor for SupportUtil. Creates a folder with format support-YYYY-MM-DD_HH-mm-ss
  224 + *
  225 + */
  226 + function __construct()
  227 + {
  228 + $config = KTConfig::getSingleton();
  229 + $tempdir = $config->get('urls/tmpDirectory');
  230 +
  231 + $this->path = $tempdir . "/support-" . date('Y-m-d_H-i-s');
  232 +
  233 + mkdir($this->path);
  234 + }
  235 +
  236 + /**
  237 + * Main function to capture as much info that is reasonable.
  238 + *
  239 + */
  240 + public function capture()
  241 + {
  242 + // get php info
  243 + $this->capture_phpinfo($this->path . '/phpinfo.htm');
  244 +
  245 + // get db schema
  246 + $tables = $this->capture_db_schema($this->path);
  247 +
  248 + // get zseq counters from taables
  249 + $this->capture_zseqs($tables, $this->path . '/zseqreport.htm');
  250 +
  251 + // get md5 on table
  252 + $tree = new MD5SourceTree();
  253 + $config = KTConfig::getSingleton();
  254 + $sourcePath = $config->get('KnowledgeTree/fileSystemRoot');
  255 + $tree->scan($sourcePath, $this->path . '/md5report.txt');
  256 +
  257 + // get plugins
  258 + $this->capture_plugins($this->path . '/plugins.htm');
  259 +
  260 + // get logs
  261 + $this->capture_logs($this->path);
  262 +
  263 + // get sys info
  264 + $this->get_sysinfo($this->path);
  265 +
  266 + // get storage engine list
  267 + $this->create_storage_engine($this->path);
  268 +
  269 + // get disk space listing
  270 + $this->capture_df($this->path);
  271 +
  272 + // get process listing
  273 + $this->capture_ps($this->path);
  274 +
  275 + // get version files
  276 + $this->capture_version_files($this->path);
  277 +
  278 + // get system settings
  279 + $this->capture_system_settings($this->path);
  280 +
  281 + // create out index file
  282 + $this->create_index($this->path);
  283 +
  284 + }
  285 +
  286 + /**
  287 + * Main helper function to cleanup after creating zip file
  288 + *
  289 + * @param stirng $path
  290 + */
  291 + private function _cleanup($path)
  292 + {
  293 + $dh = opendir($path);
  294 + while (($filename = readdir($dh)) !== false)
  295 + {
  296 + if (substr($filename,0,1) == '.') continue;
  297 +
  298 + $fullname = $path . '/' . $filename;
  299 + if (is_dir($fullname))
  300 + {
  301 + $this->_cleanup($fullname);
  302 + }
  303 + else
  304 + {
  305 + unlink($fullname);
  306 + }
  307 + }
  308 + closedir($dh);
  309 + rmdir($path);
  310 + }
  311 +
  312 + /**
  313 + * Main cleanup function
  314 + *
  315 + */
  316 + public function cleanup()
  317 + {
  318 + $this->_cleanup($this->path);
  319 + }
  320 +
  321 + /**
  322 + * Creates an archive file
  323 + *
  324 + * @return string
  325 + */
  326 + public function archive()
  327 + {
  328 + $zip = KTUtil::findCommand('export/zip', 'zip');
  329 +
  330 + chdir(dirname($this->path));
  331 + $subdir = basename($this->path);
  332 + $archivename = $this->path . '.zip';
  333 + $cmd = "'$zip' -r '$archivename' '$subdir'";
  334 +
  335 + KTUtil::pexec($cmd);
  336 +
  337 + return $archivename;
  338 + }
  339 +
  340 + /**
  341 + * Tries to get list of running processes
  342 + *
  343 + * @param string $path
  344 + */
  345 + private function capture_ps($path)
  346 + {
  347 + $ps = KTUtil::findCommand('externalBinary/ps', 'ps');
  348 + if (!file_exists($ps) || !is_executable($ps))
  349 + {
  350 + return;
  351 + }
  352 +
  353 + $cmd = "'$ps' waux";
  354 + // TODO: refactor to use KTUtil::pexec
  355 +
  356 + $ps = popen($cmd, 'r');
  357 + $content = fread($ps , 10240);
  358 + pclose($ps);
  359 +
  360 + file_put_contents($path . '/ps.txt', $content);
  361 + }
  362 +
  363 + /**
  364 + * Get list of KnowledgeTree version files
  365 + *
  366 + * @param string $path
  367 + */
  368 + private function capture_version_files($path)
  369 + {
  370 + $path = $path . '/versions';
  371 + mkdir($path);
  372 +
  373 + $ver_path = KT_DIR . '/docs';
  374 + $dh = opendir($ver_path);
  375 + while (($filename = readdir($dh)) !== false)
  376 + {
  377 + if (substr($filename, 0, 7) == 'VERSION')
  378 + {
  379 + copy($ver_path . '/' . $filename, $path . '/' . $filename);
  380 + }
  381 + }
  382 + closedir($dh);
  383 + }
  384 +
  385 + /**
  386 + * Dump the system_settings table, except for dashboard-state entries.
  387 + *
  388 + * @param string $path
  389 + */
  390 + private function capture_system_settings($path)
  391 + {
  392 + $sql = "SELECT id, name, value FROM system_settings";
  393 + $rs = DBUtil::getResultArray($sql);
  394 + $html = "<h1>System Settings</h1>";
  395 + $html .= '<br><table border=1 cellpadding=0 cellspacing=0>';
  396 + foreach($rs as $rec)
  397 + {
  398 + $id = $rec['id'];
  399 + $name = $rec['name'];
  400 + $value = $rec['value'];
  401 + if (substr($name, 0, 15) == 'dashboard-state') continue;
  402 + $html .= "<tr><td>$id<td>$name<td>$value\r\n";
  403 + }
  404 +
  405 + $html .= '</table>';
  406 + file_put_contents($path . '/systemsettings.htm', $html);
  407 + }
  408 +
  409 + /**
  410 + * Get disk usage
  411 + *
  412 + * @param string $path
  413 + */
  414 + private function capture_df($path)
  415 + {
  416 + $df = KTUtil::findCommand('externalBinary/df', 'df');
  417 + if (!file_exists($df) || !is_executable($df))
  418 + {
  419 + return;
  420 + }
  421 +
  422 + $df = popen($df, 'r');
  423 + $content = fread($df, 10240);
  424 + pclose($df);
  425 +
  426 + file_put_contents($path . '/df.txt', $content);
  427 + }
  428 +
  429 + /**
  430 + * Get php info
  431 + *
  432 + * @param string $filename
  433 + */
  434 + private function capture_phpinfo($filename)
  435 + {
  436 + ob_start();
  437 + phpinfo();
  438 + $phpinfo = ob_get_clean();
  439 + file_put_contents($filename, $phpinfo);
  440 + }
  441 +
  442 + /**
  443 + * Helper table to get schema
  444 + *
  445 + * @param string $folder
  446 + * @return string
  447 + */
  448 + private function capture_table_schema($folder)
  449 + {
  450 + $tables = array();
  451 + $sql = 'show tables';
  452 + $results = DBUtil::getResultArray($sql);
  453 +
  454 + foreach($results as $rec)
  455 + {
  456 + $rec = array_values($rec);
  457 + $tablename = $rec[0];
  458 + $sql = "show create table $tablename";
  459 + $sql = DBUtil::getOneResultKey($sql,'Create Table');
  460 +
  461 + file_put_contents($folder . '/' . $tablename . '.sql.txt', $sql);
  462 +
  463 + $sql = strtolower($sql);
  464 + if (strpos($sql, 'innodb') === false)
  465 + $this->noninnodb[] = $tablename;
  466 + else
  467 + $this->innodb[] = $tablename;
  468 +
  469 +
  470 + $tables[] = $tablename;
  471 + }
  472 +
  473 + return $tables;
  474 + }
  475 +
  476 + /**
  477 + * Get database schema
  478 + *
  479 + * @param string $folder
  480 + * @param string $suffix
  481 + * @return array
  482 + */
  483 + private function capture_db_schema($folder, $suffix='')
  484 + {
  485 + $schema_folder = $folder . '/' . $suffix . 'schema';
  486 + mkdir($schema_folder);
  487 +
  488 + return $this->capture_table_schema($schema_folder);
  489 + }
  490 +
  491 + /**
  492 + * Get list of plugins
  493 + *
  494 + * @param string $filename
  495 + */
  496 + private function capture_plugins($filename)
  497 + {
  498 + $sql = 'select namespace,path, disabled, unavailable,friendly_name from plugins';
  499 + $result = DBUtil::getResultArray($sql);
  500 + $plugins = "<h1>Plugin Status Report</h1>";
  501 +
  502 + $plugins .= '<table border=1 cellpadding=0 cellspacing=0u >';
  503 + $plugins .= '<tr><th>Display Name<th>Availability<th>Namespace<th>Path';
  504 + foreach($result as $rec)
  505 + {
  506 + $fileexists = file_exists(KT_DIR . '/' . $rec['path'])?'':'<font color="red">';
  507 + $status = ($rec['disabled'] == 0)?'<font color="green">':'<font color="orange">';
  508 + $unavailable = ($rec['unavailable'] == 0)?'available':'<font color="orange">unavailable';
  509 +
  510 + $plugins .= '<tr>';
  511 + $plugins .= '<td>' . $status . $rec['friendly_name'];
  512 + $plugins .= '<td>' . $unavailable;
  513 + $plugins .= '<td>' . $rec['namespace'];
  514 + $plugins .= '<td>' . $fileexists . $rec['path'] . "\r\n";
  515 + }
  516 + $plugins .= '</table>';
  517 + $plugins .= '<br>Plugin name is <font color=green>green</font> if enabled and <font color=orange>orange</font> if disabled .';
  518 + $plugins .= '<br>Availability indicates that KnowledgeTree has detected the plugin not to be available.';
  519 + $plugins .= '<br>Path is coloured <font color=red>red</font> if the plugin file cannot be resolved. If the path is not resolved, it should be flagged unavailable.';
  520 + file_put_contents($filename, $plugins);
  521 + }
  522 +
  523 + /**
  524 + * Make a zseq report
  525 + *
  526 + * @param string $tables
  527 + * @param string $filename
  528 + */
  529 + private function capture_zseqs($tables, $filename)
  530 + {
  531 + $zseqs = '<h1>Table Counter Report</h1>';
  532 +
  533 + $zseqs .= '<table border=1 cellpadding=0 cellspacing=0>';
  534 + $zseqs .= '<tr><td>Table<td>Max ID<td>ZSEQ<td>Status';
  535 +
  536 + foreach($tables as $ztablename)
  537 + {
  538 + if (substr($ztablename, 0, 5) != 'zseq_')
  539 + {
  540 + continue;
  541 + }
  542 +
  543 + $tablename = substr($ztablename, 5);
  544 + $sql = "SELECT max(id) as maxid FROM $tablename";
  545 + $maxid = DBUtil::getOneResultKey($sql, 'maxid');
  546 +
  547 + $sql = "SELECT id FROM $ztablename";
  548 + $zseqid = DBUtil::getOneResultKey($sql, 'id');
  549 +
  550 + $note = (is_null($maxid) || $maxid <= $zseqid)?'OK':'FAIL';
  551 + if ($note == 'FAIL' && $maxid > $zseqid)
  552 + {
  553 + $note = 'COUNTER PROBLEM! maxid should be less than or equal to zseq';
  554 + }
  555 + if (PEAR::isError($maxid))
  556 + {
  557 + $maxid = '??';
  558 + $note = "STRANGE - DB ERROR ON $tablename";
  559 + }
  560 + if (PEAR::isError($zseqid))
  561 + {
  562 + $zseqid = '??';
  563 + $note = "STRANGE - DB ERROR ON $ztablename";
  564 + }
  565 + if (is_null($maxid))
  566 + {
  567 + $maxid='empty';
  568 + }
  569 + if (is_null($zseqid))
  570 + {
  571 + $zseqid='empty';
  572 + $note = "STRANGE - ZSEQ SHOULD NOT BE EMPTY ON $ztablename";
  573 + }
  574 + $zseqs .= "<tr><td>$tablename<td>$maxid<td>$zseqid<td>$note\r\n";
  575 + }
  576 + $zseqs .= "</table>";
  577 + file_put_contents($filename, $zseqs);
  578 + }
  579 +
  580 + /**
  581 + * Get log files
  582 + *
  583 + * @param string $path
  584 + */
  585 + private function capture_logs($path)
  586 + {
  587 + $path = $path . '/logs';
  588 + mkdir($path);
  589 +
  590 + $this->capture_kt_log($path);
  591 + $this->capture_apache_log($path);
  592 + $this->capture_php_log($path);
  593 + $this->capture_mysql_log($path);
  594 +
  595 + }
  596 +
  597 + /**
  598 + * Get Php log file. KT makes a php_error_log when tweak setting is enabled.
  599 + *
  600 + * @param string $path
  601 + */
  602 + private function capture_php_log($path)
  603 + {
  604 + $config = KTConfig::getSingleton();
  605 + $logdir = $config->get('urls/logDirectory');
  606 + $logfile = $logdir . '/php_error_log';
  607 + if (file_exists($logfile))
  608 + {
  609 + copy($logfile, $path . '/php-error_log.txt');
  610 + }
  611 + }
  612 +
  613 + /**
  614 + * Get mysql log from stack. It is difficult to resolve otherwise.
  615 + *
  616 + * @param string $path
  617 + */
  618 + private function capture_mysql_log($path)
  619 + {
  620 + $stack_path = realpath(KT_DIR . '/../mysql/data');
  621 + if ($stack_path === false || !is_dir($stack_path))
  622 + {
  623 + return;
  624 + }
  625 +
  626 + $dh = opendir($stack_path);
  627 + while (($filename = readdir($dh)) !== false)
  628 + {
  629 + if (substr($filename, -4) == '.log' && strpos($filename, 'err') !== false)
  630 + {
  631 + copy($stack_path . '/' . $filename, $path . '/mysql-' . $filename);
  632 + }
  633 + }
  634 + closedir($dh);
  635 + }
  636 +
  637 + /**
  638 + * Get Apache log file from stack. It is difficult to resolve otherwise.
  639 + *
  640 + * @param string $path
  641 + */
  642 + private function capture_apache_log($path)
  643 + {
  644 + $stack_path = realpath(KT_DIR . '/../apache2/logs');
  645 + if ($stack_path === false || !is_dir($stack_path))
  646 + {
  647 + return;
  648 + }
  649 +
  650 + $dh = opendir($stack_path);
  651 + while (($filename = readdir($dh)) !== false)
  652 + {
  653 + if (substr($filename, -4) == '.log' && strpos($filename, 'err') !== false)
  654 + {
  655 + copy($stack_path . '/' . $filename, $path . '/apache-' . $filename);
  656 + }
  657 + }
  658 + closedir($dh);
  659 + }
  660 +
  661 + /**
  662 + * Get KT log file.
  663 + *
  664 + * @param string $path
  665 + */
  666 + private function capture_kt_log($path)
  667 + {
  668 + $date = date('Y-m-d');
  669 + $config = KTConfig::getSingleton();
  670 + $logdir = $config->get('urls/logDirectory');
  671 + $dh = opendir($logdir);
  672 + while (($filename = readdir($dh)) !== false)
  673 + {
  674 + if (substr($filename,0,14) != 'log-' . $date)
  675 + {
  676 + continue;
  677 + }
  678 + copy($logdir . '/' . $filename, $path . '/kt-' . $filename);
  679 + }
  680 + closedir($dh);
  681 + }
  682 +
  683 + /**
  684 + * Get some basic info on Linux if possible. Get cpuinfo, loadavg, meminfo
  685 + *
  686 + * @param string $path
  687 + */
  688 + private function get_sysinfo($path)
  689 + {
  690 + if (!OS_UNIX && !is_dir('/proc'))
  691 + {
  692 + return;
  693 + }
  694 +
  695 + $path .= '/sysinfo';
  696 + mkdir($path);
  697 +
  698 + $this->get_sysinfo_file('cpuinfo', $path);
  699 + $this->get_sysinfo_file('loadavg', $path);
  700 + $this->get_sysinfo_file('meminfo', $path);
  701 +
  702 + }
  703 +
  704 + /**
  705 + * Helper to get linux sysinfo
  706 + *
  707 + * @param string $filename
  708 + * @param string $path
  709 + */
  710 + private function get_sysinfo_file($filename, $path)
  711 + {
  712 + if (!is_readable('/proc/' . $filename))
  713 + {
  714 + return;
  715 + }
  716 + $content = file_get_contents('/proc/' . $filename);
  717 + file_put_contents($path . '/' . $filename . '.txt', $content);
  718 + }
  719 +
  720 + /**
  721 + * Helper to create the index file for the support archive.
  722 + *
  723 + * @param string $title
  724 + * @param string $path
  725 + * @param boolean $relative
  726 + * @return string
  727 + */
  728 +
  729 + private function get_index_contents($title, $path, $relative = true)
  730 + {
  731 + $contents = array();
  732 + $dh = opendir($path);
  733 + while (($filename = readdir($dh)) !== false)
  734 + {
  735 + if (substr($filename,0,1) == '.') continue;
  736 +
  737 + $fullname = $path . '/' . $filename;
  738 +
  739 + if (!file_exists($fullname) || is_dir($fullname))
  740 + {
  741 + continue;
  742 + }
  743 +
  744 + $contents[] = $fullname;
  745 + }
  746 + closedir($dh);
  747 + sort($contents);
  748 +
  749 + $html = $title;
  750 +
  751 + if (empty($contents))
  752 + {
  753 + $html .= 'There is no content for this section.';
  754 + return $html;
  755 + }
  756 +
  757 + $dir = '';
  758 + if ($relative) $dir = basename($path) . '/';
  759 + foreach($contents as $filename)
  760 + {
  761 + $corename = basename($filename);
  762 + $ext = pathinfo($corename, PATHINFO_EXTENSION);
  763 + $basename = substr($corename, 0, -strlen($ext)-1);
  764 + $html .= "<a href=\"$dir$corename\">$basename</a><br>";
  765 + }
  766 + return $html;
  767 + }
  768 +
  769 + /**
  770 + * Create the support archvie index.htm
  771 + *
  772 + * @param string $path
  773 + */
  774 + private function create_index($path)
  775 + {
  776 + $contents = $this->get_index_contents('<h1>Support Info</h1><br>', $path, false);
  777 +
  778 + $contents .= $this->get_index_contents('<h2>System Info</h2>', $path . '/sysinfo');
  779 + $contents .= $this->get_index_contents('<h2>Logs</h2>', $path . '/logs');
  780 + $contents .= $this->get_index_contents('<h2>Schema</h2>', $path . '/schema');
  781 + file_put_contents($path . '/index.htm', $contents);
  782 +
  783 + }
  784 +
  785 + /**
  786 + * Get list of tables based on InnoDB
  787 + *
  788 + * @param string $path
  789 + */
  790 +
  791 + private function create_storage_engine($path)
  792 + {
  793 + $html = '<h1>Table Storage Engines<h1>';
  794 + $html .= '<table>';
  795 + $html .= '<tr><td valign=top>';
  796 +
  797 + $html .= '<h2>InnoDB</h2>';
  798 + foreach($this->innodb as $tablename)
  799 + {
  800 + $html .= "$tablename<br>";
  801 + }
  802 +
  803 +
  804 + $html .= '<td valign=top>';
  805 +
  806 + $html .= '<h2>Non-InnoDB</h2>';
  807 + foreach($this->noninnodb as $tablename)
  808 + {
  809 + $html .= "$tablename<br>";
  810 + }
  811 +
  812 + $html .= '</table>';
  813 +
  814 + file_put_contents($path . '/tablestorage.htm', $html);
  815 + }
  816 +
  817 +}
  818 +
  819 +
  820 +
  821 +
  822 +?>
0 823 \ No newline at end of file
... ...
plugins/ktcore/admin/techsupport.php
... ... @@ -5,32 +5,32 @@
5 5 * KnowledgeTree Open Source Edition
6 6 * Document Management Made Simple
7 7 * Copyright (C) 2004 - 2008 The Jam Warehouse Software (Pty) Limited
8   - *
  8 + *
9 9 * This program is free software; you can redistribute it and/or modify it under
10 10 * the terms of the GNU General Public License version 3 as published by the
11 11 * Free Software Foundation.
12   - *
  12 + *
13 13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 15 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 16 * details.
17   - *
  17 + *
18 18 * You should have received a copy of the GNU General Public License
19 19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20   - *
  20 + *
21 21 * You can contact The Jam Warehouse Software (Pty) Limited, Unit 1, Tramber Place,
22 22 * Blake Street, Observatory, 7925 South Africa. or email info@knowledgetree.com.
23   - *
  23 + *
24 24 * The interactive user interfaces in modified source and object code versions
25 25 * of this program must display Appropriate Legal Notices, as required under
26 26 * Section 5 of the GNU General Public License version 3.
27   - *
  27 + *
28 28 * In accordance with Section 7(b) of the GNU General Public License version 3,
29 29 * these Appropriate Legal Notices must retain the display of the "Powered by
30   - * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  30 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
31 31 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
32   - * must display the words "Powered by KnowledgeTree" and retain the original
33   - * copyright notice.
  32 + * must display the words "Powered by KnowledgeTree" and retain the original
  33 + * copyright notice.
34 34 * Contributor( s): ______________________________________
35 35 *
36 36 */
... ... @@ -39,6 +39,7 @@ require_once(KT_LIB_DIR . &quot;/templating/templating.inc.php&quot;);
39 39 require_once(KT_LIB_DIR . "/dispatcher.inc.php");
40 40 require_once(KT_LIB_DIR . "/browse/Criteria.inc");
41 41 require_once(KT_LIB_DIR . "/search/savedsearch.inc.php");
  42 +require_once(KT_LIB_DIR . "/util/support.inc.php");
42 43  
43 44 class KTSupportDispatcher extends KTAdminDispatcher {
44 45 var $bAutomaticTransaction = true;
... ... @@ -56,18 +57,25 @@ class KTSupportDispatcher extends KTAdminDispatcher {
56 57 ));
57 58 return $oTemplate->render();
58 59 }
59   -
  60 +
60 61 function do_actualInfo() {
61   - $download = KTUtil::arrayGet($_REQUEST, 'fDownload', false);
62   - if ($download != false) {
63   - header("Content-Disposition: attachment; filename=\"php_info.htm\"");
64   - header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
65   - header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
66   - header("Cache-Control: must-revalidate");
67   - }
68   -
69   - print phpinfo();
70   - exit(0);
  62 +
  63 + $supportutil = new SupportUtil();
  64 + $supportutil->capture();
  65 + $archivefile = $supportutil->archive();
  66 + $supportutil->cleanup();
  67 +
  68 + $basename = basename($archivefile);
  69 +
  70 + header("Content-Type: application/zip");
  71 + header("Content-Disposition: attachment; filename=\"$basename\"");
  72 + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
  73 + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
  74 + header("Cache-Control: must-revalidate");
  75 +
  76 + readfile($archivefile);
  77 + unlink($archivefile);
  78 + exit(0);
71 79 }
72 80  
73 81 }
... ...
templates/ktcore/support.smarty
1 1 <h2>{i18n}Support and System Information{/i18n}</h2>
2 2  
3 3 {capture assign=kt_tracker_location}<a href="http://support.knowledgetree.com/">{i18n arg_appname="$appname"}#appname# Issue Tracker{/i18n}</a>{/capture}
4   -<p class="descriptiveText">{i18n arg_tracker=$kt_tracker_location}Visit the #tracker#{/i18n}</a>
  4 +<p class="descriptiveText">{i18n arg_tracker=$kt_tracker_location}Visit the #tracker#{/i18n}</a>
5 5 {i18n}first if you believe you have found a bug. Always check for known issues relating
6 6 to the version you are using &mdash; we may already have found the problem you're referring to,
7   -and may have fixed it in a newer version. If we ask for your PHP_INFO data, we're
8   -looking for the information described below.{/i18n}</p>
  7 +and may have fixed it in a newer version. {/i18n}</p>
  8 +<p class="descriptiveText">
  9 +{i18n}The following download action allows you to download a zip archive of information that may assist the KnowledgeTree team to diagnose problems on your system. This archive contains:{/i18n}
  10 +
  11 +<br>*
  12 +{i18n}PHP Information{/i18n}
  13 +<br>*
  14 +{i18n}Log Files (KnowledgeTree, Apache, Mysql){/i18n}
  15 +<br>*
  16 +{i18n}KnowledgeTree System Settings{/i18n}
  17 +<br>*
  18 +{i18n}KnowledgeTree Version Files{/i18n}
  19 +<br>*
  20 +{i18n}KnowledgeTree Database Schema (the structure of the database only){/i18n}
  21 +<br>*
  22 +{i18n}KnowledgeTree Database Counters Report{/i18n}
  23 +<br>*
  24 +{i18n}KnowledgeTree Database Storage Engine Report{/i18n}
  25 +<br>*
  26 +{i18n}System Information (Disk Usage, Process List, if easily detectable){/i18n}
  27 +<br>*
  28 +{i18n}MD5 Checksum of files (used to ensure files have not been tampered with){/i18n}
  29 +</p>
  30 +<p><a href="{addQS}action=actualInfo&fDownload=1{/addQS}"
  31 + class="ktInline ktAction ktDownload" title="Download Support Information">{i18n}Download Support information{/i18n}</a>
  32 +<a href="{addQS}action=actualInfo&fDownload=1{/addQS}">{i18n}Download Support information{/i18n}</a> </p>
  33 +
  34 +
9 35  
10 36 <p class="descriptiveText">{i18n}If you feel that the information presents to much
11 37 specific information about your system (e.g. you feel that it would be a security
12 38 risk to reveal aspects of it), please do sanitise the information, or ask us
13 39 if you can mail it directly to the developer who is dealing with your issue.{/i18n}</p>
14 40  
15   -<p><a href="{addQS}action=actualInfo&fDownload=1{/addQS}"
16   - class="ktInline ktAction ktDownload" title="Download PHP Information">{i18n}Download PHP information{/i18n}</a>
17   -<a href="{addQS}action=actualInfo&fDownload=1{/addQS}">{i18n}Download PHP information{/i18n}</a> </p>
18 41  
19   -<iframe src="{addQS}action=actualInfo{/addQS}" id="support-block">
20 42  
21   -</iframe>
  43 +
... ...