diff --git a/administrator/components/com_admin/models/sysinfo.php b/administrator/components/com_admin/models/sysinfo.php
index bcc95712246da..923c0bb5738b6 100644
--- a/administrator/components/com_admin/models/sysinfo.php
+++ b/administrator/components/com_admin/models/sysinfo.php
@@ -50,6 +50,90 @@ class AdminModelSysInfo extends JModelLegacy
*/
protected $php_info = null;
+ /**
+ * Array containing the phpinfo() data.
+ *
+ * @var array
+ *
+ * @since 3.5
+ */
+ protected $phpInfoArray;
+
+ /**
+ * Private/critical data that we don't want to share
+ *
+ * @var array
+ *
+ * @since 3.5
+ */
+ protected $privateSettings = array(
+ 'phpInfoArray' => array(
+ 'CONTEXT_DOCUMENT_ROOT',
+ 'DOCUMENT_ROOT',
+ 'extension_dir',
+ 'Host',
+ 'HTTP_COOKIE',
+ 'HTTP_HOST',
+ 'HTTP_ORIGIN',
+ 'HTTP_REFERER',
+ 'HTTP Request',
+ 'include_path',
+ 'mysql.default_socket',
+ 'MYSQL_SOCKET',
+ 'MYSQL_INCLUDE',
+ 'MYSQL_LIBS',
+ 'mysqli.default_socket',
+ 'MYSQLI_SOCKET',
+ 'PATH',
+ 'Path to sendmail',
+ 'pdo_mysql.default_socket',
+ 'Referer',
+ 'REMOTE_ADDR',
+ 'SCRIPT_FILENAME',
+ 'sendmail_path',
+ 'SERVER_ADDR',
+ 'SERVER_ADMIN',
+ 'Server Administrator',
+ 'SERVER_NAME',
+ 'Server Root',
+ 'session.name',
+ 'session.save_path',
+ 'User/Group',
+ ),
+ 'other' => array(
+ 'db',
+ 'dbprefix',
+ 'fromname',
+ 'live_site',
+ 'log_path',
+ 'mailfrom',
+ 'memcache_server_host',
+ 'memcached_server_host',
+ 'open_basedir',
+ 'Origin',
+ 'proxy_host',
+ 'proxy_user',
+ 'proxy_pass',
+ 'secret',
+ 'sendmail',
+ 'session.save_path',
+ 'session_memcache_server_host',
+ 'session_memcached_server_host',
+ 'sitename',
+ 'smtphost',
+ 'tmp_path'
+ )
+ );
+
+ /**
+ * System values that can be "safely" shared
+ *
+ * @var array
+ *
+ * @since 3.5
+ */
+ protected $safeData;
+
/**
* Information about writable state of directories
*
@@ -66,6 +150,67 @@ class AdminModelSysInfo extends JModelLegacy
*/
protected $editor = null;
+ /**
+ * Remove sections of data marked as private in the privateSettings
+ *
+ * @param array $dataArray Array with data tha may contain private informati
+ * @param string $dataType Type of data to search for an specific section in the privateSettings array
+ *
+ * @return array
+ *
+ * @since 3.5
+ */
+ protected function cleanPrivateData($dataArray, $dataType = 'other')
+ {
+ $dataType = isset($this->privateSettings[$dataType]) ? $dataType : 'other';
+
+ $privateSettings = $this->privateSettings[$dataType];
+
+ if (!$privateSettings)
+ {
+ return $dataArray;
+ }
+
+ foreach ($dataArray as $section => $values)
+ {
+ if (is_array($values))
+ {
+ $dataArray[$section] = $this->cleanPrivateData($values, $dataType);
+ }
+
+ if (in_array($section, $privateSettings, true))
+ {
+ $dataArray[$section] = $this->cleanSectionPrivateData($values);
+ }
+ }
+
+ return $dataArray;
+ }
+
+ /**
+ * Offuscate section values
+ *
+ * @param mixed $sectionValues Section data
+ *
+ * @return mixed
+ *
+ * @since 3.5
+ */
+ protected function cleanSectionPrivateData($sectionValues)
+ {
+ if (!is_array($sectionValues))
+ {
+ return strlen($sectionValues) ? 'xxxxxx' : '';
+ }
+
+ foreach ($sectionValues as $setting => $value)
+ {
+ $sectionValues[$setting] = strlen($value) ? 'xxxxxx' : '';
+ }
+
+ return $sectionValues;
+ }
+
/**
* Method to get the PHP settings
*
@@ -175,6 +320,36 @@ public function phpinfoEnabled()
return !in_array('phpinfo', explode(',', ini_get('disable_functions')));
}
+ /**
+ * Method to get filter data from the model
+ *
+ * @param string $dataType Type of data to get safely
+ *
+ * @return array
+ *
+ * @since 3.5
+ */
+ public function getSafeData($dataType)
+ {
+ if (isset($this->safeData[$dataType]))
+ {
+ return $this->safeData[$dataType];
+ }
+
+ $methodName = 'get' . ucfirst($dataType);
+
+ if (!method_exists($this, $methodName))
+ {
+ return array();
+ }
+
+ $data = $this->$methodName();
+
+ $this->safeData[$dataType] = $this->cleanPrivateData($data, $dataType);
+
+ return $this->safeData[$dataType];
+ }
+
/**
* Method to get the PHP info
*
@@ -214,6 +389,96 @@ public function &getPHPInfo()
return $this->php_info;
}
+ /**
+ * Get phpinfo() output as array
+ *
+ * @return array
+ *
+ * @since 3.5
+ */
+ public function getPhpInfoArray()
+ {
+ // Already cached
+ if (null !== $this->phpInfoArray)
+ {
+ return $this->phpInfoArray;
+ }
+
+ $phpInfo = $this->getPhpInfo();
+
+ $this->phpInfoArray = $this->parsePhpInfo($phpInfo);
+
+ return $this->phpInfoArray;
+ }
+
+ /**
+ * Method to get a list of installed extensions
+ *
+ * @return array installed extensions
+ *
+ * @since 3.5
+ */
+ public function getExtensions()
+ {
+ $installed = array();
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true)
+ ->select('*')
+ ->from($db->qn('#__extensions'));
+ $db->setQuery($query);
+
+ try
+ {
+ $extensions = $db->loadObjectList();
+ }
+ catch (Exception $e)
+ {
+ JLog::add(JText::sprintf('JLIB_DATABASE_ERROR_FUNCTION_FAILED', $e->getCode(), $e->getMessage()), JLog::WARNING, 'jerror');
+
+ return $installed;
+ }
+
+ if (empty($extensions))
+ {
+ return $installed;
+ }
+
+ foreach ($extensions as $extension)
+ {
+ if (strlen($extension->name) == 0)
+ {
+ continue;
+ }
+
+ $installed[$extension->name] = array(
+ 'name' => $extension->name,
+ 'type' => $extension->type,
+ 'author' => 'unknown',
+ 'version' => 'unknown',
+ 'creationDate' => 'unknown',
+ 'authorUrl' => 'unknown'
+ );
+
+ $manifest = json_decode($extension->manifest_cache);
+
+ if (!$manifest instanceof stdClass)
+ {
+ continue;
+ }
+
+ $extraData = array(
+ 'author' => $manifest->author,
+ 'version' => $manifest->version,
+ 'creationDate' => $manifest->creationDate,
+ 'authorUrl' => $manifest->authorUrl
+ );
+
+ $installed[$extension->name] = array_merge($installed[$extension->name], $extraData);
+ }
+
+ return $installed;
+ }
+
/**
* Method to get the directory states
*
@@ -371,4 +636,52 @@ public function &getEditor()
return $this->editor;
}
+
+ /**
+ * Parse phpinfo output into an array
+ * Source https://gist.github.com/sbmzhcn/6255314
+ *
+ * @param string $html Output of phpinfo()
+ *
+ * @return array
+ *
+ * @since 3.5
+ */
+ protected function parsePhpInfo($html)
+ {
+ $html = strip_tags($html, '
| ');
+ $html = preg_replace('/ | ]*>([^<]+)<\/th>/', '\1', $html);
+ $html = preg_replace('/ | ]*>([^<]+)<\/td>/', '\1', $html);
+ $t = preg_split('/(]*>[^<]+<\/h2>)/', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
+ $r = array();
+ $count = count($t);
+ $p1 = '([^<]+)<\/info>';
+ $p2 = '/' . $p1 . '\s*' . $p1 . '\s*' . $p1 . '/';
+ $p3 = '/' . $p1 . '\s*' . $p1 . '/';
+
+ for ($i = 1; $i < $count; $i++)
+ {
+ if (preg_match('/]*>([^<]+)<\/h2>/', $t[$i], $matchs))
+ {
+ $name = trim($matchs[1]);
+ $vals = explode("\n", $t[$i + 1]);
+
+ foreach ($vals AS $val)
+ {
+ // 3cols
+ if (preg_match($p2, $val, $matchs))
+ {
+ $r[$name][trim($matchs[1])] = array(trim($matchs[2]), trim($matchs[3]));
+ }
+ // 2cols
+ elseif (preg_match($p3, $val, $matchs))
+ {
+ $r[$name][trim($matchs[1])] = trim($matchs[2]);
+ }
+ }
+ }
+ }
+
+ return $r;
+ }
}
diff --git a/administrator/components/com_admin/views/sysinfo/tmpl/default.php b/administrator/components/com_admin/views/sysinfo/tmpl/default.php
index d1aa1eb6fb2c3..c4ff26354b2da 100644
--- a/administrator/components/com_admin/views/sysinfo/tmpl/default.php
+++ b/administrator/components/com_admin/views/sysinfo/tmpl/default.php
@@ -13,7 +13,7 @@
JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html');
?>
-
diff --git a/administrator/components/com_admin/views/sysinfo/view.html.php b/administrator/components/com_admin/views/sysinfo/view.html.php
index b9c465c516f42..b0547719863d3 100644
--- a/administrator/components/com_admin/views/sysinfo/view.html.php
+++ b/administrator/components/com_admin/views/sysinfo/view.html.php
@@ -116,6 +116,8 @@ protected function _setSubMenu()
protected function addToolbar()
{
JToolbarHelper::title(JText::_('COM_ADMIN_SYSTEM_INFORMATION'), 'info-2 systeminfo');
+ JToolbarHelper::link(JRoute::_('index.php?option=com_admin&view=sysinfo&format=text'), 'COM_ADMIN_DOWNLOAD_SYSTEM_INFORMATION_TEXT', 'download');
+ JToolbarHelper::link(JRoute::_('index.php?option=com_admin&view=sysinfo&format=json'), 'COM_ADMIN_DOWNLOAD_SYSTEM_INFORMATION_JSON', 'download');
JToolbarHelper::help('JHELP_SITE_SYSTEM_INFORMATION');
}
}
diff --git a/administrator/components/com_admin/views/sysinfo/view.json.php b/administrator/components/com_admin/views/sysinfo/view.json.php
new file mode 100644
index 0000000000000..0c8022f4892ef
--- /dev/null
+++ b/administrator/components/com_admin/views/sysinfo/view.json.php
@@ -0,0 +1,67 @@
+authorise('core.admin'))
+ {
+ return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR'));
+ }
+
+ header('MIME-Version: 1.0');
+ header('Content-Disposition: attachment; filename="systeminfo-' . date("c") . '.json"');
+ header('Content-Transfer-Encoding: binary');
+
+ $data = $this->getLayoutData();
+
+ echo json_encode($data);
+
+ JFactory::getApplication()->close();
+ }
+
+ /**
+ * Get the data for the view
+ *
+ * @return array
+ *
+ * @since 3.5
+ */
+ protected function getLayoutData()
+ {
+ $model = $this->getModel();
+
+ return array(
+ 'info' => $model->getSafeData('info'),
+ 'phpSettings' => $model->getSafeData('phpSettings'),
+ 'config' => $model->getSafeData('config'),
+ 'directories' => $model->getSafeData('directory'),
+ 'phpInfo' => $model->getSafeData('phpInfoArray'),
+ 'extensions' => $model->getSafeData('extensions')
+ );
+ }
+}
diff --git a/administrator/components/com_admin/views/sysinfo/view.text.php b/administrator/components/com_admin/views/sysinfo/view.text.php
new file mode 100644
index 0000000000000..78b45e4e1395e
--- /dev/null
+++ b/administrator/components/com_admin/views/sysinfo/view.text.php
@@ -0,0 +1,175 @@
+authorise('core.admin'))
+ {
+ return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR'));
+ }
+
+ header('Content-Description: File Transfer');
+ header('Content-Disposition: attachment; filename="systeminfo-' . date("c") . '.txt"');
+ header('Cache-Control: must-revalidate');
+
+ $data = $this->getLayoutData();
+
+ $lines = array();
+
+ foreach ($data as $sectionName => $section)
+ {
+ $customRenderingMethod = 'render' . ucfirst($sectionName);
+
+ if (method_exists($this, $customRenderingMethod))
+ {
+ $lines[] = $this->$customRenderingMethod($section['title'], $section['data']);
+ }
+ else
+ {
+ $lines[] = $this->renderSection($section['title'], $section['data']);
+ }
+ }
+
+ echo implode("\n\n", $lines);
+
+ JFactory::getApplication()->close();
+ }
+
+ /**
+ * Get the data for the view
+ *
+ * @return array
+ *
+ * @since 3.5
+ */
+ protected function getLayoutData()
+ {
+ $model = $this->getModel();
+
+ return array(
+ 'info' => array(
+ 'title' => JText::_('COM_ADMIN_SYSTEM_INFORMATION', true),
+ 'data' => $model->getSafeData('info')
+ ),
+ 'phpSettings' => array(
+ 'title' => JText::_('COM_ADMIN_PHP_SETTINGS', true),
+ 'data' => $model->getSafeData('phpSettings')
+ ),
+ 'config' => array(
+ 'title' => JText::_('COM_ADMIN_CONFIGURATION_FILE', true),
+ 'data' => $model->getSafeData('config')
+ ),
+ 'directories' => array(
+ 'title' => JText::_('COM_ADMIN_DIRECTORY_PERMISSIONS', true),
+ 'data' => $model->getSafeData('directory')
+ ),
+ 'phpInfo' => array(
+ 'title' => JText::_('COM_ADMIN_PHP_INFORMATION', true),
+ 'data' => $model->getSafeData('phpInfoArray')
+ ),
+ 'extensions' => array(
+ 'title' => JText::_('COM_ADMIN_EXTENSIONS', true),
+ 'data' => $model->getSafeData('extensions')
+ )
+ );
+ }
+
+ /**
+ * Render a section
+ *
+ * @param string $sectionName Name of the section to render
+ * @param array $sectionData Data of the section to render
+ * @param integer $level Depth level for indentation
+ *
+ * @return string
+ *
+ * @since 3.5
+ */
+ protected function renderSection($sectionName, $sectionData, $level = 0)
+ {
+ $lines = array();
+
+ $margin = ($level > 0) ? str_repeat("\t", $level) : null;
+
+ $lines[] = $margin . "=============";
+ $lines[] = $margin . $sectionName;
+ $lines[] = $margin . "=============";
+ $level++;
+
+ foreach ($sectionData as $name => $value)
+ {
+ if (is_array($value))
+ {
+ if ($name == 'Directive')
+ {
+ continue;
+ }
+
+ $lines[] = "";
+ $lines[] = $this->renderSection($name, $value, $level);
+ }
+ else
+ {
+ if (is_bool($value))
+ {
+ $value = $value ? 'true' : 'false';
+ }
+
+ if (is_int($name) && ($name == 0 || $name == 1))
+ {
+ $name = ($name == 0 ? 'Local Value' : 'Master Value');
+ }
+
+ $lines[] = $margin . $name . ': ' . $value;
+ }
+ }
+
+ return implode("\n", $lines);
+ }
+
+ /**
+ * Specific rendering for directories
+ *
+ * @param string $sectionName Name of the section
+ * @param array $sectionData Directories information
+ * @param integer $level Starting level
+ *
+ * @return string
+ *
+ * @since 3.5
+ */
+ protected function renderDirectories($sectionName, $sectionData, $level = -1)
+ {
+ foreach ($sectionData as $directory => $data)
+ {
+ $sectionData[$directory] = $data['writable'] ? ' writable' : ' NOT writable';
+ }
+
+ return $this->renderSection($sectionName, $sectionData, $level);
+ }
+}
diff --git a/administrator/includes/toolbar.php b/administrator/includes/toolbar.php
index cba3e1c7a0870..b618ff34beab8 100644
--- a/administrator/includes/toolbar.php
+++ b/administrator/includes/toolbar.php
@@ -153,6 +153,24 @@ public static function back($alt = 'JTOOLBAR_BACK', $href = 'javascript:history.
$bar->appendButton('Link', 'back', $alt, $href);
}
+ /**
+ * Creates a button to redirect to a link
+ *
+ * @param string $url The link url
+ * @param string $text Button text
+ * @param string $name Name to be used as apart of the id
+ *
+ * @return void
+ *
+ * @since 3.5
+ */
+ public static function link($url, $text, $name = 'link')
+ {
+ $bar = JToolbar::getInstance('toolbar');
+
+ $bar->appendButton('Link', $name, $text, $url);
+ }
+
/**
* Writes a media_manager button.
*
diff --git a/administrator/language/en-GB/en-GB.com_admin.ini b/administrator/language/en-GB/en-GB.com_admin.ini
index ec969fd3a7618..0f573f0c990bf 100644
--- a/administrator/language/en-GB/en-GB.com_admin.ini
+++ b/administrator/language/en-GB/en-GB.com_admin.ini
@@ -15,6 +15,9 @@ COM_ADMIN_DIRECTORY="Folder"
COM_ADMIN_DIRECTORY_PERMISSIONS="Folder Permissions"
COM_ADMIN_DISABLED_FUNCTIONS="Disabled Functions"
COM_ADMIN_DISPLAY_ERRORS="Display Errors"
+COM_ADMIN_DOWNLOAD_SYSTEM_INFORMATION_TEXT="Download as text"
+COM_ADMIN_DOWNLOAD_SYSTEM_INFORMATION_JSON="Download as JSON"
+COM_ADMIN_EXTENSIONS="Extensions"
COM_ADMIN_FILE_UPLOADS="File Uploads"
COM_ADMIN_GLOSSARY="Glossary"
COM_ADMIN_GO="Go"
|