Version Notes
Download this release
Release Info
Developer | NEKLO |
Extension | neklo_monitor |
Version | 1.1.2 |
Comparing to | |
See all releases |
Version 1.1.2
- app/code/community/Neklo/Core/Block/System/Contact.php +16 -0
- app/code/community/Neklo/Core/Block/System/Contact/Header.php +17 -0
- app/code/community/Neklo/Core/Block/System/Contact/Send.php +20 -0
- app/code/community/Neklo/Core/Block/System/Contact/Send/Button.php +35 -0
- app/code/community/Neklo/Core/Block/System/Extension.php +16 -0
- app/code/community/Neklo/Core/Block/System/Extension/List.php +104 -0
- app/code/community/Neklo/Core/Block/System/Newsletter/Subscribe.php +20 -0
- app/code/community/Neklo/Core/Block/System/Newsletter/Subscribe/Button.php +35 -0
- app/code/community/Neklo/Core/Helper/Config.php +16 -0
- app/code/community/Neklo/Core/Helper/Data.php +28 -0
- app/code/community/Neklo/Core/Helper/Extension.php +104 -0
- app/code/community/Neklo/Core/Model/Feed.php +92 -0
- app/code/community/Neklo/Core/Model/Feed/Extension.php +48 -0
- app/code/community/Neklo/Core/Model/Observer.php +52 -0
- app/code/community/Neklo/Core/Model/Source/Reason.php +28 -0
- app/code/community/Neklo/Core/Model/Source/Subscription/Type.php +45 -0
- app/code/community/Neklo/Core/Model/System/Config/Backend/Empty.php +9 -0
- app/code/community/Neklo/Core/controllers/Adminhtml/Neklo/Core/ContactController.php +51 -0
- app/code/community/Neklo/Core/controllers/Adminhtml/Neklo/Core/NewsletterController.php +47 -0
- app/code/community/Neklo/Core/etc/adminhtml.xml +26 -0
- app/code/community/Neklo/Core/etc/config.xml +83 -0
- app/code/community/Neklo/Core/etc/system.xml +164 -0
- app/code/community/Neklo/Monitor/Autoload.php +32 -0
- app/code/community/Neklo/Monitor/Block/Adminhtml/System/Config/Frontend/Label.php +9 -0
- app/code/community/Neklo/Monitor/Block/Adminhtml/System/Config/Frontend/Status.php +35 -0
- app/code/community/Neklo/Monitor/Controller/Abstract.php +72 -0
- app/code/community/Neklo/Monitor/Helper/Config.php +148 -0
- app/code/community/Neklo/Monitor/Helper/Country.php +19 -0
- app/code/community/Neklo/Monitor/Helper/Data.php +5 -0
- app/code/community/Neklo/Monitor/Helper/Date.php +15 -0
- app/code/community/Neklo/Monitor/Helper/Request.php +177 -0
- app/code/community/Neklo/Monitor/Helper/Request/Validator.php +108 -0
- app/code/community/Neklo/Monitor/Model/Cron/Abstract.php +66 -0
- app/code/community/Neklo/Monitor/Model/Cron/Server.php +46 -0
- app/code/community/Neklo/Monitor/Model/Cron/Store.php +58 -0
- app/code/community/Neklo/Monitor/Model/Gateway/Connector.php +104 -0
- app/code/community/Neklo/Monitor/Model/Linfo.php +296 -0
- app/code/community/Neklo/Monitor/Model/Linfo/Os/Linux.php +39 -0
- app/code/community/Neklo/Monitor/Model/Log.php +6 -0
- app/code/community/Neklo/Monitor/Model/Minfo.php +69 -0
- app/code/community/Neklo/Monitor/Model/Minfo/Log.php +195 -0
- app/code/community/Neklo/Monitor/Model/Minfo/Parser.php +206 -0
- app/code/community/Neklo/Monitor/Model/Minfo/Report.php +154 -0
- app/code/community/Neklo/Monitor/Model/Resource/Minfo/Log.php +55 -0
- app/code/community/Neklo/Monitor/Model/Resource/Minfo/Log/Collection.php +10 -0
- app/code/community/Neklo/Monitor/Model/Resource/Minfo/Report.php +49 -0
- app/code/community/Neklo/Monitor/Model/Resource/Minfo/Report/Collection.php +10 -0
- app/code/community/Neklo/Monitor/Model/System/Config/Backend/Empty.php +9 -0
- app/code/community/Neklo/Monitor/Model/System/Config/Backend/Token.php +17 -0
- app/code/community/Neklo/Monitor/Model/System/Config/Source/Server/Type.php +35 -0
- app/code/community/Neklo/Monitor/controllers/AuthController.php +30 -0
- app/code/community/Neklo/Monitor/controllers/CustomerController.php +212 -0
- app/code/community/Neklo/Monitor/controllers/DashboardController.php +437 -0
- app/code/community/Neklo/Monitor/controllers/InfoController.php +73 -0
- app/code/community/Neklo/Monitor/controllers/OrderController.php +118 -0
- app/code/community/Neklo/Monitor/controllers/ProductController.php +32 -0
- app/code/community/Neklo/Monitor/controllers/Report/SalesController.php +187 -0
- app/code/community/Neklo/Monitor/controllers/State/CacheController.php +46 -0
- app/code/community/Neklo/Monitor/controllers/State/IndexerController.php +53 -0
- app/code/community/Neklo/Monitor/controllers/Var/LogController.php +86 -0
- app/code/community/Neklo/Monitor/controllers/Var/ReportController.php +89 -0
- app/code/community/Neklo/Monitor/etc/adminhtml.xml +26 -0
- app/code/community/Neklo/Monitor/etc/config.xml +95 -0
- app/code/community/Neklo/Monitor/etc/system.xml +177 -0
- app/code/community/Neklo/Monitor/sql/neklo_monitor_setup/mysql4-install-1.0.0.php +24 -0
- app/code/community/Neklo/Monitor/sql/neklo_monitor_setup/mysql4-upgrade-1.0.0-1.1.0.php +26 -0
- app/code/community/Neklo/Monitor/sql/neklo_monitor_setup/mysql4-upgrade-1.1.0-1.1.1.php +18 -0
- app/code/community/Neklo/Monitor/sql/neklo_monitor_setup/mysql4-upgrade-1.1.1-1.1.2.php +16 -0
- app/design/adminhtml/default/default/layout/neklo/core.xml +10 -0
- app/design/adminhtml/default/default/template/neklo/core/system/contact/button.phtml +190 -0
- app/design/adminhtml/default/default/template/neklo/core/system/contact/header.phtml +2 -0
- app/design/adminhtml/default/default/template/neklo/core/system/extension/list.phtml +25 -0
- app/design/adminhtml/default/default/template/neklo/core/system/subscribe/button.phtml +180 -0
- app/etc/modules/Neklo_Core.xml +10 -0
- app/etc/modules/Neklo_Monitor.xml +9 -0
- app/locale/en_US/Neklo_Core.csv +19 -0
- lib/Linfo/Common.php +190 -0
- lib/Linfo/Exceptions/FatalException.php +25 -0
- lib/Linfo/Extension/Apcaccess.php +200 -0
- lib/Linfo/Extension/Cups.php +229 -0
- lib/Linfo/Extension/Dhcpd3_leases.php +292 -0
- lib/Linfo/Extension/Dnsmasq_dhcpd.php +151 -0
- lib/Linfo/Extension/Extension.php +33 -0
- lib/Linfo/Extension/Ipmi.php +128 -0
- lib/Linfo/Extension/Libvirt.php +216 -0
- lib/Linfo/Extension/Smb.php +323 -0
- lib/Linfo/Extension/Soldat.php +250 -0
- lib/Linfo/Extension/Transmission.php +363 -0
- lib/Linfo/Extension/Truecrypt.php +215 -0
- lib/Linfo/Extension/Utorrent.php +297 -0
- lib/Linfo/Lang/de.php +101 -0
- lib/Linfo/Lang/en.php +107 -0
- lib/Linfo/Lang/fi.php +104 -0
- lib/Linfo/Lang/fr.php +101 -0
- lib/Linfo/Lang/it.php +105 -0
- lib/Linfo/Lang/pl.php +103 -0
- lib/Linfo/Lang/pt.php +104 -0
- lib/Linfo/Lang/zh.php +105 -0
- lib/Linfo/Linfo.php +504 -0
- lib/Linfo/Meta/Errors.php +77 -0
- lib/Linfo/Meta/Timer.php +35 -0
- lib/Linfo/OS/BSDcommon.php +157 -0
- lib/Linfo/OS/Darwin.php +622 -0
- lib/Linfo/OS/DragonFly.php +415 -0
- lib/Linfo/OS/FreeBSD.php +729 -0
- lib/Linfo/OS/Linux.php +1729 -0
- lib/Linfo/OS/Minix.php +139 -0
- lib/Linfo/OS/NetBSD.php +498 -0
- lib/Linfo/OS/OS.php +106 -0
- lib/Linfo/OS/OpenBSD.php +469 -0
- lib/Linfo/OS/SunOS.php +456 -0
- lib/Linfo/OS/Unixcommon.php +77 -0
- lib/Linfo/OS/Windows.php +769 -0
- lib/Linfo/Output/Html.php +1006 -0
- lib/Linfo/Output/Json.php +45 -0
- lib/Linfo/Output/Ncurses.php +260 -0
- lib/Linfo/Output/Output.php +29 -0
- lib/Linfo/Output/Serialized.php +27 -0
- lib/Linfo/Output/Xml.php +326 -0
- lib/Linfo/Parsers/CallExt.php +130 -0
- lib/Linfo/Parsers/Hddtemp.php +180 -0
- lib/Linfo/Parsers/Hwpci.php +308 -0
- lib/Linfo/Parsers/Mbmon.php +93 -0
- lib/Linfo/Parsers/Sensord.php +70 -0
- package.xml +2 -0
- skin/adminhtml/default/default/neklo/core/css/style.css +52 -0
- skin/adminhtml/default/default/neklo/core/images/ok.gif +0 -0
- skin/adminhtml/default/default/neklo/core/images/update.gif +0 -0
- skin/adminhtml/default/default/neklo/monitor/css/styles.css +6 -0
app/code/community/Neklo/Core/Block/System/Contact.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Block_System_Contact extends Mage_Adminhtml_Block_System_Config_Form_Fieldset
|
4 |
+
{
|
5 |
+
protected function _getHeaderHtml($element)
|
6 |
+
{
|
7 |
+
return parent::_getHeaderHtml($element) . $this->_getAfterHeaderHtml();
|
8 |
+
}
|
9 |
+
|
10 |
+
protected function _getAfterHeaderHtml()
|
11 |
+
{
|
12 |
+
$subscribeButton = $this->getLayout()->createBlock('neklo_core/system_contact_header', 'neklo_core_contact_header');
|
13 |
+
$subscribeButton->setTemplate('neklo/core/system/contact/header.phtml');
|
14 |
+
return $subscribeButton->toHtml();
|
15 |
+
}
|
16 |
+
}
|
app/code/community/Neklo/Core/Block/System/Contact/Header.php
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Block_System_Contact_Header extends Mage_Adminhtml_Block_Template
|
4 |
+
{
|
5 |
+
const STORE_URL = 'http://store.neklo.com/';
|
6 |
+
const STORE_LABEL = 'store.neklo.com';
|
7 |
+
|
8 |
+
public function getStoreUrl()
|
9 |
+
{
|
10 |
+
return self::STORE_URL;
|
11 |
+
}
|
12 |
+
|
13 |
+
public function getStoreLabel()
|
14 |
+
{
|
15 |
+
return self::STORE_LABEL;
|
16 |
+
}
|
17 |
+
}
|
app/code/community/Neklo/Core/Block/System/Contact/Send.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Block_System_Contact_Send extends Mage_Adminhtml_Block_System_Config_Form_Field
|
4 |
+
{
|
5 |
+
public function render(Varien_Data_Form_Element_Abstract $element)
|
6 |
+
{
|
7 |
+
$element->setScope(false);
|
8 |
+
$element->setCanUseWebsiteValue(false);
|
9 |
+
$element->setCanUseDefaultValue(false);
|
10 |
+
return parent::render($element);
|
11 |
+
}
|
12 |
+
|
13 |
+
protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
|
14 |
+
{
|
15 |
+
$subscribeButton = $this->getLayout()->createBlock('neklo_core/system_contact_send_button', 'neklo_core_contact_send');
|
16 |
+
$subscribeButton->setTemplate('neklo/core/system/contact/button.phtml');
|
17 |
+
$subscribeButton->setContainerId($element->getContainer()->getHtmlId());
|
18 |
+
return $subscribeButton->toHtml();
|
19 |
+
}
|
20 |
+
}
|
app/code/community/Neklo/Core/Block/System/Contact/Send/Button.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Block_System_Contact_Send_Button extends Mage_Adminhtml_Block_Template
|
4 |
+
{
|
5 |
+
/**
|
6 |
+
* @return Mage_Adminhtml_Block_Widget_Button
|
7 |
+
*/
|
8 |
+
public function getButton()
|
9 |
+
{
|
10 |
+
$button = $this->getLayout()->createBlock('adminhtml/widget_button');
|
11 |
+
$button
|
12 |
+
->setType('button')
|
13 |
+
->setLabel($this->__('Send'))
|
14 |
+
->setStyle("width:280px")
|
15 |
+
->setId('neklo_core_contact_send')
|
16 |
+
;
|
17 |
+
return $button;
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @return string
|
22 |
+
*/
|
23 |
+
public function getButtonHtml()
|
24 |
+
{
|
25 |
+
return $this->getButton()->toHtml();
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @return string
|
30 |
+
*/
|
31 |
+
public function getContainerId()
|
32 |
+
{
|
33 |
+
return parent::getContainerId();
|
34 |
+
}
|
35 |
+
}
|
app/code/community/Neklo/Core/Block/System/Extension.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Block_System_Extension extends Mage_Adminhtml_Block_System_Config_Form_Fieldset
|
4 |
+
{
|
5 |
+
protected function _getHeaderHtml($element)
|
6 |
+
{
|
7 |
+
return parent::_getHeaderHtml($element) . $this->_getContentHtml();
|
8 |
+
}
|
9 |
+
|
10 |
+
protected function _getContentHtml()
|
11 |
+
{
|
12 |
+
$extensionListBlock = $this->getLayout()->createBlock('neklo_core/system_extension_list', 'neklo_core_extension_list');
|
13 |
+
$extensionListBlock->setTemplate('neklo/core/system/extension/list.phtml');
|
14 |
+
return $extensionListBlock->toHtml();
|
15 |
+
}
|
16 |
+
}
|
app/code/community/Neklo/Core/Block/System/Extension/List.php
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Block_System_Extension_List extends Mage_Adminhtml_Block_Template
|
4 |
+
{
|
5 |
+
const DOMAIN = 'http://store.neklo.com/';
|
6 |
+
const IMAGE_EXTENSION = '.jpg';
|
7 |
+
|
8 |
+
protected $_feedData = null;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @param string $code
|
12 |
+
*
|
13 |
+
* @return bool
|
14 |
+
*/
|
15 |
+
public function canShowExtension($code)
|
16 |
+
{
|
17 |
+
$feedData = $this->_getExtensionInfo(strtolower($code));
|
18 |
+
return !!count($feedData);
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @return array
|
23 |
+
*/
|
24 |
+
public function getExtensionList()
|
25 |
+
{
|
26 |
+
return Mage::helper('neklo_core/extension')->getModuleConfigList();
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @param string $code
|
31 |
+
*
|
32 |
+
* @return mixed
|
33 |
+
*/
|
34 |
+
public function getExtensionName($code)
|
35 |
+
{
|
36 |
+
$feedData = $this->_getExtensionInfo(strtolower($code));
|
37 |
+
if (!array_key_exists('name', $feedData)) {
|
38 |
+
return $code;
|
39 |
+
}
|
40 |
+
return $feedData['name'];
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* @param string $code
|
45 |
+
* @param $config
|
46 |
+
*
|
47 |
+
* @return bool
|
48 |
+
*/
|
49 |
+
public function isExtensionVersionOutdated($code, $config)
|
50 |
+
{
|
51 |
+
$currentVersion = $this->getExtensionVersion($config);
|
52 |
+
$lastVersion = $this->getLastExtensionVersion($code);
|
53 |
+
return version_compare($currentVersion, $lastVersion) === -1;
|
54 |
+
}
|
55 |
+
|
56 |
+
public function getExtensionVersion($config)
|
57 |
+
{
|
58 |
+
$version = (string)$config->version;
|
59 |
+
if (!$version) {
|
60 |
+
return '';
|
61 |
+
}
|
62 |
+
return $version;
|
63 |
+
}
|
64 |
+
|
65 |
+
public function getLastExtensionVersion($code)
|
66 |
+
{
|
67 |
+
$feedData = $this->_getExtensionInfo(strtolower($code));
|
68 |
+
if (!array_key_exists('version', $feedData)) {
|
69 |
+
return '0';
|
70 |
+
}
|
71 |
+
return $feedData['version'];
|
72 |
+
}
|
73 |
+
|
74 |
+
public function getExtensionUrl($code)
|
75 |
+
{
|
76 |
+
$feedData = $this->_getExtensionInfo(strtolower($code));
|
77 |
+
if (!array_key_exists('url', $feedData)) {
|
78 |
+
return null;
|
79 |
+
}
|
80 |
+
return $feedData['url'];
|
81 |
+
}
|
82 |
+
|
83 |
+
public function getImageUrl($code)
|
84 |
+
{
|
85 |
+
$imgUrl = self::DOMAIN . 'cache/' . ($this->_getCacheKey() ? $this->_getCacheKey() . '/' : '') . strtolower($code) . self::IMAGE_EXTENSION;
|
86 |
+
return $imgUrl;
|
87 |
+
}
|
88 |
+
|
89 |
+
protected function _getCacheKey()
|
90 |
+
{
|
91 |
+
return Mage::helper('neklo_core/extension')->getCacheKey();
|
92 |
+
}
|
93 |
+
|
94 |
+
protected function _getExtensionInfo($code)
|
95 |
+
{
|
96 |
+
if (is_null($this->_feedData)) {
|
97 |
+
$this->_feedData = Mage::getModel('neklo_core/feed_extension')->getFeed();
|
98 |
+
}
|
99 |
+
if (!array_key_exists($code, $this->_feedData)) {
|
100 |
+
return array();
|
101 |
+
}
|
102 |
+
return $this->_feedData[$code];
|
103 |
+
}
|
104 |
+
}
|
app/code/community/Neklo/Core/Block/System/Newsletter/Subscribe.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Block_System_Newsletter_Subscribe extends Mage_Adminhtml_Block_System_Config_Form_Field
|
4 |
+
{
|
5 |
+
public function render(Varien_Data_Form_Element_Abstract $element)
|
6 |
+
{
|
7 |
+
$element->setScope(false);
|
8 |
+
$element->setCanUseWebsiteValue(false);
|
9 |
+
$element->setCanUseDefaultValue(false);
|
10 |
+
return parent::render($element);
|
11 |
+
}
|
12 |
+
|
13 |
+
protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
|
14 |
+
{
|
15 |
+
$subscribeButton = $this->getLayout()->createBlock('neklo_core/system_newsletter_subscribe_button', 'neklo_core_subscribe');
|
16 |
+
$subscribeButton->setTemplate('neklo/core/system/subscribe/button.phtml');
|
17 |
+
$subscribeButton->setContainerId($element->getContainer()->getHtmlId());
|
18 |
+
return $subscribeButton->toHtml();
|
19 |
+
}
|
20 |
+
}
|
app/code/community/Neklo/Core/Block/System/Newsletter/Subscribe/Button.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Block_System_Newsletter_Subscribe_Button extends Mage_Adminhtml_Block_Template
|
4 |
+
{
|
5 |
+
/**
|
6 |
+
* @return Mage_Adminhtml_Block_Widget_Button
|
7 |
+
*/
|
8 |
+
public function getButton()
|
9 |
+
{
|
10 |
+
$button = $this->getLayout()->createBlock('adminhtml/widget_button');
|
11 |
+
$button
|
12 |
+
->setType('button')
|
13 |
+
->setLabel($this->__('Subscribe'))
|
14 |
+
->setStyle("width:280px")
|
15 |
+
->setId('neklo_core_subscribe')
|
16 |
+
;
|
17 |
+
return $button;
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @return string
|
22 |
+
*/
|
23 |
+
public function getButtonHtml()
|
24 |
+
{
|
25 |
+
return $this->getButton()->toHtml();
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @return string
|
30 |
+
*/
|
31 |
+
public function getContainerId()
|
32 |
+
{
|
33 |
+
return parent::getContainerId();
|
34 |
+
}
|
35 |
+
}
|
app/code/community/Neklo/Core/Helper/Config.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Helper_Config extends Mage_Compiler_Helper_Data
|
4 |
+
{
|
5 |
+
const NOTIFICATION_TYPE = 'neklo_core/notification/type';
|
6 |
+
|
7 |
+
/**
|
8 |
+
* @param null|int|Mage_Core_Model_Store $store
|
9 |
+
*
|
10 |
+
* @return array
|
11 |
+
*/
|
12 |
+
public function getNotificationTypeList($store = null)
|
13 |
+
{
|
14 |
+
return explode(',', Mage::getStoreConfig(self::NOTIFICATION_TYPE, $store));
|
15 |
+
}
|
16 |
+
}
|
app/code/community/Neklo/Core/Helper/Data.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Helper_Data extends Mage_Core_Helper_Abstract
|
4 |
+
{
|
5 |
+
const DOMAIN = 'http://store.neklo.com/';
|
6 |
+
const LOGO_IMG = 'neklo.png';
|
7 |
+
|
8 |
+
public function __()
|
9 |
+
{
|
10 |
+
$args = func_get_args();
|
11 |
+
if ($args[0] == '[NEKLO]') {
|
12 |
+
return '<img src="' . $this->_getLogoUrl() . '" height="11" alt="Neklo" title="" />';
|
13 |
+
}
|
14 |
+
$expr = new Mage_Core_Model_Translate_Expr(array_shift($args), $this->_getModuleName());
|
15 |
+
array_unshift($args, $expr);
|
16 |
+
return Mage::app()->getTranslator()->translate($args);
|
17 |
+
}
|
18 |
+
|
19 |
+
protected function _getLogoUrl()
|
20 |
+
{
|
21 |
+
return self::DOMAIN . 'cache/' . ($this->_getCacheKey() ? $this->_getCacheKey() . '/' : '') . self::LOGO_IMG;
|
22 |
+
}
|
23 |
+
|
24 |
+
protected function _getCacheKey()
|
25 |
+
{
|
26 |
+
return Mage::helper('neklo_core/extension')->getCacheKey();
|
27 |
+
}
|
28 |
+
}
|
app/code/community/Neklo/Core/Helper/Extension.php
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Helper_Extension extends Mage_Core_Helper_Abstract
|
4 |
+
{
|
5 |
+
protected $_protectedModuleCodeList = array(
|
6 |
+
'Neklo_Core'
|
7 |
+
);
|
8 |
+
|
9 |
+
protected $_cacheKey = null;
|
10 |
+
protected $_moduleConfigList = null;
|
11 |
+
protected $_moduleList = null;
|
12 |
+
|
13 |
+
public function getModuleList()
|
14 |
+
{
|
15 |
+
if (is_null($this->_moduleList)) {
|
16 |
+
$moduleList = array();
|
17 |
+
foreach ($this->getModuleConfigList() as $moduleCode => $moduleConfig) {
|
18 |
+
$moduleList[$moduleCode] = array(
|
19 |
+
'name' => $moduleConfig->extension_name ? $moduleConfig->extension_name : $moduleCode,
|
20 |
+
'version' => $moduleConfig->version,
|
21 |
+
);
|
22 |
+
}
|
23 |
+
$this->_moduleList = $moduleList;
|
24 |
+
}
|
25 |
+
return $this->_moduleList;
|
26 |
+
}
|
27 |
+
|
28 |
+
public function getModuleConfigList()
|
29 |
+
{
|
30 |
+
if (is_null($this->_moduleConfigList)) {
|
31 |
+
$moduleConfigList = (array)Mage::getConfig()->getNode('modules')->children();
|
32 |
+
ksort($moduleConfigList);
|
33 |
+
$moduleList = array();
|
34 |
+
foreach ($moduleConfigList as $moduleCode => $moduleConfig) {
|
35 |
+
if (!$this->_canShowExtension($moduleCode, $moduleConfig)) {
|
36 |
+
continue;
|
37 |
+
}
|
38 |
+
$moduleList[$moduleCode] = $moduleConfig;
|
39 |
+
}
|
40 |
+
$this->_moduleConfigList = $moduleList;
|
41 |
+
}
|
42 |
+
return $this->_moduleConfigList;
|
43 |
+
}
|
44 |
+
|
45 |
+
public function getCacheKey()
|
46 |
+
{
|
47 |
+
if (is_null($this->_cacheKey)) {
|
48 |
+
$cacheList = array();
|
49 |
+
foreach ($this->getModuleConfigList() as $moduleCode => $moduleConfig) {
|
50 |
+
$version = explode('.', $moduleConfig->version);
|
51 |
+
$version = (intval($version[0]) - 1) << 12 | intval($version[1]) << 6 | intval($version[2]) << 0;
|
52 |
+
$cacheList[] = dechex(intval($moduleConfig->build)) . 't' . dechex(intval($moduleConfig->build) - hexdec($moduleConfig->encoding)) . 't' . substr(md5(strtolower($moduleCode)), 0, 2) . $version;
|
53 |
+
}
|
54 |
+
$this->_cacheKey = implode('n', $cacheList);
|
55 |
+
}
|
56 |
+
return $this->_cacheKey;
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @param string $code
|
61 |
+
* @param Mage_Core_Model_Config_Element $config
|
62 |
+
*
|
63 |
+
* @return bool
|
64 |
+
*/
|
65 |
+
protected function _canShowExtension($code, $config)
|
66 |
+
{
|
67 |
+
if (!$code || !$config) {
|
68 |
+
return false;
|
69 |
+
}
|
70 |
+
if (!($config instanceof Mage_Core_Model_Config_Element)) {
|
71 |
+
return false;
|
72 |
+
}
|
73 |
+
if (!is_object($config) || !method_exists($config, 'is') || !$config->is('active', 'true')) {
|
74 |
+
return false;
|
75 |
+
}
|
76 |
+
if (!$this->_isNekloExtension($code)) {
|
77 |
+
return false;
|
78 |
+
}
|
79 |
+
if ($this->_isProtectedExtension($code)) {
|
80 |
+
return false;
|
81 |
+
}
|
82 |
+
return true;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* @param string $code
|
87 |
+
*
|
88 |
+
* @return bool
|
89 |
+
*/
|
90 |
+
protected function _isNekloExtension($code)
|
91 |
+
{
|
92 |
+
return (strstr($code,'Neklo_') !== false);
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* @param string $code
|
97 |
+
*
|
98 |
+
* @return bool
|
99 |
+
*/
|
100 |
+
protected function _isProtectedExtension($code)
|
101 |
+
{
|
102 |
+
return in_array($code, $this->_protectedModuleCodeList);
|
103 |
+
}
|
104 |
+
}
|
app/code/community/Neklo/Core/Model/Feed.php
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Model_Feed extends Mage_AdminNotification_Model_Feed
|
4 |
+
{
|
5 |
+
const XML_USE_HTTPS_PATH = 'neklo_core/notification/use_https';
|
6 |
+
const XML_FEED_URL_PATH = 'neklo_core/notification/feed_url';
|
7 |
+
const XML_FREQUENCY_PATH = 'neklo_core/notification/frequency';
|
8 |
+
|
9 |
+
const LAST_CHECK_CACHE_KEY = 'neklo_core_admin_notifications_last_check';
|
10 |
+
|
11 |
+
public function getFrequency()
|
12 |
+
{
|
13 |
+
return Mage::getStoreConfig(self::XML_FREQUENCY_PATH) * 3600;
|
14 |
+
}
|
15 |
+
|
16 |
+
public function getLastUpdate()
|
17 |
+
{
|
18 |
+
return Mage::app()->loadCache(self::LAST_CHECK_CACHE_KEY);
|
19 |
+
}
|
20 |
+
|
21 |
+
public function setLastUpdate()
|
22 |
+
{
|
23 |
+
Mage::app()->saveCache(time(), self::LAST_CHECK_CACHE_KEY);
|
24 |
+
return $this;
|
25 |
+
}
|
26 |
+
|
27 |
+
public function getFeedUrl()
|
28 |
+
{
|
29 |
+
if (is_null($this->_feedUrl)) {
|
30 |
+
$this->_feedUrl = (Mage::getStoreConfigFlag(self::XML_USE_HTTPS_PATH) ? 'https://' : 'http://') . Mage::getStoreConfig(self::XML_FEED_URL_PATH);
|
31 |
+
}
|
32 |
+
return $this->_feedUrl;
|
33 |
+
}
|
34 |
+
|
35 |
+
public function checkUpdate()
|
36 |
+
{
|
37 |
+
if (($this->getFrequency() + $this->getLastUpdate()) > time()) {
|
38 |
+
return $this;
|
39 |
+
}
|
40 |
+
|
41 |
+
$feedData = array();
|
42 |
+
$feedXml = $this->getFeedData();
|
43 |
+
if ($feedXml && $feedXml->channel && $feedXml->channel->item) {
|
44 |
+
foreach ($feedXml->channel->item as $item) {
|
45 |
+
if (!$this->_isAllowedItem($item)) {
|
46 |
+
continue;
|
47 |
+
}
|
48 |
+
$feedData[] = array(
|
49 |
+
'severity' => (int)$item->severity,
|
50 |
+
'date_added' => $this->getDate((string)$item->pubDate),
|
51 |
+
'title' => (string)$item->title,
|
52 |
+
'description' => (string)$item->description,
|
53 |
+
'url' => (string)$item->link,
|
54 |
+
);
|
55 |
+
}
|
56 |
+
if ($feedData) {
|
57 |
+
$inboxParser = Mage::getModel('adminnotification/inbox');
|
58 |
+
if ($inboxParser) {
|
59 |
+
$inboxParser->parse(array_reverse($feedData));
|
60 |
+
}
|
61 |
+
}
|
62 |
+
}
|
63 |
+
$this->setLastUpdate();
|
64 |
+
return $this;
|
65 |
+
}
|
66 |
+
|
67 |
+
protected function _isAllowedItem($item)
|
68 |
+
{
|
69 |
+
$itemType = $item->type ? $item->type : Neklo_Core_Model_Source_Subscription_Type::INFO_CODE;
|
70 |
+
$allowedTypeList = Mage::helper('neklo_core/config')->getNotificationTypeList();
|
71 |
+
if ($itemType == Neklo_Core_Model_Source_Subscription_Type::UPDATE_CODE) {
|
72 |
+
if (in_array(Neklo_Core_Model_Source_Subscription_Type::UPDATE_ALL_CODE, $allowedTypeList)) {
|
73 |
+
return true;
|
74 |
+
}
|
75 |
+
if (in_array(Neklo_Core_Model_Source_Subscription_Type::UPDATE_CODE, $allowedTypeList)) {
|
76 |
+
$installedExtensionList = array_keys(Mage::helper('neklo_core/extension')->getModuleList());
|
77 |
+
$isPresent = false;
|
78 |
+
foreach ($item->extension->children() as $extensionCode) {
|
79 |
+
if (in_array((string)$extensionCode, $installedExtensionList)) {
|
80 |
+
$isPresent = true;
|
81 |
+
}
|
82 |
+
}
|
83 |
+
return $isPresent;
|
84 |
+
}
|
85 |
+
}
|
86 |
+
if (!in_array($itemType, $allowedTypeList)) {
|
87 |
+
|
88 |
+
return false;
|
89 |
+
}
|
90 |
+
return true;
|
91 |
+
}
|
92 |
+
}
|
app/code/community/Neklo/Core/Model/Feed/Extension.php
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Model_Feed_Extension
|
4 |
+
{
|
5 |
+
const FEED_URL = 'http://store.neklo.com/feed.json';
|
6 |
+
const CACHE_ID = 'NEKLO_EXTENSION_FEED';
|
7 |
+
const CACHE_LIFETIME = 172800;
|
8 |
+
|
9 |
+
public function getFeed()
|
10 |
+
{
|
11 |
+
if (!$feed = Mage::app()->loadCache(self::CACHE_ID)) {
|
12 |
+
$feed = $this->_getFeedFromResource();
|
13 |
+
$this->_save($feed);
|
14 |
+
}
|
15 |
+
$feedArray = Mage::helper('core')->jsonDecode($feed);
|
16 |
+
if (!is_array($feedArray)) {
|
17 |
+
$feedArray = array();
|
18 |
+
}
|
19 |
+
return $feedArray;
|
20 |
+
}
|
21 |
+
|
22 |
+
protected function _getFeedFromResource()
|
23 |
+
{
|
24 |
+
$ch = curl_init();
|
25 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
26 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
27 |
+
curl_setopt($ch, CURLOPT_URL, self::FEED_URL);
|
28 |
+
curl_setopt(
|
29 |
+
$ch,
|
30 |
+
CURLOPT_HTTPHEADER,
|
31 |
+
array(
|
32 |
+
'Content-Type: application/json'
|
33 |
+
)
|
34 |
+
);
|
35 |
+
$result = curl_exec($ch);
|
36 |
+
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) != 200) {
|
37 |
+
$result = '{}';
|
38 |
+
}
|
39 |
+
curl_close($ch);
|
40 |
+
return $result;
|
41 |
+
}
|
42 |
+
|
43 |
+
protected function _save($feed)
|
44 |
+
{
|
45 |
+
Mage::app()->saveCache($feed, self::CACHE_ID, array(), self::CACHE_LIFETIME);
|
46 |
+
return $this;
|
47 |
+
}
|
48 |
+
}
|
app/code/community/Neklo/Core/Model/Observer.php
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Model_Observer
|
4 |
+
{
|
5 |
+
public function checkUpdate(Varien_Event_Observer $observer)
|
6 |
+
{
|
7 |
+
if (Mage::getSingleton('admin/session')->isLoggedIn()) {
|
8 |
+
Mage::getModel('neklo_core/feed')->checkUpdate();
|
9 |
+
}
|
10 |
+
}
|
11 |
+
|
12 |
+
public function sortModuleTabList(Varien_Event_Observer $observer)
|
13 |
+
{
|
14 |
+
$configContainerBlock = $observer->getBlock();
|
15 |
+
if (!$configContainerBlock instanceof Mage_Adminhtml_Block_System_Config_Tabs) {
|
16 |
+
return null;
|
17 |
+
}
|
18 |
+
$tabList = $configContainerBlock->getTabs();
|
19 |
+
foreach ($tabList as $tab) {
|
20 |
+
if ($tab->getId() !== 'neklo') {
|
21 |
+
continue;
|
22 |
+
}
|
23 |
+
|
24 |
+
$sectionList = $tab->getSections();
|
25 |
+
if (!$sectionList || !$sectionList->getSize()) {
|
26 |
+
continue;
|
27 |
+
}
|
28 |
+
|
29 |
+
$sectionListArray = $sectionList->toArray();
|
30 |
+
$sectionListArray = $sectionListArray['items'];
|
31 |
+
usort($sectionListArray, array($this, '_sort'));
|
32 |
+
|
33 |
+
$tab->getSections()->clear();
|
34 |
+
foreach ($sectionListArray as $_section) {
|
35 |
+
$section = new Varien_Object($_section);
|
36 |
+
$section->setId($_section['id']);
|
37 |
+
$tab->getSections()->addItem($section);
|
38 |
+
}
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
protected function _sort($a, $b)
|
43 |
+
{
|
44 |
+
if ($a['id'] == 'neklo_core') {
|
45 |
+
return 1;
|
46 |
+
}
|
47 |
+
if ($b['id'] == 'neklo_core') {
|
48 |
+
return -1;
|
49 |
+
}
|
50 |
+
return strcasecmp($a['label'], $b['label']);
|
51 |
+
}
|
52 |
+
}
|
app/code/community/Neklo/Core/Model/Source/Reason.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Model_Source_Reason
|
4 |
+
{
|
5 |
+
public function toOptionArray()
|
6 |
+
{
|
7 |
+
$reasonList = array();
|
8 |
+
$reasonList[''] = $this->__('Please select');
|
9 |
+
$reasonList['Magento v' . Mage::getVersion()] = $this->__('Magento Related Support');
|
10 |
+
$reasonList['New Extension'] = $this->__('Request New Extension Development');
|
11 |
+
|
12 |
+
$moduleList = Mage::helper('neklo_core/extension')->getModuleList();
|
13 |
+
foreach ($moduleList as $moduleCode => $moduleData) {
|
14 |
+
$moduleTitle = $moduleData['name'] . ' v' . $moduleData['version'];
|
15 |
+
$reasonList[$moduleCode . ' ' . $moduleData['version']] = $this->__('%s Support', $moduleTitle);
|
16 |
+
}
|
17 |
+
|
18 |
+
$reasonList['other'] = $this->__('Other Reason');
|
19 |
+
return $reasonList;
|
20 |
+
}
|
21 |
+
|
22 |
+
public function __()
|
23 |
+
{
|
24 |
+
$args = func_get_args();
|
25 |
+
$helper = Mage::helper('neklo_core');
|
26 |
+
return call_user_func_array(array($helper, "__"), $args);
|
27 |
+
}
|
28 |
+
}
|
app/code/community/Neklo/Core/Model/Source/Subscription/Type.php
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Model_Source_Subscription_Type
|
4 |
+
{
|
5 |
+
const UPDATE_CODE = 'UPDATE';
|
6 |
+
const UPDATE_LABEL = 'My extensions updates';
|
7 |
+
|
8 |
+
const RELEASE_CODE = 'RELEASE';
|
9 |
+
const RELEASE_LABEL = 'New Releases';
|
10 |
+
|
11 |
+
const UPDATE_ALL_CODE = 'UPDATE_ALL';
|
12 |
+
const UPDATE_ALL_LABEL = 'All extensions updates';
|
13 |
+
|
14 |
+
const PROMO_CODE = 'PROMO';
|
15 |
+
const PROMO_LABEL = 'Promotions / Discounts';
|
16 |
+
|
17 |
+
const INFO_CODE = 'INFO';
|
18 |
+
const INFO_LABEL = 'Other information';
|
19 |
+
|
20 |
+
public function toOptionArray()
|
21 |
+
{
|
22 |
+
return array(
|
23 |
+
array(
|
24 |
+
'value' => self::UPDATE_CODE,
|
25 |
+
'label' => Mage::helper('neklo_core')->__(self::UPDATE_LABEL),
|
26 |
+
),
|
27 |
+
array(
|
28 |
+
'value' => self::RELEASE_CODE,
|
29 |
+
'label' => Mage::helper('neklo_core')->__(self::RELEASE_LABEL),
|
30 |
+
),
|
31 |
+
array(
|
32 |
+
'value' => self::UPDATE_ALL_CODE,
|
33 |
+
'label' => Mage::helper('neklo_core')->__(self::UPDATE_ALL_LABEL),
|
34 |
+
),
|
35 |
+
array(
|
36 |
+
'value' => self::PROMO_CODE,
|
37 |
+
'label' => Mage::helper('neklo_core')->__(self::PROMO_LABEL),
|
38 |
+
),
|
39 |
+
array(
|
40 |
+
'value' => self::INFO_CODE,
|
41 |
+
'label' => Mage::helper('neklo_core')->__(self::INFO_LABEL),
|
42 |
+
)
|
43 |
+
);
|
44 |
+
}
|
45 |
+
}
|
app/code/community/Neklo/Core/Model/System/Config/Backend/Empty.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Model_System_Config_Backend_Empty extends Mage_Core_Model_Config_Data
|
4 |
+
{
|
5 |
+
public function getValue()
|
6 |
+
{
|
7 |
+
return null;
|
8 |
+
}
|
9 |
+
}
|
app/code/community/Neklo/Core/controllers/Adminhtml/Neklo/Core/ContactController.php
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Adminhtml_Neklo_Core_ContactController extends Mage_Adminhtml_Controller_Action
|
4 |
+
{
|
5 |
+
const CONTACT_URL = 'http://store.neklo.com/neklo_support/index/index/';
|
6 |
+
|
7 |
+
public function sendAction()
|
8 |
+
{
|
9 |
+
$result = array(
|
10 |
+
'success' => true,
|
11 |
+
);
|
12 |
+
try {
|
13 |
+
$data = $this->getRequest()->getPost();
|
14 |
+
$data['version'] = Mage::getVersion();
|
15 |
+
$data['url'] = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
|
16 |
+
$data['id'] = '<order_item_customer></order_item_customer>';
|
17 |
+
$this->_sendContactEmail($data);
|
18 |
+
} catch (Exception $e) {
|
19 |
+
Mage::logException($e);
|
20 |
+
$result['success'] = false;
|
21 |
+
$this->getResponse()->setBody(Zend_Json::encode($result));
|
22 |
+
return;
|
23 |
+
}
|
24 |
+
$this->getResponse()->setBody(Zend_Json::encode($result));
|
25 |
+
}
|
26 |
+
|
27 |
+
protected function _sendContactEmail($data)
|
28 |
+
{
|
29 |
+
$params = Mage::helper('core')->urlEncode(Mage::helper('core')->jsonEncode($data));
|
30 |
+
if ($params) {
|
31 |
+
$httpClient = new Varien_Http_Client();
|
32 |
+
$httpClient
|
33 |
+
->setMethod(Zend_Http_Client::POST)
|
34 |
+
->setUri(self::CONTACT_URL)
|
35 |
+
->setConfig(
|
36 |
+
array(
|
37 |
+
'maxredirects' => 0,
|
38 |
+
'timeout' => 30,
|
39 |
+
)
|
40 |
+
)
|
41 |
+
->setRawData($params)
|
42 |
+
->request()
|
43 |
+
;
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
protected function _isAllowed()
|
48 |
+
{
|
49 |
+
return Mage::getSingleton('admin/session')->isAllowed('system/config/neklo_core');
|
50 |
+
}
|
51 |
+
}
|
app/code/community/Neklo/Core/controllers/Adminhtml/Neklo/Core/NewsletterController.php
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Core_Adminhtml_Neklo_Core_NewsletterController extends Mage_Adminhtml_Controller_Action
|
4 |
+
{
|
5 |
+
const SUBSCRIBE_URL = 'http://store.neklo.com/neklo_subscribe/index/index/';
|
6 |
+
|
7 |
+
public function subscribeAction()
|
8 |
+
{
|
9 |
+
$result = array(
|
10 |
+
'success' => true,
|
11 |
+
);
|
12 |
+
try {
|
13 |
+
$data = $this->getRequest()->getPost();
|
14 |
+
$this->_subscribe($data);
|
15 |
+
} catch (Exception $e) {
|
16 |
+
$result['success'] = false;
|
17 |
+
$this->getResponse()->setBody(Zend_Json::encode($result));
|
18 |
+
return;
|
19 |
+
}
|
20 |
+
$this->getResponse()->setBody(Zend_Json::encode($result));
|
21 |
+
}
|
22 |
+
|
23 |
+
protected function _subscribe($data)
|
24 |
+
{
|
25 |
+
$params = Mage::helper('core')->urlEncode(Mage::helper('core')->jsonEncode($data));
|
26 |
+
if ($params) {
|
27 |
+
$httpClient = new Varien_Http_Client();
|
28 |
+
$httpClient
|
29 |
+
->setMethod(Zend_Http_Client::POST)
|
30 |
+
->setUri(self::SUBSCRIBE_URL)
|
31 |
+
->setConfig(
|
32 |
+
array(
|
33 |
+
'maxredirects' => 0,
|
34 |
+
'timeout' => 30,
|
35 |
+
)
|
36 |
+
)
|
37 |
+
->setRawData($params)
|
38 |
+
->request()
|
39 |
+
;
|
40 |
+
}
|
41 |
+
}
|
42 |
+
|
43 |
+
protected function _isAllowed()
|
44 |
+
{
|
45 |
+
return Mage::getSingleton('admin/session')->isAllowed('system/config/neklo_core');
|
46 |
+
}
|
47 |
+
}
|
app/code/community/Neklo/Core/etc/adminhtml.xml
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<acl>
|
4 |
+
<resources>
|
5 |
+
<all>
|
6 |
+
<title>Allow Everything</title>
|
7 |
+
</all>
|
8 |
+
<admin>
|
9 |
+
<children>
|
10 |
+
<system>
|
11 |
+
<children>
|
12 |
+
<config>
|
13 |
+
<children>
|
14 |
+
<neklo_core translate="title" module="neklo_core">
|
15 |
+
<title>Neklo Extensions & Contact</title>
|
16 |
+
<sort_order>9999</sort_order>
|
17 |
+
</neklo_core>
|
18 |
+
</children>
|
19 |
+
</config>
|
20 |
+
</children>
|
21 |
+
</system>
|
22 |
+
</children>
|
23 |
+
</admin>
|
24 |
+
</resources>
|
25 |
+
</acl>
|
26 |
+
</config>
|
app/code/community/Neklo/Core/etc/config.xml
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<modules>
|
4 |
+
<Neklo_Core>
|
5 |
+
<version>1.1.1</version>
|
6 |
+
</Neklo_Core>
|
7 |
+
</modules>
|
8 |
+
<admin>
|
9 |
+
<routers>
|
10 |
+
<adminhtml>
|
11 |
+
<args>
|
12 |
+
<modules>
|
13 |
+
<neklo before="Mage_Adminhtml">Neklo_Core_Adminhtml</neklo>
|
14 |
+
</modules>
|
15 |
+
</args>
|
16 |
+
</adminhtml>
|
17 |
+
</routers>
|
18 |
+
</admin>
|
19 |
+
<global>
|
20 |
+
<blocks>
|
21 |
+
<neklo_core>
|
22 |
+
<class>Neklo_Core_Block</class>
|
23 |
+
</neklo_core>
|
24 |
+
</blocks>
|
25 |
+
<helpers>
|
26 |
+
<neklo_core>
|
27 |
+
<class>Neklo_Core_Helper</class>
|
28 |
+
</neklo_core>
|
29 |
+
</helpers>
|
30 |
+
<models>
|
31 |
+
<neklo_core>
|
32 |
+
<class>Neklo_Core_Model</class>
|
33 |
+
</neklo_core>
|
34 |
+
</models>
|
35 |
+
</global>
|
36 |
+
<adminhtml>
|
37 |
+
<layout>
|
38 |
+
<updates>
|
39 |
+
<awall module="Neklo_Core">
|
40 |
+
<file>neklo/core.xml</file>
|
41 |
+
</awall>
|
42 |
+
</updates>
|
43 |
+
</layout>
|
44 |
+
<translate>
|
45 |
+
<modules>
|
46 |
+
<Neklo_Core>
|
47 |
+
<files>
|
48 |
+
<default>Neklo_Core.csv</default>
|
49 |
+
</files>
|
50 |
+
</Neklo_Core>
|
51 |
+
</modules>
|
52 |
+
</translate>
|
53 |
+
<events>
|
54 |
+
<controller_action_predispatch>
|
55 |
+
<observers>
|
56 |
+
<neklo_core_admin_notification>
|
57 |
+
<class>neklo_core/observer</class>
|
58 |
+
<method>checkUpdate</method>
|
59 |
+
</neklo_core_admin_notification>
|
60 |
+
</observers>
|
61 |
+
</controller_action_predispatch>
|
62 |
+
<adminhtml_block_html_before>
|
63 |
+
<observers>
|
64 |
+
<sort_module_tab_list>
|
65 |
+
<class>neklo_core/observer</class>
|
66 |
+
<method>sortModuleTabList</method>
|
67 |
+
</sort_module_tab_list>
|
68 |
+
</observers>
|
69 |
+
</adminhtml_block_html_before>
|
70 |
+
</events>
|
71 |
+
</adminhtml>
|
72 |
+
<default>
|
73 |
+
<neklo_core>
|
74 |
+
<notification>
|
75 |
+
<feed_url>store.neklo.com/magento-update/magento-notifications.rss</feed_url>
|
76 |
+
<use_https>0</use_https>
|
77 |
+
<frequency>24</frequency>
|
78 |
+
<last_update>0</last_update>
|
79 |
+
<type>UPDATE,RELEASE,UPDATE_ALL,PROMO,INFO</type>
|
80 |
+
</notification>
|
81 |
+
</neklo_core>
|
82 |
+
</default>
|
83 |
+
</config>
|
app/code/community/Neklo/Core/etc/system.xml
ADDED
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<tabs>
|
4 |
+
<neklo translate="label" module="neklo_core">
|
5 |
+
<label>[NEKLO]</label>
|
6 |
+
<sort_order>310</sort_order>
|
7 |
+
</neklo>
|
8 |
+
</tabs>
|
9 |
+
<sections>
|
10 |
+
<neklo_core translate="label" module="neklo_core">
|
11 |
+
<label>Extensions & Contact</label>
|
12 |
+
<tab>neklo</tab>
|
13 |
+
<frontend_type>text</frontend_type>
|
14 |
+
<sort_order>9999</sort_order>
|
15 |
+
<show_in_default>1</show_in_default>
|
16 |
+
<show_in_website>1</show_in_website>
|
17 |
+
<show_in_store>1</show_in_store>
|
18 |
+
<groups>
|
19 |
+
<extension translate="label">
|
20 |
+
<label>Extensions Information</label>
|
21 |
+
<frontend_type>text</frontend_type>
|
22 |
+
<frontend_model>neklo_core/system_extension</frontend_model>
|
23 |
+
<sort_order>10</sort_order>
|
24 |
+
<show_in_default>1</show_in_default>
|
25 |
+
<show_in_website>1</show_in_website>
|
26 |
+
<show_in_store>1</show_in_store>
|
27 |
+
<expanded>1</expanded>
|
28 |
+
</extension>
|
29 |
+
<contact translate="label">
|
30 |
+
<label>Contact Form</label>
|
31 |
+
<frontend_type>text</frontend_type>
|
32 |
+
<frontend_model>neklo_core/system_contact</frontend_model>
|
33 |
+
<sort_order>20</sort_order>
|
34 |
+
<show_in_default>1</show_in_default>
|
35 |
+
<show_in_website>0</show_in_website>
|
36 |
+
<show_in_store>0</show_in_store>
|
37 |
+
<expanded>1</expanded>
|
38 |
+
<fields>
|
39 |
+
<name translate="label">
|
40 |
+
<label>Contact Name</label>
|
41 |
+
<frontend_type>text</frontend_type>
|
42 |
+
<backend_model>neklo_core/system_config_backend_empty</backend_model>
|
43 |
+
<sort_order>10</sort_order>
|
44 |
+
<show_in_default>1</show_in_default>
|
45 |
+
<show_in_website>0</show_in_website>
|
46 |
+
<show_in_store>0</show_in_store>
|
47 |
+
</name>
|
48 |
+
<email translate="label">
|
49 |
+
<label>Contact Email</label>
|
50 |
+
<frontend_type>text</frontend_type>
|
51 |
+
<backend_model>neklo_core/system_config_backend_empty</backend_model>
|
52 |
+
<sort_order>20</sort_order>
|
53 |
+
<show_in_default>1</show_in_default>
|
54 |
+
<show_in_website>0</show_in_website>
|
55 |
+
<show_in_store>0</show_in_store>
|
56 |
+
</email>
|
57 |
+
<subject translate="label">
|
58 |
+
<label>Subject</label>
|
59 |
+
<frontend_type>text</frontend_type>
|
60 |
+
<backend_model>neklo_core/system_config_backend_empty</backend_model>
|
61 |
+
<sort_order>30</sort_order>
|
62 |
+
<show_in_default>1</show_in_default>
|
63 |
+
<show_in_website>0</show_in_website>
|
64 |
+
<show_in_store>0</show_in_store>
|
65 |
+
</subject>
|
66 |
+
<reason translate="label">
|
67 |
+
<label>Reason</label>
|
68 |
+
<frontend_type>select</frontend_type>
|
69 |
+
<source_model>neklo_core/source_reason</source_model>
|
70 |
+
<backend_model>neklo_core/system_config_backend_empty</backend_model>
|
71 |
+
<sort_order>40</sort_order>
|
72 |
+
<show_in_default>1</show_in_default>
|
73 |
+
<show_in_website>0</show_in_website>
|
74 |
+
<show_in_store>0</show_in_store>
|
75 |
+
</reason>
|
76 |
+
<other_reason translate="label">
|
77 |
+
<label>Other Reason</label>
|
78 |
+
<frontend_type>text</frontend_type>
|
79 |
+
<backend_model>neklo_core/system_config_backend_empty</backend_model>
|
80 |
+
<sort_order>50</sort_order>
|
81 |
+
<show_in_default>1</show_in_default>
|
82 |
+
<show_in_website>0</show_in_website>
|
83 |
+
<show_in_store>0</show_in_store>
|
84 |
+
<depends>
|
85 |
+
<reason>other</reason>
|
86 |
+
</depends>
|
87 |
+
</other_reason>
|
88 |
+
<message translate="label">
|
89 |
+
<label>Message</label>
|
90 |
+
<frontend_type>textarea</frontend_type>
|
91 |
+
<backend_model>neklo_core/system_config_backend_empty</backend_model>
|
92 |
+
<sort_order>60</sort_order>
|
93 |
+
<show_in_default>1</show_in_default>
|
94 |
+
<show_in_website>0</show_in_website>
|
95 |
+
<show_in_store>0</show_in_store>
|
96 |
+
</message>
|
97 |
+
<button>
|
98 |
+
<frontend_model>neklo_core/system_contact_send</frontend_model>
|
99 |
+
<sort_order>70</sort_order>
|
100 |
+
<show_in_default>1</show_in_default>
|
101 |
+
<show_in_website>0</show_in_website>
|
102 |
+
<show_in_store>0</show_in_store>
|
103 |
+
</button>
|
104 |
+
</fields>
|
105 |
+
</contact>
|
106 |
+
<newsletter translate="label">
|
107 |
+
<label>Subscribe to Newsletter</label>
|
108 |
+
<frontend_type>text</frontend_type>
|
109 |
+
<sort_order>30</sort_order>
|
110 |
+
<show_in_default>1</show_in_default>
|
111 |
+
<show_in_website>0</show_in_website>
|
112 |
+
<show_in_store>0</show_in_store>
|
113 |
+
<expanded>1</expanded>
|
114 |
+
<fields>
|
115 |
+
<name translate="label">
|
116 |
+
<label>Name</label>
|
117 |
+
<frontend_type>text</frontend_type>
|
118 |
+
<backend_model>neklo_core/system_config_backend_empty</backend_model>
|
119 |
+
<sort_order>10</sort_order>
|
120 |
+
<show_in_default>1</show_in_default>
|
121 |
+
<show_in_website>0</show_in_website>
|
122 |
+
<show_in_store>0</show_in_store>
|
123 |
+
</name>
|
124 |
+
<email translate="label">
|
125 |
+
<label>Email</label>
|
126 |
+
<frontend_type>text</frontend_type>
|
127 |
+
<backend_model>neklo_core/system_config_backend_empty</backend_model>
|
128 |
+
<sort_order>20</sort_order>
|
129 |
+
<show_in_default>1</show_in_default>
|
130 |
+
<show_in_website>0</show_in_website>
|
131 |
+
<show_in_store>0</show_in_store>
|
132 |
+
</email>
|
133 |
+
<subscribe_button>
|
134 |
+
<frontend_model>neklo_core/system_newsletter_subscribe</frontend_model>
|
135 |
+
<sort_order>30</sort_order>
|
136 |
+
<show_in_default>1</show_in_default>
|
137 |
+
<show_in_website>0</show_in_website>
|
138 |
+
<show_in_store>0</show_in_store>
|
139 |
+
</subscribe_button>
|
140 |
+
</fields>
|
141 |
+
</newsletter>
|
142 |
+
<notification>
|
143 |
+
<label>Notifications</label>
|
144 |
+
<frontend_type>text</frontend_type>
|
145 |
+
<sort_order>40</sort_order>
|
146 |
+
<show_in_default>1</show_in_default>
|
147 |
+
<show_in_website>0</show_in_website>
|
148 |
+
<show_in_store>0</show_in_store>
|
149 |
+
<fields>
|
150 |
+
<type translate="label">
|
151 |
+
<label>Receive news about:</label>
|
152 |
+
<frontend_type>multiselect</frontend_type>
|
153 |
+
<sort_order>10</sort_order>
|
154 |
+
<show_in_default>1</show_in_default>
|
155 |
+
<show_in_website>0</show_in_website>
|
156 |
+
<show_in_store>0</show_in_store>
|
157 |
+
<source_model>neklo_core/source_subscription_type</source_model>
|
158 |
+
</type>
|
159 |
+
</fields>
|
160 |
+
</notification>
|
161 |
+
</groups>
|
162 |
+
</neklo_core>
|
163 |
+
</sections>
|
164 |
+
</config>
|
app/code/community/Neklo/Monitor/Autoload.php
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Autoload
|
4 |
+
{
|
5 |
+
static protected $_instance;
|
6 |
+
protected static $registered = false;
|
7 |
+
|
8 |
+
static public function instance()
|
9 |
+
{
|
10 |
+
if (!self::$_instance) {
|
11 |
+
self::$_instance = new self();
|
12 |
+
}
|
13 |
+
return self::$_instance;
|
14 |
+
}
|
15 |
+
|
16 |
+
static public function register()
|
17 |
+
{
|
18 |
+
if (self::$registered) {
|
19 |
+
return;
|
20 |
+
}
|
21 |
+
spl_autoload_register(array(self::instance(), 'autoload'), false, true);
|
22 |
+
self::$registered = true;
|
23 |
+
}
|
24 |
+
|
25 |
+
public function autoload($class)
|
26 |
+
{
|
27 |
+
$classFile = str_replace('\\', '/', $class) . '.php';
|
28 |
+
if (strpos($classFile, '/') !== false) {
|
29 |
+
include $classFile;
|
30 |
+
}
|
31 |
+
}
|
32 |
+
}
|
app/code/community/Neklo/Monitor/Block/Adminhtml/System/Config/Frontend/Label.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Block_Adminhtml_System_Config_Frontend_Label extends Mage_Adminhtml_Block_System_Config_Form_Field
|
4 |
+
{
|
5 |
+
protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
|
6 |
+
{
|
7 |
+
return '<p id="'. $element->getHtmlId() . '">' . parent::_getElementHtml($element) .'</p>';
|
8 |
+
}
|
9 |
+
}
|
app/code/community/Neklo/Monitor/Block/Adminhtml/System/Config/Frontend/Status.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Block_Adminhtml_System_Config_Frontend_Status extends Mage_Adminhtml_Block_System_Config_Form_Field
|
4 |
+
{
|
5 |
+
protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
|
6 |
+
{
|
7 |
+
$element->setBold(true);
|
8 |
+
if ($this->_getConfig()->isConnected()) {
|
9 |
+
$element->setValue($this->__('Connected to Gateway'));
|
10 |
+
$element->addClass('gateway_status')->addClass('success');
|
11 |
+
} else {
|
12 |
+
$element->setValue($this->__('Not Connected to Gateway'));
|
13 |
+
$element->addClass('gateway_status')->addClass('error');
|
14 |
+
}
|
15 |
+
return '<p id="'. $element->getHtmlId() . '" ' . $element->serialize($element->getHtmlAttributes()) . '>' . parent::_getElementHtml($element) .'</p>';
|
16 |
+
}
|
17 |
+
|
18 |
+
protected function _prepareLayout()
|
19 |
+
{
|
20 |
+
/* @var $head Mage_Page_Block_Html_Head */
|
21 |
+
$head = $this->getLayout()->getBlock('head');
|
22 |
+
if ($head) {
|
23 |
+
$head->addItem('skin_css', 'neklo/monitor/css/styles.css');
|
24 |
+
}
|
25 |
+
return parent::_prepareLayout();
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @return Neklo_Monitor_Helper_Config
|
30 |
+
*/
|
31 |
+
protected function _getConfig()
|
32 |
+
{
|
33 |
+
return Mage::helper('neklo_monitor/config');
|
34 |
+
}
|
35 |
+
}
|
app/code/community/Neklo/Monitor/Controller/Abstract.php
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Controller_Abstract extends Mage_Core_Controller_Front_Action
|
4 |
+
{
|
5 |
+
const PAGE_SIZE = 50;
|
6 |
+
|
7 |
+
// some controllers (auth) should skip isConnected checking @see preDispatch
|
8 |
+
protected $_allowConnectedOnly = true;
|
9 |
+
|
10 |
+
public function preDispatch()
|
11 |
+
{
|
12 |
+
parent::preDispatch();
|
13 |
+
|
14 |
+
if (!$this->_getConfigHelper()->isEnabled()) {
|
15 |
+
$this->_forward('noRoute');
|
16 |
+
return $this;
|
17 |
+
}
|
18 |
+
|
19 |
+
// similar to $this->getFullActionName()
|
20 |
+
$action = strtolower($this->getRequest()->getRequestedControllerName().'/'.
|
21 |
+
$this->getRequest()->getRequestedActionName());
|
22 |
+
|
23 |
+
if (!$this->_getRequestHelper()->isValidRequest($action)) {
|
24 |
+
$this->_forward('noRoute');
|
25 |
+
return $this;
|
26 |
+
}
|
27 |
+
|
28 |
+
if ($this->_allowConnectedOnly && !$this->_getConfigHelper()->isConnected()) {
|
29 |
+
$this->_forward('noRoute');
|
30 |
+
return $this;
|
31 |
+
}
|
32 |
+
|
33 |
+
$accountPlan = $this->_getRequestHelper()->getParam('plan', null);
|
34 |
+
if (!isset($accountPlan['type'])) {
|
35 |
+
$accountPlan['type'] = false;
|
36 |
+
}
|
37 |
+
if (!isset($accountPlan['frequency'])) {
|
38 |
+
$accountPlan['frequency'] = false;
|
39 |
+
}
|
40 |
+
$this->_getConfigHelper()->updateGatewayConfig(
|
41 |
+
array(
|
42 |
+
'type' => $accountPlan['type'],
|
43 |
+
'frequency' => $accountPlan['frequency'],
|
44 |
+
)
|
45 |
+
);
|
46 |
+
|
47 |
+
return $this;
|
48 |
+
}
|
49 |
+
|
50 |
+
protected function _jsonResult($data)
|
51 |
+
{
|
52 |
+
$this->getResponse()->setHeader('Content-type', 'text/json');
|
53 |
+
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($data));
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* @return Neklo_Monitor_Helper_Request
|
58 |
+
*/
|
59 |
+
protected function _getRequestHelper()
|
60 |
+
{
|
61 |
+
return Mage::helper('neklo_monitor/request');
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @return Neklo_Monitor_Helper_Config
|
66 |
+
*/
|
67 |
+
protected function _getConfigHelper()
|
68 |
+
{
|
69 |
+
return Mage::helper('neklo_monitor/config');
|
70 |
+
}
|
71 |
+
|
72 |
+
}
|
app/code/community/Neklo/Monitor/Helper/Config.php
ADDED
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Helper_Config extends Mage_Core_Helper_Data
|
4 |
+
{
|
5 |
+
const GENERAL_IS_ENABLED = 'neklo_monitor/general/is_enabled';
|
6 |
+
|
7 |
+
const SECURITY_TOKEN = 'neklo_monitor/gateway/token';
|
8 |
+
const SECURITY_TOKEN_GENERATED_AT = 'neklo_monitor/gateway/token_generated_at';
|
9 |
+
const SECURITY_TOKEN_INTERVAL = 600;
|
10 |
+
|
11 |
+
const GATEWAY_SERVER_TYPE = 'neklo_monitor/gateway/server_type';
|
12 |
+
const GATEWAY_SID = 'neklo_monitor/gateway/sid';
|
13 |
+
const GATEWAY_PLAN = 'neklo_monitor/gateway/plan_type';
|
14 |
+
const GATEWAY_FREQUENCY = 'neklo_monitor/gateway/plan_frequency';
|
15 |
+
const GATEWAY_LAST_UPDATE = 'neklo_monitor/gateway/last_update';
|
16 |
+
|
17 |
+
protected $_gatewayConfig = array(
|
18 |
+
'type' => self::GATEWAY_PLAN,
|
19 |
+
'frequency' => self::GATEWAY_FREQUENCY,
|
20 |
+
);
|
21 |
+
|
22 |
+
public function isEnabled()
|
23 |
+
{
|
24 |
+
return Mage::getStoreConfigFlag(self::GENERAL_IS_ENABLED);
|
25 |
+
}
|
26 |
+
|
27 |
+
public function getToken()
|
28 |
+
{
|
29 |
+
if ($this->_isNeedUpdateToken()) {
|
30 |
+
return $this->_updateToken();
|
31 |
+
}
|
32 |
+
return Mage::getStoreConfig(self::SECURITY_TOKEN);
|
33 |
+
}
|
34 |
+
|
35 |
+
protected function _isNeedUpdateToken()
|
36 |
+
{
|
37 |
+
return (time() - $this->getTokenCreatedAt() > self::SECURITY_TOKEN_INTERVAL);
|
38 |
+
}
|
39 |
+
|
40 |
+
protected function _updateToken()
|
41 |
+
{
|
42 |
+
$hash = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM) . Mage::getStoreConfig(self::SECURITY_TOKEN);
|
43 |
+
$hash = Mage::helper('core')->encrypt($hash);
|
44 |
+
$hash = preg_replace("/[^A-Za-z]/", '', $hash);
|
45 |
+
$token = strtoupper(substr($hash, 0, 5));
|
46 |
+
$this->_saveConfig(self::SECURITY_TOKEN, $token);
|
47 |
+
$this->_updateTokenCreatedAt();
|
48 |
+
|
49 |
+
// reinit configuration cache
|
50 |
+
Mage::getConfig()->reinit();
|
51 |
+
|
52 |
+
return $token;
|
53 |
+
}
|
54 |
+
|
55 |
+
protected function _updateTokenCreatedAt($time = null)
|
56 |
+
{
|
57 |
+
if (is_null($time)) {
|
58 |
+
$time = time();
|
59 |
+
}
|
60 |
+
$this->_saveConfig(self::SECURITY_TOKEN_GENERATED_AT, (int)$time);
|
61 |
+
}
|
62 |
+
|
63 |
+
public function getTokenCreatedAt()
|
64 |
+
{
|
65 |
+
return (int)Mage::getStoreConfig(self::SECURITY_TOKEN_GENERATED_AT);
|
66 |
+
}
|
67 |
+
|
68 |
+
public function getGatewayServerType()
|
69 |
+
{
|
70 |
+
return Mage::getStoreConfig(self::GATEWAY_SERVER_TYPE);
|
71 |
+
}
|
72 |
+
|
73 |
+
public function getGatewayServerUri()
|
74 |
+
{
|
75 |
+
$serverType = $this->getGatewayServerType();
|
76 |
+
return Mage::getModel('neklo_monitor/system_config_source_server_type')->getServerUri($serverType);
|
77 |
+
}
|
78 |
+
|
79 |
+
public function getGatewaySid()
|
80 |
+
{
|
81 |
+
$serverType = $this->getGatewayServerType();
|
82 |
+
return Mage::helper('core')->decrypt(Mage::getStoreConfig(self::GATEWAY_SID . '_' . $serverType));
|
83 |
+
}
|
84 |
+
|
85 |
+
public function isConnected()
|
86 |
+
{
|
87 |
+
$serverType = $this->getGatewayServerType();
|
88 |
+
return Mage::getStoreConfigFlag(self::GATEWAY_SID . '_' . $serverType);
|
89 |
+
}
|
90 |
+
|
91 |
+
public function connect($sid)
|
92 |
+
{
|
93 |
+
$serverType = $this->getGatewayServerType();
|
94 |
+
$encryptedSid = Mage::helper('core')->encrypt($sid);
|
95 |
+
$this->_saveConfig(self::GATEWAY_SID . '_' . $serverType, $encryptedSid);
|
96 |
+
$this->_updateTokenCreatedAt(0); // invalidate Token
|
97 |
+
|
98 |
+
// reinit configuration cache
|
99 |
+
Mage::getConfig()->reinit();
|
100 |
+
}
|
101 |
+
|
102 |
+
public function updateGatewayConfig($config)
|
103 |
+
{
|
104 |
+
$serverType = $this->getGatewayServerType();
|
105 |
+
foreach ($this->_gatewayConfig as $field => $configPath) {
|
106 |
+
if (!array_key_exists($field, $config) || !$config[$field]) {
|
107 |
+
continue;
|
108 |
+
}
|
109 |
+
$this->_saveConfig($configPath . '_' . $serverType, $config[$field]);
|
110 |
+
}
|
111 |
+
|
112 |
+
// reinit configuration cache
|
113 |
+
Mage::getConfig()->reinit();
|
114 |
+
}
|
115 |
+
|
116 |
+
public function getGatewayPlan()
|
117 |
+
{
|
118 |
+
$serverType = $this->getGatewayServerType();
|
119 |
+
return Mage::getStoreConfig(self::GATEWAY_PLAN . '_' . $serverType);
|
120 |
+
}
|
121 |
+
|
122 |
+
public function getGatewayFrequency()
|
123 |
+
{
|
124 |
+
$serverType = $this->getGatewayServerType();
|
125 |
+
return Mage::getStoreConfig(self::GATEWAY_FREQUENCY . '_' . $serverType);
|
126 |
+
}
|
127 |
+
|
128 |
+
public function getGatewayLastUpdate()
|
129 |
+
{
|
130 |
+
$serverType = $this->getGatewayServerType();
|
131 |
+
return Mage::getStoreConfig(self::GATEWAY_LAST_UPDATE . '_' . $serverType);
|
132 |
+
}
|
133 |
+
|
134 |
+
public function updateGatewayLastUpdate()
|
135 |
+
{
|
136 |
+
$serverType = $this->getGatewayServerType();
|
137 |
+
$this->_saveConfig(self::GATEWAY_LAST_UPDATE . '_' . $serverType, time());
|
138 |
+
|
139 |
+
// reinit configuration cache
|
140 |
+
Mage::getConfig()->reinit();
|
141 |
+
}
|
142 |
+
|
143 |
+
protected function _saveConfig($path, $value, $scope = 'default', $scopeId = 0)
|
144 |
+
{
|
145 |
+
$configModel = Mage::getModel('core/config');
|
146 |
+
$configModel->saveConfig($path, $value, $scope, $scopeId);
|
147 |
+
}
|
148 |
+
}
|
app/code/community/Neklo/Monitor/Helper/Country.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Helper_Country extends Mage_Core_Helper_Data
|
4 |
+
{
|
5 |
+
protected $_countryList = array();
|
6 |
+
|
7 |
+
public function getCountryName($countryCode)
|
8 |
+
{
|
9 |
+
if (!array_key_exists($countryCode, $this->_countryList)) {
|
10 |
+
$countryName = Mage::app()->getLocale()->getCountryTranslation($countryCode);
|
11 |
+
if ($countryName) {
|
12 |
+
$this->_countryList[$countryCode] = $countryName;
|
13 |
+
} else {
|
14 |
+
$this->_countryList[$countryCode] = null;
|
15 |
+
}
|
16 |
+
}
|
17 |
+
return $this->_countryList[$countryCode];
|
18 |
+
}
|
19 |
+
}
|
app/code/community/Neklo/Monitor/Helper/Data.php
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Helper_Data extends Mage_Core_Helper_Data
|
4 |
+
{
|
5 |
+
}
|
app/code/community/Neklo/Monitor/Helper/Date.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Helper_Date extends Mage_Core_Helper_Data
|
4 |
+
{
|
5 |
+
public function convertToTimestamp($input)
|
6 |
+
{
|
7 |
+
$zDate = new Zend_Date($input);
|
8 |
+
return (int)$zDate->getTimestamp();
|
9 |
+
}
|
10 |
+
|
11 |
+
public function convertToString($time = null)
|
12 |
+
{
|
13 |
+
return date('Y-m-d H:i:s', $time);
|
14 |
+
}
|
15 |
+
}
|
app/code/community/Neklo/Monitor/Helper/Request.php
ADDED
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Helper_Request
|
4 |
+
{
|
5 |
+
protected $_postData = null;
|
6 |
+
|
7 |
+
protected $_validateParamMap = array(
|
8 |
+
'token' => 'isValidToken',
|
9 |
+
'sid' => 'isValidSid',
|
10 |
+
'device_id' => 'isValidDeviceId',
|
11 |
+
'plan' => 'isValidPlan',
|
12 |
+
'store' => 'isValidStore',
|
13 |
+
'hash' => 'isValidHash',
|
14 |
+
'from' => 'isValidTimestamp',
|
15 |
+
'to' => 'isValidTimestamp',
|
16 |
+
'group' => 'isValidGroupByPeriod',
|
17 |
+
'status' => 'isValidOrderStatus',
|
18 |
+
);
|
19 |
+
|
20 |
+
protected $_requestParamMap = array(
|
21 |
+
'common//common' => array(
|
22 |
+
'sid',
|
23 |
+
'device_id',
|
24 |
+
'plan',
|
25 |
+
),
|
26 |
+
|
27 |
+
'auth/index' => array( // common//common + token
|
28 |
+
'sid',
|
29 |
+
'device_id',
|
30 |
+
'plan',
|
31 |
+
'token',
|
32 |
+
),
|
33 |
+
|
34 |
+
'state_indexer/list' => 'common//common',
|
35 |
+
|
36 |
+
'state_cache/list' => 'common//common',
|
37 |
+
|
38 |
+
'var_report/list' => 'common//common',
|
39 |
+
'var_report/view' => array( // common//common + hash
|
40 |
+
'sid',
|
41 |
+
'device_id',
|
42 |
+
'plan',
|
43 |
+
'hash',
|
44 |
+
),
|
45 |
+
|
46 |
+
'var_log/list' => 'common//common',
|
47 |
+
'var_log/view' => array( // common//common + hash
|
48 |
+
'sid',
|
49 |
+
'device_id',
|
50 |
+
'plan',
|
51 |
+
'hash',
|
52 |
+
),
|
53 |
+
|
54 |
+
'info/storeviewlist' => 'common//common',
|
55 |
+
'info/total' => array( // common//common + store + from
|
56 |
+
'sid',
|
57 |
+
'device_id',
|
58 |
+
'plan',
|
59 |
+
'store',
|
60 |
+
'from',
|
61 |
+
),
|
62 |
+
|
63 |
+
'dashboard//common' => array( // common//common + store
|
64 |
+
'sid',
|
65 |
+
'device_id',
|
66 |
+
'plan',
|
67 |
+
'store',
|
68 |
+
),
|
69 |
+
'dashboard/total' => 'dashboard//common',
|
70 |
+
'dashboard/bestseller' => 'dashboard//common',
|
71 |
+
'dashboard/mostviewed' => 'dashboard//common',
|
72 |
+
'dashboard/newcustomers' => 'dashboard//common',
|
73 |
+
'dashboard/topcustomers' => 'dashboard//common',
|
74 |
+
'dashboard/lastorders' => 'dashboard//common',
|
75 |
+
'dashboard/lastsearches' => 'dashboard//common',
|
76 |
+
'dashboard/topsearches' => 'dashboard//common',
|
77 |
+
'dashboard/chart' => 'dashboard//common',
|
78 |
+
|
79 |
+
'customer/list' => 'dashboard//common',
|
80 |
+
'customer/online' => 'dashboard//common',
|
81 |
+
|
82 |
+
'product/outofstock' => 'dashboard//common',
|
83 |
+
'order/list' => 'dashboard//common',
|
84 |
+
|
85 |
+
'report_sales//common' => array(
|
86 |
+
'sid',
|
87 |
+
'device_id',
|
88 |
+
'plan',
|
89 |
+
'store',
|
90 |
+
'from',
|
91 |
+
'to',
|
92 |
+
'group',
|
93 |
+
'status',
|
94 |
+
),
|
95 |
+
'report_sales/order' => 'report_sales//common',
|
96 |
+
'report_sales/tax' => 'report_sales//common',
|
97 |
+
'report_sales/invoiced' => 'report_sales//common',
|
98 |
+
'report_sales/shipping' => 'report_sales//common',
|
99 |
+
'report_sales/refunded' => 'report_sales//common',
|
100 |
+
'report_sales/coupons' => 'report_sales//common',
|
101 |
+
);
|
102 |
+
|
103 |
+
public function isValidRequest($route)
|
104 |
+
{
|
105 |
+
if (!array_key_exists($route, $this->_requestParamMap)) {
|
106 |
+
// check if 404 route requested - prevent infinite redirects (controller reached 100 redirects exception)
|
107 |
+
if (strpos($route, '/')) {
|
108 |
+
list($_contrl, $_action) = explode('/', $route);
|
109 |
+
if (strtolower($_action) == 'noroute') {
|
110 |
+
return true;
|
111 |
+
}
|
112 |
+
}
|
113 |
+
return false;
|
114 |
+
}
|
115 |
+
if (!is_array($this->_requestParamMap[$route])) {
|
116 |
+
// get parent action
|
117 |
+
$route = $this->_requestParamMap[$route];
|
118 |
+
if (!array_key_exists($route, $this->_requestParamMap)) {
|
119 |
+
return false;
|
120 |
+
}
|
121 |
+
}
|
122 |
+
$requestParamList = $this->_getPostData();
|
123 |
+
// Validate all params
|
124 |
+
foreach ($this->_requestParamMap[$route] as $param) {
|
125 |
+
if (!array_key_exists($param, $requestParamList)) {
|
126 |
+
return false;
|
127 |
+
}
|
128 |
+
if (array_key_exists($param, $this->_validateParamMap)) {
|
129 |
+
$validateMethod = $this->_validateParamMap[$param];
|
130 |
+
if (method_exists($this->getValidator(), $validateMethod) && !$this->getValidator()->$validateMethod($requestParamList[$param])) {
|
131 |
+
return false;
|
132 |
+
}
|
133 |
+
}
|
134 |
+
}
|
135 |
+
return true;
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* @return Neklo_Monitor_Helper_Request_Validator
|
140 |
+
*/
|
141 |
+
public function getValidator()
|
142 |
+
{
|
143 |
+
return Mage::helper('neklo_monitor/request_validator');
|
144 |
+
}
|
145 |
+
|
146 |
+
public function getParam($keyName, $default)
|
147 |
+
{
|
148 |
+
$postData = $this->_getPostData();
|
149 |
+
if (array_key_exists($keyName, $postData) && $postData[$keyName]) {
|
150 |
+
return $postData[$keyName];
|
151 |
+
}
|
152 |
+
return $default;
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* @return array
|
157 |
+
*/
|
158 |
+
protected function _getPostData()
|
159 |
+
{
|
160 |
+
if ($this->_postData === null) {
|
161 |
+
|
162 |
+
$this->_postData = array();
|
163 |
+
$input = file_get_contents('php://input');
|
164 |
+
if ($input
|
165 |
+
&& substr_count('{', $input) == substr_count('}', $input)
|
166 |
+
&& substr_count('[', $input) == substr_count(']', $input)) {
|
167 |
+
try {
|
168 |
+
$this->_postData = Mage::helper('core')->jsonDecode($input);
|
169 |
+
} catch (Exception $e) {
|
170 |
+
|
171 |
+
}
|
172 |
+
}
|
173 |
+
}
|
174 |
+
|
175 |
+
return $this->_postData;
|
176 |
+
}
|
177 |
+
}
|
app/code/community/Neklo/Monitor/Helper/Request/Validator.php
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Helper_Request_Validator
|
4 |
+
{
|
5 |
+
public function isValidToken($token)
|
6 |
+
{
|
7 |
+
if (!$token) {
|
8 |
+
return false;
|
9 |
+
}
|
10 |
+
if ($this->_getConfig()->getToken() !== $token) {
|
11 |
+
return false;
|
12 |
+
}
|
13 |
+
return true;
|
14 |
+
}
|
15 |
+
|
16 |
+
public function isValidSid($sid)
|
17 |
+
{
|
18 |
+
if (strlen($sid) !== 32) {
|
19 |
+
return false;
|
20 |
+
}
|
21 |
+
if ($this->_getConfig()->getGatewaySid() && $this->_getConfig()->getGatewaySid() !== $sid) {
|
22 |
+
return false;
|
23 |
+
}
|
24 |
+
return true;
|
25 |
+
}
|
26 |
+
|
27 |
+
public function isValidHash($hash)
|
28 |
+
{
|
29 |
+
if (strlen($hash) !== 32) {
|
30 |
+
return false;
|
31 |
+
}
|
32 |
+
return true;
|
33 |
+
}
|
34 |
+
|
35 |
+
public function isValidDeviceId($deviceId)
|
36 |
+
{
|
37 |
+
if (!$deviceId) {
|
38 |
+
return false;
|
39 |
+
}
|
40 |
+
// TODO: add expression for device id
|
41 |
+
return true;
|
42 |
+
}
|
43 |
+
|
44 |
+
public function isValidPlan($plan)
|
45 |
+
{
|
46 |
+
if (!is_array($plan)) {
|
47 |
+
return false;
|
48 |
+
}
|
49 |
+
if (!array_key_exists('type', $plan) || !$plan['type']) {
|
50 |
+
return false;
|
51 |
+
}
|
52 |
+
if (!array_key_exists('frequency', $plan) || !$plan['frequency']) {
|
53 |
+
return false;
|
54 |
+
}
|
55 |
+
return true;
|
56 |
+
}
|
57 |
+
|
58 |
+
public function isValidStore($storeId)
|
59 |
+
{
|
60 |
+
$storeId = (int)$storeId;
|
61 |
+
if ($storeId) {
|
62 |
+
$store = Mage::app()->getStore($storeId);
|
63 |
+
if (!$store->getId() || $storeId != $store->getId()) {
|
64 |
+
return false;
|
65 |
+
}
|
66 |
+
}
|
67 |
+
return true;
|
68 |
+
}
|
69 |
+
|
70 |
+
public function isValidTimestamp($time)
|
71 |
+
{
|
72 |
+
if (is_numeric($time)) {
|
73 |
+
return true;
|
74 |
+
}
|
75 |
+
return false;
|
76 |
+
}
|
77 |
+
|
78 |
+
public function isValidGroupByPeriod($period)
|
79 |
+
{
|
80 |
+
if (!in_array($period, array(
|
81 |
+
'day', 'month', 'year'
|
82 |
+
))) {
|
83 |
+
return false;
|
84 |
+
}
|
85 |
+
return true;
|
86 |
+
}
|
87 |
+
|
88 |
+
public function isValidOrderStatus($status)
|
89 |
+
{
|
90 |
+
// parameter is optional
|
91 |
+
if (!$status) {
|
92 |
+
return true;
|
93 |
+
}
|
94 |
+
// but we validate its value if sent
|
95 |
+
if (!in_array($status, array_keys(Mage::getSingleton('sales/order_config')->getStatuses()))) {
|
96 |
+
return false;
|
97 |
+
}
|
98 |
+
return true;
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* @return Neklo_Monitor_Helper_Config
|
103 |
+
*/
|
104 |
+
protected function _getConfig()
|
105 |
+
{
|
106 |
+
return Mage::helper('neklo_monitor/config');
|
107 |
+
}
|
108 |
+
}
|
app/code/community/Neklo/Monitor/Model/Cron/Abstract.php
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
abstract class Neklo_Monitor_Model_Cron_Abstract
|
4 |
+
{
|
5 |
+
protected $_name = '';
|
6 |
+
|
7 |
+
public function run(Mage_Cron_Model_Schedule $schedule)
|
8 |
+
{
|
9 |
+
if (!$this->_getConfig()->isEnabled()) {
|
10 |
+
$schedule->setMessages('Disabled');
|
11 |
+
return;
|
12 |
+
}
|
13 |
+
|
14 |
+
if (!$this->_getConfig()->isConnected()) {
|
15 |
+
$schedule->setMessages('Not connected');
|
16 |
+
return;
|
17 |
+
}
|
18 |
+
|
19 |
+
if ($this->_isLocked()) {
|
20 |
+
$schedule->setMessages('Locked');
|
21 |
+
return;
|
22 |
+
}
|
23 |
+
|
24 |
+
$this->_lock();
|
25 |
+
$this->_passData($schedule);
|
26 |
+
|
27 |
+
$msg = $schedule->getMessages();
|
28 |
+
if ($msg) {
|
29 |
+
$msg .= "\n";
|
30 |
+
}
|
31 |
+
$msg .= 'Sent';
|
32 |
+
$schedule->setMessages($msg);
|
33 |
+
}
|
34 |
+
|
35 |
+
abstract protected function _passData(Mage_Cron_Model_Schedule $schedule);
|
36 |
+
|
37 |
+
protected function _isLocked()
|
38 |
+
{
|
39 |
+
$lockedAt = Mage::app()->loadCache($this->_name);
|
40 |
+
if ($lockedAt && (time() - $lockedAt < $this->_getConfig()->getGatewayFrequency() * 60)) {
|
41 |
+
return true;
|
42 |
+
}
|
43 |
+
return false;
|
44 |
+
}
|
45 |
+
|
46 |
+
protected function _lock()
|
47 |
+
{
|
48 |
+
Mage::app()->saveCache(time(), $this->_name, array(), $this->_getConfig()->getGatewayFrequency() * 60);
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* @return Neklo_Monitor_Helper_Config
|
53 |
+
*/
|
54 |
+
protected function _getConfig()
|
55 |
+
{
|
56 |
+
return Mage::helper('neklo_monitor/config');
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @return Neklo_Monitor_Model_Gateway_Connector
|
61 |
+
*/
|
62 |
+
protected function _getConnector()
|
63 |
+
{
|
64 |
+
return Mage::getSingleton('neklo_monitor/gateway_connector');
|
65 |
+
}
|
66 |
+
}
|
app/code/community/Neklo/Monitor/Model/Cron/Server.php
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Model_Cron_Server extends Neklo_Monitor_Model_Cron_Abstract
|
4 |
+
{
|
5 |
+
protected $_name = 'neklo_monitor_cron_server_lock_id';
|
6 |
+
|
7 |
+
protected function _passData(Mage_Cron_Model_Schedule $schedule)
|
8 |
+
{
|
9 |
+
$serverData = $this->_collectServerData($schedule);
|
10 |
+
try {
|
11 |
+
$gatewayConfig = $this->_getConnector()->sendInfo('server', $serverData);
|
12 |
+
$this->_getConfig()->updateGatewayConfig($gatewayConfig);
|
13 |
+
$this->_getConfig()->updateGatewayLastUpdate();
|
14 |
+
} catch (Exception $e) {
|
15 |
+
Mage::logException($e);
|
16 |
+
$msg = $schedule->getMessages();
|
17 |
+
if ($msg) {
|
18 |
+
$msg .= "\n";
|
19 |
+
}
|
20 |
+
$msg .= $e->getMessage();
|
21 |
+
$schedule->setMessages($msg);
|
22 |
+
}
|
23 |
+
}
|
24 |
+
|
25 |
+
protected function _collectServerData(Mage_Cron_Model_Schedule $schedule)
|
26 |
+
{
|
27 |
+
$info = null;
|
28 |
+
try {
|
29 |
+
Neklo_Monitor_Autoload::register();
|
30 |
+
/** @var Neklo_Monitor_Model_Linfo $linfo */
|
31 |
+
$linfo = Mage::getModel('neklo_monitor/linfo');
|
32 |
+
$linfo->scan();
|
33 |
+
$info = $linfo->getInfo();
|
34 |
+
} catch (Exception $e) {
|
35 |
+
Mage::logException($e);
|
36 |
+
$msg = $schedule->getMessages();
|
37 |
+
if ($msg) {
|
38 |
+
$msg .= "\n";
|
39 |
+
}
|
40 |
+
$msg .= $e->getMessage();
|
41 |
+
$schedule->setMessages($msg);
|
42 |
+
}
|
43 |
+
return $info;
|
44 |
+
}
|
45 |
+
|
46 |
+
}
|
app/code/community/Neklo/Monitor/Model/Cron/Store.php
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Model_Cron_Store extends Neklo_Monitor_Model_Cron_Abstract
|
4 |
+
{
|
5 |
+
protected $_name = 'neklo_monitor_cron_store_lock_id';
|
6 |
+
|
7 |
+
protected function _passData(Mage_Cron_Model_Schedule $schedule)
|
8 |
+
{
|
9 |
+
$storeData = $this->_collectStoreData($schedule);
|
10 |
+
try {
|
11 |
+
$gatewayConfig = $this->_getConnector()->sendInfo('store', $storeData);
|
12 |
+
$this->_getConfig()->updateGatewayConfig($gatewayConfig);
|
13 |
+
$this->_getConfig()->updateGatewayLastUpdate();
|
14 |
+
} catch (Exception $e) {
|
15 |
+
Mage::logException($e);
|
16 |
+
$msg = $schedule->getMessages();
|
17 |
+
if ($msg) {
|
18 |
+
$msg .= "\n";
|
19 |
+
}
|
20 |
+
$msg .= $e->getMessage();
|
21 |
+
$schedule->setMessages($msg);
|
22 |
+
}
|
23 |
+
}
|
24 |
+
|
25 |
+
protected function _collectStoreData(Mage_Cron_Model_Schedule $schedule)
|
26 |
+
{
|
27 |
+
$info = null;
|
28 |
+
try {
|
29 |
+
/* @var $minfo Neklo_Monitor_Model_Minfo */
|
30 |
+
$minfo = Mage::getModel('neklo_monitor/minfo');
|
31 |
+
$minfo->scan();
|
32 |
+
$info = $minfo->getInfo();
|
33 |
+
} catch (Exception $e) {
|
34 |
+
Mage::logException($e);
|
35 |
+
$msg = $schedule->getMessages();
|
36 |
+
if ($msg) {
|
37 |
+
$msg .= "\n";
|
38 |
+
}
|
39 |
+
$msg .= $e->getMessage();
|
40 |
+
$schedule->setMessages($msg);
|
41 |
+
}
|
42 |
+
return $info;
|
43 |
+
}
|
44 |
+
|
45 |
+
public function collect()
|
46 |
+
{
|
47 |
+
if (!$this->_getConfig()->isEnabled()) {
|
48 |
+
return;
|
49 |
+
}
|
50 |
+
|
51 |
+
/** @var Neklo_Monitor_Model_Minfo_Parser $parser */
|
52 |
+
$parser = Mage::getModel('neklo_monitor/minfo_parser');
|
53 |
+
$parser->generateReportStats();
|
54 |
+
$parser->generateLogStats('system');
|
55 |
+
$parser->generateLogStats('exception');
|
56 |
+
}
|
57 |
+
|
58 |
+
}
|
app/code/community/Neklo/Monitor/Model/Gateway/Connector.php
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Model_Gateway_Connector
|
4 |
+
{
|
5 |
+
protected $_client = null;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* @return null|Varien_Http_Client
|
9 |
+
* @throws Zend_Http_Client_Exception
|
10 |
+
*/
|
11 |
+
public function getClient()
|
12 |
+
{
|
13 |
+
if ($this->_client === null) {
|
14 |
+
$this->_client = new Varien_Http_Client();
|
15 |
+
$this->_client
|
16 |
+
->setMethod(Zend_Http_Client::POST)
|
17 |
+
->setConfig(
|
18 |
+
array(
|
19 |
+
'maxredirects' => 0,
|
20 |
+
'timeout' => 30,
|
21 |
+
)
|
22 |
+
)
|
23 |
+
->setHeaders('SID', $this->_getConfig()->getGatewaySid())
|
24 |
+
;
|
25 |
+
}
|
26 |
+
return $this->_client;
|
27 |
+
}
|
28 |
+
|
29 |
+
public function sendInfo($type, $info)
|
30 |
+
{
|
31 |
+
$requestData = array(
|
32 |
+
$type => $info,
|
33 |
+
);
|
34 |
+
$client = $this->getClient();
|
35 |
+
|
36 |
+
$client->setUri($this->_getUri());
|
37 |
+
|
38 |
+
$result = $client
|
39 |
+
->setRawData(Mage::helper('core')->jsonEncode($requestData))
|
40 |
+
->request()
|
41 |
+
;
|
42 |
+
|
43 |
+
if (!$result->isSuccessful()) {
|
44 |
+
throw new Exception('Error sending request: '.$result->getMessage());
|
45 |
+
}
|
46 |
+
|
47 |
+
return Mage::helper('core')->jsonDecode($this->_getBody($result));
|
48 |
+
}
|
49 |
+
|
50 |
+
protected function _getUri()
|
51 |
+
{
|
52 |
+
return $this->_getConfig()->getGatewayServerUri() . 'server/info';
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* @return Neklo_Monitor_Helper_Config
|
57 |
+
*/
|
58 |
+
protected function _getConfig()
|
59 |
+
{
|
60 |
+
return Mage::helper('neklo_monitor/config');
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* similar to Zend_Http_Response::getBody()
|
65 |
+
*/
|
66 |
+
protected function _getBody(Zend_Http_Response $response)
|
67 |
+
{
|
68 |
+
$body = $response->getRawBody();
|
69 |
+
|
70 |
+
// 'transfer-encoding' header is 'chunked', but the body does not seem to be chunked, hmm
|
71 |
+
// just silent catch for such cases
|
72 |
+
try {
|
73 |
+
// Decode the body if it was transfer-encoded
|
74 |
+
if (strtolower($response->getHeader('transfer-encoding')) == 'chunked') {
|
75 |
+
// Handle chunked body
|
76 |
+
$body = Zend_Http_Response::decodeChunkedBody($body);
|
77 |
+
}
|
78 |
+
} catch (Zend_Http_Exception $e) {
|
79 |
+
if (false === strpos($e->getMessage(), 'Error parsing body')) {
|
80 |
+
throw $e;
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
// Decode any content-encoding (gzip or deflate) if needed
|
85 |
+
switch (strtolower($response->getHeader('content-encoding'))) {
|
86 |
+
|
87 |
+
// Handle gzip encoding
|
88 |
+
case 'gzip':
|
89 |
+
$body = Zend_Http_Response::decodeGzip($body);
|
90 |
+
break;
|
91 |
+
|
92 |
+
// Handle deflate encoding
|
93 |
+
case 'deflate':
|
94 |
+
$body = Zend_Http_Response::decodeDeflate($body);
|
95 |
+
break;
|
96 |
+
|
97 |
+
default:
|
98 |
+
break;
|
99 |
+
}
|
100 |
+
|
101 |
+
return $body;
|
102 |
+
}
|
103 |
+
|
104 |
+
}
|
app/code/community/Neklo/Monitor/Model/Linfo.php
ADDED
@@ -0,0 +1,296 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Model_Linfo extends \Linfo\Linfo
|
4 |
+
{
|
5 |
+
protected $_defaultConfig = array(
|
6 |
+
'byte_notation' => 1024,
|
7 |
+
'dates' => Varien_Date::DATETIME_INTERNAL_FORMAT,
|
8 |
+
'language' => 'en',
|
9 |
+
'show' => array(
|
10 |
+
'os' => true,
|
11 |
+
'distro' => true,
|
12 |
+
'load' => true,
|
13 |
+
'ram' => true,
|
14 |
+
'mounts' => true,
|
15 |
+
'network' => true,
|
16 |
+
'uptime' => true,
|
17 |
+
'cpu' => true,
|
18 |
+
'connection' => true,
|
19 |
+
'kernel' => false,
|
20 |
+
'ip' => false,
|
21 |
+
'hd' => false,
|
22 |
+
'mounts_options' => false,
|
23 |
+
'webservice' => false,
|
24 |
+
'phpversion' => false,
|
25 |
+
'process_stats' => false,
|
26 |
+
'hostname' => false,
|
27 |
+
'devices' => false,
|
28 |
+
'model' => false,
|
29 |
+
'numLoggedIn' => false,
|
30 |
+
'virtualization' => false,
|
31 |
+
'duplicate_mounts' => false,
|
32 |
+
'temps' => false,
|
33 |
+
'raid' => false,
|
34 |
+
'battery' => false,
|
35 |
+
'sound' => false,
|
36 |
+
'wifi' => false,
|
37 |
+
'services' => false,
|
38 |
+
),
|
39 |
+
'hide' => array(
|
40 |
+
'filesystems' => array(
|
41 |
+
'tmpfs',
|
42 |
+
'ecryptfs',
|
43 |
+
'nfsd',
|
44 |
+
'rpc_pipefs',
|
45 |
+
'usbfs',
|
46 |
+
'devpts',
|
47 |
+
'fusectl',
|
48 |
+
'securityfs',
|
49 |
+
'fuse.truecrypt',
|
50 |
+
),
|
51 |
+
'storage_devices' => array(
|
52 |
+
'gvfs-fuse-daemon',
|
53 |
+
'none',
|
54 |
+
),
|
55 |
+
'mountpoints_regex' => array(
|
56 |
+
'/^\/.+$/s'
|
57 |
+
),
|
58 |
+
'fs_mount_options' => array(
|
59 |
+
'ecryptfs',
|
60 |
+
),
|
61 |
+
),
|
62 |
+
'cpu_usage' => true,
|
63 |
+
'show_errors' => false,
|
64 |
+
);
|
65 |
+
|
66 |
+
protected $_infoMap = array(
|
67 |
+
// General
|
68 |
+
'timestamp' => 'server_created_at',
|
69 |
+
|
70 |
+
// OS
|
71 |
+
'OS' => 'os/name',
|
72 |
+
'Distro/name' => 'os/distro/name',
|
73 |
+
'Distro/version' => 'os/distro/version',
|
74 |
+
|
75 |
+
// RAM
|
76 |
+
'RAM/total' => 'ram/total',
|
77 |
+
'RAM/free' => 'ram/free',
|
78 |
+
|
79 |
+
// Mounts
|
80 |
+
'Mounts/*/size' => 'mount/*/total',
|
81 |
+
'Mounts/*/free' => 'mount/*/free',
|
82 |
+
'Mounts/*/free_percent' => 'mount/*/free_percent',
|
83 |
+
'Mounts/*/used' => 'mount/*/used',
|
84 |
+
'Mounts/*/used_percent' => 'mount/*/used_percent',
|
85 |
+
|
86 |
+
// CPU
|
87 |
+
'Load' => 'cpu/load',
|
88 |
+
'CPUArchitecture' => 'cpu/architecture',
|
89 |
+
'CPU/*/Vendor' => 'cpu/core/*/vendor',
|
90 |
+
'CPU/*/Model' => 'cpu/core/*/model',
|
91 |
+
'CPU/*/MHz' => 'cpu/core/*/mhz',
|
92 |
+
'CPU/*/usage_percentage' => 'cpu/core/*/usage_percent',
|
93 |
+
|
94 |
+
// Network
|
95 |
+
'Network Devices/*/state' => 'network/*/state',
|
96 |
+
'Network Devices/*/recieved/bytes' => 'network/*/received/bytes',
|
97 |
+
'Network Devices/*/recieved/errors' => 'network/*/received/errors',
|
98 |
+
'Network Devices/*/recieved/packets' => 'network/*/received/packets',
|
99 |
+
'Network Devices/*/sent/bytes' => 'network/*/sent/bytes',
|
100 |
+
'Network Devices/*/sent/errors' => 'network/*/sent/errors',
|
101 |
+
'Network Devices/*/sent/packets' => 'network/*/sent/packets',
|
102 |
+
|
103 |
+
// UpTime
|
104 |
+
'UpTime/bootedTimestamp' => 'uptime/booted_timestamp',
|
105 |
+
'UpTime/text' => 'uptime/booted_timestamp_text',
|
106 |
+
|
107 |
+
// Connection
|
108 |
+
'Connection/connect' => 'connection/connect',
|
109 |
+
'Connection/ttfb' => 'connection/ttfb',
|
110 |
+
'Connection/total' => 'connection/total',
|
111 |
+
);
|
112 |
+
|
113 |
+
public function &getInfo()
|
114 |
+
{
|
115 |
+
$timestamp = time();
|
116 |
+
$info = parent::getInfo();
|
117 |
+
$info['timestamp'] = $timestamp;
|
118 |
+
|
119 |
+
$infoMap = $this->_prepareInfoMap($info);
|
120 |
+
$result = $this->_applyInfoMap($info, $infoMap);
|
121 |
+
|
122 |
+
return $result;
|
123 |
+
}
|
124 |
+
|
125 |
+
protected function _applyInfoMap($data, $infoMap)
|
126 |
+
{
|
127 |
+
$result = array();
|
128 |
+
foreach ($infoMap as $linfoPath => $monitorPath) {
|
129 |
+
|
130 |
+
$linfoPathList = explode('/', $linfoPath);
|
131 |
+
$linfoKeyValue = $data;
|
132 |
+
foreach ($linfoPathList as $key) {
|
133 |
+
if (!array_key_exists($key, $linfoKeyValue)) {
|
134 |
+
continue;
|
135 |
+
}
|
136 |
+
$linfoKeyValue = $linfoKeyValue[$key];
|
137 |
+
}
|
138 |
+
|
139 |
+
$monitorPathList = explode('/', $monitorPath);
|
140 |
+
$monitorKeyValue = &$result;
|
141 |
+
foreach ($monitorPathList as $key) {
|
142 |
+
if (!array_key_exists($key, $monitorKeyValue)) {
|
143 |
+
$monitorKeyValue[$key] = array();
|
144 |
+
}
|
145 |
+
$monitorKeyValue = &$monitorKeyValue[$key];
|
146 |
+
}
|
147 |
+
$monitorKeyValue = $linfoKeyValue;
|
148 |
+
}
|
149 |
+
return $result;
|
150 |
+
}
|
151 |
+
|
152 |
+
protected function _prepareInfoMap($data)
|
153 |
+
{
|
154 |
+
$_infoMap = array();
|
155 |
+
foreach ($this->_infoMap as $linfoPath => $monitorPath) {
|
156 |
+
if (strpos($linfoPath, '*') === false) {
|
157 |
+
$_infoMap[$linfoPath] = $monitorPath;
|
158 |
+
continue;
|
159 |
+
}
|
160 |
+
|
161 |
+
$linfoPathList = explode('/', $linfoPath);
|
162 |
+
$linfoKeyValue = $data;
|
163 |
+
foreach ($linfoPathList as $key) {
|
164 |
+
if ($key == '*') {
|
165 |
+
$realInfoKeyList = array_keys($linfoKeyValue);
|
166 |
+
foreach ($realInfoKeyList as $realInfoKey) {
|
167 |
+
$_infoMap[str_replace('*', $realInfoKey, $linfoPath)] = str_replace('*', $realInfoKey, $monitorPath);
|
168 |
+
}
|
169 |
+
continue;
|
170 |
+
}
|
171 |
+
if (!array_key_exists($key, $linfoKeyValue)) {
|
172 |
+
continue;
|
173 |
+
}
|
174 |
+
$linfoKeyValue = $linfoKeyValue[$key];
|
175 |
+
}
|
176 |
+
}
|
177 |
+
return $_infoMap;
|
178 |
+
}
|
179 |
+
|
180 |
+
public function scan()
|
181 |
+
{
|
182 |
+
parent::scan();
|
183 |
+
$this->_scanAdditional();
|
184 |
+
}
|
185 |
+
|
186 |
+
protected function loadSettings($settings = array())
|
187 |
+
{
|
188 |
+
if (!is_array($settings) || !count($settings)) {
|
189 |
+
$settings = $this->_defaultConfig;
|
190 |
+
}
|
191 |
+
|
192 |
+
// Running unit tests?
|
193 |
+
if (defined('LINFO_TESTING')) {
|
194 |
+
$this->settings = \Linfo\Common::getVarFromFile($this->linfo_testdir.'/test_settings.php', 'settings');
|
195 |
+
if (!is_array($this->settings)) {
|
196 |
+
throw new \Linfo\Exceptions\FatalException('Failed getting test-specific settings');
|
197 |
+
}
|
198 |
+
return;
|
199 |
+
}
|
200 |
+
|
201 |
+
// Don't just blindly assume we have the ob_* functions...
|
202 |
+
if (!function_exists('ob_start')) {
|
203 |
+
$settings['compress_content'] = false;
|
204 |
+
}
|
205 |
+
|
206 |
+
if (!isset($settings['hide'])) {
|
207 |
+
$settings['hide'] = array(
|
208 |
+
'filesystems' => array(),
|
209 |
+
'storage_devices' => array(),
|
210 |
+
);
|
211 |
+
}
|
212 |
+
|
213 |
+
// Make sure these are arrays
|
214 |
+
$settings['hide']['filesystems'] = is_array($settings['hide']['filesystems']) ? $settings['hide']['filesystems'] : array();
|
215 |
+
$settings['hide']['storage_devices'] = is_array($settings['hide']['storage_devices']) ? $settings['hide']['storage_devices'] : array();
|
216 |
+
|
217 |
+
// Make sure these are always hidden
|
218 |
+
$settings['hide']['filesystems'][] = 'rootfs';
|
219 |
+
$settings['hide']['filesystems'][] = 'binfmt_misc';
|
220 |
+
|
221 |
+
// Default timeformat
|
222 |
+
$settings['dates'] = array_key_exists('dates', $settings) ? $settings['dates'] : 'm/d/y h:i A (T)';
|
223 |
+
|
224 |
+
// Default to english translation if garbage is passed
|
225 |
+
if (empty($settings['language']) || !preg_match('/^[a-z]{2}$/', $settings['language'])) {
|
226 |
+
$settings['language'] = 'en';
|
227 |
+
}
|
228 |
+
|
229 |
+
// If it can't be found default to english
|
230 |
+
if (!is_file($this->linfo_localdir.'lib/Linfo/Lang/'.$settings['language'].'.php')) {
|
231 |
+
$settings['language'] = 'en';
|
232 |
+
}
|
233 |
+
|
234 |
+
$this->settings = $settings;
|
235 |
+
}
|
236 |
+
|
237 |
+
protected function loadLanguage()
|
238 |
+
{
|
239 |
+
// Running unit tests?
|
240 |
+
if (defined('LINFO_TESTING')) {
|
241 |
+
$this->lang = require $this->linfo_testdir.'/test_lang.php';
|
242 |
+
if (!is_array($this->lang)) {
|
243 |
+
throw new \Linfo\Exceptions\FatalException('Failed getting test-specific language');
|
244 |
+
}
|
245 |
+
|
246 |
+
return;
|
247 |
+
}
|
248 |
+
|
249 |
+
// Load translation, defaulting to english of keys are missing (assuming
|
250 |
+
// we're not using english anyway and the english translation indeed exists)
|
251 |
+
if (is_file($this->linfo_localdir.'lib/Linfo/Lang/en.php') && $this->settings['language'] != 'en') {
|
252 |
+
$this->lang = array_merge(require($this->linfo_localdir.'lib/Linfo/Lang/en.php'),
|
253 |
+
require($this->linfo_localdir.'lib/Linfo/Lang/'.$this->settings['language'].'.php'));
|
254 |
+
}
|
255 |
+
|
256 |
+
// Otherwise snag desired translation, be it english or a non-english without english to fall back on
|
257 |
+
else {
|
258 |
+
$this->lang = require $this->linfo_localdir.'lib/Linfo/Lang/'.$this->settings['language'].'.php';
|
259 |
+
}
|
260 |
+
}
|
261 |
+
|
262 |
+
protected function _scanAdditional()
|
263 |
+
{
|
264 |
+
$os = $this->getOS();
|
265 |
+
|
266 |
+
if (!$os) {
|
267 |
+
throw new \Linfo\Exceptions\FatalException('Unknown/unsupported operating system');
|
268 |
+
}
|
269 |
+
|
270 |
+
$parser = Mage::getModel('neklo_monitor/linfo_os_' . strtolower($os), $this->settings);
|
271 |
+
|
272 |
+
$reflector = new ReflectionClass($parser);
|
273 |
+
|
274 |
+
$fields = array(
|
275 |
+
'Connection' => array(
|
276 |
+
'show' => !empty($this->settings['show']['connection']),
|
277 |
+
'default' => '',
|
278 |
+
'method' => 'getConnection',
|
279 |
+
),
|
280 |
+
);
|
281 |
+
|
282 |
+
foreach ($fields as $key => $data) {
|
283 |
+
if (!$data['show']) {
|
284 |
+
$this->info[$key] = $data['default'];
|
285 |
+
continue;
|
286 |
+
}
|
287 |
+
|
288 |
+
try {
|
289 |
+
$method = $reflector->getMethod($data['method']);
|
290 |
+
$this->info[$key] = $method->invoke($parser);
|
291 |
+
} catch (ReflectionException $e) {
|
292 |
+
$this->info[$key] = $data['default'];
|
293 |
+
}
|
294 |
+
}
|
295 |
+
}
|
296 |
+
}
|
app/code/community/Neklo/Monitor/Model/Linfo/Os/Linux.php
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Model_Linfo_Os_Linux extends \Linfo\OS\Linux
|
4 |
+
{
|
5 |
+
protected $exec = null;
|
6 |
+
|
7 |
+
public function __construct(array $settings)
|
8 |
+
{
|
9 |
+
parent::__construct($settings);
|
10 |
+
$this->exec = new \Linfo\Parsers\CallExt();
|
11 |
+
$this->exec->setSearchPaths(array('/sbin', '/bin', '/usr/bin', '/usr/local/bin', '/usr/sbin'));
|
12 |
+
}
|
13 |
+
|
14 |
+
public function getConnection()
|
15 |
+
{
|
16 |
+
if (!empty($this->settings['connection'])) {
|
17 |
+
$t = new \Linfo\Meta\Timer('Connection');
|
18 |
+
}
|
19 |
+
$result = array();
|
20 |
+
try {
|
21 |
+
$command = $this->exec->exec('curl', ' -so /dev/null -w "connect:%{time_connect};ttfb:%{time_starttransfer};total:%{time_total};" ' . Mage::getBaseUrl());
|
22 |
+
$lines = explode(";", $command);
|
23 |
+
$result = array();
|
24 |
+
foreach ($lines as $line) {
|
25 |
+
if (!$line) {
|
26 |
+
continue;
|
27 |
+
}
|
28 |
+
list($key, $value) = explode(':', $line);
|
29 |
+
if (!$key || !$value) {
|
30 |
+
continue;
|
31 |
+
}
|
32 |
+
$result[$key] = $value;
|
33 |
+
}
|
34 |
+
} catch (Exception $e) {
|
35 |
+
\Linfo\Meta\Errors::add('Linux Core', 'Failed running curl.');
|
36 |
+
}
|
37 |
+
return $result;
|
38 |
+
}
|
39 |
+
}
|
app/code/community/Neklo/Monitor/Model/Log.php
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Model_Log
|
4 |
+
{
|
5 |
+
|
6 |
+
}
|
app/code/community/Neklo/Monitor/Model/Minfo.php
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Model_Minfo
|
4 |
+
{
|
5 |
+
protected $_info = array();
|
6 |
+
|
7 |
+
protected $_config = array(
|
8 |
+
'magento' => array(
|
9 |
+
'var_log' => true,
|
10 |
+
'var_report' => true,
|
11 |
+
'customer_online' => true,
|
12 |
+
'products_outofstock' => true,
|
13 |
+
),
|
14 |
+
);
|
15 |
+
|
16 |
+
public function getInfo()
|
17 |
+
{
|
18 |
+
return $this->_info;
|
19 |
+
}
|
20 |
+
|
21 |
+
public function scan()
|
22 |
+
{
|
23 |
+
/** @var Neklo_Monitor_Model_Minfo_Parser $parser */
|
24 |
+
$parser = Mage::getModel('neklo_monitor/minfo_parser');
|
25 |
+
|
26 |
+
$timestamp = time();
|
27 |
+
$fields = array(
|
28 |
+
'var_log' => array(
|
29 |
+
'show' => !empty($this->_config['magento']['var_log']),
|
30 |
+
'default' => null,
|
31 |
+
'method' => 'getVarLog',
|
32 |
+
),
|
33 |
+
'var_report' => array(
|
34 |
+
'show' => !empty($this->_config['magento']['var_report']),
|
35 |
+
'default' => null,
|
36 |
+
'method' => 'getVarReport',
|
37 |
+
),
|
38 |
+
'customer_online' => array(
|
39 |
+
'show' => !empty($this->_config['magento']['customer_online']),
|
40 |
+
'default' => null,
|
41 |
+
'method' => 'getCustomerOnline',
|
42 |
+
),
|
43 |
+
'products_outofstock' => array(
|
44 |
+
'show' => !empty($this->_config['magento']['customer_online']),
|
45 |
+
'default' => null,
|
46 |
+
'method' => 'getProductsOutofstock',
|
47 |
+
),
|
48 |
+
);
|
49 |
+
|
50 |
+
foreach ($fields as $key => $data) {
|
51 |
+
$this->_info[$key] = $data['default'];
|
52 |
+
|
53 |
+
if (!$data['show']) {
|
54 |
+
continue;
|
55 |
+
}
|
56 |
+
|
57 |
+
try {
|
58 |
+
$methodName = $data['method'];
|
59 |
+
if (method_exists($parser, $methodName)) {
|
60 |
+
$this->_info[$key] = $parser->$methodName();
|
61 |
+
}
|
62 |
+
} catch (Exception $e) {
|
63 |
+
Mage::logException($e);
|
64 |
+
}
|
65 |
+
}
|
66 |
+
$this->_info['server_created_at'] = $timestamp;
|
67 |
+
return $this;
|
68 |
+
}
|
69 |
+
}
|
app/code/community/Neklo/Monitor/Model/Minfo/Log.php
ADDED
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @method Neklo_Monitor_Model_Resource_Minfo_Log getResource()
|
5 |
+
*/
|
6 |
+
class Neklo_Monitor_Model_Minfo_Log extends Mage_Core_Model_Abstract
|
7 |
+
{
|
8 |
+
protected function _construct()
|
9 |
+
{
|
10 |
+
$this->_init('neklo_monitor/minfo_log');
|
11 |
+
}
|
12 |
+
|
13 |
+
public function generateLogs($type)
|
14 |
+
{
|
15 |
+
$logActive = Mage::getStoreConfig('dev/log/active');
|
16 |
+
if (!Mage::getIsDeveloperMode() && !$logActive) {
|
17 |
+
return false;
|
18 |
+
}
|
19 |
+
|
20 |
+
$file = Mage::getStoreConfig('dev/log/file');
|
21 |
+
if ('system' != $type) {
|
22 |
+
$type = 'exception';
|
23 |
+
$file = Mage::getStoreConfig('dev/log/exception_file');
|
24 |
+
}
|
25 |
+
$logFile = Mage::getBaseDir('var') . DS . 'log' . DS . $file;
|
26 |
+
if (!file_exists($logFile)) {
|
27 |
+
return false;
|
28 |
+
}
|
29 |
+
|
30 |
+
$logs = array();
|
31 |
+
|
32 |
+
$fh = fopen($logFile, "r");
|
33 |
+
if (!$fh) {
|
34 |
+
return false;
|
35 |
+
}
|
36 |
+
|
37 |
+
$maxTime = $this->getResource()->fetchMaxTime($type);
|
38 |
+
|
39 |
+
// read log lines according to format
|
40 |
+
// '%timestamp% %priorityName% (%priority%): %message%' . PHP_EOL;
|
41 |
+
// see Mage::log()
|
42 |
+
// exception's $message starts with "/n", i.e. can be found on next line
|
43 |
+
|
44 |
+
while (($line = fgets($fh)) !== false) {
|
45 |
+
// line should contain datetime, priorityName, $priority value least
|
46 |
+
// e.g. "2016-04-18T13:39:42+00:00 ERR (3):"
|
47 |
+
// yes, minimal priorityName is ERR, see Zend_Log
|
48 |
+
if (strlen($line) < 34) {
|
49 |
+
continue;
|
50 |
+
}
|
51 |
+
|
52 |
+
// skip exception stack traces
|
53 |
+
if ('exception' == $type && 0 === strpos($line, '#')) {
|
54 |
+
continue;
|
55 |
+
}
|
56 |
+
|
57 |
+
// search for line with datetime at the beginning
|
58 |
+
// timestamp format is YYYY-mm-ddTHH:ii:ss+00:00
|
59 |
+
$offsetTimezone = strpos($line, '+00:00 ');
|
60 |
+
if (19 !== $offsetTimezone) { // 19 is strlen of 'YYYY-mm-ddTHH:ii:ss'
|
61 |
+
continue;
|
62 |
+
}
|
63 |
+
|
64 |
+
$lineDate = substr($line, 0, $offsetTimezone);
|
65 |
+
$lineTime = strtotime($lineDate);
|
66 |
+
// invalid date?
|
67 |
+
if (false === $lineTime) {
|
68 |
+
continue;
|
69 |
+
}
|
70 |
+
// process only new dates
|
71 |
+
if ($lineTime < $maxTime) {
|
72 |
+
continue;
|
73 |
+
}
|
74 |
+
|
75 |
+
$offsetPriority = $offsetTimezone + 7; // 7 is strlen of '+00:00 ', i.e. 19+7=26
|
76 |
+
$offsetMessage = strpos($line, ': ', $offsetPriority);
|
77 |
+
if (false === $offsetMessage) {
|
78 |
+
continue; // hmmm
|
79 |
+
}
|
80 |
+
$linePriorityInfo = substr($line, $offsetPriority, $offsetMessage - $offsetPriority);
|
81 |
+
list($linePriorityName, $linePriorityValue) = explode(' ', $linePriorityInfo);
|
82 |
+
// skip manual debug lines in system.log
|
83 |
+
if ('debug' == strtolower($linePriorityName)) {
|
84 |
+
continue;
|
85 |
+
}
|
86 |
+
|
87 |
+
$offsetMessage += 2; // ': ' between $priority and $message
|
88 |
+
if ('exception' == $type || $offsetMessage >= strlen($line)) {
|
89 |
+
// read next line for message
|
90 |
+
$line = fgets($fh);
|
91 |
+
if (false == $line) {
|
92 |
+
break; // EOF
|
93 |
+
}
|
94 |
+
$lineMessage = $line;
|
95 |
+
} else {
|
96 |
+
$lineMessage = substr($line, $offsetMessage);
|
97 |
+
}
|
98 |
+
$lineMessage = trim($lineMessage);
|
99 |
+
|
100 |
+
$hash = md5($lineMessage);
|
101 |
+
if (isset($logs[$hash])) {
|
102 |
+
$logs[$hash]['qty']++;
|
103 |
+
if ($lineTime > $logs[$hash]['last_time']) {
|
104 |
+
$logs[$hash]['last_time'] = $lineTime;
|
105 |
+
}
|
106 |
+
$logs[$hash]['times'][] = $lineTime;
|
107 |
+
} else {
|
108 |
+
$logs[$hash] = array(
|
109 |
+
'hash' => $hash,
|
110 |
+
'message' => $lineMessage,
|
111 |
+
'qty' => 1,
|
112 |
+
'last_time' => $lineTime,
|
113 |
+
'times' => array($lineTime),
|
114 |
+
);
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
fclose($fh);
|
119 |
+
|
120 |
+
// calculate first_time
|
121 |
+
foreach ($logs as $hash => $_log) {
|
122 |
+
$_times = $_log['times'];
|
123 |
+
sort($_times);
|
124 |
+
$logs[$hash]['first_time'] = current($_times);
|
125 |
+
}
|
126 |
+
|
127 |
+
|
128 |
+
list($inserted, $updated) = $this->getResource()->saveLogs($type, $logs);
|
129 |
+
|
130 |
+
return ($inserted+$updated);
|
131 |
+
}
|
132 |
+
|
133 |
+
protected function _afterLoad()
|
134 |
+
{
|
135 |
+
$list = explode(',', $this->_getData('times'));
|
136 |
+
|
137 |
+
// sort by time DESC
|
138 |
+
$list = array_unique($list, SORT_NUMERIC);
|
139 |
+
sort($list, SORT_NUMERIC);
|
140 |
+
$list = array_reverse($list);
|
141 |
+
|
142 |
+
$this->_data['times_list'] = $list;
|
143 |
+
return parent::_afterLoad();
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* @return Varien_Data_Collection
|
148 |
+
*/
|
149 |
+
public function getTimesCollection($startFrom = 0, $limit = null, $filter = array())
|
150 |
+
{
|
151 |
+
// apply filters
|
152 |
+
|
153 |
+
$list = $this->_getData('times_list');
|
154 |
+
if ($filter) {
|
155 |
+
foreach ($list as $_key => $_data) {
|
156 |
+
$valid = true;
|
157 |
+
foreach ($filter as $_expr => $_value) {
|
158 |
+
if ('lt' == $_expr) { if ($_data >= $_value) $valid = false; }
|
159 |
+
// else if ('lteq' == $_expr) { if ($_data[$_field] > $_value) $valid = false; }
|
160 |
+
// else if ('gt' == $_expr) { if ($_data[$_field] <= $_value) $valid = false; }
|
161 |
+
else if ('gteq' == $_expr) { if ($_data < $_value) $valid = false; }
|
162 |
+
// else if ('eq' == $_expr) { if ($_data[$_field] <> $_value) $valid = false; }
|
163 |
+
// else if ('neq' == $_expr) { if ($_data[$_field] == $_value) $valid = false; }
|
164 |
+
}
|
165 |
+
if (!$valid) {
|
166 |
+
unset($list[$_key]);
|
167 |
+
}
|
168 |
+
}
|
169 |
+
}
|
170 |
+
|
171 |
+
// apply limits
|
172 |
+
|
173 |
+
$lastIdx = count($list) - 1;
|
174 |
+
if (is_null($limit)) {
|
175 |
+
$finishAt = $lastIdx;
|
176 |
+
} else {
|
177 |
+
$finishAt = $startFrom + $limit - 1;
|
178 |
+
if ($finishAt > $lastIdx) {
|
179 |
+
$finishAt = $lastIdx;
|
180 |
+
}
|
181 |
+
}
|
182 |
+
|
183 |
+
$collection = new Varien_Data_Collection();
|
184 |
+
$k = $startFrom;
|
185 |
+
$list = array_values($list); // avoid assoc array, convert to numeric array keys
|
186 |
+
while ($k <= $finishAt) {
|
187 |
+
$_file = new Varien_Object($list[$k]);
|
188 |
+
$collection->addItem($_file);
|
189 |
+
$k++;
|
190 |
+
}
|
191 |
+
|
192 |
+
return $collection;
|
193 |
+
}
|
194 |
+
|
195 |
+
}
|
app/code/community/Neklo/Monitor/Model/Minfo/Parser.php
ADDED
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Model_Minfo_Parser
|
4 |
+
{
|
5 |
+
const VAR_REPORT = 'report';
|
6 |
+
const VAR_LOG = 'log';
|
7 |
+
|
8 |
+
public function getVarLog()
|
9 |
+
{
|
10 |
+
$statFiles = $this->_getDirectoryStats(self::VAR_LOG);
|
11 |
+
$statDb = $this->_getCollectedLogStats();
|
12 |
+
return array(
|
13 |
+
'size' => $statFiles->getSize(),
|
14 |
+
'count' => $statFiles->getCount(),
|
15 |
+
'details' => $statDb->getDetails(),
|
16 |
+
);
|
17 |
+
}
|
18 |
+
|
19 |
+
public function getVarReport()
|
20 |
+
{
|
21 |
+
$statFiles = $this->_getDirectoryStats(self::VAR_REPORT);
|
22 |
+
$statDb = $this->_getCollectedReportStats();
|
23 |
+
return array(
|
24 |
+
'size' => $statFiles->getSize(),
|
25 |
+
'count' => $statFiles->getCount(),
|
26 |
+
'details' => $statDb->getDetails(),
|
27 |
+
);
|
28 |
+
}
|
29 |
+
|
30 |
+
protected function _getDirectoryStats($directory)
|
31 |
+
{
|
32 |
+
$directoryPath = Mage::getBaseDir('var') . DS . $directory;
|
33 |
+
if (!is_dir($directoryPath) || !is_readable($directoryPath)) {
|
34 |
+
return new Varien_Object();
|
35 |
+
}
|
36 |
+
|
37 |
+
$size = 0;
|
38 |
+
$count = 0;
|
39 |
+
$directoryIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directoryPath));
|
40 |
+
foreach ($directoryIterator as $file) {
|
41 |
+
/* @var $file SplFileInfo */
|
42 |
+
if (!$file->isFile()) {
|
43 |
+
continue;
|
44 |
+
}
|
45 |
+
$size += $file->getSize();
|
46 |
+
$count++;
|
47 |
+
}
|
48 |
+
|
49 |
+
$stats = new Varien_Object(array(
|
50 |
+
'size' => (int) $size,
|
51 |
+
'count' => (int) $count,
|
52 |
+
));
|
53 |
+
|
54 |
+
return $stats;
|
55 |
+
}
|
56 |
+
|
57 |
+
protected function _getCollectedLogStats()
|
58 |
+
{
|
59 |
+
/** @var Neklo_Monitor_Model_Resource_Minfo_Log_Collection $collection */
|
60 |
+
$collection = Mage::getResourceModel('neklo_monitor/minfo_log_collection');
|
61 |
+
$collection->addFieldToSelect(array('type', 'qty', 'hash'));
|
62 |
+
$collection->getSelect(); // Init fields for select
|
63 |
+
$collection->load();
|
64 |
+
|
65 |
+
$gatewayReport = array();
|
66 |
+
foreach ($collection as $hash => $data) {
|
67 |
+
$gatewayReport[] = array(
|
68 |
+
'type' => $data['type'],
|
69 |
+
'hash' => $data['hash'],
|
70 |
+
'qty' => (int) $data['qty'],
|
71 |
+
);
|
72 |
+
}
|
73 |
+
|
74 |
+
$stats = new Varien_Object(array(
|
75 |
+
'details' => $gatewayReport,
|
76 |
+
));
|
77 |
+
|
78 |
+
return $stats;
|
79 |
+
}
|
80 |
+
|
81 |
+
protected function _getCollectedReportStats()
|
82 |
+
{
|
83 |
+
/** @var Neklo_Monitor_Model_Resource_Minfo_Report_Collection $collection */
|
84 |
+
$collection = Mage::getResourceModel('neklo_monitor/minfo_report_collection');
|
85 |
+
$collection->addFieldToSelect(array('qty', 'hash'));
|
86 |
+
$collection->getSelect(); // Init fields for select
|
87 |
+
$collection->load();
|
88 |
+
|
89 |
+
$gatewayReport = array();
|
90 |
+
foreach ($collection as $hash => $data) {
|
91 |
+
$gatewayReport[] = array(
|
92 |
+
'hash' => $data['hash'],
|
93 |
+
'qty' => (int) $data['qty'],
|
94 |
+
);
|
95 |
+
}
|
96 |
+
|
97 |
+
$stats = new Varien_Object(array(
|
98 |
+
'details' => $gatewayReport,
|
99 |
+
));
|
100 |
+
|
101 |
+
return $stats;
|
102 |
+
}
|
103 |
+
|
104 |
+
public function getCustomerOnline()
|
105 |
+
{
|
106 |
+
/** @var Mage_Log_Model_Visitor_Online $logModel */
|
107 |
+
$logModel = Mage::getModel('log/visitor_online');
|
108 |
+
$logModel->prepare();
|
109 |
+
/* @var $collection Mage_Log_Model_Mysql4_Visitor_Online_Collection */
|
110 |
+
$collection = $logModel->getCollection();
|
111 |
+
return array('count' => $collection->getSize());
|
112 |
+
}
|
113 |
+
|
114 |
+
public function getProductsOutofstock()
|
115 |
+
{
|
116 |
+
$collection = $this->getProductsOutofstockCollection();
|
117 |
+
return array('count' => $collection->getSize());
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* @param null $storeId
|
122 |
+
* @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
|
123 |
+
*/
|
124 |
+
public function getProductsOutofstockCollection($storeId = null)
|
125 |
+
{
|
126 |
+
/* @var $collection Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection */
|
127 |
+
$collection = Mage::getResourceModel('catalog/product_collection');
|
128 |
+
if ($storeId) {
|
129 |
+
$collection->addStoreFilter($storeId);
|
130 |
+
}
|
131 |
+
|
132 |
+
// copy-pasted from CE 1.4 Layer Model
|
133 |
+
/*
|
134 |
+
$attributes = Mage::getSingleton('catalog/config')->getProductAttributes();
|
135 |
+
$collection->addAttributeToSelect($attributes)
|
136 |
+
->addMinimalPrice()
|
137 |
+
->addFinalPrice()
|
138 |
+
->addTaxPercents()
|
139 |
+
;
|
140 |
+
*/
|
141 |
+
|
142 |
+
$collection->addAttributeToSelect(
|
143 |
+
array(
|
144 |
+
'name',
|
145 |
+
'price',
|
146 |
+
'small_image', // exists in collection when Flat Product is enabled
|
147 |
+
)
|
148 |
+
);
|
149 |
+
$collection
|
150 |
+
->joinField(
|
151 |
+
'is_in_stock',
|
152 |
+
'cataloginventory/stock_item',
|
153 |
+
'is_in_stock',
|
154 |
+
'product_id=entity_id',
|
155 |
+
'{{table}}.stock_id=1',
|
156 |
+
'left'
|
157 |
+
)
|
158 |
+
->addAttributeToFilter('is_in_stock', 0)
|
159 |
+
// TODO: investigate qty = 0
|
160 |
+
// ->joinField(
|
161 |
+
// 'qty',
|
162 |
+
// 'cataloginventory/stock_item',
|
163 |
+
// 'qty',
|
164 |
+
// 'product_id=entity_id',
|
165 |
+
// '{{table}}.stock_id=1',
|
166 |
+
// 'left'
|
167 |
+
// )
|
168 |
+
// ->addAttributeToFilter('qty', array('eq' => 0))
|
169 |
+
;
|
170 |
+
return $collection;
|
171 |
+
}
|
172 |
+
|
173 |
+
public function generateReportStats()
|
174 |
+
{
|
175 |
+
$directoryPath = Mage::getBaseDir('var') . DS . self::VAR_REPORT . DS;
|
176 |
+
if (!is_dir($directoryPath)) {
|
177 |
+
return false;
|
178 |
+
}
|
179 |
+
|
180 |
+
$count = 0;
|
181 |
+
$directoryIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directoryPath));
|
182 |
+
$files = array();
|
183 |
+
foreach ($directoryIterator as $_file) {
|
184 |
+
/** @var SplFileInfo $_file */
|
185 |
+
if (!$_file->isFile()) {
|
186 |
+
continue;
|
187 |
+
}
|
188 |
+
$files[$_file->getMTime()][$_file->getFilename()] = $_file;
|
189 |
+
$count++;
|
190 |
+
}
|
191 |
+
ksort($files);
|
192 |
+
return Mage::getSingleton('neklo_monitor/minfo_report')->generateReports($files);
|
193 |
+
}
|
194 |
+
|
195 |
+
public function generateLogStats($type)
|
196 |
+
{
|
197 |
+
return Mage::getSingleton('neklo_monitor/minfo_log')->generateLogs($type);
|
198 |
+
}
|
199 |
+
|
200 |
+
protected function _format($bytes)
|
201 |
+
{
|
202 |
+
$exp = (int)floor(log($bytes) / log(1024));
|
203 |
+
$symbols = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB');
|
204 |
+
return sprintf('%.2f ' . $symbols[$exp], ($bytes / pow(1024, floor($exp))));
|
205 |
+
}
|
206 |
+
}
|
app/code/community/Neklo/Monitor/Model/Minfo/Report.php
ADDED
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @method Neklo_Monitor_Model_Resource_Minfo_Report getResource()
|
5 |
+
*/
|
6 |
+
class Neklo_Monitor_Model_Minfo_Report extends Mage_Core_Model_Abstract
|
7 |
+
{
|
8 |
+
protected function _construct()
|
9 |
+
{
|
10 |
+
$this->_init('neklo_monitor/minfo_report');
|
11 |
+
}
|
12 |
+
|
13 |
+
public function generateReports($files)
|
14 |
+
{
|
15 |
+
$reports = array();
|
16 |
+
|
17 |
+
// $maxMtime = $this->getResource()->fetchMaxMtime();
|
18 |
+
foreach ($files as $_mtime => $_files) {
|
19 |
+
// if ($_mtime < $maxMtime) {
|
20 |
+
// continue;
|
21 |
+
// }
|
22 |
+
foreach ($_files as $_name => $_file) {
|
23 |
+
/** @var SplFileInfo $_file */
|
24 |
+
$_path = $_file->getPathname();
|
25 |
+
$_dataSer = file_get_contents($_path);
|
26 |
+
if ('a:5:{i:0;s:' != substr($_dataSer, 0, 11)) {
|
27 |
+
continue;
|
28 |
+
}
|
29 |
+
$_data = @unserialize($_dataSer);
|
30 |
+
if ($_data && is_array($_data)) {
|
31 |
+
$message = $_data[0];
|
32 |
+
$hash = md5($message);
|
33 |
+
if (isset($reports[$hash])) {
|
34 |
+
$reports[$hash]['qty']++;
|
35 |
+
if ($_mtime > $reports[$hash]['last_time']) {
|
36 |
+
$reports[$hash]['last_time'] = $_mtime;
|
37 |
+
}
|
38 |
+
$reports[$hash]['files'][] = array(
|
39 |
+
'name' => ''.$_name,
|
40 |
+
'path' => ''.$_path,
|
41 |
+
'time' => (int) $_mtime,
|
42 |
+
'size' => (int) $_file->getSize(),
|
43 |
+
);
|
44 |
+
} else {
|
45 |
+
$reports[$hash] = array(
|
46 |
+
'hash' => $hash,
|
47 |
+
'message' => $message,
|
48 |
+
'qty' => 1,
|
49 |
+
'last_time' => $_mtime,
|
50 |
+
'files' => array(
|
51 |
+
array(
|
52 |
+
'name' => ''.$_name,
|
53 |
+
'path' => ''.$_path,
|
54 |
+
'time' => (int) $_mtime,
|
55 |
+
'size' => (int) $_file->getSize(),
|
56 |
+
)
|
57 |
+
),
|
58 |
+
);
|
59 |
+
}
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
// calculate first_mtime
|
64 |
+
foreach ($reports as $hash => $_report) {
|
65 |
+
$minTime = time()*2; // server file mtime (incl. locale timezone) might be bigger than now GMT
|
66 |
+
foreach ($_report['files'] as $_file) {
|
67 |
+
if ($_file['time'] < $minTime) {
|
68 |
+
$minTime = $_file['time'];
|
69 |
+
}
|
70 |
+
}
|
71 |
+
$reports[$hash]['first_time'] = $minTime;
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
list($inserted, $updated) = $this->getResource()->saveReports($reports);
|
76 |
+
|
77 |
+
return ($inserted+$updated);
|
78 |
+
}
|
79 |
+
|
80 |
+
protected function _afterLoad()
|
81 |
+
{
|
82 |
+
$files = Mage::helper('core')->jsonDecode($this->_getData('files'));
|
83 |
+
|
84 |
+
$list = array();
|
85 |
+
foreach ($files as $_data) {
|
86 |
+
$key = $_data['time'] . '_' . $_data['name'];
|
87 |
+
// $_data['key'] = $key;
|
88 |
+
$list[$key] = $_data;
|
89 |
+
}
|
90 |
+
|
91 |
+
// sort by mtime DESC
|
92 |
+
|
93 |
+
ksort($list);
|
94 |
+
$list = array_reverse($list, true);
|
95 |
+
|
96 |
+
$this->_data['files_list'] = $list;
|
97 |
+
return parent::_afterLoad();
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* @return Varien_Data_Collection
|
102 |
+
*/
|
103 |
+
public function getFilesCollection($startFrom = 0, $limit = null, $filter = array())
|
104 |
+
{
|
105 |
+
// apply filters
|
106 |
+
|
107 |
+
$list = $this->_getData('files_list');
|
108 |
+
if ($filter) {
|
109 |
+
foreach ($list as $_key => $_data) {
|
110 |
+
$valid = true;
|
111 |
+
foreach ($filter as $_field => $_cond) {
|
112 |
+
if (!isset($_data[$_field])) {
|
113 |
+
$_data[$_field] = 0; // temporary, will not affect $list
|
114 |
+
}
|
115 |
+
foreach ($_cond as $_expr => $_value) {
|
116 |
+
if ('lt' == $_expr) { if ($_data[$_field] >= $_value) $valid = false; }
|
117 |
+
// else if ('lteq' == $_expr) { if ($_data[$_field] > $_value) $valid = false; }
|
118 |
+
// else if ('gt' == $_expr) { if ($_data[$_field] <= $_value) $valid = false; }
|
119 |
+
else if ('gteq' == $_expr) { if ($_data[$_field] < $_value) $valid = false; }
|
120 |
+
// else if ('eq' == $_expr) { if ($_data[$_field] <> $_value) $valid = false; }
|
121 |
+
// else if ('neq' == $_expr) { if ($_data[$_field] == $_value) $valid = false; }
|
122 |
+
}
|
123 |
+
}
|
124 |
+
if (!$valid) {
|
125 |
+
unset($list[$_key]);
|
126 |
+
}
|
127 |
+
}
|
128 |
+
}
|
129 |
+
|
130 |
+
// apply limits
|
131 |
+
|
132 |
+
$lastIdx = count($list) - 1;
|
133 |
+
if (is_null($limit)) {
|
134 |
+
$finishAt = $lastIdx;
|
135 |
+
} else {
|
136 |
+
$finishAt = $startFrom + $limit - 1;
|
137 |
+
if ($finishAt > $lastIdx) {
|
138 |
+
$finishAt = $lastIdx;
|
139 |
+
}
|
140 |
+
}
|
141 |
+
|
142 |
+
$collection = new Varien_Data_Collection();
|
143 |
+
$k = $startFrom;
|
144 |
+
$list = array_values($list); // avoid assoc array, convert to numeric array keys
|
145 |
+
while ($k <= $finishAt) {
|
146 |
+
$_file = new Varien_Object($list[$k]);
|
147 |
+
$collection->addItem($_file);
|
148 |
+
$k++;
|
149 |
+
}
|
150 |
+
|
151 |
+
return $collection;
|
152 |
+
}
|
153 |
+
|
154 |
+
}
|
app/code/community/Neklo/Monitor/Model/Resource/Minfo/Log.php
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
class Neklo_Monitor_Model_Resource_Minfo_Log extends Mage_Core_Model_Mysql4_Abstract
|
5 |
+
{
|
6 |
+
protected function _construct()
|
7 |
+
{
|
8 |
+
$this->_init('neklo_monitor/log', 'log_id');
|
9 |
+
}
|
10 |
+
|
11 |
+
public function fetchMaxtime($type)
|
12 |
+
{
|
13 |
+
$select = $this->_getReadAdapter()->select()
|
14 |
+
->from($this->getMainTable(), array('max_time' => new Zend_Db_Expr('MAX(`last_time`)')))
|
15 |
+
->where('type = ?', $type);
|
16 |
+
return (int) $this->_getReadAdapter()->fetchOne($select);
|
17 |
+
}
|
18 |
+
|
19 |
+
public function saveLogs($type, $logs)
|
20 |
+
{
|
21 |
+
$conn = $this->_getWriteAdapter();
|
22 |
+
$updated = $inserted = 0;
|
23 |
+
foreach ($logs as $hash => $data) {
|
24 |
+
|
25 |
+
$select = $conn->select()
|
26 |
+
->from($this->getMainTable())
|
27 |
+
->where('hash = ?', $hash)
|
28 |
+
->where('type = ?', $type);
|
29 |
+
$row = $conn->fetchRow($select);
|
30 |
+
|
31 |
+
$data['times'] = array_unique($data['times'], SORT_NUMERIC);
|
32 |
+
sort($data['times'], SORT_NUMERIC);
|
33 |
+
$data['times'] = array_reverse($data['times']);
|
34 |
+
|
35 |
+
$dbData = array(
|
36 |
+
'last_time' => $data['last_time'],
|
37 |
+
'qty' => $data['qty'],
|
38 |
+
'times' => implode(',', $data['times']),
|
39 |
+
);
|
40 |
+
if ($row) {
|
41 |
+
$conn->update($this->getMainTable(), $dbData, array('log_id = ?' => $row['log_id']));
|
42 |
+
$updated++;
|
43 |
+
} else {
|
44 |
+
$dbData['first_time'] = $data['first_time'];
|
45 |
+
$dbData['hash'] = $hash;
|
46 |
+
$dbData['type'] = $type;
|
47 |
+
$dbData['message'] = $data['message'];
|
48 |
+
$conn->insert($this->getMainTable(), $dbData);
|
49 |
+
$inserted++;
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
return array($inserted, $updated);
|
54 |
+
}
|
55 |
+
}
|
app/code/community/Neklo/Monitor/Model/Resource/Minfo/Log/Collection.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
class Neklo_Monitor_Model_Resource_Minfo_Log_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
|
5 |
+
{
|
6 |
+
protected function _construct()
|
7 |
+
{
|
8 |
+
$this->_init('neklo_monitor/minfo_log');
|
9 |
+
}
|
10 |
+
}
|
app/code/community/Neklo/Monitor/Model/Resource/Minfo/Report.php
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
class Neklo_Monitor_Model_Resource_Minfo_Report extends Mage_Core_Model_Mysql4_Abstract
|
5 |
+
{
|
6 |
+
protected function _construct()
|
7 |
+
{
|
8 |
+
$this->_init('neklo_monitor/report', 'report_id');
|
9 |
+
}
|
10 |
+
|
11 |
+
public function fetchMaxMtime()
|
12 |
+
{
|
13 |
+
$select = $this->_getReadAdapter()->select()
|
14 |
+
->from($this->getMainTable(), array('max_mtime' => new Zend_Db_Expr('MAX(`last_time`)')));
|
15 |
+
return (int) $this->_getReadAdapter()->fetchOne($select);
|
16 |
+
}
|
17 |
+
|
18 |
+
public function saveReports($reports)
|
19 |
+
{
|
20 |
+
$conn = $this->_getWriteAdapter();
|
21 |
+
$updated = $inserted = 0;
|
22 |
+
foreach ($reports as $hash => $data) {
|
23 |
+
|
24 |
+
$select = $conn->select()
|
25 |
+
->from($this->getMainTable())
|
26 |
+
->where('hash = ?', $hash);
|
27 |
+
$row = $conn->fetchRow($select);
|
28 |
+
|
29 |
+
$dbData = array(
|
30 |
+
'last_time' => $data['last_time'],
|
31 |
+
'qty' => $data['qty'],
|
32 |
+
'files' => Mage::helper('core')->jsonEncode($data['files']),
|
33 |
+
);
|
34 |
+
if ($row) {
|
35 |
+
$conn->update($this->getMainTable(), $dbData, array('report_id = ?' => $row['report_id']));
|
36 |
+
$updated++;
|
37 |
+
} else {
|
38 |
+
$dbData['hash'] = $hash;
|
39 |
+
$dbData['message'] = $data['message'];
|
40 |
+
$dbData['first_time'] = $data['first_time'];
|
41 |
+
$conn->insert($this->getMainTable(), $dbData);
|
42 |
+
$inserted++;
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
return array($inserted, $updated);
|
47 |
+
}
|
48 |
+
|
49 |
+
}
|
app/code/community/Neklo/Monitor/Model/Resource/Minfo/Report/Collection.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
class Neklo_Monitor_Model_Resource_Minfo_Report_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
|
5 |
+
{
|
6 |
+
protected function _construct()
|
7 |
+
{
|
8 |
+
$this->_init('neklo_monitor/minfo_report');
|
9 |
+
}
|
10 |
+
}
|
app/code/community/Neklo/Monitor/Model/System/Config/Backend/Empty.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Model_System_Config_Backend_Empty extends Mage_Core_Model_Config_Data
|
4 |
+
{
|
5 |
+
public function getValue()
|
6 |
+
{
|
7 |
+
return null;
|
8 |
+
}
|
9 |
+
}
|
app/code/community/Neklo/Monitor/Model/System/Config/Backend/Token.php
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Model_System_Config_Backend_Token extends Mage_Core_Model_Config_Data
|
4 |
+
{
|
5 |
+
public function getValue()
|
6 |
+
{
|
7 |
+
return $this->_getConfig()->getToken();
|
8 |
+
}
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @return Neklo_Monitor_Helper_Config
|
12 |
+
*/
|
13 |
+
protected function _getConfig()
|
14 |
+
{
|
15 |
+
return Mage::helper('neklo_monitor/config');
|
16 |
+
}
|
17 |
+
}
|
app/code/community/Neklo/Monitor/Model/System/Config/Source/Server/Type.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Model_System_Config_Source_Server_Type
|
4 |
+
{
|
5 |
+
const PRODUCTION_CODE = 'production';
|
6 |
+
const PRODUCTION_LABEL = 'Production';
|
7 |
+
const PRODUCTION_URL = 'http://magento1.m1stats.neklodev.com/';
|
8 |
+
|
9 |
+
const SANDBOX_CODE = 'sandbox';
|
10 |
+
const SANDBOX_LABEL = 'Sandbox';
|
11 |
+
const SANDBOX_URL = 'http://magento1.m1stats.neklodev.com/';
|
12 |
+
|
13 |
+
public function toOptionArray()
|
14 |
+
{
|
15 |
+
$helper = Mage::helper('neklo_monitor');
|
16 |
+
return array(
|
17 |
+
array(
|
18 |
+
'value' => self::PRODUCTION_CODE,
|
19 |
+
'label' => $helper->__(self::PRODUCTION_LABEL)
|
20 |
+
),
|
21 |
+
array(
|
22 |
+
'value' => self::SANDBOX_CODE,
|
23 |
+
'label' => $helper->__(self::SANDBOX_LABEL)
|
24 |
+
),
|
25 |
+
);
|
26 |
+
}
|
27 |
+
|
28 |
+
public function getServerUri($type)
|
29 |
+
{
|
30 |
+
if ($type === self::PRODUCTION_CODE) {
|
31 |
+
return self::PRODUCTION_URL;
|
32 |
+
}
|
33 |
+
return self::SANDBOX_URL;
|
34 |
+
}
|
35 |
+
}
|
app/code/community/Neklo/Monitor/controllers/AuthController.php
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_AuthController extends Neklo_Monitor_Controller_Abstract
|
4 |
+
{
|
5 |
+
public function preDispatch()
|
6 |
+
{
|
7 |
+
// allow disconnected requests to any auth-action
|
8 |
+
// either indexAction or norouteAction()
|
9 |
+
// @see parent::preDispatch
|
10 |
+
$this->_allowConnectedOnly = false;
|
11 |
+
|
12 |
+
return parent::preDispatch();
|
13 |
+
}
|
14 |
+
|
15 |
+
public function indexAction()
|
16 |
+
{
|
17 |
+
if (!$this->_getConfigHelper()->isConnected()) {
|
18 |
+
$sid = $this->_getRequestHelper()->getParam('sid', null);
|
19 |
+
$this->_getConfigHelper()->connect($sid);
|
20 |
+
}
|
21 |
+
|
22 |
+
// Return store icon and store name
|
23 |
+
$result = array(
|
24 |
+
'name' => Mage::getStoreConfig('design/head/default_title'),
|
25 |
+
'icon' => Mage::getDesign()->getSkinUrl('favicon.ico'),
|
26 |
+
);
|
27 |
+
|
28 |
+
$this->_jsonResult($result);
|
29 |
+
}
|
30 |
+
}
|
app/code/community/Neklo/Monitor/controllers/CustomerController.php
ADDED
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_CustomerController extends Neklo_Monitor_Controller_Abstract
|
4 |
+
{
|
5 |
+
public function listAction()
|
6 |
+
{
|
7 |
+
/** @var Neklo_Monitor_Helper_Date $hlpDate */
|
8 |
+
$hlpDate = Mage::helper('neklo_monitor/date');
|
9 |
+
/** @var Neklo_Monitor_Helper_Country $hlpCountry */
|
10 |
+
$hlpCountry = Mage::helper('neklo_monitor/country');
|
11 |
+
|
12 |
+
/* @var $collection Mage_Customer_Model_Entity_Customer_Collection */
|
13 |
+
$collection = Mage::getResourceModel('customer/customer_collection');
|
14 |
+
$collection
|
15 |
+
->addNameToSelect()
|
16 |
+
->addAttributeToSelect('email')
|
17 |
+
->addAttributeToSelect('created_at')
|
18 |
+
->addAttributeToSelect('group_id')
|
19 |
+
->joinAttribute('billing_postcode', 'customer_address/postcode', 'default_billing', null, 'left')
|
20 |
+
->joinAttribute('billing_city', 'customer_address/city', 'default_billing', null, 'left')
|
21 |
+
->joinAttribute('billing_telephone', 'customer_address/telephone', 'default_billing', null, 'left')
|
22 |
+
->joinAttribute('billing_region', 'customer_address/region', 'default_billing', null, 'left')
|
23 |
+
->joinAttribute('billing_country_id', 'customer_address/country_id', 'default_billing', null, 'left')
|
24 |
+
->setOrder('created_at')
|
25 |
+
;
|
26 |
+
|
27 |
+
$storeId = $this->_getRequestHelper()->getParam('store', null);
|
28 |
+
if ($storeId) {
|
29 |
+
$collection->addFieldToFilter('store_id', $storeId);
|
30 |
+
}
|
31 |
+
|
32 |
+
$queryTimestamp = (int) $this->_getRequestHelper()->getParam('query_timestamp', 0);
|
33 |
+
$queryDate = $hlpDate->convertToString($queryTimestamp);
|
34 |
+
if ($queryTimestamp > 0) {
|
35 |
+
$collection->addFieldToFilter('created_at', array('lt' => $queryDate));
|
36 |
+
}
|
37 |
+
|
38 |
+
$offset = $this->_getRequestHelper()->getParam('offset', 0);
|
39 |
+
$page = ceil($offset / self::PAGE_SIZE) + 1;
|
40 |
+
$collection->setPage($page, self::PAGE_SIZE);
|
41 |
+
|
42 |
+
$groupList = Mage::getResourceModel('customer/group_collection')
|
43 |
+
->addFieldToFilter('customer_group_id', array('gt' => 0))
|
44 |
+
->load()
|
45 |
+
->toOptionHash()
|
46 |
+
;
|
47 |
+
|
48 |
+
$customerList = array(
|
49 |
+
'result' => array(),
|
50 |
+
);
|
51 |
+
foreach ($collection as $customer) {
|
52 |
+
|
53 |
+
if ((array_key_exists($customer->getData('group_id'), $groupList))) {
|
54 |
+
$customerGroup = $groupList[$customer->getData('group_id')];
|
55 |
+
} else {
|
56 |
+
$customerGroup = 'N/A';
|
57 |
+
}
|
58 |
+
|
59 |
+
$customerData = array(
|
60 |
+
'id' => $customer->getData('entity_id'),
|
61 |
+
'email' => $customer->getData('email'),
|
62 |
+
'name' => $customer->getData('name'),
|
63 |
+
'created_at' => $hlpDate->convertToTimestamp($customer->getData('created_at')),
|
64 |
+
'group' => $customerGroup,
|
65 |
+
'billing_country' => $hlpCountry->getCountryName($customer->getData('billing_country_id')),
|
66 |
+
'billing_region' => $customer->getData('billing_region'),
|
67 |
+
'billing_city' => $customer->getData('billing_city'),
|
68 |
+
'billing_postcode' => $customer->getData('billing_postcode'),
|
69 |
+
'billing_telephone' => $customer->getData('billing_telephone'),
|
70 |
+
);
|
71 |
+
|
72 |
+
$customerList['result'][] = $customerData;
|
73 |
+
}
|
74 |
+
|
75 |
+
// get new entities count
|
76 |
+
|
77 |
+
if ($queryTimestamp > 0) {
|
78 |
+
/* @var $collection Mage_Customer_Model_Entity_Customer_Collection */
|
79 |
+
$collection = Mage::getResourceModel('customer/customer_collection');
|
80 |
+
$collection->addFieldToFilter('created_at', array('gteq' => $queryDate));
|
81 |
+
$customerList['new_entities_count'] = $collection->getSize();
|
82 |
+
// $customerList['sql'] = $collection->getSelectCountSql()->__toString();
|
83 |
+
}
|
84 |
+
|
85 |
+
$this->_jsonResult($customerList);
|
86 |
+
}
|
87 |
+
|
88 |
+
public function onlineAction()
|
89 |
+
{
|
90 |
+
/* @var $logModel Mage_Log_Model_Visitor_Online */
|
91 |
+
$logModel = Mage::getModel('log/visitor_online');
|
92 |
+
$logModel->prepare();
|
93 |
+
|
94 |
+
// get online customers list $customerIdList
|
95 |
+
|
96 |
+
/* @var $logVisitorCustomers Mage_Log_Model_Mysql4_Visitor_Online_Collection */
|
97 |
+
$logVisitorCustomers = $logModel->getCollection();
|
98 |
+
$logVisitorCustomers->addFieldToFilter('customer_id', array('notnull' => true));
|
99 |
+
|
100 |
+
$customerIdList = $logVisitorCustomers->getColumnValues('customer_id');
|
101 |
+
$customerIdList = array_unique($customerIdList);
|
102 |
+
$customerIdList = array_filter($customerIdList);
|
103 |
+
|
104 |
+
// fetch online customers info $customerList
|
105 |
+
|
106 |
+
$groupList = Mage::getResourceModel('customer/group_collection')
|
107 |
+
->addFieldToFilter('customer_group_id', array('gt' => 0))
|
108 |
+
->load()
|
109 |
+
->toOptionHash()
|
110 |
+
;
|
111 |
+
|
112 |
+
/* @var $customerCollection Mage_Customer_Model_Entity_Customer_Collection */
|
113 |
+
$customerCollection = Mage::getResourceModel('customer/customer_collection');
|
114 |
+
$customerCollection
|
115 |
+
->addNameToSelect()
|
116 |
+
->addFieldToFilter('entity_id', array('in' => $customerIdList))
|
117 |
+
->addAttributeToSelect('email')
|
118 |
+
->addAttributeToSelect('created_at')
|
119 |
+
->addAttributeToSelect('group_id')
|
120 |
+
->joinAttribute('billing_postcode', 'customer_address/postcode', 'default_billing', null, 'left')
|
121 |
+
->joinAttribute('billing_city', 'customer_address/city', 'default_billing', null, 'left')
|
122 |
+
->joinAttribute('billing_telephone', 'customer_address/telephone', 'default_billing', null, 'left')
|
123 |
+
->joinAttribute('billing_region', 'customer_address/region', 'default_billing', null, 'left')
|
124 |
+
->joinAttribute('billing_country_id', 'customer_address/country_id', 'default_billing', null, 'left')
|
125 |
+
;
|
126 |
+
|
127 |
+
/** @var Neklo_Monitor_Helper_Date $hlpDate */
|
128 |
+
$hlpDate = Mage::helper('neklo_monitor/date');
|
129 |
+
/** @var Neklo_Monitor_Helper_Country $hlpCountry */
|
130 |
+
$hlpCountry = Mage::helper('neklo_monitor/country');
|
131 |
+
|
132 |
+
$customerList = array();
|
133 |
+
foreach ($customerCollection as $customer) {
|
134 |
+
if ((array_key_exists($customer->getData('group_id'), $groupList))) {
|
135 |
+
$customerGroup = $groupList[$customer->getData('group_id')];
|
136 |
+
} else {
|
137 |
+
$customerGroup = 'N/A';
|
138 |
+
}
|
139 |
+
|
140 |
+
$customerData = array(
|
141 |
+
'id' => $customer->getData('entity_id'),
|
142 |
+
'email' => $customer->getData('email'),
|
143 |
+
'name' => $customer->getData('name'),
|
144 |
+
'created_at' => $hlpDate->convertToTimestamp($customer->getData('created_at')),
|
145 |
+
'group' => $customerGroup,
|
146 |
+
'billing_country' => $hlpCountry->getCountryName($customer->getData('billing_country_id')),
|
147 |
+
'billing_region' => $customer->getData('billing_region'),
|
148 |
+
'billing_city' => $customer->getData('billing_city'),
|
149 |
+
'billing_postcode' => $customer->getData('billing_postcode'),
|
150 |
+
'billing_telephone' => $customer->getData('billing_telephone'),
|
151 |
+
);
|
152 |
+
|
153 |
+
$customerList[$customer->getData('entity_id')] = $customerData;
|
154 |
+
}
|
155 |
+
|
156 |
+
// collect online visitors list $visitorList along with customers data
|
157 |
+
|
158 |
+
/* @var $collection Mage_Log_Model_Mysql4_Visitor_Online_Collection */
|
159 |
+
$collection = $logModel->getCollection();
|
160 |
+
$collection->addFieldToFilter('last_url', array('nlike' => '%neklo_monitor%'));
|
161 |
+
|
162 |
+
// for pages lists - load next page rows despite newly inserted rows
|
163 |
+
$queryTimestamp = (int) $this->_getRequestHelper()->getParam('query_timestamp', 0);
|
164 |
+
$queryDate = $hlpDate->convertToString($queryTimestamp);
|
165 |
+
if ($queryTimestamp > 0) {
|
166 |
+
$collection->addFieldToFilter('last_visit_at', array('lt' => $queryDate));
|
167 |
+
}
|
168 |
+
|
169 |
+
$offset = $this->_getRequestHelper()->getParam('offset', 0);
|
170 |
+
$page = ceil($offset / self::PAGE_SIZE) + 1;
|
171 |
+
$collection->setCurPage($page);
|
172 |
+
$collection->setPageSize(self::PAGE_SIZE);
|
173 |
+
|
174 |
+
$visitorList = array(
|
175 |
+
'result' => array(),
|
176 |
+
);
|
177 |
+
// $visitorList['sql0'] = $logVisitorCustomers->getSelectSql(true);
|
178 |
+
// $visitorList['sql1'] = $collection->getSelectSql(true);
|
179 |
+
// $visitorList['sql2'] = $customerCollection->getSelectSql(true);
|
180 |
+
foreach ($collection as $visitor) {
|
181 |
+
$visitorData = array(
|
182 |
+
'id' => $visitor->getData('visitor_id'),
|
183 |
+
"type" => $visitor->getData('visitor_type'),
|
184 |
+
"remote_addr" => $visitor->getData('remote_addr'),
|
185 |
+
"first_visit_at" => $hlpDate->convertToTimestamp($visitor->getData('first_visit_at')),
|
186 |
+
"last_visit_at" => $hlpDate->convertToTimestamp($visitor->getData('last_visit_at')),
|
187 |
+
"last_url" => $visitor->getData('last_url'),
|
188 |
+
);
|
189 |
+
|
190 |
+
$customerId = $visitor->getData('customer_id');
|
191 |
+
if ($customerId && array_key_exists($customerId, $customerList)) {
|
192 |
+
$visitorData['customer'] = $customerList[$customerId];
|
193 |
+
}
|
194 |
+
|
195 |
+
$visitorList['result'][] = $visitorData;
|
196 |
+
}
|
197 |
+
|
198 |
+
// get new entities count
|
199 |
+
|
200 |
+
if ($queryTimestamp > 0) {
|
201 |
+
/* @var $collection Mage_Log_Model_Mysql4_Visitor_Online_Collection */
|
202 |
+
$collection = $logModel->getCollection();
|
203 |
+
$collection->addFieldToFilter('last_url', array('nlike' => '%neklo_monitor%'));
|
204 |
+
$collection->addFieldToFilter('last_visit_at', array('gteq' => $queryDate));
|
205 |
+
$visitorList['new_entities_count'] = $collection->getSize();
|
206 |
+
// $visitorList['sql_new'] = $collection->getSelectCountSql()->__toString();
|
207 |
+
}
|
208 |
+
|
209 |
+
$this->_jsonResult($visitorList);
|
210 |
+
}
|
211 |
+
|
212 |
+
}
|
app/code/community/Neklo/Monitor/controllers/DashboardController.php
ADDED
@@ -0,0 +1,437 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_DashboardController extends Neklo_Monitor_Controller_Abstract
|
4 |
+
{
|
5 |
+
public function totalAction()
|
6 |
+
{
|
7 |
+
if (Mage::helper('core')->isModuleEnabled('Mage_Reports')) {
|
8 |
+
/* @var $collection Mage_Reports_Model_Mysql4_Order_Collection */
|
9 |
+
$collection = Mage::getResourceModel('reports/order_collection');
|
10 |
+
$collection->calculateSales(false);
|
11 |
+
|
12 |
+
$storeId = $this->_getRequestHelper()->getParam('store', null);
|
13 |
+
if ($storeId) {
|
14 |
+
$collection->addFieldToFilter('store_id', (int)$storeId);
|
15 |
+
}
|
16 |
+
|
17 |
+
$collection->setPageSize(1);
|
18 |
+
$collection->setCurPage(1);
|
19 |
+
|
20 |
+
$collection->load();
|
21 |
+
$salesStats = $collection->getFirstItem();
|
22 |
+
|
23 |
+
$result = array(
|
24 |
+
'lifetime' => Mage::helper('core')->currency($salesStats->getLifetime(), true, false),
|
25 |
+
'average' => Mage::helper('core')->currency($salesStats->getAverage(), true, false),
|
26 |
+
);
|
27 |
+
} else {
|
28 |
+
$result = array();
|
29 |
+
}
|
30 |
+
|
31 |
+
$this->_jsonResult($result);
|
32 |
+
}
|
33 |
+
|
34 |
+
public function bestsellerAction()
|
35 |
+
{
|
36 |
+
/* @var $collection Mage_Sales_Model_Mysql4_Report_Bestsellers_Collection */
|
37 |
+
$collection = Mage::getResourceModel('sales/report_bestsellers_collection')
|
38 |
+
->setModel('catalog/product')
|
39 |
+
;
|
40 |
+
|
41 |
+
$storeId = $this->_getRequestHelper()->getParam('store', null);
|
42 |
+
if ($storeId) {
|
43 |
+
$collection->addStoreFilter((int)$storeId);
|
44 |
+
}
|
45 |
+
|
46 |
+
$collection->setPageSize(5);
|
47 |
+
$collection->setCurPage(1);
|
48 |
+
|
49 |
+
$productIdList = $collection->getColumnValues('product_id');
|
50 |
+
|
51 |
+
/* @var $productCollection Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection */
|
52 |
+
$productCollection = Mage::getResourceModel('catalog/product_collection');
|
53 |
+
$productCollection->addFieldToFilter('entity_id', array('in' => $productIdList));
|
54 |
+
$productCollection->addAttributeToSelect(
|
55 |
+
array(
|
56 |
+
'sku', // exists in collection when Flat Product is enabled
|
57 |
+
'small_image', // exists in collection when Flat Product is enabled
|
58 |
+
)
|
59 |
+
);
|
60 |
+
$skuList = array();
|
61 |
+
$thumbList = array();
|
62 |
+
$hlp = Mage::helper('catalog/image');
|
63 |
+
/** @var Mage_Catalog_Helper_Image $hlp */
|
64 |
+
foreach ($productCollection as $row) {
|
65 |
+
/** @var Mage_Catalog_Model_Product $row */
|
66 |
+
$skuList[$row->getId()] = $row->getSku();
|
67 |
+
|
68 |
+
$hlp->init($row, 'small_image');
|
69 |
+
$thumbList[$row->getId()] = array(
|
70 |
+
'image2xUrl' => $hlp->resize(224, 300)->__toString(),
|
71 |
+
'image3xUrl' => $hlp->resize(336, 450)->__toString(),
|
72 |
+
);
|
73 |
+
}
|
74 |
+
|
75 |
+
$result = array();
|
76 |
+
foreach ($collection as $row) {
|
77 |
+
if (isset($skuList[$row->getData('product_id')])) {
|
78 |
+
$result[] = array(
|
79 |
+
'id' => $row->getData('product_id'),
|
80 |
+
'name' => $row->getData('product_name'),
|
81 |
+
'price' => Mage::helper('core')->currency($row->getData('product_price'), true, false),
|
82 |
+
'sku' => $skuList[$row->getData('product_id')],
|
83 |
+
'qty' => (int)$row->getData('qty_ordered'),
|
84 |
+
'image2xUrl' => $thumbList[$row->getData('product_id')]['image2xUrl'],
|
85 |
+
'image3xUrl' => $thumbList[$row->getData('product_id')]['image3xUrl'],
|
86 |
+
);
|
87 |
+
}
|
88 |
+
}
|
89 |
+
|
90 |
+
$this->_jsonResult($result);
|
91 |
+
}
|
92 |
+
|
93 |
+
public function mostviewedAction()
|
94 |
+
{
|
95 |
+
/* @var $collection Mage_Reports_Model_Mysql4_Product_Collection */
|
96 |
+
$collection = Mage::getResourceModel('reports/product_collection')
|
97 |
+
->addAttributeToSelect(
|
98 |
+
array(
|
99 |
+
'price',
|
100 |
+
'name',
|
101 |
+
'small_image',
|
102 |
+
)
|
103 |
+
)
|
104 |
+
->addViewsCount()
|
105 |
+
;
|
106 |
+
|
107 |
+
$storeId = $this->_getRequestHelper()->getParam('store', null);
|
108 |
+
if ($storeId) {
|
109 |
+
$collection
|
110 |
+
->setStoreId((int)$storeId)
|
111 |
+
->addStoreFilter((int)$storeId)
|
112 |
+
;
|
113 |
+
}
|
114 |
+
$collection->setPageSize(5);
|
115 |
+
$collection->setCurPage(1);
|
116 |
+
$collection->load();
|
117 |
+
|
118 |
+
$hlp = Mage::helper('catalog/image');
|
119 |
+
/** @var Mage_Catalog_Helper_Image $hlp */
|
120 |
+
$result = array();
|
121 |
+
foreach ($collection as $row) {
|
122 |
+
/** @var Mage_Catalog_Model_Product $row */
|
123 |
+
$hlp->init($row, 'small_image');
|
124 |
+
$result[] = array(
|
125 |
+
'id' => $row->getEntityId(),
|
126 |
+
'name' => $row->getName(),
|
127 |
+
'price' => Mage::helper('core')->currency($row->getPrice(), true, false),
|
128 |
+
'sku' => $row->getSku(),
|
129 |
+
'views' => (int)$row->getData('views'),
|
130 |
+
'image2xUrl' => $hlp->resize(224, 300)->__toString(),
|
131 |
+
'image3xUrl' => $hlp->resize(336, 450)->__toString(),
|
132 |
+
);
|
133 |
+
}
|
134 |
+
|
135 |
+
$this->_jsonResult($result);
|
136 |
+
}
|
137 |
+
|
138 |
+
public function newcustomersAction()
|
139 |
+
{
|
140 |
+
/* @var $collection Mage_Reports_Model_Mysql4_Customer_Collection */
|
141 |
+
$collection = Mage::getResourceModel('reports/customer_collection')->addCustomerName();
|
142 |
+
$storeFilter = 0;
|
143 |
+
$storeId = $this->_getRequestHelper()->getParam('store', null);
|
144 |
+
if ($storeId) {
|
145 |
+
$collection->addAttributeToFilter('store_id', $storeId);
|
146 |
+
$storeFilter = 1;
|
147 |
+
}
|
148 |
+
$collection->addOrdersStatistics($storeFilter);
|
149 |
+
$collection->orderByCustomerRegistration();
|
150 |
+
$collection->setPageSize(5);
|
151 |
+
$collection->setCurPage(1);
|
152 |
+
$collection->load();
|
153 |
+
|
154 |
+
$groupList = Mage::getResourceModel('customer/group_collection')
|
155 |
+
->addFieldToFilter('customer_group_id', array('gt' => 0))
|
156 |
+
->load()
|
157 |
+
->toOptionHash()
|
158 |
+
;
|
159 |
+
|
160 |
+
$result = array();
|
161 |
+
foreach ($collection as $row) {
|
162 |
+
|
163 |
+
if ((array_key_exists($row->getData('group_id'), $groupList))) {
|
164 |
+
$customerGroup = $groupList[$row->getData('group_id')];
|
165 |
+
} else {
|
166 |
+
$customerGroup = 'N/A';
|
167 |
+
}
|
168 |
+
|
169 |
+
$customerData = array(
|
170 |
+
'id' => $row->getData('entity_id'),
|
171 |
+
'email' => $row->getData('email'),
|
172 |
+
'name' => $row->getData('name'),
|
173 |
+
'created_at' => Mage::helper('neklo_monitor/date')->convertToTimestamp($row->getData('created_at')),
|
174 |
+
'group' => $customerGroup,
|
175 |
+
'average_order_amount' => Mage::helper('core')->currency($row->getData('orders_avg_amount'), true, false),
|
176 |
+
'total_order_amount' => Mage::helper('core')->currency($row->getData('orders_sum_amount'), true, false),
|
177 |
+
'order_count' => (int)$row->getData('orders_count'),
|
178 |
+
);
|
179 |
+
|
180 |
+
$result[] = $customerData;
|
181 |
+
}
|
182 |
+
|
183 |
+
$this->_jsonResult($result);
|
184 |
+
}
|
185 |
+
|
186 |
+
public function topcustomersAction()
|
187 |
+
{
|
188 |
+
/* @var $collection Mage_Reports_Model_Mysql4_Order_Collection */
|
189 |
+
$collection = Mage::getResourceModel('reports/order_collection');
|
190 |
+
$collection
|
191 |
+
->groupByCustomer()
|
192 |
+
->addOrdersCount()
|
193 |
+
->joinCustomerName()
|
194 |
+
;
|
195 |
+
$storeFilter = 0;
|
196 |
+
$storeId = $this->_getRequestHelper()->getParam('store', null);
|
197 |
+
if ($storeId) {
|
198 |
+
$collection->addAttributeToFilter('store_id', $storeId);
|
199 |
+
$storeFilter = 1;
|
200 |
+
}
|
201 |
+
$collection
|
202 |
+
->addSumAvgTotals($storeFilter)
|
203 |
+
->orderByTotalAmount()
|
204 |
+
;
|
205 |
+
|
206 |
+
$collection->getSelect()->joinLeft(
|
207 |
+
array('customer' => $collection->getTable('customer/entity')),
|
208 |
+
'main_table.customer_id = customer.entity_id',
|
209 |
+
array('customer_created_at' => 'customer.created_at')
|
210 |
+
);
|
211 |
+
|
212 |
+
$groupList = Mage::getResourceModel('customer/group_collection')
|
213 |
+
->addFieldToFilter('customer_group_id', array('gt' => 0))
|
214 |
+
->load()
|
215 |
+
->toOptionHash()
|
216 |
+
;
|
217 |
+
|
218 |
+
$collection->setPageSize(5);
|
219 |
+
$collection->setCurPage(1);
|
220 |
+
|
221 |
+
$result = array();
|
222 |
+
foreach ($collection as $row) {
|
223 |
+
if ((array_key_exists($row->getData('customer_group_id'), $groupList))) {
|
224 |
+
$customerGroup = $groupList[$row->getData('customer_group_id')];
|
225 |
+
} else {
|
226 |
+
$customerGroup = 'N/A';
|
227 |
+
}
|
228 |
+
|
229 |
+
$customerData = array(
|
230 |
+
'id' => $row->getData('customer_id'),
|
231 |
+
'email' => $row->getData('customer_email'),
|
232 |
+
'name' => $row->getData('name'),
|
233 |
+
'created_at' => Mage::helper('neklo_monitor/date')->convertToTimestamp($row->getData('customer_created_at')),
|
234 |
+
'group' => $customerGroup,
|
235 |
+
'average_order_amount' => Mage::helper('core')->currency($row->getData('orders_avg_amount'), true, false),
|
236 |
+
'total_order_amount' => Mage::helper('core')->currency($row->getData('orders_sum_amount'), true, false),
|
237 |
+
'order_count' => (int)$row->getData('orders_count'),
|
238 |
+
);
|
239 |
+
|
240 |
+
$result[] = $customerData;
|
241 |
+
}
|
242 |
+
|
243 |
+
$this->_jsonResult($result);
|
244 |
+
}
|
245 |
+
|
246 |
+
public function lastordersAction()
|
247 |
+
{
|
248 |
+
/* @var $collection Mage_Reports_Model_Mysql4_Order_Collection */
|
249 |
+
$collection = Mage::getResourceModel('reports/order_collection')
|
250 |
+
->addItemCountExpr()
|
251 |
+
->joinCustomerName('customer')
|
252 |
+
->orderByCreatedAt()
|
253 |
+
;
|
254 |
+
|
255 |
+
$storeId = $this->_getRequestHelper()->getParam('store', null);
|
256 |
+
if ($storeId) {
|
257 |
+
$collection->addAttributeToFilter('store_id', $storeId);
|
258 |
+
$collection->addRevenueToSelect();
|
259 |
+
} else {
|
260 |
+
$collection->addRevenueToSelect(true);
|
261 |
+
}
|
262 |
+
|
263 |
+
$collection->setPageSize(5);
|
264 |
+
$collection->setCurPage(1);
|
265 |
+
|
266 |
+
$orderStatusList = Mage::getSingleton('sales/order_config')->getStatuses();
|
267 |
+
|
268 |
+
$groupList = Mage::getResourceModel('customer/group_collection')
|
269 |
+
->addFieldToFilter('customer_group_id', array('gt' => 0))
|
270 |
+
->load()
|
271 |
+
->toOptionHash()
|
272 |
+
;
|
273 |
+
|
274 |
+
$result = array();
|
275 |
+
foreach ($collection as $row) {
|
276 |
+
if ((array_key_exists($row->getData('status'), $orderStatusList))) {
|
277 |
+
$orderStatus = $orderStatusList[$row->getData('status')];
|
278 |
+
} else {
|
279 |
+
$orderStatus = 'N/A';
|
280 |
+
}
|
281 |
+
|
282 |
+
if ((array_key_exists($row->getData('customer_group_id'), $groupList))) {
|
283 |
+
$customerGroup = $groupList[$row->getData('customer_group_id')];
|
284 |
+
} else {
|
285 |
+
$customerGroup = 'N/A';
|
286 |
+
}
|
287 |
+
|
288 |
+
$orderData = array(
|
289 |
+
'id' => $row->getData('entity_id'),
|
290 |
+
'increment_id' => $row->getData('increment_id'),
|
291 |
+
'created_at' => Mage::helper('neklo_monitor/date')->convertToTimestamp($row->getData('created_at')),
|
292 |
+
'status' => $orderStatus,
|
293 |
+
'grand_total' => Mage::helper('core')->currency($row->getData('revenue'), true, false),
|
294 |
+
'items_count' => (int)$row->getData('items_count'),
|
295 |
+
'customer' => array(
|
296 |
+
'id' => $row->getData('customer_id'),
|
297 |
+
'email' => $row->getData('customer_email'),
|
298 |
+
'name' => $row->getData('customer'),
|
299 |
+
'group' => $customerGroup,
|
300 |
+
),
|
301 |
+
);
|
302 |
+
|
303 |
+
$result[] = $orderData;
|
304 |
+
}
|
305 |
+
|
306 |
+
$this->_jsonResult($result);
|
307 |
+
}
|
308 |
+
|
309 |
+
public function lastsearchesAction()
|
310 |
+
{
|
311 |
+
/* @var $collection Mage_CatalogSearch_Model_Mysql4_Query_Collection */
|
312 |
+
$collection = Mage::getResourceModel('catalogsearch/query_collection');
|
313 |
+
$collection->setRecentQueryFilter();
|
314 |
+
|
315 |
+
$storeId = $this->_getRequestHelper()->getParam('store', null);
|
316 |
+
if ($storeId) {
|
317 |
+
$collection->addAttributeToFilter('store_id', $storeId);
|
318 |
+
}
|
319 |
+
|
320 |
+
$collection->setPageSize(5);
|
321 |
+
$collection->setCurPage(1);
|
322 |
+
|
323 |
+
$result = array();
|
324 |
+
foreach ($collection as $row) {
|
325 |
+
$searchData = array(
|
326 |
+
'id' => $row->getData('query_id'),
|
327 |
+
'query' => $row->getData('query_text'),
|
328 |
+
'number_of_uses' => $row->getData('popularity'),
|
329 |
+
'number_of_results' => $row->getData('num_results'),
|
330 |
+
'last_usage' => Mage::helper('neklo_monitor/date')->convertToTimestamp($row->getData('updated_at')),
|
331 |
+
);
|
332 |
+
$result[] = $searchData;
|
333 |
+
}
|
334 |
+
|
335 |
+
$this->_jsonResult($result);
|
336 |
+
}
|
337 |
+
|
338 |
+
public function topsearchesAction()
|
339 |
+
{
|
340 |
+
/* @var $collection Mage_CatalogSearch_Model_Mysql4_Query_Collection */
|
341 |
+
$collection = Mage::getResourceModel('catalogsearch/query_collection');
|
342 |
+
|
343 |
+
$storeId = $this->_getRequestHelper()->getParam('store', '');
|
344 |
+
$collection->setPopularQueryFilter($storeId);
|
345 |
+
|
346 |
+
$collection->setPageSize(5);
|
347 |
+
$collection->setCurPage(1);
|
348 |
+
|
349 |
+
$result = array();
|
350 |
+
foreach ($collection as $row) {
|
351 |
+
$searchData = array(
|
352 |
+
'query' => $row->getData('name'),
|
353 |
+
'number_of_uses' => $row->getData('popularity'),
|
354 |
+
'number_of_results' => $row->getData('num_results'),
|
355 |
+
'last_usage' => Mage::helper('neklo_monitor/date')->convertToTimestamp($row->getData('updated_at')),
|
356 |
+
);
|
357 |
+
$result[] = $searchData;
|
358 |
+
}
|
359 |
+
|
360 |
+
$this->_jsonResult($result);
|
361 |
+
}
|
362 |
+
|
363 |
+
public function chartAction()
|
364 |
+
{
|
365 |
+
$chartHelper = Mage::helper('adminhtml/dashboard_order');
|
366 |
+
|
367 |
+
$storeId = $this->_getRequestHelper()->getParam('store', null);
|
368 |
+
if ($storeId) {
|
369 |
+
$chartHelper->setParam('store', $storeId);
|
370 |
+
}
|
371 |
+
|
372 |
+
$chartType = $this->_getRequestHelper()->getParam('type', 'quantity');
|
373 |
+
if (!$chartType || !in_array($chartType, array('quantity', 'revenue'))) {
|
374 |
+
$chartType = 'quantity';
|
375 |
+
}
|
376 |
+
|
377 |
+
$availablePeriodList = Mage::helper('adminhtml/dashboard_data')->getDatePeriods();
|
378 |
+
$period = $this->_getRequestHelper()->getParam('period', '24h');
|
379 |
+
if (!$period || !in_array($period, array_keys($availablePeriodList))) {
|
380 |
+
$period = '24h';
|
381 |
+
}
|
382 |
+
$chartHelper->setParam('period', $period);
|
383 |
+
switch ($period) {
|
384 |
+
case '24h':
|
385 |
+
$periodMask = 'yyyy-MM-dd HH:00';
|
386 |
+
break;
|
387 |
+
case '7d':
|
388 |
+
case '1m':
|
389 |
+
$periodMask = 'yyyy-MM-dd';
|
390 |
+
break;
|
391 |
+
case '1y':
|
392 |
+
case '2y':
|
393 |
+
$periodMask = 'yyyy-MM';
|
394 |
+
break;
|
395 |
+
}
|
396 |
+
|
397 |
+
$chartData = array();
|
398 |
+
$items = $chartHelper->getCollection()->getItems();
|
399 |
+
foreach ($items as $item) {
|
400 |
+
$zDate = new Zend_Date($item->getData('range'), $periodMask);
|
401 |
+
$chartData[$zDate->getTimestamp()] = (float)$item->getData($chartType);
|
402 |
+
}
|
403 |
+
|
404 |
+
list ($dateStart, $dateEnd) = Mage::getResourceModel('reports/order_collection')->getDateRange($period, '', '', true);
|
405 |
+
while ($dateStart->compare($dateEnd) < 0) {
|
406 |
+
$timestamp = $dateStart->getTimestamp();
|
407 |
+
switch ($period) {
|
408 |
+
case '24h':
|
409 |
+
$dateStart->addHour(1);
|
410 |
+
break;
|
411 |
+
case '7d':
|
412 |
+
case '1m':
|
413 |
+
$dateStart->addDay(1);
|
414 |
+
break;
|
415 |
+
case '1y':
|
416 |
+
case '2y':
|
417 |
+
$dateStart->addMonth(1);
|
418 |
+
break;
|
419 |
+
}
|
420 |
+
if (!array_key_exists($timestamp, $chartData)) {
|
421 |
+
$chartData[$timestamp] = 0;
|
422 |
+
}
|
423 |
+
}
|
424 |
+
ksort($chartData);
|
425 |
+
|
426 |
+
$result = array();
|
427 |
+
foreach ($chartData as $date => $value) {
|
428 |
+
$result[] = array(
|
429 |
+
'date' => $date,
|
430 |
+
'value' => $value,
|
431 |
+
);
|
432 |
+
}
|
433 |
+
|
434 |
+
$this->_jsonResult($result);
|
435 |
+
}
|
436 |
+
|
437 |
+
}
|
app/code/community/Neklo/Monitor/controllers/InfoController.php
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_InfoController extends Neklo_Monitor_Controller_Abstract
|
4 |
+
{
|
5 |
+
public function totalAction()
|
6 |
+
{
|
7 |
+
/** @var Neklo_Monitor_Helper_Date $hlpDate */
|
8 |
+
$hlpDate = Mage::helper('neklo_monitor/date');
|
9 |
+
|
10 |
+
$fromTimestamp = $this->_getRequestHelper()->getParam('from', 0);
|
11 |
+
$fromDate = $hlpDate->convertToString($fromTimestamp);
|
12 |
+
|
13 |
+
$storeId = $this->_getRequestHelper()->getParam('store', null);
|
14 |
+
|
15 |
+
// get new orders list
|
16 |
+
|
17 |
+
/* @var $orderCollection Mage_Sales_Model_Mysql4_Order_Grid_Collection */
|
18 |
+
$orderCollection = Mage::getResourceModel('sales/order_grid_collection');
|
19 |
+
if ($storeId) {
|
20 |
+
$orderCollection->addFieldToFilter('store_id', $storeId);
|
21 |
+
}
|
22 |
+
$orderCollection->addFieldToFilter('created_at', array('gt' => $fromDate));
|
23 |
+
$ordersCount = $orderCollection->getSize();
|
24 |
+
|
25 |
+
// get new customers list
|
26 |
+
|
27 |
+
/* @var $custCollection Mage_Customer_Model_Entity_Customer_Collection */
|
28 |
+
$custCollection = Mage::getResourceModel('customer/customer_collection');
|
29 |
+
$orderCollection->addFieldToFilter('created_at', array('gt' => $fromDate));
|
30 |
+
$customersCount = $custCollection->getSize();
|
31 |
+
|
32 |
+
$result = array(
|
33 |
+
'orders_count' => $ordersCount,
|
34 |
+
'customers_count' => $customersCount,
|
35 |
+
);
|
36 |
+
|
37 |
+
$this->_jsonResult($result);
|
38 |
+
}
|
39 |
+
|
40 |
+
public function storeviewlistAction()
|
41 |
+
{
|
42 |
+
$websiteList = array();
|
43 |
+
/* @var $website Mage_Core_Model_Website */
|
44 |
+
foreach (Mage::app()->getWebsites() as $key => $website) {
|
45 |
+
$groupList = array();
|
46 |
+
foreach ($website->getGroups() as $group) {
|
47 |
+
$storeViewList = array();
|
48 |
+
foreach ($group->getStores() as $store) {
|
49 |
+
$storeViewList[] = array(
|
50 |
+
'store_id' => $store->getId(),
|
51 |
+
'name' => $store->getName(),
|
52 |
+
);
|
53 |
+
}
|
54 |
+
$groupList[] = array(
|
55 |
+
'group_id' => $group->getId(),
|
56 |
+
'name' => $group->getName(),
|
57 |
+
'store' => $storeViewList,
|
58 |
+
);
|
59 |
+
}
|
60 |
+
|
61 |
+
$websiteList[] = array(
|
62 |
+
'website_id' => $website->getId(),
|
63 |
+
'name' => $website->getName(),
|
64 |
+
'group' => $groupList,
|
65 |
+
);
|
66 |
+
}
|
67 |
+
$result = array(
|
68 |
+
'website' => $websiteList,
|
69 |
+
);
|
70 |
+
|
71 |
+
$this->_jsonResult($result);
|
72 |
+
}
|
73 |
+
}
|
app/code/community/Neklo/Monitor/controllers/OrderController.php
ADDED
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_OrderController extends Neklo_Monitor_Controller_Abstract
|
4 |
+
{
|
5 |
+
public function listAction()
|
6 |
+
{
|
7 |
+
/* @var $collection Mage_Sales_Model_Mysql4_Order_Grid_Collection */
|
8 |
+
$collection = Mage::getResourceModel('sales/order_grid_collection');
|
9 |
+
|
10 |
+
/** @var Neklo_Monitor_Helper_Date $hlpDate */
|
11 |
+
$hlpDate = Mage::helper('neklo_monitor/date');
|
12 |
+
|
13 |
+
// for pages lists - load next page rows despite newly inserted rows
|
14 |
+
$queryTimestamp = (int) $this->_getRequestHelper()->getParam('query_timestamp', 0);
|
15 |
+
$queryDate = $hlpDate->convertToString($queryTimestamp);
|
16 |
+
if ($queryTimestamp > 0) {
|
17 |
+
$collection->addFieldToFilter('main_table.created_at', array('lt' => $queryDate));
|
18 |
+
}
|
19 |
+
|
20 |
+
$offset = $this->_getRequestHelper()->getParam('offset', 0);
|
21 |
+
$page = ceil($offset / self::PAGE_SIZE) + 1;
|
22 |
+
$collection->setPage($page, self::PAGE_SIZE);
|
23 |
+
|
24 |
+
$collection->getSelect()
|
25 |
+
->join(
|
26 |
+
array('ce' => $collection->getTable('customer/entity')),
|
27 |
+
'main_table.customer_id = ce.entity_id',
|
28 |
+
array(
|
29 |
+
'email' => 'ce.email',
|
30 |
+
'customer_group_id' => 'ce.group_id',
|
31 |
+
)
|
32 |
+
)
|
33 |
+
;
|
34 |
+
|
35 |
+
if ($customerId = $this->_getRequestHelper()->getParam('customer_id', null)) {
|
36 |
+
$collection->addFieldToFilter('customer_id', $customerId);
|
37 |
+
}
|
38 |
+
|
39 |
+
$orderItemsSelect = $collection->getConnection()->select();
|
40 |
+
$orderItemsSelect
|
41 |
+
->from(
|
42 |
+
$collection->getTable('sales/order_item'),
|
43 |
+
array(
|
44 |
+
'order_id' => 'order_id',
|
45 |
+
'items_count' => 'count(item_id)',
|
46 |
+
)
|
47 |
+
)
|
48 |
+
->group('order_id')
|
49 |
+
;
|
50 |
+
|
51 |
+
$collection->getSelect()
|
52 |
+
->join(
|
53 |
+
array('oi' => $orderItemsSelect),
|
54 |
+
'main_table.entity_id = oi.order_id',
|
55 |
+
array(
|
56 |
+
'items_count' => 'oi.items_count',
|
57 |
+
)
|
58 |
+
)
|
59 |
+
;
|
60 |
+
|
61 |
+
$orderStatusList = Mage::getSingleton('sales/order_config')->getStatuses();
|
62 |
+
|
63 |
+
$groupList = Mage::getResourceModel('customer/group_collection')
|
64 |
+
->addFieldToFilter('customer_group_id', array('gt' => 0))
|
65 |
+
->load()
|
66 |
+
->toOptionHash()
|
67 |
+
;
|
68 |
+
|
69 |
+
$orderList = array(
|
70 |
+
'result' => array(),
|
71 |
+
);
|
72 |
+
foreach ($collection as $order) {
|
73 |
+
/** @var $order Mage_Sales_Model_Order */
|
74 |
+
if ((array_key_exists($order->getStatus(), $orderStatusList))) {
|
75 |
+
$orderStatus = $orderStatusList[$order->getStatus()];
|
76 |
+
} else {
|
77 |
+
$orderStatus = 'N/A';
|
78 |
+
}
|
79 |
+
|
80 |
+
$orderData = array(
|
81 |
+
'id' => $order->getId(),
|
82 |
+
'increment_id' => $order->getIncrementId(),
|
83 |
+
'created_at' => $hlpDate->convertToTimestamp($order->getCreatedAt()),
|
84 |
+
'status' => $orderStatus,
|
85 |
+
'grand_total' => Mage::helper('core')->currency($order->getBaseGrandTotal(), true, false),
|
86 |
+
'items_count' => (int)$order->getItemsCount(),
|
87 |
+
);
|
88 |
+
|
89 |
+
if ((array_key_exists($order->getCustomerGroupId(), $groupList))) {
|
90 |
+
$customerGroup = $groupList[$order->getCustomerGroupId()];
|
91 |
+
} else {
|
92 |
+
$customerGroup = 'N/A';
|
93 |
+
}
|
94 |
+
|
95 |
+
$customerData = array(
|
96 |
+
'id' => $order->getCustomerId(),
|
97 |
+
'email' => $order->getEmail(),
|
98 |
+
'name' => $order->getBillingName(),
|
99 |
+
'group' => $customerGroup,
|
100 |
+
);
|
101 |
+
$orderData['customer'] = $customerData;
|
102 |
+
|
103 |
+
$orderList['result'][] = $orderData;
|
104 |
+
}
|
105 |
+
|
106 |
+
// get new entities count
|
107 |
+
|
108 |
+
if ($queryTimestamp > 0) {
|
109 |
+
/* @var $collection Mage_Sales_Model_Mysql4_Order_Grid_Collection */
|
110 |
+
$collection = Mage::getResourceModel('sales/order_grid_collection');
|
111 |
+
$collection->addFieldToFilter('main_table.created_at', array('gteq' => $queryDate));
|
112 |
+
$orderList['new_entities_count'] = $collection->getSize();
|
113 |
+
// $orderList['sql'] = $collection->getSelectCountSql()->__toString();
|
114 |
+
}
|
115 |
+
|
116 |
+
$this->_jsonResult($orderList);
|
117 |
+
}
|
118 |
+
}
|
app/code/community/Neklo/Monitor/controllers/ProductController.php
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_ProductController extends Neklo_Monitor_Controller_Abstract
|
4 |
+
{
|
5 |
+
public function outofstockAction()
|
6 |
+
{
|
7 |
+
$storeId = $this->_getRequestHelper()->getParam('store', null);
|
8 |
+
|
9 |
+
/** @var Neklo_Monitor_Model_Minfo_Parser $parser */
|
10 |
+
$parser = Mage::getModel('neklo_monitor/minfo_parser');
|
11 |
+
$collection = $parser->getProductsOutofstockCollection($storeId);
|
12 |
+
|
13 |
+
$outOfStockProductList = array();
|
14 |
+
$hlp = Mage::helper('catalog/image');
|
15 |
+
/** @var Mage_Catalog_Helper_Image $hlp */
|
16 |
+
foreach ($collection as $row) {
|
17 |
+
/** @var Mage_Catalog_Model_Product $row */
|
18 |
+
$hlp->init($row, 'small_image');
|
19 |
+
$outOfStockProductList[] = array(
|
20 |
+
'id' => $row->getEntityId(),
|
21 |
+
'name' => $row->getName(),
|
22 |
+
'price' => Mage::helper('core')->currency($row->getPrice(), true, false),
|
23 |
+
'sku' => $row->getSku(),
|
24 |
+
'image2xUrl' => $hlp->resize(224, 300)->__toString(),
|
25 |
+
'image3xUrl' => $hlp->resize(336, 450)->__toString(),
|
26 |
+
);
|
27 |
+
}
|
28 |
+
|
29 |
+
$this->_jsonResult($outOfStockProductList);
|
30 |
+
}
|
31 |
+
|
32 |
+
}
|
app/code/community/Neklo/Monitor/controllers/Report/SalesController.php
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Report_SalesController extends Neklo_Monitor_Controller_Abstract
|
4 |
+
{
|
5 |
+
// @see Mage_Adminhtml_Block_Report_Grid_Abstract::_prepareCollection()
|
6 |
+
protected function _prepareResourceCollection($resourceCollectionName)
|
7 |
+
{
|
8 |
+
/** @var Neklo_Monitor_Helper_Date $hlpDate */
|
9 |
+
$hlpDate = Mage::helper('neklo_monitor/date');
|
10 |
+
|
11 |
+
$storeIds = $this->_getRequestHelper()->getParam('store', null);
|
12 |
+
$periodType = $this->_getRequestHelper()->getParam('group', null);
|
13 |
+
|
14 |
+
$fromTimestamp = $this->_getRequestHelper()->getParam('from', null);
|
15 |
+
$fromDate = $hlpDate->convertToString($fromTimestamp);
|
16 |
+
|
17 |
+
$toTimestamp = $this->_getRequestHelper()->getParam('to', null);
|
18 |
+
$toDate = $hlpDate->convertToString($toTimestamp);
|
19 |
+
|
20 |
+
$orderStatuses = $this->_getRequestHelper()->getParam('status', null);
|
21 |
+
|
22 |
+
/** @var Mage_Sales_Model_Mysql4_Report_Collection_Abstract $resourceCollection */
|
23 |
+
$resourceCollection = Mage::getResourceModel($resourceCollectionName);
|
24 |
+
$resourceCollection
|
25 |
+
->setPeriod($periodType)
|
26 |
+
->setDateRange($fromDate, $toDate)
|
27 |
+
->addStoreFilter(explode(',', $storeIds))
|
28 |
+
->addOrderStatusFilter($orderStatuses)
|
29 |
+
// ->setAggregatedColumns($this->_getAggregatedColumns())
|
30 |
+
;
|
31 |
+
|
32 |
+
/* if 'show_empty_rows'
|
33 |
+
Mage::helper('reports')->prepareIntervalsCollection(
|
34 |
+
$mainCollection,
|
35 |
+
$fromDate,
|
36 |
+
$toDate,
|
37 |
+
$periodType
|
38 |
+
);
|
39 |
+
*/
|
40 |
+
|
41 |
+
/** @var Mage_Sales_Model_Mysql4_Report_Collection_Abstract $totalsCollection */
|
42 |
+
$totalsCollection = Mage::getResourceModel($resourceCollectionName);
|
43 |
+
$totalsCollection
|
44 |
+
->setPeriod($periodType)
|
45 |
+
->setDateRange($fromDate, $toDate)
|
46 |
+
->addStoreFilter(explode(',', $storeIds))
|
47 |
+
->addOrderStatusFilter($orderStatuses)
|
48 |
+
// ->setAggregatedColumns($this->_getAggregatedColumns())
|
49 |
+
->isTotals(true);
|
50 |
+
|
51 |
+
return array($resourceCollection, $totalsCollection);
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* @param Mage_Sales_Model_Mysql4_Report_Collection_Abstract $resourceCollection
|
56 |
+
* @param Mage_Sales_Model_Mysql4_Report_Collection_Abstract $totalsCollection
|
57 |
+
* @param array $aggregatedColumns
|
58 |
+
* @return array
|
59 |
+
*/
|
60 |
+
protected function _fetchReport($resourceCollection, $totalsCollection, $aggregatedColumns = array())
|
61 |
+
{
|
62 |
+
/** @var Mage_Reports_Model_Grouped_Collection $mainCollection */
|
63 |
+
$mainCollection = Mage::getModel('reports/grouped_collection');
|
64 |
+
$mainCollection->setColumnGroupBy('period');
|
65 |
+
$mainCollection->setResourceCollection($resourceCollection);
|
66 |
+
|
67 |
+
$mainCollection->load();
|
68 |
+
|
69 |
+
$list = array(
|
70 |
+
'report' => array(),
|
71 |
+
'totals' => false,
|
72 |
+
);
|
73 |
+
foreach ($mainCollection->getItems() as $_period => $_item) {
|
74 |
+
/** @var Mage_Adminhtml_Model_Report_Item $_item */
|
75 |
+
$list['report'][] = $_item->getData();
|
76 |
+
}
|
77 |
+
|
78 |
+
if ($aggregatedColumns) {
|
79 |
+
$totalsCollection->setAggregatedColumns($aggregatedColumns);
|
80 |
+
$totalsCollection->load();
|
81 |
+
foreach ($totalsCollection as $_item) {
|
82 |
+
$list['totals'] = $_item->getData();
|
83 |
+
break;
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
return $list;
|
88 |
+
}
|
89 |
+
|
90 |
+
public function orderAction()
|
91 |
+
{
|
92 |
+
$resourceCollectionName = 'sales/report_order_updatedat_collection';
|
93 |
+
// $resourceCollectionName = 'sales/report_order_collection';
|
94 |
+
list($resourceCollection, $totalsCollection) = $this->_prepareResourceCollection($resourceCollectionName);
|
95 |
+
$list = $this->_fetchReport($resourceCollection, $totalsCollection, array(
|
96 |
+
'orders_count' => 'SUM(orders_count)',
|
97 |
+
'total_qty_ordered' => 'SUM(total_qty_ordered)',
|
98 |
+
'total_qty_invoiced' => 'SUM(total_qty_invoiced)',
|
99 |
+
'total_income_amount' => 'SUM(total_income_amount)',
|
100 |
+
'total_revenue_amount' => 'SUM(total_revenue_amount)',
|
101 |
+
'total_profit_amount' => 'SUM(total_profit_amount)',
|
102 |
+
'total_invoiced_amount' => 'SUM(total_invoiced_amount)',
|
103 |
+
'total_canceled_amount' => 'SUM(total_canceled_amount)',
|
104 |
+
'total_paid_amount' => 'SUM(total_paid_amount)',
|
105 |
+
'total_refunded_amount' => 'SUM(total_refunded_amount)',
|
106 |
+
'total_tax_amount' => 'SUM(total_tax_amount)',
|
107 |
+
'total_tax_amount_actual' => 'SUM(total_tax_amount_actual)',
|
108 |
+
'total_shipping_amount' => 'SUM(total_shipping_amount)',
|
109 |
+
'total_shipping_amount_actual' => 'SUM(total_shipping_amount_actual)',
|
110 |
+
'total_discount_amount' => 'SUM(total_discount_amount)',
|
111 |
+
'total_discount_amount_actual' => 'SUM(total_discount_amount_actual)',
|
112 |
+
));
|
113 |
+
$this->_jsonResult($list);
|
114 |
+
}
|
115 |
+
|
116 |
+
public function taxAction()
|
117 |
+
{
|
118 |
+
$resourceCollectionName = 'tax/report_updatedat_collection';
|
119 |
+
// $resourceCollectionName = 'tax/report_collection';
|
120 |
+
list($resourceCollection, $totalsCollection) = $this->_prepareResourceCollection($resourceCollectionName);
|
121 |
+
$list = $this->_fetchReport($resourceCollection, $totalsCollection, array(
|
122 |
+
'orders_count' => 'SUM(orders_count)',
|
123 |
+
'tax_base_amount_sum' => 'SUM(tax_base_amount_sum)',
|
124 |
+
));
|
125 |
+
$this->_jsonResult($list);
|
126 |
+
}
|
127 |
+
|
128 |
+
public function invoicedAction()
|
129 |
+
{
|
130 |
+
$resourceCollectionName = 'sales/report_invoiced_collection_invoiced';
|
131 |
+
// $resourceCollectionName = 'sales/report_invoiced_collection_order';
|
132 |
+
list($resourceCollection, $totalsCollection) = $this->_prepareResourceCollection($resourceCollectionName);
|
133 |
+
$list = $this->_fetchReport($resourceCollection, $totalsCollection, array(
|
134 |
+
'orders_count' => 'SUM(orders_count)',
|
135 |
+
'orders_invoiced' => 'SUM(orders_invoiced)',
|
136 |
+
'invoiced' => 'SUM(invoiced)',
|
137 |
+
'invoiced_captured' => 'SUM(invoiced_captured)',
|
138 |
+
'invoiced_not_captured' => 'SUM(invoiced_not_captured)',
|
139 |
+
));
|
140 |
+
$this->_jsonResult($list);
|
141 |
+
}
|
142 |
+
|
143 |
+
public function shippingAction()
|
144 |
+
{
|
145 |
+
$resourceCollectionName = 'sales/report_shipping_collection_shipment';
|
146 |
+
// $resourceCollectionName = 'sales/report_shipping_collection_order';
|
147 |
+
list($resourceCollection, $totalsCollection) = $this->_prepareResourceCollection($resourceCollectionName);
|
148 |
+
$list = $this->_fetchReport($resourceCollection, $totalsCollection, array(
|
149 |
+
'orders_count' => 'SUM(orders_count)',
|
150 |
+
'total_shipping' => 'SUM(total_shipping)',
|
151 |
+
'total_shipping_actual' => 'SUM(total_shipping_actual)',
|
152 |
+
));
|
153 |
+
$this->_jsonResult($list);
|
154 |
+
}
|
155 |
+
|
156 |
+
public function refundedAction()
|
157 |
+
{
|
158 |
+
$resourceCollectionName = 'sales/report_refunded_collection_refunded';
|
159 |
+
// $resourceCollectionName = 'sales/report_refunded_collection_order';
|
160 |
+
list($resourceCollection, $totalsCollection) = $this->_prepareResourceCollection($resourceCollectionName);
|
161 |
+
$list = $this->_fetchReport($resourceCollection, $totalsCollection, array(
|
162 |
+
'orders_count' => 'SUM(orders_count)',
|
163 |
+
'refunded' => 'SUM(refunded)',
|
164 |
+
'online_refunded' => 'SUM(online_refunded)',
|
165 |
+
'offline_refunded' => 'SUM(offline_refunded)',
|
166 |
+
));
|
167 |
+
$this->_jsonResult($list);
|
168 |
+
}
|
169 |
+
|
170 |
+
public function couponsAction()
|
171 |
+
{
|
172 |
+
$resourceCollectionName = 'salesrule/report_updatedat_collection';
|
173 |
+
// $resourceCollectionName = 'salesrule/report_collection';
|
174 |
+
list($resourceCollection, $totalsCollection) = $this->_prepareResourceCollection($resourceCollectionName);
|
175 |
+
$list = $this->_fetchReport($resourceCollection, $totalsCollection, array(
|
176 |
+
'coupon_uses' => 'SUM(coupon_uses)',
|
177 |
+
'subtotal_amount' => 'SUM(subtotal_amount)',
|
178 |
+
'discount_amount' => 'SUM(discount_amount)',
|
179 |
+
'total_amount' => 'SUM(total_amount)',
|
180 |
+
'subtotal_amount_actual' => 'SUM(subtotal_amount_actual)',
|
181 |
+
'discount_amount_actual' => 'SUM(discount_amount_actual)',
|
182 |
+
'total_amount_actual' => 'SUM(total_amount_actual)',
|
183 |
+
));
|
184 |
+
$this->_jsonResult($list);
|
185 |
+
}
|
186 |
+
|
187 |
+
}
|
app/code/community/Neklo/Monitor/controllers/State/CacheController.php
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_State_CacheController extends Neklo_Monitor_Controller_Abstract
|
4 |
+
{
|
5 |
+
public function listAction()
|
6 |
+
{
|
7 |
+
// get cachers list and their statuses
|
8 |
+
|
9 |
+
$cachers = array();
|
10 |
+
$invalidatedTypes = Mage::app()->getCacheInstance()->getInvalidatedTypes();
|
11 |
+
foreach (Mage::app()->getCacheInstance()->getTypes() as $type => $data) {
|
12 |
+
if (isset($invalidatedTypes[$data->getId()])) {
|
13 |
+
$status = 2; // $this->__('Invalidated');
|
14 |
+
} else {
|
15 |
+
if ($data->getStatus()) {
|
16 |
+
$status = 1; // $this->__('Enabled');
|
17 |
+
} else {
|
18 |
+
$status = 0; // $this->__('Disabled');
|
19 |
+
}
|
20 |
+
}
|
21 |
+
|
22 |
+
$cachers[] = array(
|
23 |
+
'id' => $data->getId(),
|
24 |
+
'label' => $data->getCacheType(),
|
25 |
+
'status' => $status,
|
26 |
+
);
|
27 |
+
}
|
28 |
+
|
29 |
+
$result = array(
|
30 |
+
'result' => $cachers,
|
31 |
+
);
|
32 |
+
|
33 |
+
$this->_jsonResult($result);
|
34 |
+
}
|
35 |
+
|
36 |
+
public function refreshAction()
|
37 |
+
{
|
38 |
+
// TODO
|
39 |
+
}
|
40 |
+
|
41 |
+
public function flushallAction()
|
42 |
+
{
|
43 |
+
// TODO
|
44 |
+
}
|
45 |
+
|
46 |
+
}
|
app/code/community/Neklo/Monitor/controllers/State/IndexerController.php
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_State_IndexerController extends Neklo_Monitor_Controller_Abstract
|
4 |
+
{
|
5 |
+
public function listAction()
|
6 |
+
{
|
7 |
+
// get indexers list and their statuses
|
8 |
+
|
9 |
+
$indexers = array();
|
10 |
+
/** @var Mage_Index_Model_Mysql4_Process_Collection $collection */
|
11 |
+
$collection = Mage::getResourceModel('index/process_collection');
|
12 |
+
|
13 |
+
foreach ($collection as $key => $item) {
|
14 |
+
/** @var Mage_Index_Model_Process $item */
|
15 |
+
if (method_exists($item->getIndexer(), 'isVisible')) { // Older Magento versions do not have this method
|
16 |
+
if (!$item->getIndexer()->isVisible()) {
|
17 |
+
$collection->removeItemByKey($key);
|
18 |
+
continue;
|
19 |
+
}
|
20 |
+
}
|
21 |
+
if ($item->isLocked()) {
|
22 |
+
$item->setStatus(Mage_Index_Model_Process::STATUS_RUNNING);
|
23 |
+
}
|
24 |
+
$indexer = array(
|
25 |
+
'id' => $item->getData('indexer_code'),
|
26 |
+
'label' => $item->getIndexer()->getName(),
|
27 |
+
'status' => $item->getStatus(), // (Mage_Index_Model_Process::STATUS_PENDING || STATUS_RUNNING || STATUS_REQUIRE_REINDEX)
|
28 |
+
'update_required' => 0,
|
29 |
+
);
|
30 |
+
if (method_exists($item, 'getUnprocessedEventsCollection')) { // Older Magento versions do not have this method
|
31 |
+
$indexer['update_required'] = ($item->getUnprocessedEventsCollection()->count() > 0 ? 1 : 0); // (0 || 1)
|
32 |
+
}
|
33 |
+
$indexers[] = $indexer;
|
34 |
+
}
|
35 |
+
|
36 |
+
$result = array(
|
37 |
+
'result' => $indexers,
|
38 |
+
);
|
39 |
+
|
40 |
+
$this->_jsonResult($result);
|
41 |
+
}
|
42 |
+
|
43 |
+
public function reindexAction()
|
44 |
+
{
|
45 |
+
// TODO
|
46 |
+
}
|
47 |
+
|
48 |
+
public function reindexallAction()
|
49 |
+
{
|
50 |
+
// TODO
|
51 |
+
}
|
52 |
+
|
53 |
+
}
|
app/code/community/Neklo/Monitor/controllers/Var/LogController.php
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Var_LogController extends Neklo_Monitor_Controller_Abstract
|
4 |
+
{
|
5 |
+
public function listAction()
|
6 |
+
{
|
7 |
+
/* @var $collection Neklo_Monitor_Model_Resource_Minfo_Log_Collection */
|
8 |
+
$collection = Mage::getResourceModel('neklo_monitor/minfo_log_collection');
|
9 |
+
|
10 |
+
// for pages lists - load next page rows despite newly inserted rows
|
11 |
+
$queryTimestamp = (int) $this->_getRequestHelper()->getParam('query_timestamp', 0);
|
12 |
+
if ($queryTimestamp > 0) {
|
13 |
+
$collection->addFieldToFilter('last_time', array('lt' => $queryTimestamp));
|
14 |
+
}
|
15 |
+
|
16 |
+
$offset = $this->_getRequestHelper()->getParam('offset', 0);
|
17 |
+
$page = ceil($offset / self::PAGE_SIZE) + 1;
|
18 |
+
$collection->setPageSize(self::PAGE_SIZE);
|
19 |
+
$collection->setCurPage($page);
|
20 |
+
|
21 |
+
$collection->setOrder('last_time');
|
22 |
+
|
23 |
+
$list = array('result' => array());
|
24 |
+
foreach ($collection as $log) {
|
25 |
+
/** @var Neklo_Monitor_Model_Minfo_Log $log */
|
26 |
+
$list['result'][] = array(
|
27 |
+
'type' => $log->getData('type'),
|
28 |
+
'hash' => $log->getData('hash'),
|
29 |
+
'message' => $log->getData('message'),
|
30 |
+
'qty' => (int)$log->getData('qty'),
|
31 |
+
'last_time' => (int)$log->getData('last_time'),
|
32 |
+
'first_time' => (int)$log->getData('first_time'),
|
33 |
+
);
|
34 |
+
}
|
35 |
+
// $list['sql1'] = $collection->getSelectSql(true);
|
36 |
+
|
37 |
+
// get new entities count
|
38 |
+
|
39 |
+
if ($queryTimestamp > 0) {
|
40 |
+
/* @var $collection Neklo_Monitor_Model_Resource_Minfo_Log_Collection */
|
41 |
+
$collection = Mage::getResourceModel('neklo_monitor/minfo_log_collection');
|
42 |
+
$collection->addFieldToFilter('last_time', array('gteq' => $queryTimestamp));
|
43 |
+
$list['new_entities_count'] = $collection->getSize();
|
44 |
+
// $list['sql2'] = $collection->getSelectCountSql()->__toString();
|
45 |
+
}
|
46 |
+
|
47 |
+
$this->_jsonResult($list);
|
48 |
+
}
|
49 |
+
|
50 |
+
public function viewAction()
|
51 |
+
{
|
52 |
+
$hash = $this->_getRequestHelper()->getParam('hash', '');
|
53 |
+
|
54 |
+
/* @var $log Neklo_Monitor_Model_Minfo_Log */
|
55 |
+
$log = Mage::getModel('neklo_monitor/minfo_log');
|
56 |
+
$log->load($hash, 'hash');
|
57 |
+
|
58 |
+
// for pages lists - load next page rows despite newly inserted rows
|
59 |
+
$filter = array();
|
60 |
+
$queryTimestamp = (int) $this->_getRequestHelper()->getParam('query_timestamp', 0);
|
61 |
+
if ($queryTimestamp > 0) {
|
62 |
+
$filter = array('lt' => $queryTimestamp);
|
63 |
+
}
|
64 |
+
|
65 |
+
$offset = $this->_getRequestHelper()->getParam('offset', 0);
|
66 |
+
|
67 |
+
$collection = $log->getTimesCollection($offset, self::PAGE_SIZE, $filter);
|
68 |
+
|
69 |
+
$list = array('result' => array());
|
70 |
+
Mage::log($collection->getItems());
|
71 |
+
foreach ($collection as $_logTime) {
|
72 |
+
/** @var Varien_Object $_logTime */
|
73 |
+
$list['result'][] = (int)$_logTime->getData();
|
74 |
+
}
|
75 |
+
|
76 |
+
// get new entities count
|
77 |
+
|
78 |
+
if ($queryTimestamp > 0) {
|
79 |
+
$collection = $log->getTimesCollection(0, null, array('gteq' => $queryTimestamp));
|
80 |
+
$list['new_entities_count'] = $collection->getSize();
|
81 |
+
}
|
82 |
+
|
83 |
+
$this->_jsonResult($list);
|
84 |
+
}
|
85 |
+
|
86 |
+
}
|
app/code/community/Neklo/Monitor/controllers/Var/ReportController.php
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Neklo_Monitor_Var_ReportController extends Neklo_Monitor_Controller_Abstract
|
4 |
+
{
|
5 |
+
public function listAction()
|
6 |
+
{
|
7 |
+
/* @var $collection Neklo_Monitor_Model_Resource_Minfo_Report_Collection */
|
8 |
+
$collection = Mage::getResourceModel('neklo_monitor/minfo_report_collection');
|
9 |
+
|
10 |
+
// for pages lists - load next page rows despite newly inserted rows
|
11 |
+
$queryTimestamp = (int) $this->_getRequestHelper()->getParam('query_timestamp', 0);
|
12 |
+
if ($queryTimestamp > 0) {
|
13 |
+
$collection->addFieldToFilter('last_time', array('lt' => $queryTimestamp));
|
14 |
+
}
|
15 |
+
|
16 |
+
$offset = $this->_getRequestHelper()->getParam('offset', 0);
|
17 |
+
$page = ceil($offset / self::PAGE_SIZE) + 1;
|
18 |
+
$collection->setPageSize(self::PAGE_SIZE);
|
19 |
+
$collection->setCurPage($page);
|
20 |
+
|
21 |
+
$collection->setOrder('last_time');
|
22 |
+
|
23 |
+
$list = array('result' => array());
|
24 |
+
foreach ($collection as $report) {
|
25 |
+
/** @var Neklo_Monitor_Model_Minfo_Report $report */
|
26 |
+
$list['result'][] = array(
|
27 |
+
'hash' => $report->getData('hash'),
|
28 |
+
'message' => $report->getData('message'),
|
29 |
+
'qty' => (int) $report->getData('qty'),
|
30 |
+
'last_time' => (int) $report->getData('last_time'),
|
31 |
+
'first_time' => (int) $report->getData('first_time'),
|
32 |
+
);
|
33 |
+
}
|
34 |
+
// $list['sql1'] = $collection->getSelectSql(true);
|
35 |
+
|
36 |
+
// get new entities count
|
37 |
+
|
38 |
+
if ($queryTimestamp > 0) {
|
39 |
+
/* @var $collection Neklo_Monitor_Model_Resource_Minfo_Report_Collection */
|
40 |
+
$collection = Mage::getResourceModel('neklo_monitor/minfo_report_collection');
|
41 |
+
$collection->addFieldToFilter('last_time', array('gteq' => $queryTimestamp));
|
42 |
+
$list['new_entities_count'] = $collection->getSize();
|
43 |
+
// $list['sql2'] = $collection->getSelectCountSql()->__toString();
|
44 |
+
}
|
45 |
+
|
46 |
+
$this->_jsonResult($list);
|
47 |
+
}
|
48 |
+
|
49 |
+
public function viewAction()
|
50 |
+
{
|
51 |
+
$hash = $this->_getRequestHelper()->getParam('hash', '');
|
52 |
+
|
53 |
+
/* @var $report Neklo_Monitor_Model_Minfo_Report */
|
54 |
+
$report = Mage::getModel('neklo_monitor/minfo_report');
|
55 |
+
$report->load($hash, 'hash');
|
56 |
+
|
57 |
+
// for pages lists - load next page rows despite newly inserted rows
|
58 |
+
$filter = array();
|
59 |
+
$queryTimestamp = (int) $this->_getRequestHelper()->getParam('query_timestamp', 0);
|
60 |
+
if ($queryTimestamp > 0) {
|
61 |
+
$filter = array('mtime' => array('lt' => $queryTimestamp));
|
62 |
+
}
|
63 |
+
|
64 |
+
$offset = $this->_getRequestHelper()->getParam('offset', 0);
|
65 |
+
|
66 |
+
$collection = $report->getFilesCollection($offset, self::PAGE_SIZE, $filter);
|
67 |
+
|
68 |
+
$list = array('result' => array());
|
69 |
+
foreach ($collection as $_reportFile) {
|
70 |
+
/** @var Varien_Object $_reportFile */
|
71 |
+
$list['result'][] = array(
|
72 |
+
'path' => '' . $_reportFile->getData('path'),
|
73 |
+
'name' => '' . $_reportFile->getData('name'),
|
74 |
+
'time' => (int) $_reportFile->getData('time'),
|
75 |
+
'size' => (int) $_reportFile->getData('size'),
|
76 |
+
);
|
77 |
+
}
|
78 |
+
|
79 |
+
// get new entities count
|
80 |
+
|
81 |
+
if ($queryTimestamp > 0) {
|
82 |
+
$collection = $report->getFilesCollection(0, null, array('mtime' => array('gteq' => $queryTimestamp)));
|
83 |
+
$list['new_entities_count'] = $collection->getSize();
|
84 |
+
}
|
85 |
+
|
86 |
+
$this->_jsonResult($list);
|
87 |
+
}
|
88 |
+
|
89 |
+
}
|
app/code/community/Neklo/Monitor/etc/adminhtml.xml
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<acl>
|
4 |
+
<resources>
|
5 |
+
<all>
|
6 |
+
<title>Allow Everything</title>
|
7 |
+
</all>
|
8 |
+
<admin>
|
9 |
+
<children>
|
10 |
+
<system>
|
11 |
+
<children>
|
12 |
+
<config>
|
13 |
+
<children>
|
14 |
+
<neklo_monitor translate="title" module="neklo_monitor">
|
15 |
+
<title>Neklo LLC - Monitor</title>
|
16 |
+
<sort_order>150</sort_order>
|
17 |
+
</neklo_monitor>
|
18 |
+
</children>
|
19 |
+
</config>
|
20 |
+
</children>
|
21 |
+
</system>
|
22 |
+
</children>
|
23 |
+
</admin>
|
24 |
+
</resources>
|
25 |
+
</acl>
|
26 |
+
</config>
|
app/code/community/Neklo/Monitor/etc/config.xml
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<config>
|
3 |
+
<modules>
|
4 |
+
<Neklo_Monitor>
|
5 |
+
<version>1.1.2</version>
|
6 |
+
</Neklo_Monitor>
|
7 |
+
</modules>
|
8 |
+
<global>
|
9 |
+
<blocks>
|
10 |
+
<neklo_monitor>
|
11 |
+
<class>Neklo_Monitor_Block</class>
|
12 |
+
</neklo_monitor>
|
13 |
+
<neklo_monitor_adminhtml>
|
14 |
+
<class>Neklo_Monitor_Block_Adminhtml</class>
|
15 |
+
</neklo_monitor_adminhtml>
|
16 |
+
</blocks>
|
17 |
+
<helpers>
|
18 |
+
<neklo_monitor>
|
19 |
+
<class>Neklo_Monitor_Helper</class>
|
20 |
+
</neklo_monitor>
|
21 |
+
</helpers>
|
22 |
+
<models>
|
23 |
+
<neklo_monitor>
|
24 |
+
<class>Neklo_Monitor_Model</class>
|
25 |
+
<resourceModel>neklo_monitor_resource</resourceModel>
|
26 |
+
</neklo_monitor>
|
27 |
+
<neklo_monitor_resource>
|
28 |
+
<class>Neklo_Monitor_Model_Resource</class>
|
29 |
+
<entities>
|
30 |
+
<report><table>neklo_monitor_report</table></report>
|
31 |
+
<log><table>neklo_monitor_log</table></log>
|
32 |
+
</entities>
|
33 |
+
</neklo_monitor_resource>
|
34 |
+
</models>
|
35 |
+
<resources>
|
36 |
+
<neklo_monitor_setup>
|
37 |
+
<setup>
|
38 |
+
<module>Neklo_Monitor</module>
|
39 |
+
</setup>
|
40 |
+
</neklo_monitor_setup>
|
41 |
+
</resources>
|
42 |
+
</global>
|
43 |
+
<frontend>
|
44 |
+
<routers>
|
45 |
+
<neklo_monitor>
|
46 |
+
<use>standard</use>
|
47 |
+
<args>
|
48 |
+
<module>Neklo_Monitor</module>
|
49 |
+
<frontName>neklo_monitor</frontName>
|
50 |
+
</args>
|
51 |
+
</neklo_monitor>
|
52 |
+
</routers>
|
53 |
+
</frontend>
|
54 |
+
<crontab>
|
55 |
+
<jobs>
|
56 |
+
<neklo_monitor_send_server_info>
|
57 |
+
<schedule>
|
58 |
+
<cron_expr>* * * * *</cron_expr>
|
59 |
+
</schedule>
|
60 |
+
<run>
|
61 |
+
<model>neklo_monitor/cron_server::run</model>
|
62 |
+
</run>
|
63 |
+
</neklo_monitor_send_server_info>
|
64 |
+
<neklo_monitor_send_store_info>
|
65 |
+
<schedule>
|
66 |
+
<cron_expr>* * * * *</cron_expr>
|
67 |
+
</schedule>
|
68 |
+
<run>
|
69 |
+
<model>neklo_monitor/cron_store::run</model>
|
70 |
+
</run>
|
71 |
+
</neklo_monitor_send_store_info>
|
72 |
+
<neklo_monitor_collect_store>
|
73 |
+
<schedule>
|
74 |
+
<cron_expr>*/5 * * * *</cron_expr>
|
75 |
+
</schedule>
|
76 |
+
<run>
|
77 |
+
<model>neklo_monitor/cron_store::collect</model>
|
78 |
+
</run>
|
79 |
+
</neklo_monitor_collect_store>
|
80 |
+
</jobs>
|
81 |
+
</crontab>
|
82 |
+
<default>
|
83 |
+
<neklo_monitor>
|
84 |
+
<general>
|
85 |
+
<is_enabled>0</is_enabled>
|
86 |
+
</general>
|
87 |
+
<gateway>
|
88 |
+
<token></token>
|
89 |
+
<token_generated_at></token_generated_at>
|
90 |
+
<server_type>production</server_type>
|
91 |
+
<sid></sid>
|
92 |
+
</gateway>
|
93 |
+
</neklo_monitor>
|
94 |
+
</default>
|
95 |
+
</config>
|
app/code/community/Neklo/Monitor/etc/system.xml
ADDED
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<tabs>
|
4 |
+
<neklo translate="label" module="neklo_monitor">
|
5 |
+
<label>[NEKLO]</label>
|
6 |
+
<sort_order>310</sort_order>
|
7 |
+
</neklo>
|
8 |
+
</tabs>
|
9 |
+
<sections>
|
10 |
+
<neklo_monitor translate="label" module="neklo_monitor">
|
11 |
+
<label>Monitor</label>
|
12 |
+
<tab>neklo</tab>
|
13 |
+
<frontend_type>text</frontend_type>
|
14 |
+
<sort_order>9999</sort_order>
|
15 |
+
<show_in_default>1</show_in_default>
|
16 |
+
<show_in_website>0</show_in_website>
|
17 |
+
<show_in_store>0</show_in_store>
|
18 |
+
<groups>
|
19 |
+
<general translate="label">
|
20 |
+
<label>General Settings</label>
|
21 |
+
<frontend_type>text</frontend_type>
|
22 |
+
<sort_order>10</sort_order>
|
23 |
+
<show_in_default>1</show_in_default>
|
24 |
+
<show_in_website>0</show_in_website>
|
25 |
+
<show_in_store>0</show_in_store>
|
26 |
+
<fields>
|
27 |
+
<is_enabled translate="label">
|
28 |
+
<label>Is Enabled</label>
|
29 |
+
<frontend_type>select</frontend_type>
|
30 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
31 |
+
<sort_order>10</sort_order>
|
32 |
+
<show_in_default>1</show_in_default>
|
33 |
+
<show_in_website>0</show_in_website>
|
34 |
+
<show_in_store>0</show_in_store>
|
35 |
+
</is_enabled>
|
36 |
+
</fields>
|
37 |
+
</general>
|
38 |
+
<!--security translate="label">
|
39 |
+
<label>Security Settings</label>
|
40 |
+
<frontend_type>text</frontend_type>
|
41 |
+
<sort_order>20</sort_order>
|
42 |
+
<show_in_default>1</show_in_default>
|
43 |
+
<show_in_website>0</show_in_website>
|
44 |
+
<show_in_store>0</show_in_store>
|
45 |
+
<fields>
|
46 |
+
</fields>
|
47 |
+
</security-->
|
48 |
+
<gateway>
|
49 |
+
<label>Gateway Settings</label>
|
50 |
+
<frontend_type>text</frontend_type>
|
51 |
+
<sort_order>30</sort_order>
|
52 |
+
<show_in_default>1</show_in_default>
|
53 |
+
<show_in_website>0</show_in_website>
|
54 |
+
<show_in_store>0</show_in_store>
|
55 |
+
<fields>
|
56 |
+
<token translate="label">
|
57 |
+
<label>Token</label>
|
58 |
+
<frontend_type>label</frontend_type>
|
59 |
+
<backend_model>neklo_monitor/system_config_backend_token</backend_model>
|
60 |
+
<sort_order>19</sort_order>
|
61 |
+
<show_in_default>1</show_in_default>
|
62 |
+
<show_in_website>0</show_in_website>
|
63 |
+
<show_in_store>0</show_in_store>
|
64 |
+
</token>
|
65 |
+
<!--server_type>
|
66 |
+
<label>Server Type</label>
|
67 |
+
<frontend_type>select</frontend_type>
|
68 |
+
<source_model>neklo_monitor/system_config_source_server_type</source_model>
|
69 |
+
<sort_order>10</sort_order>
|
70 |
+
<show_in_default>1</show_in_default>
|
71 |
+
<show_in_website>0</show_in_website>
|
72 |
+
<show_in_store>0</show_in_store>
|
73 |
+
</server_type-->
|
74 |
+
<status_production translate="label">
|
75 |
+
<label>Status</label>
|
76 |
+
<frontend_type>label</frontend_type>
|
77 |
+
<frontend_model>neklo_monitor_adminhtml/system_config_frontend_status</frontend_model>
|
78 |
+
<backend_model>neklo_monitor/system_config_backend_empty</backend_model>
|
79 |
+
<sort_order>20</sort_order>
|
80 |
+
<show_in_default>1</show_in_default>
|
81 |
+
<show_in_website>0</show_in_website>
|
82 |
+
<show_in_store>0</show_in_store>
|
83 |
+
<depends>
|
84 |
+
<server_type>production</server_type>
|
85 |
+
</depends>
|
86 |
+
</status_production>
|
87 |
+
<!--status_sandbox translate="label">
|
88 |
+
<label>Status</label>
|
89 |
+
<frontend_type>label</frontend_type>
|
90 |
+
<frontend_model>neklo_monitor_adminhtml/system_config_frontend_status</frontend_model>
|
91 |
+
<backend_model>neklo_monitor/system_config_backend_empty</backend_model>
|
92 |
+
<sort_order>20</sort_order>
|
93 |
+
<show_in_default>1</show_in_default>
|
94 |
+
<show_in_website>0</show_in_website>
|
95 |
+
<show_in_store>0</show_in_store>
|
96 |
+
<depends>
|
97 |
+
<server_type>sandbox</server_type>
|
98 |
+
</depends>
|
99 |
+
</status_sandbox>
|
100 |
+
<plan_production translate="label">
|
101 |
+
<label>Plan</label>
|
102 |
+
<frontend_type>label</frontend_type>
|
103 |
+
<frontend_model>neklo_monitor_adminhtml/system_config_frontend_label</frontend_model>
|
104 |
+
<sort_order>30</sort_order>
|
105 |
+
<show_in_default>1</show_in_default>
|
106 |
+
<show_in_website>0</show_in_website>
|
107 |
+
<show_in_store>0</show_in_store>
|
108 |
+
<depends>
|
109 |
+
<server_type>production</server_type>
|
110 |
+
</depends>
|
111 |
+
</plan_production>
|
112 |
+
<plan_sandbox translate="label">
|
113 |
+
<label>Plan</label>
|
114 |
+
<frontend_type>label</frontend_type>
|
115 |
+
<frontend_model>neklo_monitor_adminhtml/system_config_frontend_label</frontend_model>
|
116 |
+
<sort_order>30</sort_order>
|
117 |
+
<show_in_default>1</show_in_default>
|
118 |
+
<show_in_website>0</show_in_website>
|
119 |
+
<show_in_store>0</show_in_store>
|
120 |
+
<depends>
|
121 |
+
<server_type>sandbox</server_type>
|
122 |
+
</depends>
|
123 |
+
</plan_sandbox>
|
124 |
+
<frequency_production translate="label">
|
125 |
+
<label>Frequency</label>
|
126 |
+
<frontend_type>label</frontend_type>
|
127 |
+
<frontend_model>neklo_monitor_adminhtml/system_config_frontend_label</frontend_model>
|
128 |
+
<sort_order>40</sort_order>
|
129 |
+
<show_in_default>1</show_in_default>
|
130 |
+
<show_in_website>0</show_in_website>
|
131 |
+
<show_in_store>0</show_in_store>
|
132 |
+
<depends>
|
133 |
+
<server_type>production</server_type>
|
134 |
+
</depends>
|
135 |
+
</frequency_production>
|
136 |
+
<frequency_sandbox translate="label">
|
137 |
+
<label>Frequency</label>
|
138 |
+
<frontend_type>label</frontend_type>
|
139 |
+
<frontend_model>neklo_monitor_adminhtml/system_config_frontend_label</frontend_model>
|
140 |
+
<sort_order>40</sort_order>
|
141 |
+
<show_in_default>1</show_in_default>
|
142 |
+
<show_in_website>0</show_in_website>
|
143 |
+
<show_in_store>0</show_in_store>
|
144 |
+
<depends>
|
145 |
+
<server_type>sandbox</server_type>
|
146 |
+
</depends>
|
147 |
+
</frequency_sandbox>
|
148 |
+
<last_update_production translate="label">
|
149 |
+
<label>Last Update</label>
|
150 |
+
<frontend_type>label</frontend_type>
|
151 |
+
<frontend_model>neklo_monitor_adminhtml/system_config_frontend_label</frontend_model>
|
152 |
+
<sort_order>50</sort_order>
|
153 |
+
<show_in_default>1</show_in_default>
|
154 |
+
<show_in_website>0</show_in_website>
|
155 |
+
<show_in_store>0</show_in_store>
|
156 |
+
<depends>
|
157 |
+
<server_type>production</server_type>
|
158 |
+
</depends>
|
159 |
+
</last_update_production>
|
160 |
+
<last_update_sandbox translate="label">
|
161 |
+
<label>Last Update</label>
|
162 |
+
<frontend_type>label</frontend_type>
|
163 |
+
<frontend_model>neklo_monitor_adminhtml/system_config_frontend_label</frontend_model>
|
164 |
+
<sort_order>50</sort_order>
|
165 |
+
<show_in_default>1</show_in_default>
|
166 |
+
<show_in_website>0</show_in_website>
|
167 |
+
<show_in_store>0</show_in_store>
|
168 |
+
<depends>
|
169 |
+
<server_type>sandbox</server_type>
|
170 |
+
</depends>
|
171 |
+
</last_update_sandbox-->
|
172 |
+
</fields>
|
173 |
+
</gateway>
|
174 |
+
</groups>
|
175 |
+
</neklo_monitor>
|
176 |
+
</sections>
|
177 |
+
</config>
|
app/code/community/Neklo/Monitor/sql/neklo_monitor_setup/mysql4-install-1.0.0.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/** @var $installer Mage_Core_Model_Resource_Setup */
|
4 |
+
$installer = $this;
|
5 |
+
|
6 |
+
$installer->startSetup();
|
7 |
+
$tbl = $installer->getTable('neklo_monitor/report');
|
8 |
+
$installer->run("
|
9 |
+
|
10 |
+
CREATE TABLE `$tbl` (
|
11 |
+
`report_id` INT(11) NOT NULL AUTO_INCREMENT,
|
12 |
+
`last_mtime` INT(11) UNSIGNED NOT NULL,
|
13 |
+
`qty` INT(11) unsigned NOT NULL,
|
14 |
+
`message` TEXT NOT NULL,
|
15 |
+
`hash` VARCHAR(32) NOT NULL,
|
16 |
+
`files` TEXT NOT NULL,
|
17 |
+
PRIMARY KEY (`report_id`),
|
18 |
+
KEY `hash` (`hash`),
|
19 |
+
KEY `last_mtime` (`last_mtime`)
|
20 |
+
) ENGINE=InnoDB;
|
21 |
+
|
22 |
+
");
|
23 |
+
|
24 |
+
$installer->endSetup();
|
app/code/community/Neklo/Monitor/sql/neklo_monitor_setup/mysql4-upgrade-1.0.0-1.1.0.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/** @var $installer Mage_Core_Model_Resource_Setup */
|
4 |
+
$installer = $this;
|
5 |
+
|
6 |
+
$installer->startSetup();
|
7 |
+
$tbl = $installer->getTable('neklo_monitor/log');
|
8 |
+
$installer->run("
|
9 |
+
|
10 |
+
CREATE TABLE `$tbl` (
|
11 |
+
`log_id` INT(11) NOT NULL AUTO_INCREMENT,
|
12 |
+
`type` VARCHAR(10) NOT NULL,
|
13 |
+
`last_time` INT(11) UNSIGNED NOT NULL,
|
14 |
+
`qty` INT(11) unsigned NOT NULL,
|
15 |
+
`message` TEXT NOT NULL,
|
16 |
+
`hash` VARCHAR(32) NOT NULL,
|
17 |
+
`times` TEXT NOT NULL,
|
18 |
+
PRIMARY KEY (`log_id`),
|
19 |
+
KEY `hash` (`hash`),
|
20 |
+
KEY `last_time` (`last_time`),
|
21 |
+
KEY `type` (`type`)
|
22 |
+
) ENGINE=InnoDB;
|
23 |
+
|
24 |
+
");
|
25 |
+
|
26 |
+
$installer->endSetup();
|
app/code/community/Neklo/Monitor/sql/neklo_monitor_setup/mysql4-upgrade-1.1.0-1.1.1.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/** @var $installer Mage_Core_Model_Resource_Setup */
|
4 |
+
$installer = $this;
|
5 |
+
|
6 |
+
$installer->startSetup();
|
7 |
+
|
8 |
+
$installer->run("
|
9 |
+
|
10 |
+
ALTER TABLE `{$installer->getTable('neklo_monitor/report')}`
|
11 |
+
ADD COLUMN `first_mtime` INT(11) UNSIGNED NOT NULL AFTER `report_id`;
|
12 |
+
|
13 |
+
ALTER TABLE `{$installer->getTable('neklo_monitor/log')}`
|
14 |
+
ADD COLUMN `first_time` INT(11) UNSIGNED NOT NULL AFTER `type`;
|
15 |
+
|
16 |
+
");
|
17 |
+
|
18 |
+
$installer->endSetup();
|
app/code/community/Neklo/Monitor/sql/neklo_monitor_setup/mysql4-upgrade-1.1.1-1.1.2.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/** @var $installer Mage_Core_Model_Resource_Setup */
|
4 |
+
$installer = $this;
|
5 |
+
|
6 |
+
$installer->startSetup();
|
7 |
+
|
8 |
+
$installer->run("
|
9 |
+
|
10 |
+
ALTER TABLE `{$installer->getTable('neklo_monitor/report')}`
|
11 |
+
CHANGE COLUMN `first_mtime` `first_time` INT(11) UNSIGNED NOT NULL,
|
12 |
+
CHANGE COLUMN `last_mtime` `last_time` INT(11) UNSIGNED NOT NULL;
|
13 |
+
|
14 |
+
");
|
15 |
+
|
16 |
+
$installer->endSetup();
|
app/design/adminhtml/default/default/layout/neklo/core.xml
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<layout>
|
3 |
+
<adminhtml_system_config_edit>
|
4 |
+
<reference name="head">
|
5 |
+
<action method="addCss">
|
6 |
+
<name>neklo/core/css/style.css</name>
|
7 |
+
</action>
|
8 |
+
</reference>
|
9 |
+
</adminhtml_system_config_edit>
|
10 |
+
</layout>
|
app/design/adminhtml/default/default/template/neklo/core/system/contact/button.phtml
ADDED
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /* @var $this Neklo_Core_Block_System_Contact_Send_Button */ ?>
|
2 |
+
<?php echo $this->getButtonHtml(); ?>
|
3 |
+
<div class="neklo_core_message contact"></div>
|
4 |
+
<script>
|
5 |
+
var NekloCoreContact = Class.create({
|
6 |
+
initialize: function (config) {
|
7 |
+
this.initConfig(config);
|
8 |
+
this.initElements();
|
9 |
+
this.initObservers();
|
10 |
+
},
|
11 |
+
|
12 |
+
initConfig: function (config) {
|
13 |
+
this.config = config;
|
14 |
+
this.sendUrl = this.config.sendUrl || '';
|
15 |
+
|
16 |
+
this.successMessage = this.config.successMessage || '';
|
17 |
+
this.errorMessage = this.config.errorMessage || '';
|
18 |
+
|
19 |
+
this.successMessageClass = this.config.successMessageClass || '';
|
20 |
+
this.errorMessageClass = this.config.errorMessageClass || '';
|
21 |
+
|
22 |
+
|
23 |
+
this.formContainerId = this.config.formContainerId || '';
|
24 |
+
this.formElementSelectorList = this.config.formElementSelectorList || [];
|
25 |
+
},
|
26 |
+
|
27 |
+
initElements: function () {
|
28 |
+
this.sendButton = $(this.config.sendButtonId) || null;
|
29 |
+
this.loadingMask = $(this.config.loadingMaskId) || null;
|
30 |
+
this.messageContainer = $$(this.config.messageContainerSelector).first() || null;
|
31 |
+
},
|
32 |
+
|
33 |
+
initObservers: function () {
|
34 |
+
if (this.sendButton) {
|
35 |
+
this.sendButton.observe('click', this.send.bind(this));
|
36 |
+
}
|
37 |
+
},
|
38 |
+
|
39 |
+
send: function () {
|
40 |
+
if (!this.sendUrl) {
|
41 |
+
return;
|
42 |
+
}
|
43 |
+
if (!this.validate()) {
|
44 |
+
return;
|
45 |
+
}
|
46 |
+
|
47 |
+
var me = this;
|
48 |
+
var sendData = {};
|
49 |
+
$H(this.formElementSelectorList).map().each(function(elementSelector) {
|
50 |
+
if (Validation.isVisible($(me.formContainerId + '_' + elementSelector.key))) {
|
51 |
+
sendData[elementSelector.key] = $(me.formContainerId + '_' + elementSelector.key).getValue();
|
52 |
+
}
|
53 |
+
});
|
54 |
+
|
55 |
+
new Ajax.Request(
|
56 |
+
this.sendUrl,
|
57 |
+
{
|
58 |
+
method: 'post',
|
59 |
+
parameters: sendData,
|
60 |
+
onCreate: this._onSendCreate.bind(this),
|
61 |
+
onComplete: this._onSendComplete.bind(this),
|
62 |
+
onSuccess: this._onSendSuccess.bind(this),
|
63 |
+
onFailure: this._onSendFailure.bind(this)
|
64 |
+
}
|
65 |
+
);
|
66 |
+
},
|
67 |
+
|
68 |
+
validate: function () {
|
69 |
+
var me = this;
|
70 |
+
var result = true;
|
71 |
+
$H(this.formElementSelectorList).map().each(function(elementSelector) {
|
72 |
+
var element = $(me.formContainerId + '_' + elementSelector.key);
|
73 |
+
elementSelector.value.each(function(className) {
|
74 |
+
element.addClassName(className);
|
75 |
+
});
|
76 |
+
result = Validation.validate($(me.formContainerId + '_' + elementSelector.key)) && result;
|
77 |
+
elementSelector.value.each(function(className) {
|
78 |
+
element.removeClassName(className);
|
79 |
+
});
|
80 |
+
});
|
81 |
+
return result;
|
82 |
+
},
|
83 |
+
|
84 |
+
showLoadingMask: function () {
|
85 |
+
if (this.loadingMask) {
|
86 |
+
this.loadingMask.show();
|
87 |
+
}
|
88 |
+
},
|
89 |
+
|
90 |
+
hideLoadingMask: function () {
|
91 |
+
if (this.loadingMask) {
|
92 |
+
this.loadingMask.hide();
|
93 |
+
}
|
94 |
+
},
|
95 |
+
|
96 |
+
_onSendCreate: function () {
|
97 |
+
this.clearMessageContainer();
|
98 |
+
this.showLoadingMask();
|
99 |
+
},
|
100 |
+
|
101 |
+
_onSendComplete: function () {
|
102 |
+
this.hideLoadingMask();
|
103 |
+
},
|
104 |
+
|
105 |
+
_onSendSuccess: function (response) {
|
106 |
+
try {
|
107 |
+
var result = response.responseText.evalJSON();
|
108 |
+
if (typeof(result.success) != 'undefined') {
|
109 |
+
if (result.success) {
|
110 |
+
this.showSuccess();
|
111 |
+
this.clearForm();
|
112 |
+
} else {
|
113 |
+
this.showError();
|
114 |
+
}
|
115 |
+
}
|
116 |
+
} catch (e) {
|
117 |
+
this.showError();
|
118 |
+
}
|
119 |
+
},
|
120 |
+
|
121 |
+
_onSendFailure: function () {
|
122 |
+
this.showError();
|
123 |
+
},
|
124 |
+
|
125 |
+
showSuccess: function () {
|
126 |
+
this.showMessage(this.successMessage, this.successMessageClass);
|
127 |
+
},
|
128 |
+
|
129 |
+
showError: function () {
|
130 |
+
this.showMessage(this.errorMessage, this.errorMessageClass);
|
131 |
+
},
|
132 |
+
|
133 |
+
showMessage: function (message, className) {
|
134 |
+
this.clearMessageContainer();
|
135 |
+
var messageElement = new Element('p', {'class': className}).update(this.prepareMessage(message));
|
136 |
+
this.messageContainer.appendChild(messageElement);
|
137 |
+
},
|
138 |
+
|
139 |
+
clearMessageContainer: function () {
|
140 |
+
this.messageContainer.update('');
|
141 |
+
},
|
142 |
+
|
143 |
+
prepareMessage: function (message) {
|
144 |
+
if ((typeof message) == 'string') {
|
145 |
+
return message;
|
146 |
+
}
|
147 |
+
if (Array.isArray(message)) {
|
148 |
+
return message.join("<br/>");
|
149 |
+
}
|
150 |
+
return '';
|
151 |
+
},
|
152 |
+
|
153 |
+
clearForm: function() {
|
154 |
+
var me = this;
|
155 |
+
$H(this.formElementSelectorList).map().each(function(elementSelector) {
|
156 |
+
$(me.formContainerId + '_' + elementSelector.key).setValue('');
|
157 |
+
});
|
158 |
+
}
|
159 |
+
});
|
160 |
+
|
161 |
+
var contactForm = new NekloCoreContact({
|
162 |
+
'sendUrl': '<?php echo $this->getUrl('adminhtml/neklo_core_contact/send'); ?>',
|
163 |
+
|
164 |
+
'successMessage': [
|
165 |
+
'<?php echo $this->jsQuoteEscape($this->__("Thank you for your request.")); ?>',
|
166 |
+
'<?php echo $this->jsQuoteEscape($this->__("We'll respond as soon as possible.")); ?>',
|
167 |
+
'<?php echo $this->jsQuoteEscape($this->__("We'll send copy of your request to your email.")); ?>'
|
168 |
+
],
|
169 |
+
'errorMessage': [
|
170 |
+
'<?php echo $this->jsQuoteEscape($this->__('Oops! Something went wrong!')); ?>'
|
171 |
+
],
|
172 |
+
|
173 |
+
'successMessageClass': 'success',
|
174 |
+
'errorMessageClass': 'error',
|
175 |
+
|
176 |
+
'formContainerId' : '<?php echo $this->getContainerId(); ?>',
|
177 |
+
'formElementSelectorList': {
|
178 |
+
'name': ['required-entry'],
|
179 |
+
'email': ['required-entry', 'validate-email'],
|
180 |
+
'subject': ['required-entry'],
|
181 |
+
'reason': ['required-entry'],
|
182 |
+
'other_reason': ['required-entry'],
|
183 |
+
'message': ['required-entry']
|
184 |
+
},
|
185 |
+
|
186 |
+
'sendButtonId': 'neklo_core_contact_send',
|
187 |
+
'loadingMaskId': 'loading-mask',
|
188 |
+
'messageContainerSelector': '.neklo_core_message.contact'
|
189 |
+
});
|
190 |
+
</script>
|
app/design/adminhtml/default/default/template/neklo/core/system/contact/header.phtml
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
<?php /* @var $this Neklo_Core_Block_System_Contact_Header */ ?>
|
2 |
+
<h4><?php echo $this->__('Contact Neklo Support Team or visit <a href="%s" target="_blank">%s</a> for additional information', $this->getStoreUrl(), $this->getStoreLabel()); ?></h4>
|
app/design/adminhtml/default/default/template/neklo/core/system/extension/list.phtml
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /* @var $this Neklo_Core_Block_System_Extension_List */ ?>
|
2 |
+
<h4><?php echo $this->__('Installed Neklo Extensions') ?></h4>
|
3 |
+
<?php $moduleConfigList = $this->getExtensionList(); ?>
|
4 |
+
<ul id="neklo_core_extension_list">
|
5 |
+
<?php foreach ($moduleConfigList as $moduleCode => $moduleConfig): ?>
|
6 |
+
<?php if (!$this->canShowExtension($moduleCode)) continue; ?>
|
7 |
+
<li class="neklo-item">
|
8 |
+
<?php if ($this->getExtensionUrl($moduleCode)): ?>
|
9 |
+
<a class="neklo-link" href="<?php echo $this->getExtensionUrl($moduleCode); ?>" target="_blank">
|
10 |
+
<?php endif; ?>
|
11 |
+
<div class="ovh">
|
12 |
+
<div class="neklo-row neklo-ext-name"><?php echo $this->getExtensionName($moduleCode); ?> <?php echo $this->getExtensionVersion($moduleConfig); ?></div>
|
13 |
+
<div class="neklo-img neklo-row"><img src="<?php echo $this->getImageUrl($moduleCode); ?>"/></div>
|
14 |
+
<?php if ($this->isExtensionVersionOutdated($moduleCode, $moduleConfig)): ?>
|
15 |
+
<?php echo $this->__('New release %s is available', $this->getLastExtensionVersion($moduleCode)); ?> <img src="<?php echo $this->getSkinUrl('neklo/core/images/update.gif'); ?>" alt="">
|
16 |
+
<?php else: ?>
|
17 |
+
<?php echo $this->__('Your version is up to date'); ?> <img src="<?php echo $this->getSkinUrl('neklo/core/images/ok.gif'); ?>" alt="">
|
18 |
+
<?php endif; ?>
|
19 |
+
</div>
|
20 |
+
<?php if ($this->getExtensionUrl($moduleCode)): ?>
|
21 |
+
</a>
|
22 |
+
<?php endif; ?>
|
23 |
+
</li>
|
24 |
+
<?php endforeach; ?>
|
25 |
+
</ul>
|
app/design/adminhtml/default/default/template/neklo/core/system/subscribe/button.phtml
ADDED
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /* @var $this Neklo_Core_Block_System_Newsletter_Subscribe_Button */ ?>
|
2 |
+
<?php echo $this->getButtonHtml(); ?>
|
3 |
+
<div class="neklo_core_message subscribe"></div>
|
4 |
+
<script>
|
5 |
+
var NekloCoreSubscribe = Class.create({
|
6 |
+
initialize: function (config) {
|
7 |
+
this.initConfig(config);
|
8 |
+
this.initElements();
|
9 |
+
this.initObservers();
|
10 |
+
},
|
11 |
+
|
12 |
+
initConfig: function (config) {
|
13 |
+
this.config = config;
|
14 |
+
this.subscribeUrl = this.config.subscribeUrl || '';
|
15 |
+
|
16 |
+
this.successMessage = this.config.successMessage || '';
|
17 |
+
this.errorMessage = this.config.errorMessage || '';
|
18 |
+
|
19 |
+
this.successMessageClass = this.config.successMessageClass || '';
|
20 |
+
this.errorMessageClass = this.config.errorMessageClass || '';
|
21 |
+
|
22 |
+
|
23 |
+
this.formContainerId = this.config.formContainerId || '';
|
24 |
+
this.formElementSelectorList = this.config.formElementSelectorList || [];
|
25 |
+
},
|
26 |
+
|
27 |
+
initElements: function () {
|
28 |
+
this.sendButton = $(this.config.subscribeButtonId) || null;
|
29 |
+
this.loadingMask = $(this.config.loadingMaskId) || null;
|
30 |
+
this.messageContainer = $$(this.config.messageContainerSelector).first() || null;
|
31 |
+
},
|
32 |
+
|
33 |
+
initObservers: function () {
|
34 |
+
if (this.sendButton) {
|
35 |
+
this.sendButton.observe('click', this.subscribe.bind(this));
|
36 |
+
}
|
37 |
+
},
|
38 |
+
|
39 |
+
subscribe: function () {
|
40 |
+
if (!this.subscribeUrl) {
|
41 |
+
return;
|
42 |
+
}
|
43 |
+
if (!this.validate()) {
|
44 |
+
return;
|
45 |
+
}
|
46 |
+
|
47 |
+
var me = this;
|
48 |
+
var subscribeData = {};
|
49 |
+
$H(this.formElementSelectorList).map().each(function(elementSelector) {
|
50 |
+
if (Validation.isVisible($(me.formContainerId + '_' + elementSelector.key))) {
|
51 |
+
subscribeData[elementSelector.key] = $(me.formContainerId + '_' + elementSelector.key).getValue();
|
52 |
+
}
|
53 |
+
});
|
54 |
+
|
55 |
+
new Ajax.Request(
|
56 |
+
this.subscribeUrl,
|
57 |
+
{
|
58 |
+
method: 'post',
|
59 |
+
parameters: subscribeData,
|
60 |
+
onCreate: this._onSubscribeCreate.bind(this),
|
61 |
+
onComplete: this._onSubscribeComplete.bind(this),
|
62 |
+
onSuccess: this._onSubscribeSuccess.bind(this),
|
63 |
+
onFailure: this._onSubscribeFailure.bind(this)
|
64 |
+
}
|
65 |
+
);
|
66 |
+
},
|
67 |
+
|
68 |
+
validate: function () {
|
69 |
+
var me = this;
|
70 |
+
var result = true;
|
71 |
+
$H(this.formElementSelectorList).map().each(function(elementSelector) {
|
72 |
+
var element = $(me.formContainerId + '_' + elementSelector.key);
|
73 |
+
elementSelector.value.each(function(className) {
|
74 |
+
element.addClassName(className);
|
75 |
+
});
|
76 |
+
result = Validation.validate($(me.formContainerId + '_' + elementSelector.key)) && result;
|
77 |
+
elementSelector.value.each(function(className) {
|
78 |
+
element.removeClassName(className);
|
79 |
+
});
|
80 |
+
});
|
81 |
+
return result;
|
82 |
+
},
|
83 |
+
|
84 |
+
showLoadingMask: function () {
|
85 |
+
if (this.loadingMask) {
|
86 |
+
this.loadingMask.show();
|
87 |
+
}
|
88 |
+
},
|
89 |
+
|
90 |
+
hideLoadingMask: function () {
|
91 |
+
if (this.loadingMask) {
|
92 |
+
this.loadingMask.hide();
|
93 |
+
}
|
94 |
+
},
|
95 |
+
|
96 |
+
_onSubscribeCreate: function () {
|
97 |
+
this.clearMessageContainer();
|
98 |
+
this.showLoadingMask();
|
99 |
+
},
|
100 |
+
|
101 |
+
_onSubscribeComplete: function () {
|
102 |
+
this.hideLoadingMask();
|
103 |
+
},
|
104 |
+
|
105 |
+
_onSubscribeSuccess: function (response) {
|
106 |
+
try {
|
107 |
+
var result = response.responseText.evalJSON();
|
108 |
+
if (typeof(result.success) != 'undefined') {
|
109 |
+
if (result.success) {
|
110 |
+
this.showSuccess();
|
111 |
+
this.clearForm();
|
112 |
+
} else {
|
113 |
+
this.showError();
|
114 |
+
}
|
115 |
+
}
|
116 |
+
} catch (e) {
|
117 |
+
this.showError();
|
118 |
+
}
|
119 |
+
},
|
120 |
+
|
121 |
+
_onSubscribeFailure: function () {
|
122 |
+
this.showError();
|
123 |
+
},
|
124 |
+
|
125 |
+
showSuccess: function () {
|
126 |
+
this.showMessage(this.successMessage, this.successMessageClass);
|
127 |
+
},
|
128 |
+
|
129 |
+
showError: function () {
|
130 |
+
this.showMessage(this.errorMessage, this.errorMessageClass);
|
131 |
+
},
|
132 |
+
|
133 |
+
showMessage: function (message, className) {
|
134 |
+
this.clearMessageContainer();
|
135 |
+
var messageElement = new Element('p', {'class': className}).update(this.prepareMessage(message));
|
136 |
+
this.messageContainer.appendChild(messageElement);
|
137 |
+
},
|
138 |
+
|
139 |
+
clearMessageContainer: function () {
|
140 |
+
this.messageContainer.update('');
|
141 |
+
},
|
142 |
+
|
143 |
+
prepareMessage: function (message) {
|
144 |
+
if ((typeof message) == 'string') {
|
145 |
+
return message;
|
146 |
+
}
|
147 |
+
if (Array.isArray(message)) {
|
148 |
+
return message.join("<br/>");
|
149 |
+
}
|
150 |
+
return '';
|
151 |
+
},
|
152 |
+
|
153 |
+
clearForm: function() {
|
154 |
+
var me = this;
|
155 |
+
$H(this.formElementSelectorList).map().each(function(elementSelector) {
|
156 |
+
$(me.formContainerId + '_' + elementSelector.key).setValue('');
|
157 |
+
});
|
158 |
+
}
|
159 |
+
});
|
160 |
+
|
161 |
+
var subscribeForm = new NekloCoreSubscribe({
|
162 |
+
'subscribeUrl': '<?php echo $this->getUrl('adminhtml/neklo_core_newsletter/subscribe'); ?>',
|
163 |
+
|
164 |
+
'successMessage': '<?php echo $this->jsQuoteEscape($this->__('Successfully subscribed')); ?>',
|
165 |
+
'errorMessage': '<?php echo $this->jsQuoteEscape($this->__('Oops! Something went wrong!')); ?>',
|
166 |
+
|
167 |
+
'successMessageClass': 'success',
|
168 |
+
'errorMessageClass': 'error',
|
169 |
+
|
170 |
+
'formContainerId' : '<?php echo $this->getContainerId(); ?>',
|
171 |
+
'formElementSelectorList': {
|
172 |
+
'name': ['required-entry'],
|
173 |
+
'email': ['required-entry', 'validate-email']
|
174 |
+
},
|
175 |
+
|
176 |
+
'subscribeButtonId': 'neklo_core_subscribe',
|
177 |
+
'loadingMaskId': 'loading-mask',
|
178 |
+
'messageContainerSelector': '.neklo_core_message.subscribe'
|
179 |
+
});
|
180 |
+
</script>
|
app/etc/modules/Neklo_Core.xml
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<modules>
|
4 |
+
<Neklo_Core>
|
5 |
+
<active>true</active>
|
6 |
+
<codePool>community</codePool>
|
7 |
+
<extension_name>Neklo Core</extension_name>
|
8 |
+
</Neklo_Core>
|
9 |
+
</modules>
|
10 |
+
</config>
|
app/etc/modules/Neklo_Monitor.xml
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<modules>
|
4 |
+
<Neklo_Monitor>
|
5 |
+
<active>true</active>
|
6 |
+
<codePool>community</codePool>
|
7 |
+
</Neklo_Monitor>
|
8 |
+
</modules>
|
9 |
+
</config>
|
app/locale/en_US/Neklo_Core.csv
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
%s Support (%s),%s Support (%s)
|
2 |
+
Contact Email,Contact Email
|
3 |
+
Contact Form,Contact Form
|
4 |
+
Contact Name,Contact Name
|
5 |
+
"Contact Neklo Support Team or visit <a href=""%s"" target=""_blank"">%s</a> for additional information","Contact Neklo Support Team or visit <a href=""%s"" target=""_blank"">%s</a> for additional information"
|
6 |
+
Extensions & Contact,Extensions & Contact
|
7 |
+
Extensions Information,Extensions Information
|
8 |
+
Installed Neklo Extensions,Installed Neklo Extensions
|
9 |
+
free,free
|
10 |
+
Magento Related Support (paid),Magento Related Support (paid)
|
11 |
+
Message,Message
|
12 |
+
Neklo Extensions & Contact,Neklo Extensions & Contact
|
13 |
+
Other Reason,Other Reason
|
14 |
+
Reason,Reason
|
15 |
+
Request New Extension Development (paid),Request New Extension Development (paid)
|
16 |
+
paid,paid
|
17 |
+
Please select,Please select
|
18 |
+
Send,Send
|
19 |
+
Subject,Subject
|
lib/Linfo/Common.php
ADDED
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file is part of Linfo (c) 2014 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*/
|
19 |
+
namespace Linfo;
|
20 |
+
|
21 |
+
class Common
|
22 |
+
{
|
23 |
+
protected static $settings = array(),
|
24 |
+
$lang = array();
|
25 |
+
|
26 |
+
// Used for unit tests
|
27 |
+
public static $path_prefix = false;
|
28 |
+
|
29 |
+
public static function config(Linfo $linfo)
|
30 |
+
{
|
31 |
+
self::$settings = $linfo->getSettings();
|
32 |
+
self::$lang = $linfo->getLang();
|
33 |
+
}
|
34 |
+
|
35 |
+
public static function unconfig()
|
36 |
+
{
|
37 |
+
self::$settings = array();
|
38 |
+
self::$lang = array();
|
39 |
+
}
|
40 |
+
|
41 |
+
// Certain files, specifcally the pci/usb ids files, vary in location from
|
42 |
+
// linux distro to linux distro. This function, when passed an array of
|
43 |
+
// possible file location, picks the first it finds and returns it. When
|
44 |
+
// none are found, it returns false
|
45 |
+
public static function locateActualPath($paths)
|
46 |
+
{
|
47 |
+
foreach ((array) $paths as $path) {
|
48 |
+
if (is_file($path)) {
|
49 |
+
return $path;
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
return false;
|
54 |
+
}
|
55 |
+
|
56 |
+
// Append a string to the end of each element in a 2d array
|
57 |
+
public static function arrayAppendString($array, $string = '', $format = '%1s%2s')
|
58 |
+
{
|
59 |
+
|
60 |
+
// Get to it
|
61 |
+
foreach ($array as $k => $v) {
|
62 |
+
$array[$k] = is_string($v) ? sprintf($format, $v, $string) : $v;
|
63 |
+
}
|
64 |
+
|
65 |
+
// Give
|
66 |
+
return $array;
|
67 |
+
}
|
68 |
+
|
69 |
+
// Get a file who's contents should just be an int. Returns zero on failure.
|
70 |
+
public static function getIntFromFile($file)
|
71 |
+
{
|
72 |
+
return self::getContents($file, 0);
|
73 |
+
}
|
74 |
+
|
75 |
+
// Convert bytes to stuff like KB MB GB TB etc
|
76 |
+
public static function byteConvert($size, $precision = 2)
|
77 |
+
{
|
78 |
+
|
79 |
+
// Sanity check
|
80 |
+
if (!is_numeric($size)) {
|
81 |
+
return '?';
|
82 |
+
}
|
83 |
+
|
84 |
+
// Get the notation
|
85 |
+
$notation = self::$settings['byte_notation'] == 1000 ? 1000 : 1024;
|
86 |
+
|
87 |
+
// Fixes large disk size overflow issue
|
88 |
+
// Found at http://www.php.net/manual/en/function.disk-free-space.php#81207
|
89 |
+
$types = array('B', 'KB', 'MB', 'GB', 'TB');
|
90 |
+
$types_i = array('B', 'KiB', 'MiB', 'GiB', 'TiB');
|
91 |
+
for ($i = 0; $size >= $notation && $i < (count($types) - 1); $size /= $notation, $i++);
|
92 |
+
|
93 |
+
return(round($size, $precision).' '.($notation == 1000 ? $types[$i] : $types_i[$i]));
|
94 |
+
}
|
95 |
+
|
96 |
+
// Like above, but for seconds
|
97 |
+
public static function secondsConvert($uptime)
|
98 |
+
{
|
99 |
+
|
100 |
+
// Method here heavily based on freebsd's uptime source
|
101 |
+
$uptime += $uptime > 60 ? 30 : 0;
|
102 |
+
$years = floor($uptime / 31556926);
|
103 |
+
$uptime %= 31556926;
|
104 |
+
$days = floor($uptime / 86400);
|
105 |
+
$uptime %= 86400;
|
106 |
+
$hours = floor($uptime / 3600);
|
107 |
+
$uptime %= 3600;
|
108 |
+
$minutes = floor($uptime / 60);
|
109 |
+
$seconds = floor($uptime % 60);
|
110 |
+
|
111 |
+
// Send out formatted string
|
112 |
+
$return = array();
|
113 |
+
|
114 |
+
if ($years > 0) {
|
115 |
+
$return[] = $years.' '.($years > 1 ? self::$lang['years'] : substr(self::$lang['years'], 0, strlen(self::$lang['years']) - 1));
|
116 |
+
}
|
117 |
+
|
118 |
+
if ($days > 0) {
|
119 |
+
$return[] = $days.' '.self::$lang['days'];
|
120 |
+
}
|
121 |
+
|
122 |
+
if ($hours > 0) {
|
123 |
+
$return[] = $hours.' '.self::$lang['hours'];
|
124 |
+
}
|
125 |
+
|
126 |
+
if ($minutes > 0) {
|
127 |
+
$return[] = $minutes.' '.self::$lang['minutes'];
|
128 |
+
}
|
129 |
+
|
130 |
+
if ($seconds > 0) {
|
131 |
+
$return[] = $seconds.(date('m/d') == '06/03' ? ' sex' : ' '.self::$lang['seconds']);
|
132 |
+
}
|
133 |
+
|
134 |
+
return implode(', ', $return);
|
135 |
+
}
|
136 |
+
|
137 |
+
// Get a file's contents, or default to second param
|
138 |
+
public static function getContents($file, $default = '')
|
139 |
+
{
|
140 |
+
if (is_string(self::$path_prefix)) {
|
141 |
+
$file = self::$path_prefix.$file;
|
142 |
+
}
|
143 |
+
|
144 |
+
return !is_file($file) || !is_readable($file) || !($contents = @file_get_contents($file)) ? $default : trim($contents);
|
145 |
+
}
|
146 |
+
|
147 |
+
// Like above, but in lines instead of a big string
|
148 |
+
public static function getLines($file)
|
149 |
+
{
|
150 |
+
return !is_file($file) || !is_readable($file) || !($lines = @file($file, FILE_SKIP_EMPTY_LINES)) ? array() : $lines;
|
151 |
+
}
|
152 |
+
|
153 |
+
// Make a string safe for being in an xml tag name
|
154 |
+
public static function xmlStringSanitize($string)
|
155 |
+
{
|
156 |
+
return strtolower(preg_replace('/([^a-zA-Z]+)/', '_', $string));
|
157 |
+
}
|
158 |
+
|
159 |
+
// Get a variable from a file. Include it in this function to avoid
|
160 |
+
// clobbering the main namespace
|
161 |
+
public static function getVarFromFile($file, $variable)
|
162 |
+
{
|
163 |
+
|
164 |
+
// Let's not waste our time, now
|
165 |
+
if (!is_file($file)) {
|
166 |
+
return false;
|
167 |
+
}
|
168 |
+
|
169 |
+
require $file;
|
170 |
+
|
171 |
+
// Double dollar sign means treat variable contents
|
172 |
+
// as the name of a variable.
|
173 |
+
if (isset($$variable)) {
|
174 |
+
return $$variable;
|
175 |
+
}
|
176 |
+
|
177 |
+
return false;
|
178 |
+
}
|
179 |
+
|
180 |
+
// Prevent silly conditionals like if (in_array() || in_array() || in_array())
|
181 |
+
// Poor man's python's any() on a list comprehension kinda
|
182 |
+
public static function anyInArray($needles, $haystack)
|
183 |
+
{
|
184 |
+
if (!is_array($needles) || !is_array($haystack)) {
|
185 |
+
return false;
|
186 |
+
}
|
187 |
+
|
188 |
+
return count(array_intersect($needles, $haystack)) > 0;
|
189 |
+
}
|
190 |
+
}
|
lib/Linfo/Exceptions/FatalException.php
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file is part of Linfo (c) 2014 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*/
|
19 |
+
namespace Linfo\Exceptions;
|
20 |
+
|
21 |
+
use Exception;
|
22 |
+
|
23 |
+
class FatalException extends Exception
|
24 |
+
{
|
25 |
+
}
|
lib/Linfo/Extension/Apcaccess.php
ADDED
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
|
5 |
+
This lets you view the command output of the APC program apcaccess.
|
6 |
+
|
7 |
+
Make sure that you have your UPS connected correctly, the apc package installed, and that
|
8 |
+
running apcaccess produces output you find interesting enough for Linfo to display.
|
9 |
+
|
10 |
+
Installation:
|
11 |
+
- The following lines must be added to your config.inc.php:
|
12 |
+
$settings['extensions']['apcaccess'] = true;
|
13 |
+
|
14 |
+
*/
|
15 |
+
|
16 |
+
/*
|
17 |
+
* This file is part of Linfo (c) 2011 Joseph Gillotti.
|
18 |
+
*
|
19 |
+
* Linfo is free software: you can redistribute it and/or modify
|
20 |
+
* it under the terms of the GNU General Public License as published by
|
21 |
+
* the Free Software Foundation, either version 3 of the License, or
|
22 |
+
* (at your option) any later version.
|
23 |
+
*
|
24 |
+
* Linfo is distributed in the hope that it will be useful,
|
25 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
26 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
27 |
+
* GNU General Public License for more details.
|
28 |
+
*
|
29 |
+
* You should have received a copy of the GNU General Public License
|
30 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
31 |
+
*
|
32 |
+
*/
|
33 |
+
|
34 |
+
namespace Linfo\Extension;
|
35 |
+
|
36 |
+
use Linfo\Linfo;
|
37 |
+
use Linfo\Common;
|
38 |
+
use Linfo\Meta\Errors;
|
39 |
+
use Linfo\Parsers\CallExt;
|
40 |
+
use Linfo\Meta\Timer;
|
41 |
+
use Exception;
|
42 |
+
|
43 |
+
/*
|
44 |
+
* Get status on apcaccess volumes.
|
45 |
+
*/
|
46 |
+
class Apcaccess implements Extension
|
47 |
+
{
|
48 |
+
// Store these tucked away here
|
49 |
+
private $_CallExt,
|
50 |
+
$_res;
|
51 |
+
|
52 |
+
// Localize important classes
|
53 |
+
public function __construct(Linfo $linfo)
|
54 |
+
{
|
55 |
+
$this->_CallExt = new CallExt();
|
56 |
+
$this->_CallExt->setSearchPaths(array('/usr/bin', '/usr/local/bin', '/sbin', '/usr/local/sbin'));
|
57 |
+
}
|
58 |
+
|
59 |
+
// call apcaccess and parse it
|
60 |
+
private function _call()
|
61 |
+
{
|
62 |
+
|
63 |
+
// Time this
|
64 |
+
$t = new Timer('apcaccess Extension');
|
65 |
+
|
66 |
+
// Deal with calling it
|
67 |
+
try {
|
68 |
+
$result = $this->_CallExt->exec('apcaccess');
|
69 |
+
} catch (Exception $e) {
|
70 |
+
// messed up somehow
|
71 |
+
Errors::add('apcaccess Extension', $e->getMessage());
|
72 |
+
$this->_res = false;
|
73 |
+
|
74 |
+
// Don't bother going any further
|
75 |
+
return false;
|
76 |
+
}
|
77 |
+
|
78 |
+
// Store them here
|
79 |
+
$this->_res = array();
|
80 |
+
|
81 |
+
// Get name
|
82 |
+
if (preg_match('/^UPSNAME\s+:\s+(.+)$/m', $result, $m)) {
|
83 |
+
$this->_res['name'] = $m[1];
|
84 |
+
}
|
85 |
+
|
86 |
+
// Get model
|
87 |
+
if (preg_match('/^MODEL\s+:\s+(.+)$/m', $result, $m)) {
|
88 |
+
$this->_res['model'] = $m[1];
|
89 |
+
}
|
90 |
+
|
91 |
+
// Get battery voltage
|
92 |
+
if (preg_match('/^BATTV\s+:\s+(\d+\.\d+)/m', $result, $m)) {
|
93 |
+
$this->_res['volts'] = $m[1];
|
94 |
+
}
|
95 |
+
|
96 |
+
// Get charge percentage, and get it cool
|
97 |
+
if (preg_match('/^BCHARGE\s+:\s+(\d+(?:\.\d+)?)/m', $result, $m)) {
|
98 |
+
$charge = (int) $m[1];
|
99 |
+
$this->_res['charge'] = '
|
100 |
+
<div class="bar_chart">
|
101 |
+
<div class="bar_inner" style="width: '.(int) $charge.'%;">
|
102 |
+
<div class="bar_text">
|
103 |
+
'.($charge ? $charge.'%' : '?').'
|
104 |
+
</div>
|
105 |
+
</div>
|
106 |
+
</div>
|
107 |
+
';
|
108 |
+
}
|
109 |
+
|
110 |
+
// Get time remaning
|
111 |
+
if (preg_match('/^TIMELEFT\s+:\s+([\d\.]+)/m', $result, $m)) {
|
112 |
+
$this->_res['time_left'] = Common::secondsConvert($m[1] * 60);
|
113 |
+
}
|
114 |
+
|
115 |
+
// Get status
|
116 |
+
if (preg_match('/^STATUS\s+:\s+([A-Z]+)/m', $result, $m)) {
|
117 |
+
$this->_res['status'] = $m[1] == 'ONBATT' ? 'On Battery' : ucfirst(strtolower($m[1]));
|
118 |
+
}
|
119 |
+
|
120 |
+
// Load percentage looking cool
|
121 |
+
if (preg_match('/^LOADPCT\s+:\s+(\d+\.\d+)/m', $result, $m)) {
|
122 |
+
$load = (int) $m[1];
|
123 |
+
$this->_res['load'] = '
|
124 |
+
<div class="bar_chart">
|
125 |
+
<div class="bar_inner" style="width: '.(int) $load.'%;">
|
126 |
+
<div class="bar_text">
|
127 |
+
'.($load ? $load.'%' : '?').'
|
128 |
+
</div>
|
129 |
+
</div>
|
130 |
+
</div>
|
131 |
+
';
|
132 |
+
}
|
133 |
+
|
134 |
+
// Attempt getting wattage
|
135 |
+
if (isset($load) && preg_match('/^NOMPOWER\s+:\s+(\d+)/m', $result, $m)) {
|
136 |
+
$watts = (int) $m['1'];
|
137 |
+
$this->_res['watts_used'] = $load * round($watts / 100);
|
138 |
+
} else {
|
139 |
+
$this->_res['watts_used'] = false;
|
140 |
+
}
|
141 |
+
|
142 |
+
// Apparent success
|
143 |
+
return true;
|
144 |
+
}
|
145 |
+
|
146 |
+
// Called to get working
|
147 |
+
public function work()
|
148 |
+
{
|
149 |
+
$this->_call();
|
150 |
+
}
|
151 |
+
|
152 |
+
// Get result. Essentially take results and make it usable by the Common::createTable function
|
153 |
+
public function result()
|
154 |
+
{
|
155 |
+
|
156 |
+
// Don't bother if it didn't go well
|
157 |
+
if ($this->_res === false) {
|
158 |
+
return false;
|
159 |
+
}
|
160 |
+
|
161 |
+
// Store rows here
|
162 |
+
$rows = array();
|
163 |
+
|
164 |
+
// Start showing connections
|
165 |
+
$rows[] = array(
|
166 |
+
'type' => 'header',
|
167 |
+
'columns' => array(
|
168 |
+
'UPS Name',
|
169 |
+
'Model',
|
170 |
+
'Battery Volts',
|
171 |
+
'Battery Charge',
|
172 |
+
'Time Left',
|
173 |
+
'Current Load',
|
174 |
+
$this->_res['watts_used'] ? 'Current Usage' : false,
|
175 |
+
'Status',
|
176 |
+
),
|
177 |
+
);
|
178 |
+
|
179 |
+
// And all the values
|
180 |
+
$rows[] = array(
|
181 |
+
'type' => 'values',
|
182 |
+
'columns' => array(
|
183 |
+
$this->_res['name'],
|
184 |
+
$this->_res['model'],
|
185 |
+
$this->_res['volts'],
|
186 |
+
$this->_res['charge'],
|
187 |
+
$this->_res['time_left'],
|
188 |
+
$this->_res['load'],
|
189 |
+
$this->_res['watts_used'] ? $this->_res['watts_used'].'W' : false,
|
190 |
+
$this->_res['status'],
|
191 |
+
),
|
192 |
+
);
|
193 |
+
|
194 |
+
// Give it off
|
195 |
+
return array(
|
196 |
+
'root_title' => 'APC UPS Status',
|
197 |
+
'rows' => $rows,
|
198 |
+
);
|
199 |
+
}
|
200 |
+
}
|
lib/Linfo/Extension/Cups.php
ADDED
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
|
5 |
+
This impliments a CUPS printer queue status parser.
|
6 |
+
|
7 |
+
Installation:
|
8 |
+
- The following lines must be added to your config.inc.php:
|
9 |
+
$settings['extensions']['cups'] = true;
|
10 |
+
|
11 |
+
*/
|
12 |
+
|
13 |
+
/*
|
14 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
15 |
+
*
|
16 |
+
* Linfo is free software: you can redistribute it and/or modify
|
17 |
+
* it under the terms of the GNU General Public License as published by
|
18 |
+
* the Free Software Foundation, either version 3 of the License, or
|
19 |
+
* (at your option) any later version.
|
20 |
+
*
|
21 |
+
* Linfo is distributed in the hope that it will be useful,
|
22 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
23 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
24 |
+
* GNU General Public License for more details.
|
25 |
+
*
|
26 |
+
* You should have received a copy of the GNU General Public License
|
27 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
28 |
+
*
|
29 |
+
*/
|
30 |
+
|
31 |
+
namespace Linfo\Extension;
|
32 |
+
|
33 |
+
use Linfo\Linfo;
|
34 |
+
use Linfo\Common;
|
35 |
+
use Linfo\Meta\Errors;
|
36 |
+
use Linfo\Parsers\CallExt;
|
37 |
+
use Linfo\Meta\Timer;
|
38 |
+
use Exception;
|
39 |
+
|
40 |
+
/*
|
41 |
+
* Get info on a cups install by running lpq
|
42 |
+
*/
|
43 |
+
class Cups implements Extension
|
44 |
+
{
|
45 |
+
// Store these tucked away here
|
46 |
+
private $_CallExt,
|
47 |
+
$_res;
|
48 |
+
|
49 |
+
// Localize important classes
|
50 |
+
public function __construct(Linfo $linfo)
|
51 |
+
{
|
52 |
+
$this->_CallExt = new CallExt();
|
53 |
+
$this->_CallExt->setSearchPaths(array('/usr/bin', '/usr/local/bin', '/sbin', '/usr/local/sbin'));
|
54 |
+
}
|
55 |
+
|
56 |
+
// call lpq and parse it
|
57 |
+
private function _call()
|
58 |
+
{
|
59 |
+
|
60 |
+
// Time this
|
61 |
+
$t = new Timer('CUPS extension');
|
62 |
+
|
63 |
+
// Deal with calling it
|
64 |
+
try {
|
65 |
+
$result = $this->_CallExt->exec('lpstat', '-p -o -l');
|
66 |
+
} catch (Exception $e) {
|
67 |
+
// messed up somehow
|
68 |
+
Errors::add('CUPS Extension', $e->getMessage());
|
69 |
+
$this->_res = false;
|
70 |
+
|
71 |
+
// Don't bother going any further
|
72 |
+
return false;
|
73 |
+
}
|
74 |
+
|
75 |
+
// Split it into lines
|
76 |
+
$lines = explode("\n", $result);
|
77 |
+
|
78 |
+
// Hold temporarily values here
|
79 |
+
$printers = array();
|
80 |
+
$queue = array();
|
81 |
+
$begin_queue_list = false;
|
82 |
+
|
83 |
+
// Go through it line by line
|
84 |
+
for ($i = 0, $num = count($lines); $i < $num; ++$i) {
|
85 |
+
|
86 |
+
// So regexes don't break on endlines
|
87 |
+
$lines[$i] = trim($lines[$i]);
|
88 |
+
|
89 |
+
// If there are no entries, don't waste time and end here
|
90 |
+
if ($lines[$i] == 'no entries') {
|
91 |
+
break;
|
92 |
+
} elseif (preg_match('/^printer (.+) is idle\. (.+)$/', $lines[$i], $printers_match) == 1) {
|
93 |
+
$printers[] = array(
|
94 |
+
'name' => str_replace('_', ' ', $printers_match[1]),
|
95 |
+
'status' => $printers_match[2],
|
96 |
+
);
|
97 |
+
}
|
98 |
+
|
99 |
+
// A printer entry
|
100 |
+
elseif (preg_match('/^(.+)+ is (ready|ready and printing|not ready)$/', $lines[$i], $printers_match) == 1) {
|
101 |
+
$printers[] = array(
|
102 |
+
'name' => str_replace('_', ' ', $printers_match[1]),
|
103 |
+
'status' => $printers_match[2],
|
104 |
+
);
|
105 |
+
}
|
106 |
+
|
107 |
+
// The beginning of the queue list
|
108 |
+
elseif (preg_match('/^Rank\s+Owner\s+Job\s+File\(s\)\s+Total Size$/', $lines[$i])) {
|
109 |
+
$begin_queue_list = true;
|
110 |
+
}
|
111 |
+
|
112 |
+
// A job in the queue
|
113 |
+
elseif ($begin_queue_list && preg_match('/^([a-z0-9]+)\s+(\S+)\s+(\d+)\s+(.+)\s+(\d+) bytes$/', $lines[$i], $queue_match)) {
|
114 |
+
$queue[] = array(
|
115 |
+
'rank' => $queue_match[1],
|
116 |
+
'owner' => $queue_match[2],
|
117 |
+
'job' => $queue_match[3],
|
118 |
+
'files' => $queue_match[4],
|
119 |
+
'size' => Common::byteConvert($queue_match[5]),
|
120 |
+
);
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
// Save result lset
|
125 |
+
$this->_res = array(
|
126 |
+
'printers' => $printers,
|
127 |
+
'queue' => $queue,
|
128 |
+
);
|
129 |
+
|
130 |
+
// Apparent success
|
131 |
+
return true;
|
132 |
+
}
|
133 |
+
|
134 |
+
// Called to get working
|
135 |
+
public function work()
|
136 |
+
{
|
137 |
+
$this->_call();
|
138 |
+
}
|
139 |
+
|
140 |
+
// Get result. Essentially take results and make it usable by the Common::createTable function
|
141 |
+
public function result()
|
142 |
+
{
|
143 |
+
|
144 |
+
// Don't bother if it didn't go well
|
145 |
+
if ($this->_res == false) {
|
146 |
+
return false;
|
147 |
+
}
|
148 |
+
|
149 |
+
// it did; continue
|
150 |
+
else {
|
151 |
+
|
152 |
+
// Store rows here
|
153 |
+
$rows = array();
|
154 |
+
|
155 |
+
// start off printers list
|
156 |
+
$rows[] = array(
|
157 |
+
'type' => 'header',
|
158 |
+
'columns' => array(
|
159 |
+
array(5, 'Printers'),
|
160 |
+
),
|
161 |
+
);
|
162 |
+
$rows[] = array(
|
163 |
+
'type' => 'header',
|
164 |
+
'columns' => array(
|
165 |
+
'Name',
|
166 |
+
array(4, 'Status'),
|
167 |
+
),
|
168 |
+
);
|
169 |
+
|
170 |
+
// show printers if we have them
|
171 |
+
if (count($this->_res['printers']) == 0) {
|
172 |
+
$rows[] = array('type' => 'none', 'columns' => array(array(5, 'None found')));
|
173 |
+
} else {
|
174 |
+
foreach ($this->_res['printers'] as $printer) {
|
175 |
+
$rows[] = array(
|
176 |
+
'type' => 'values',
|
177 |
+
'columns' => array(
|
178 |
+
$printer['name'],
|
179 |
+
array(4, $printer['status']),
|
180 |
+
),
|
181 |
+
);
|
182 |
+
}
|
183 |
+
}
|
184 |
+
|
185 |
+
// show printer queue list
|
186 |
+
$rows[] = array(
|
187 |
+
'type' => 'header',
|
188 |
+
'columns' => array(
|
189 |
+
array(5, 'Queue'),
|
190 |
+
),
|
191 |
+
);
|
192 |
+
|
193 |
+
$rows[] = array(
|
194 |
+
'type' => 'header',
|
195 |
+
'columns' => array(
|
196 |
+
'Rank',
|
197 |
+
'Owner',
|
198 |
+
'Job',
|
199 |
+
'Files',
|
200 |
+
'Size',
|
201 |
+
),
|
202 |
+
);
|
203 |
+
|
204 |
+
// Go through each item in the lsit
|
205 |
+
if (count($this->_res['queue']) == 0) {
|
206 |
+
$rows[] = array('type' => 'none', 'columns' => array(array(5, 'Empty')));
|
207 |
+
} else {
|
208 |
+
foreach ($this->_res['queue'] as $job) {
|
209 |
+
$rows[] = array(
|
210 |
+
'type' => 'values',
|
211 |
+
'columns' => array(
|
212 |
+
$job['rank'],
|
213 |
+
$job['owner'],
|
214 |
+
$job['job'],
|
215 |
+
$job['files'],
|
216 |
+
$job['size'],
|
217 |
+
),
|
218 |
+
);
|
219 |
+
}
|
220 |
+
}
|
221 |
+
|
222 |
+
// give info
|
223 |
+
return array(
|
224 |
+
'root_title' => 'CUPS Printer Status',
|
225 |
+
'rows' => $rows,
|
226 |
+
);
|
227 |
+
}
|
228 |
+
}
|
229 |
+
}
|
lib/Linfo/Extension/Dhcpd3_leases.php
ADDED
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
|
5 |
+
This implements a ddhcpd.leases parser for dhcp3 servers.
|
6 |
+
|
7 |
+
Installation:
|
8 |
+
- The following lines must be added to your config.inc.php:
|
9 |
+
$settings['extensions']['dhcpd3_leases'] = true;
|
10 |
+
$settings['dhcpd3_hide_mac'] = true; // set to false to show mac addresses
|
11 |
+
|
12 |
+
*/
|
13 |
+
|
14 |
+
/**
|
15 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
16 |
+
*
|
17 |
+
* Linfo is free software: you can redistribute it and/or modify
|
18 |
+
* it under the terms of the GNU General Public License as published by
|
19 |
+
* the Free Software Foundation, either version 3 of the License, or
|
20 |
+
* (at your option) any later version.
|
21 |
+
*
|
22 |
+
* Linfo is distributed in the hope that it will be useful,
|
23 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
24 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
25 |
+
* GNU General Public License for more details.
|
26 |
+
*
|
27 |
+
* You should have received a copy of the GNU General Public License
|
28 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
29 |
+
*/
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Keep out hackers...
|
33 |
+
*/
|
34 |
+
namespace Linfo\Extension;
|
35 |
+
|
36 |
+
use Linfo\Linfo;
|
37 |
+
use Linfo\Common;
|
38 |
+
use Linfo\Meta\Errors;
|
39 |
+
use Linfo\Meta\Timer;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Get status on dhcp3 leases.
|
43 |
+
*/
|
44 |
+
class Dhcpd3_leases implements Extension
|
45 |
+
{
|
46 |
+
// How dates should look
|
47 |
+
const
|
48 |
+
DATE_FORMAT = 'm/d/y h:i A';
|
49 |
+
|
50 |
+
// Store these tucked away here
|
51 |
+
private
|
52 |
+
$_hide_mac,
|
53 |
+
$_res,
|
54 |
+
$_leases = array();
|
55 |
+
|
56 |
+
/**
|
57 |
+
* localize important stuff.
|
58 |
+
* @param Linfo $linfo
|
59 |
+
*/
|
60 |
+
public function __construct(Linfo $linfo)
|
61 |
+
{
|
62 |
+
$settings = $linfo->getSettings();
|
63 |
+
|
64 |
+
// Should we hide mac addresses, to prevent stuff like mac address spoofing?
|
65 |
+
$this->_hide_mac = array_key_exists('dhcpd3_hide_mac', $settings) ? (bool) $settings['dhcpd3_hide_mac'] : false;
|
66 |
+
|
67 |
+
// Find leases file
|
68 |
+
$this->_leases_file = Common::locateActualPath(array(
|
69 |
+
'/var/lib/dhcp/dhcpd.leases', // modern-er debian
|
70 |
+
'/var/lib/dhcp3/dhcpd.leases', // debian/ubuntu/others probably
|
71 |
+
'/var/lib/dhcpd/dhcpd.leases', // Possibly redhatish distros and others
|
72 |
+
'/var/state/dhcp/dhcpd.leases', // Arch linux, maybe others
|
73 |
+
'/var/db/dhcpd/dhcpd.leases', // FreeBSD
|
74 |
+
'/var/db/dhcpd.leases', // OpenBSD/NetBSD/Darwin(lol)/DragonFLY afaik
|
75 |
+
));
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Deal with it.
|
80 |
+
*/
|
81 |
+
private function _call()
|
82 |
+
{
|
83 |
+
// Time this
|
84 |
+
$t = new Timer('dhcpd3 leases extension');
|
85 |
+
|
86 |
+
// We couldn't find leases file?
|
87 |
+
if ($this->_leases_file === false) {
|
88 |
+
Errors::add('dhcpd3 leases extension', 'couldn\'t find leases file');
|
89 |
+
$this->_res = false;
|
90 |
+
|
91 |
+
return;
|
92 |
+
}
|
93 |
+
|
94 |
+
// Get contents
|
95 |
+
$contents = Common::getContents($this->_leases_file, false);
|
96 |
+
|
97 |
+
// Couldn't?
|
98 |
+
if ($contents === false) {
|
99 |
+
Errors::add('dhcpd3 leases extension', 'Error getting contents of leases file');
|
100 |
+
$this->_res = false;
|
101 |
+
|
102 |
+
return;
|
103 |
+
}
|
104 |
+
|
105 |
+
// All dates in the file are in UTC format. Attempt finding out local time zone to convert UTC to local.
|
106 |
+
// This prevents confusing the hell out of people.
|
107 |
+
$do_date_conversion = false;
|
108 |
+
$local_timezone = false;
|
109 |
+
|
110 |
+
// Make sure we have what we need. Stuff this requires doesn't exist on certain php installations
|
111 |
+
if (function_exists('date_default_timezone_get') && class_exists('DateTime') && class_exists('DateTimeZone')) {
|
112 |
+
// I only want this called once, hence value stored here. It also might fail
|
113 |
+
$local_timezone = @date_default_timezone_get();
|
114 |
+
|
115 |
+
// Make sure it didn't fail
|
116 |
+
if ($local_timezone !== false && is_string($local_timezone)) {
|
117 |
+
$do_date_conversion = true;
|
118 |
+
} // Say we'll allow conversion later on
|
119 |
+
}
|
120 |
+
|
121 |
+
// Get it into lines
|
122 |
+
$lines = explode("\n", $contents);
|
123 |
+
|
124 |
+
// Store temp entries here
|
125 |
+
$curr = false;
|
126 |
+
|
127 |
+
// Parse each line, while ignoring certain useless'ish values
|
128 |
+
// I'd do a single preg_match_all() using multiline regex, but the values in each lease block are inconsistent. :-/
|
129 |
+
for ($i = 0, $num_lines = count($lines); $i < $num_lines; ++$i) {
|
130 |
+
|
131 |
+
// Kill padding whitespace
|
132 |
+
$lines[$i] = trim($lines[$i]);
|
133 |
+
|
134 |
+
// Last line in entry
|
135 |
+
if ($lines[$i] == '}') {
|
136 |
+
// Have we a current entry to save?
|
137 |
+
if (is_array($curr)) {
|
138 |
+
$this->_leases[] = $curr;
|
139 |
+
}
|
140 |
+
|
141 |
+
// Make it empty for next time
|
142 |
+
$curr = false;
|
143 |
+
}
|
144 |
+
|
145 |
+
// First line in entry. Save IP
|
146 |
+
elseif (preg_match('/^lease (\d+\.\d+\.\d+\.\d+) \{$/', $lines[$i], $m)) {
|
147 |
+
$curr = array('ip' => $m[1]);
|
148 |
+
}
|
149 |
+
|
150 |
+
// Line with lease start
|
151 |
+
elseif ($curr && preg_match('/^starts \d+ (\d+\/\d+\/\d+ \d+:\d+:\d+);$/', $lines[$i], $m)) {
|
152 |
+
|
153 |
+
// Get it in unix time stamp for prettier formatting later and easier tz offset conversion
|
154 |
+
$curr['lease_start'] = strtotime($m[1]);
|
155 |
+
|
156 |
+
// Handle offset conversion
|
157 |
+
if ($do_date_conversion) {
|
158 |
+
|
159 |
+
// This handy class helps out with timezone offsets. Pass it original date, not unix timestamp
|
160 |
+
$d = new DateTime($m[1], new DateTimeZone($local_timezone));
|
161 |
+
$offset = $d->getOffset();
|
162 |
+
|
163 |
+
// If ofset looks good, deal with it
|
164 |
+
if (is_numeric($offset) && $offset != 0) {
|
165 |
+
$curr['lease_start'] += $offset;
|
166 |
+
}
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
// Line with lease end
|
171 |
+
elseif ($curr && preg_match('/^ends \d+ (\d+\/\d+\/\d+ \d+:\d+:\d+);$/', $lines[$i], $m)) {
|
172 |
+
|
173 |
+
// Get it in unix time stamp for prettier formatting later and easier tz offset conversion
|
174 |
+
$curr['lease_end'] = strtotime($m[1]);
|
175 |
+
|
176 |
+
// Handle offset conversion
|
177 |
+
if ($do_date_conversion) {
|
178 |
+
|
179 |
+
// This handy class helps out with timezone offsets. Pass it original date, not unix timestamp
|
180 |
+
$d = new DateTime($m[1], new DateTimeZone($local_timezone));
|
181 |
+
$offset = $d->getOffset();
|
182 |
+
|
183 |
+
// If ofset looks good, deal with it
|
184 |
+
if (is_numeric($offset) && $offset != 0) {
|
185 |
+
$curr['lease_end'] += $offset;
|
186 |
+
}
|
187 |
+
}
|
188 |
+
|
189 |
+
// Is this old?
|
190 |
+
// The file seems to contain all leases since the dhcpd server was started for the first time
|
191 |
+
if (time() > $curr['lease_end']) {
|
192 |
+
|
193 |
+
// Kill current entry and ignore any following parts of this lease
|
194 |
+
$curr = false;
|
195 |
+
|
196 |
+
// Jump out right now
|
197 |
+
continue;
|
198 |
+
}
|
199 |
+
}
|
200 |
+
|
201 |
+
// Line with MAC address
|
202 |
+
elseif (!$this->_hide_mac && $curr && preg_match('/^hardware ethernet (\w+:\w+:\w+:\w+:\w+:\w+);$/', $lines[$i], $m)) {
|
203 |
+
$curr['mac'] = $m[1];
|
204 |
+
}
|
205 |
+
|
206 |
+
// [optional] Line with hostname
|
207 |
+
elseif ($curr && preg_match('/^client\-hostname "([^"]+)";$/', $lines[$i], $m)) {
|
208 |
+
$curr['hostname'] = $m[1];
|
209 |
+
}
|
210 |
+
}
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* Do the job.
|
215 |
+
*/
|
216 |
+
public function work()
|
217 |
+
{
|
218 |
+
$this->_call();
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Return result.
|
223 |
+
*
|
224 |
+
* @return false on failure|array of the leases
|
225 |
+
*/
|
226 |
+
public function result()
|
227 |
+
{
|
228 |
+
// Don't bother if it didn't go well
|
229 |
+
if ($this->_res === false) {
|
230 |
+
return false;
|
231 |
+
}
|
232 |
+
|
233 |
+
// Store rows here
|
234 |
+
$rows = array();
|
235 |
+
|
236 |
+
// Start showing connections
|
237 |
+
$rows[] = array(
|
238 |
+
'type' => 'header',
|
239 |
+
'columns' =>
|
240 |
+
|
241 |
+
// Not hiding mac address?
|
242 |
+
!$this->_hide_mac ? array(
|
243 |
+
'IP Address',
|
244 |
+
'MAC Address',
|
245 |
+
'Hostname',
|
246 |
+
'Lease Start',
|
247 |
+
'Lease End',
|
248 |
+
) :
|
249 |
+
|
250 |
+
// Hiding it indeed
|
251 |
+
array(
|
252 |
+
'IP Address',
|
253 |
+
'Hostname',
|
254 |
+
'Lease Start',
|
255 |
+
'Lease End',
|
256 |
+
),
|
257 |
+
);
|
258 |
+
|
259 |
+
// Append each lease
|
260 |
+
for ($i = 0, $num_leases = count($this->_leases); $i < $num_leases; ++$i) {
|
261 |
+
$rows[] = array(
|
262 |
+
'type' => 'values',
|
263 |
+
'columns' =>
|
264 |
+
|
265 |
+
// Not hiding mac addresses?
|
266 |
+
!$this->_hide_mac ? array(
|
267 |
+
$this->_leases[$i]['ip'],
|
268 |
+
$this->_leases[$i]['mac'],
|
269 |
+
array_key_exists('hostname', $this->_leases[$i]) ?
|
270 |
+
$this->_leases[$i]['hostname'] : '<em>unknown</em>',
|
271 |
+
date(self::DATE_FORMAT, $this->_leases[$i]['lease_start']),
|
272 |
+
date(self::DATE_FORMAT, $this->_leases[$i]['lease_end']),
|
273 |
+
) :
|
274 |
+
|
275 |
+
// Hiding them indeed
|
276 |
+
array(
|
277 |
+
$this->_leases[$i]['ip'],
|
278 |
+
array_key_exists('hostname', $this->_leases[$i]) ?
|
279 |
+
$this->_leases[$i]['hostname'] : '<em>unknown</em>',
|
280 |
+
date(self::DATE_FORMAT, $this->_leases[$i]['lease_start']),
|
281 |
+
date(self::DATE_FORMAT, $this->_leases[$i]['lease_end']),
|
282 |
+
),
|
283 |
+
);
|
284 |
+
}
|
285 |
+
|
286 |
+
// Give it off
|
287 |
+
return array(
|
288 |
+
'root_title' => 'DHCPD IP Leases',
|
289 |
+
'rows' => $rows,
|
290 |
+
);
|
291 |
+
}
|
292 |
+
}
|
lib/Linfo/Extension/Dnsmasq_dhcpd.php
ADDED
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
|
5 |
+
This parses dnsmasq's dhcpd leases file. Commonly used to show dynamic IP's given to
|
6 |
+
libvirt's virtual machines. This does not require libvirt-php to be installed.
|
7 |
+
|
8 |
+
Installation:
|
9 |
+
- The following lines must be added to your config.inc.php:
|
10 |
+
$settings['extensions']['Dnsmasq_dhcpd'] = true;
|
11 |
+
$settings['dnsmasq_hide_mac'] = true; // set to false to show mac addresses
|
12 |
+
$settings['dnsmasq_leases'] = 'path'; // change path to the leases file. defaults to /var/lib/libvirt/dnsmasq/default.leases
|
13 |
+
|
14 |
+
*/
|
15 |
+
|
16 |
+
/**
|
17 |
+
* This file is part of Linfo (c) 2015 Joseph Gillotti.
|
18 |
+
*
|
19 |
+
* Linfo is free software: you can redistribute it and/or modify
|
20 |
+
* it under the terms of the GNU General Public License as published by
|
21 |
+
* the Free Software Foundation, either version 3 of the License, or
|
22 |
+
* (at your option) any later version.
|
23 |
+
*
|
24 |
+
* Linfo is distributed in the hope that it will be useful,
|
25 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
26 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
27 |
+
* GNU General Public License for more details.
|
28 |
+
*
|
29 |
+
* You should have received a copy of the GNU General Public License
|
30 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
31 |
+
*/
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Keep out hackers...
|
35 |
+
*/
|
36 |
+
namespace Linfo\Extension;
|
37 |
+
|
38 |
+
use Linfo\Linfo;
|
39 |
+
use Linfo\Common;
|
40 |
+
use Linfo\Meta\Errors;
|
41 |
+
use Linfo\Meta\Timer;
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Get status on dhcp3 leases.
|
45 |
+
*/
|
46 |
+
class Dnsmasq_dhcpd implements Extension
|
47 |
+
{
|
48 |
+
// How dates should look
|
49 |
+
const
|
50 |
+
DATE_FORMAT = 'm/d/y h:i A';
|
51 |
+
|
52 |
+
// Store these tucked away here
|
53 |
+
private
|
54 |
+
$_hide_mac,
|
55 |
+
$_leases = array();
|
56 |
+
|
57 |
+
/**
|
58 |
+
* localize important stuff.
|
59 |
+
* @param Linfo $linfo
|
60 |
+
*/
|
61 |
+
public function __construct(Linfo $linfo)
|
62 |
+
{
|
63 |
+
$settings = $linfo->getSettings();
|
64 |
+
|
65 |
+
// Should we hide mac addresses, to prevent stuff like mac address spoofing?
|
66 |
+
$this->_hide_mac = array_key_exists('dnsmasq_hide_mac', $settings) ? (bool) $settings['dnsmasq_hide_mac'] : false;
|
67 |
+
|
68 |
+
// Find leases file
|
69 |
+
$this->_leases_file = isset($settings['dnsmasq_leases']) && is_file($settings['dnsmasq_leases']) ?
|
70 |
+
$settings['dnsmasq_leases'] : Common::locateActualPath(array(
|
71 |
+
'/var/lib/libvirt/dnsmasq/default.leases',
|
72 |
+
));
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Do the job.
|
77 |
+
*/
|
78 |
+
public function work()
|
79 |
+
{
|
80 |
+
$t = new Timer('dnsmasq leases extension');
|
81 |
+
|
82 |
+
foreach (Common::getLines($this->_leases_file) as $line) {
|
83 |
+
if (!preg_match('/^(\d+) ([a-z0-9:]+) (\S+) (\S+)/', $line, $m))
|
84 |
+
continue;
|
85 |
+
$this->_leases[] = array_combine(array('lease_end', 'mac', 'ip', 'hostname'), array_slice($m, 1));
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Return result.
|
91 |
+
*
|
92 |
+
* @return array of the leases
|
93 |
+
*/
|
94 |
+
public function result()
|
95 |
+
{
|
96 |
+
// Store rows here
|
97 |
+
$rows = array();
|
98 |
+
|
99 |
+
// Start showing connections
|
100 |
+
$rows[] = array(
|
101 |
+
'type' => 'header',
|
102 |
+
'columns' =>
|
103 |
+
|
104 |
+
// Not hiding mac address?
|
105 |
+
!$this->_hide_mac ? array(
|
106 |
+
'IP Address',
|
107 |
+
'MAC Address',
|
108 |
+
'Hostname',
|
109 |
+
'Lease End',
|
110 |
+
) :
|
111 |
+
|
112 |
+
// Hiding it indeed
|
113 |
+
array(
|
114 |
+
'IP Address',
|
115 |
+
'Hostname',
|
116 |
+
'Lease End',
|
117 |
+
),
|
118 |
+
);
|
119 |
+
|
120 |
+
// Append each lease
|
121 |
+
foreach ($this->_leases as $lease) {
|
122 |
+
$rows[] = array(
|
123 |
+
'type' => 'values',
|
124 |
+
'columns' =>
|
125 |
+
|
126 |
+
// Not hiding mac addresses?
|
127 |
+
!$this->_hide_mac ? array(
|
128 |
+
$lease['ip'],
|
129 |
+
$lease['mac'],
|
130 |
+
array_key_exists('hostname', $lease) ?
|
131 |
+
$lease['hostname'] : '<em>unknown</em>',
|
132 |
+
date(self::DATE_FORMAT, $lease['lease_end']),
|
133 |
+
) :
|
134 |
+
|
135 |
+
// Hiding them indeed
|
136 |
+
array(
|
137 |
+
$lease['ip'],
|
138 |
+
array_key_exists('hostname', $lease) ?
|
139 |
+
$lease['hostname'] : '<em>unknown</em>',
|
140 |
+
date(self::DATE_FORMAT, $lease['lease_end']),
|
141 |
+
),
|
142 |
+
);
|
143 |
+
}
|
144 |
+
|
145 |
+
// Give it off
|
146 |
+
return array(
|
147 |
+
'root_title' => 'DnsMasq DHCPD IP Leases',
|
148 |
+
'rows' => $rows,
|
149 |
+
);
|
150 |
+
}
|
151 |
+
}
|
lib/Linfo/Extension/Extension.php
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Extension;
|
22 |
+
|
23 |
+
use Linfo\Linfo;
|
24 |
+
|
25 |
+
/*
|
26 |
+
* Extensions must conform to this
|
27 |
+
*/
|
28 |
+
interface Extension
|
29 |
+
{
|
30 |
+
public function __construct(Linfo $linfo); // Have them localize useful things
|
31 |
+
public function work(); // Do the job
|
32 |
+
public function result(); // Return the result
|
33 |
+
}
|
lib/Linfo/Extension/Ipmi.php
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
|
5 |
+
This implements a ipmi status checker for temps/voltages
|
6 |
+
|
7 |
+
Installation:
|
8 |
+
- The following lines must be added to your config.inc.php:
|
9 |
+
$settings['extensions']['ipmi'] = true;
|
10 |
+
|
11 |
+
- The ipmitool command most likely needs to be run as root, so,
|
12 |
+
if you don't have php running as root, configure sudo appropriately
|
13 |
+
for the user the php scripts are running as, comment out 'Defaults requiretty' in your sudoers
|
14 |
+
file, and add 'ipmitool' to the $settings['sudo_apps'] array in config.inc.php
|
15 |
+
|
16 |
+
*/
|
17 |
+
|
18 |
+
/*
|
19 |
+
* This file is part of Linfo (c) 2011 Joseph Gillotti.
|
20 |
+
*
|
21 |
+
* Linfo is free software: you can redistribute it and/or modify
|
22 |
+
* it under the terms of the GNU General Public License as published by
|
23 |
+
* the Free Software Foundation, either version 3 of the License, or
|
24 |
+
* (at your option) any later version.
|
25 |
+
*
|
26 |
+
* Linfo is distributed in the hope that it will be useful,
|
27 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
28 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
29 |
+
* GNU General Public License for more details.
|
30 |
+
*
|
31 |
+
* You should have received a copy of the GNU General Public License
|
32 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
33 |
+
*
|
34 |
+
*/
|
35 |
+
|
36 |
+
namespace Linfo\Extension;
|
37 |
+
|
38 |
+
use Linfo\Linfo;
|
39 |
+
use Linfo\Meta\Errors;
|
40 |
+
use Linfo\Meta\Timer;
|
41 |
+
use Linfo\Parsers\CallExt;
|
42 |
+
use Exception;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* IPMI extension for temps/voltages.
|
46 |
+
*
|
47 |
+
* @author Joseph Gillotti
|
48 |
+
*/
|
49 |
+
class Ipmi implements Extension
|
50 |
+
{
|
51 |
+
// Minimum version of Linfo required
|
52 |
+
const
|
53 |
+
LINFO_INTEGRATE = true,
|
54 |
+
EXTENSION_NAME = 'ipmi';
|
55 |
+
|
56 |
+
// Store these tucked away here
|
57 |
+
private $_CallExt,
|
58 |
+
$linfo;
|
59 |
+
|
60 |
+
// Start us off
|
61 |
+
public function __construct(Linfo $linfo)
|
62 |
+
{
|
63 |
+
$this->linfo = $linfo;
|
64 |
+
$this->_CallExt = new CallExt();
|
65 |
+
$this->_CallExt->setSearchPaths(array('/usr/bin', '/usr/local/bin', '/sbin', '/usr/local/sbin'));
|
66 |
+
}
|
67 |
+
|
68 |
+
// Work it, baby
|
69 |
+
public function work()
|
70 |
+
{
|
71 |
+
$info = &$this->linfo->getInfo();
|
72 |
+
|
73 |
+
// Make sure this is an array
|
74 |
+
$info['Temps'] = (array) $info['Temps'];
|
75 |
+
|
76 |
+
// Time this
|
77 |
+
$t = new Timer(self::EXTENSION_NAME.' Extension');
|
78 |
+
|
79 |
+
// Deal with calling it
|
80 |
+
try {
|
81 |
+
$result = $this->_CallExt->exec('ipmitool', ' sdr');
|
82 |
+
} catch (Exception $e) {
|
83 |
+
// messed up somehow
|
84 |
+
Errors::add(self::EXTENSION_NAME.' Extension', $e->getMessage());
|
85 |
+
|
86 |
+
return;
|
87 |
+
}
|
88 |
+
|
89 |
+
// Match it up
|
90 |
+
if (!preg_match_all('/^([^|]+)\| ([\d\.]+ (?:Volts|degrees [CF]))\s+\| ok$/m', $result, $matches, PREG_SET_ORDER)) {
|
91 |
+
return;
|
92 |
+
}
|
93 |
+
|
94 |
+
// Go through with it
|
95 |
+
foreach ($matches as $m) {
|
96 |
+
|
97 |
+
// Separate them by normal spaces
|
98 |
+
$v_parts = explode(' ', trim($m[2]));
|
99 |
+
|
100 |
+
// Deal with the type of it
|
101 |
+
switch ($v_parts[1]) {
|
102 |
+
case 'Volts':
|
103 |
+
$unit = 'v';
|
104 |
+
break;
|
105 |
+
case 'degrees':
|
106 |
+
$unit = $v_parts[2];
|
107 |
+
break;
|
108 |
+
default:
|
109 |
+
$unit = '';
|
110 |
+
break;
|
111 |
+
}
|
112 |
+
|
113 |
+
// Save this one
|
114 |
+
$info['Temps'][] = array(
|
115 |
+
'path' => 'N/A',
|
116 |
+
'name' => trim($m[1]),
|
117 |
+
'temp' => $v_parts[0],
|
118 |
+
'unit' => $unit,
|
119 |
+
);
|
120 |
+
}
|
121 |
+
}
|
122 |
+
|
123 |
+
// Not needed
|
124 |
+
public function result()
|
125 |
+
{
|
126 |
+
return false;
|
127 |
+
}
|
128 |
+
}
|
lib/Linfo/Extension/Libvirt.php
ADDED
@@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
|
5 |
+
This shows a cursory list of running VMs managed by libvirt and their stats.
|
6 |
+
Requires libvirt php extension (http://libvirt.org/php/):
|
7 |
+
sudo apt-get install php5-libvirt-php
|
8 |
+
|
9 |
+
To enable this extension, add/tweak the following to your config.inc.php
|
10 |
+
|
11 |
+
$settings['extensions']['libvirt'] = true;
|
12 |
+
$settings['libvirt_connection'] = array(
|
13 |
+
'url' => 'qemu:///system', // For xen do 'xen:///' instead
|
14 |
+
'credentials' => NULL
|
15 |
+
);
|
16 |
+
|
17 |
+
|
18 |
+
*/
|
19 |
+
|
20 |
+
/**
|
21 |
+
* This file is part of Linfo (c) 2013 Joseph Gillotti.
|
22 |
+
*
|
23 |
+
* Linfo is free software: you can redistribute it and/or modify
|
24 |
+
* it under the terms of the GNU General Public License as published by
|
25 |
+
* the Free Software Foundation, either version 3 of the License, or
|
26 |
+
* (at your option) any later version.
|
27 |
+
*
|
28 |
+
* Linfo is distributed in the hope that it will be useful,
|
29 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
30 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
31 |
+
* GNU General Public License for more details.
|
32 |
+
*
|
33 |
+
* You should have received a copy of the GNU General Public License
|
34 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
35 |
+
*/
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Keep out hackers...
|
39 |
+
*/
|
40 |
+
namespace Linfo\Extension;
|
41 |
+
|
42 |
+
use Linfo\Linfo;
|
43 |
+
use Linfo\Common;
|
44 |
+
use Linfo\Meta\Errors;
|
45 |
+
use Linfo\Meta\Timer;
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Get status on libvirt VMs.
|
49 |
+
*/
|
50 |
+
class Libvirt implements Extension
|
51 |
+
{
|
52 |
+
private
|
53 |
+
$VMs = array(),
|
54 |
+
$connection = false,
|
55 |
+
$connectionSettings = array(),
|
56 |
+
$res = false;
|
57 |
+
|
58 |
+
public function __construct(Linfo $linfo)
|
59 |
+
{
|
60 |
+
$settings = $linfo->getSettings();
|
61 |
+
|
62 |
+
$this->connectionSettings = $settings['libvirt_connection'];
|
63 |
+
}
|
64 |
+
|
65 |
+
private function connect()
|
66 |
+
{
|
67 |
+
if (!($this->connection =
|
68 |
+
@libvirt_connect($this->connectionSettings['url'], true))) {
|
69 |
+
Errors::add('libvirt extension', 'Error connecting');
|
70 |
+
$this->res = false;
|
71 |
+
|
72 |
+
return false;
|
73 |
+
}
|
74 |
+
|
75 |
+
return true;
|
76 |
+
}
|
77 |
+
|
78 |
+
public function work()
|
79 |
+
{
|
80 |
+
$t = new Timer('libvirt extension');
|
81 |
+
|
82 |
+
if (!extension_loaded('libvirt')) {
|
83 |
+
Errors::add('libvirt extension', 'Libvirt PHP extension not installed');
|
84 |
+
$this->res = false;
|
85 |
+
|
86 |
+
return;
|
87 |
+
}
|
88 |
+
|
89 |
+
if (!$this->connect()) {
|
90 |
+
Errors::add('libvirt extension', 'Failed connecting');
|
91 |
+
return;
|
92 |
+
}
|
93 |
+
|
94 |
+
if (!($doms = libvirt_list_domains($this->connection))) {
|
95 |
+
Errors::add('libvirt extension', 'Failed getting domain list');
|
96 |
+
$this->res = false;
|
97 |
+
|
98 |
+
return;
|
99 |
+
}
|
100 |
+
|
101 |
+
foreach ($doms as $name) {
|
102 |
+
if (!($domain = libvirt_domain_lookup_by_name($this->connection, $name))) {
|
103 |
+
continue;
|
104 |
+
}
|
105 |
+
|
106 |
+
if (!($info = libvirt_domain_get_info($domain)) || !is_array($info)) {
|
107 |
+
continue;
|
108 |
+
}
|
109 |
+
|
110 |
+
$info['autostart'] = libvirt_domain_get_autostart($domain);
|
111 |
+
|
112 |
+
if ($info['autostart'] == 1) {
|
113 |
+
$info['autostart'] = 'Yes';
|
114 |
+
} elseif ($info['autostart'] == 0) {
|
115 |
+
$info['autostart'] = 'No';
|
116 |
+
} else {
|
117 |
+
$info['autostart'] = 'N/A';
|
118 |
+
}
|
119 |
+
|
120 |
+
$info['nets'] = array();
|
121 |
+
|
122 |
+
$nets = @libvirt_domain_get_interface_devices($domain);
|
123 |
+
|
124 |
+
foreach ($nets as $key => $net) {
|
125 |
+
if (!is_numeric($key)) {
|
126 |
+
continue;
|
127 |
+
}
|
128 |
+
$info['nets'][] = $net;
|
129 |
+
}
|
130 |
+
|
131 |
+
$info['storage'] = array();
|
132 |
+
|
133 |
+
foreach ((array) @libvirt_domain_get_disk_devices($domain) as $blockName) {
|
134 |
+
if (!is_string($blockName)) {
|
135 |
+
continue;
|
136 |
+
}
|
137 |
+
|
138 |
+
// Sometime device exists but libvirt fails to get more docs. just settle for device name
|
139 |
+
if (!($blockInfo = @libvirt_domain_get_block_info($domain, $blockName)) || !is_array($blockInfo)) {
|
140 |
+
$info['storage'][] = array(
|
141 |
+
'device' => $blockName,
|
142 |
+
);
|
143 |
+
continue;
|
144 |
+
}
|
145 |
+
|
146 |
+
if (isset($blockInfo['partition']) && !isset($blockInfo['file'])) {
|
147 |
+
$blockInfo['file'] = $blockInfo['partition'];
|
148 |
+
}
|
149 |
+
|
150 |
+
$info['storage'][] = $blockInfo;
|
151 |
+
}
|
152 |
+
|
153 |
+
$this->VMs[$name] = $info;
|
154 |
+
}
|
155 |
+
|
156 |
+
$this->res = true;
|
157 |
+
}
|
158 |
+
|
159 |
+
public function result()
|
160 |
+
{
|
161 |
+
if (!$this->res) {
|
162 |
+
return false;
|
163 |
+
}
|
164 |
+
|
165 |
+
$rows[] = array(
|
166 |
+
'type' => 'header',
|
167 |
+
'columns' => array(
|
168 |
+
'VM Name',
|
169 |
+
'Status',
|
170 |
+
'RAM Allocation',
|
171 |
+
'CPUs',
|
172 |
+
'CPU Time',
|
173 |
+
'Autostart',
|
174 |
+
'Block Storage',
|
175 |
+
'Network Devices',
|
176 |
+
),
|
177 |
+
);
|
178 |
+
|
179 |
+
$running = 0;
|
180 |
+
$allram = 0;
|
181 |
+
|
182 |
+
foreach ($this->VMs as $name => $info) {
|
183 |
+
$disks = array();
|
184 |
+
|
185 |
+
foreach ($info['storage'] as $disk) {
|
186 |
+
$disks[] = $disk['device']
|
187 |
+
.(isset($disk['file']) && isset($disk['capacity']) ? ': '.$disk['file'].' ('.Common::byteConvert($disk['capacity'], 2).')' : '');
|
188 |
+
}
|
189 |
+
|
190 |
+
$rows[] = array(
|
191 |
+
'type' => 'values',
|
192 |
+
'columns' => array(
|
193 |
+
$name,
|
194 |
+
$info['state'] == 1 ? '<span style="color: green;">On</span>' : '<span style="color: maroon;">Off</span>',
|
195 |
+
Common::byteConvert($info['memory'] * 1024, 2),
|
196 |
+
$info['nrVirtCpu'],
|
197 |
+
$info['cpuUsed'] ? $info['cpuUsed'] : 'N/A',
|
198 |
+
$info['autostart'],
|
199 |
+
$disks ? implode('<br />', $disks) : 'None',
|
200 |
+
$info['nets'] ? implode('<br />', $info['nets']) : 'None',
|
201 |
+
),
|
202 |
+
);
|
203 |
+
|
204 |
+
if ($info['state'] == 1)
|
205 |
+
$running++;
|
206 |
+
|
207 |
+
$allram += $info['memory'];
|
208 |
+
}
|
209 |
+
|
210 |
+
// Give it off
|
211 |
+
return array(
|
212 |
+
'root_title' => 'libvirt Virtual Machines <span style="font-size: 80%;">('.$running.' running - using '.Common::byteConvert($allram * 1024, 2).' RAM)</span>',
|
213 |
+
'rows' => $rows,
|
214 |
+
);
|
215 |
+
}
|
216 |
+
}
|
lib/Linfo/Extension/Smb.php
ADDED
@@ -0,0 +1,323 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
|
5 |
+
This impliments a current samba usage status
|
6 |
+
|
7 |
+
Installation:
|
8 |
+
- The following lines must be added to your config.inc.php:
|
9 |
+
$settings['extensions']['smb'] = true;
|
10 |
+
|
11 |
+
|
12 |
+
*/
|
13 |
+
|
14 |
+
/*
|
15 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
16 |
+
*
|
17 |
+
* Linfo is free software: you can redistribute it and/or modify
|
18 |
+
* it under the terms of the GNU General Public License as published by
|
19 |
+
* the Free Software Foundation, either version 3 of the License, or
|
20 |
+
* (at your option) any later version.
|
21 |
+
*
|
22 |
+
* Linfo is distributed in the hope that it will be useful,
|
23 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
24 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
25 |
+
* GNU General Public License for more details.
|
26 |
+
*
|
27 |
+
* You should have received a copy of the GNU General Public License
|
28 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
29 |
+
*
|
30 |
+
*/
|
31 |
+
|
32 |
+
namespace Linfo\Extension;
|
33 |
+
|
34 |
+
use Linfo\Linfo;
|
35 |
+
use Linfo\Meta\Errors;
|
36 |
+
use Linfo\Meta\Timer;
|
37 |
+
use Linfo\Parsers\CallExt;
|
38 |
+
use Exception;
|
39 |
+
|
40 |
+
/*
|
41 |
+
* Get info on a samba install by running smbstatus
|
42 |
+
*/
|
43 |
+
class Smb implements Extension
|
44 |
+
{
|
45 |
+
// Store these tucked away here
|
46 |
+
private $_CallExt,
|
47 |
+
$_res,
|
48 |
+
$_date_format = 'm/d/y @ h:i A';
|
49 |
+
|
50 |
+
// Localize important classes
|
51 |
+
public function __construct(Linfo $linfo)
|
52 |
+
{
|
53 |
+
$this->_CallExt = new CallExt();
|
54 |
+
$this->_CallExt->setSearchPaths(array('/usr/bin', '/usr/local/bin', '/sbin', '/usr/local/sbin'));
|
55 |
+
}
|
56 |
+
|
57 |
+
// call samba and parse it
|
58 |
+
private function _call()
|
59 |
+
{
|
60 |
+
|
61 |
+
// Time this
|
62 |
+
$t = new Timer('Samba Status extension');
|
63 |
+
|
64 |
+
// Deal with calling it
|
65 |
+
try {
|
66 |
+
$result = $this->_CallExt->exec('smbstatus');
|
67 |
+
} catch (Exception $e) {
|
68 |
+
// messed up somehow
|
69 |
+
Errors::add('Samba Status Extension', $e->getMessage());
|
70 |
+
$this->_res = false;
|
71 |
+
|
72 |
+
// Don't bother going any further
|
73 |
+
return false;
|
74 |
+
}
|
75 |
+
|
76 |
+
// Split it into lines
|
77 |
+
$lines = explode("\n", $result);
|
78 |
+
|
79 |
+
// Store temp stuff here
|
80 |
+
$connections = array();
|
81 |
+
$services = array();
|
82 |
+
$files = array();
|
83 |
+
$current_location = false;
|
84 |
+
|
85 |
+
// Parse
|
86 |
+
for ($i = 0, $num = count($lines); $i < $num; ++$i) {
|
87 |
+
|
88 |
+
// Deal with pointlessness appropriately
|
89 |
+
$lines[$i] = trim($lines[$i]);
|
90 |
+
|
91 |
+
// Is this pointless?
|
92 |
+
if ($lines[$i] == '' || preg_match('/^\-+$/', $lines[$i])) {
|
93 |
+
continue;
|
94 |
+
}
|
95 |
+
|
96 |
+
// Beginning connections list?
|
97 |
+
elseif (preg_match('/^PID\s+Username\s+Group\s+Machine$/', $lines[$i])) {
|
98 |
+
$current_location = 'c';
|
99 |
+
}
|
100 |
+
|
101 |
+
// A connection?
|
102 |
+
elseif ($current_location == 'c' && preg_match('/^(\d+)\s+(\w+)\s+(\w+)\s+(\S+)\s+\(([^)]+)\)$/', $lines[$i], $connection_match)) {
|
103 |
+
$connections[] = array(
|
104 |
+
'pid' => $connection_match[1],
|
105 |
+
'username' => $connection_match[2],
|
106 |
+
'group' => $connection_match[3],
|
107 |
+
'hostname' => $connection_match[4],
|
108 |
+
'ip' => $connection_match[5],
|
109 |
+
);
|
110 |
+
}
|
111 |
+
|
112 |
+
// Beginning services list?
|
113 |
+
elseif (preg_match('/^Service\s+pid\s+machine\s+Connected at$/', $lines[$i])) {
|
114 |
+
$current_location = 's';
|
115 |
+
}
|
116 |
+
|
117 |
+
// A service?
|
118 |
+
elseif ($current_location == 's' && preg_match('/^(\w+)\s+(\d+)\s+(\S+)\s+([a-zA-z]+ [a-zA-Z]+ \d+ \d+:\d+:\d+ \d+)$/', $lines[$i], $service_match)) {
|
119 |
+
$services[] = array(
|
120 |
+
'service' => $service_match[1],
|
121 |
+
'pid' => $service_match[2],
|
122 |
+
'machine' => $service_match[3],
|
123 |
+
'date' => strtotime($service_match[4]),
|
124 |
+
);
|
125 |
+
}
|
126 |
+
|
127 |
+
// Beginning locked files list?
|
128 |
+
elseif (preg_match('/^Pid\s+Uid\s+DenyMode\s+Access\s+R\/W\s+Oplock\s+SharePath\s+Name\s+Time$/', $lines[$i])) {
|
129 |
+
$current_location = 'f';
|
130 |
+
}
|
131 |
+
|
132 |
+
// A locked file?
|
133 |
+
elseif ($current_location == 'f' && preg_match('/^(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+([A-Z]+)\s+([A-Z+]+)\s+(\S+)\s+(.+)\s+([a-zA-Z]+ [a-zA-Z]+ \d+ \d+:\d+:\d+ \d+)$/', $lines[$i], $file_match)) {
|
134 |
+
$files[] = array(
|
135 |
+
'pid' => $file_match[1],
|
136 |
+
'uid' => $file_match[2],
|
137 |
+
'deny_mode' => $file_match[3],
|
138 |
+
'access' => $file_match[4],
|
139 |
+
'rw' => $file_match[5],
|
140 |
+
'oplock' => $file_match[6],
|
141 |
+
'share' => $file_match[7],
|
142 |
+
'filename' => $file_match[8],
|
143 |
+
'date' => strtotime($file_match[9]),
|
144 |
+
);
|
145 |
+
}
|
146 |
+
}
|
147 |
+
|
148 |
+
// Give result
|
149 |
+
$this->_res = array(
|
150 |
+
'connections' => $connections,
|
151 |
+
'services' => $services,
|
152 |
+
'files' => $files,
|
153 |
+
);
|
154 |
+
|
155 |
+
// Success
|
156 |
+
return true;
|
157 |
+
}
|
158 |
+
|
159 |
+
public function work()
|
160 |
+
{
|
161 |
+
$this->_call();
|
162 |
+
}
|
163 |
+
public function result()
|
164 |
+
{
|
165 |
+
// Don't bother if it didn't go well
|
166 |
+
if ($this->_res === false) {
|
167 |
+
return false;
|
168 |
+
}
|
169 |
+
// it did; continue
|
170 |
+
else {
|
171 |
+
|
172 |
+
// Store rows here
|
173 |
+
$rows = array();
|
174 |
+
|
175 |
+
// Start showing connections
|
176 |
+
$rows[] = array(
|
177 |
+
'type' => 'header',
|
178 |
+
'columns' => array(
|
179 |
+
array(5, 'Connections'),
|
180 |
+
),
|
181 |
+
);
|
182 |
+
$rows[] = array(
|
183 |
+
'type' => 'header',
|
184 |
+
'columns' => array(
|
185 |
+
'Username',
|
186 |
+
'Group',
|
187 |
+
array(3,'Machine'),
|
188 |
+
),
|
189 |
+
);
|
190 |
+
|
191 |
+
// Show them
|
192 |
+
if (count($this->_res['connections']) > 0) {
|
193 |
+
foreach ($this->_res['connections'] as $conn) {
|
194 |
+
$rows[] = array(
|
195 |
+
'type' => 'values',
|
196 |
+
'columns' => array(
|
197 |
+
$conn['username'],
|
198 |
+
$conn['group'],
|
199 |
+
array(3,$conn['hostname'].($conn['hostname'] != $conn['ip'] ? ' <span class="perc">('.$conn['ip'].')</span>' : '')),
|
200 |
+
),
|
201 |
+
);
|
202 |
+
}
|
203 |
+
} else {
|
204 |
+
$rows[] = array(
|
205 |
+
'type' => 'none',
|
206 |
+
'columns' => array(
|
207 |
+
array(5, 'None found'),
|
208 |
+
),
|
209 |
+
);
|
210 |
+
}
|
211 |
+
|
212 |
+
// Now services
|
213 |
+
$rows[] = array(
|
214 |
+
'type' => 'header',
|
215 |
+
'columns' => array(
|
216 |
+
array(5, 'Services'),
|
217 |
+
),
|
218 |
+
);
|
219 |
+
$rows[] = array(
|
220 |
+
'type' => 'header',
|
221 |
+
'columns' => array(
|
222 |
+
'Service',
|
223 |
+
'Machine',
|
224 |
+
array(3,'Date'),
|
225 |
+
),
|
226 |
+
);
|
227 |
+
|
228 |
+
// Show them
|
229 |
+
if (count($this->_res['services']) > 0) {
|
230 |
+
// Show them
|
231 |
+
foreach ($this->_res['services'] as $service) {
|
232 |
+
$rows[] = array(
|
233 |
+
'type' => 'values',
|
234 |
+
'columns' => array(
|
235 |
+
$service['service'],
|
236 |
+
$service['machine'],
|
237 |
+
array(3, date($this->_date_format, $service['date'])),
|
238 |
+
),
|
239 |
+
);
|
240 |
+
}
|
241 |
+
} else {
|
242 |
+
$rows[] = array(
|
243 |
+
'type' => 'none',
|
244 |
+
'columns' => array(
|
245 |
+
array(5, 'None found'),
|
246 |
+
),
|
247 |
+
);
|
248 |
+
}
|
249 |
+
|
250 |
+
// Files time
|
251 |
+
$rows[] = array(
|
252 |
+
'type' => 'header',
|
253 |
+
'columns' => array(
|
254 |
+
array(5, 'Locked files'),
|
255 |
+
),
|
256 |
+
);
|
257 |
+
$rows[] = array(
|
258 |
+
'type' => 'header',
|
259 |
+
'columns' => array(
|
260 |
+
'UID',
|
261 |
+
'Mode',
|
262 |
+
'Share',
|
263 |
+
'Filename',
|
264 |
+
'Date',
|
265 |
+
),
|
266 |
+
);
|
267 |
+
|
268 |
+
// Show them
|
269 |
+
if (count($this->_res['files']) > 0) {
|
270 |
+
foreach ($this->_res['files'] as $f) {
|
271 |
+
|
272 |
+
// See if we can turn the uid into a username
|
273 |
+
$username = false;
|
274 |
+
if (function_exists('posix_getpwuid')) {
|
275 |
+
if ($user_info = @posix_getpwuid($f['uid'])) {
|
276 |
+
$username = $user_info['name'];
|
277 |
+
}
|
278 |
+
}
|
279 |
+
|
280 |
+
// Try making better sense of the R/W column
|
281 |
+
switch ($f['rw']) {
|
282 |
+
case 'RDONLY':
|
283 |
+
$rw = 'Read Only';
|
284 |
+
break;
|
285 |
+
case 'RDWR':
|
286 |
+
$rw = 'Read/Write';
|
287 |
+
break;
|
288 |
+
case 'WRONLY':
|
289 |
+
$rw = 'Write Only';
|
290 |
+
break;
|
291 |
+
default:
|
292 |
+
$rw = false;
|
293 |
+
break;
|
294 |
+
}
|
295 |
+
|
296 |
+
// Save entry
|
297 |
+
$rows[] = array(
|
298 |
+
'type' => 'values',
|
299 |
+
'columns' => array(
|
300 |
+
$f['uid'].($username != false ? ' ('.$username.')' : ''),
|
301 |
+
$rw ? $rw : $f['rw'],
|
302 |
+
$f['share'],
|
303 |
+
$f['filename'],
|
304 |
+
date($this->_date_format, $f['date']),
|
305 |
+
), );
|
306 |
+
}
|
307 |
+
} else {
|
308 |
+
$rows[] = array(
|
309 |
+
'type' => 'none',
|
310 |
+
'columns' => array(
|
311 |
+
array(5, 'None found'),
|
312 |
+
),
|
313 |
+
);
|
314 |
+
}
|
315 |
+
|
316 |
+
// Give it off
|
317 |
+
return array(
|
318 |
+
'root_title' => 'Samba Status',
|
319 |
+
'rows' => $rows,
|
320 |
+
);
|
321 |
+
}
|
322 |
+
}
|
323 |
+
}
|
lib/Linfo/Extension/Soldat.php
ADDED
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
|
5 |
+
This impliments a soldat (soldat.pl) dedicated server gamestat.txt parser
|
6 |
+
|
7 |
+
Installation:
|
8 |
+
- Copy/move the class.ext.soldat.php into the lib/ folder
|
9 |
+
- The following lines must be added to your config.inc.php:
|
10 |
+
$settings['extensions']['soldat'] = true;
|
11 |
+
|
12 |
+
// paths to the gamestat.txt files
|
13 |
+
$settings['soldat_servers'] = array(
|
14 |
+
//'CTF #1' => '/home/soldat/ctf/logs/gamestat.txt' # example usage
|
15 |
+
);
|
16 |
+
|
17 |
+
*/
|
18 |
+
|
19 |
+
/*
|
20 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
21 |
+
*
|
22 |
+
* Linfo is free software: you can redistribute it and/or modify
|
23 |
+
* it under the terms of the GNU General Public License as published by
|
24 |
+
* the Free Software Foundation, either version 3 of the License, or
|
25 |
+
* (at your option) any later version.
|
26 |
+
*
|
27 |
+
* Linfo is distributed in the hope that it will be useful,
|
28 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
29 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
30 |
+
* GNU General Public License for more details.
|
31 |
+
*
|
32 |
+
* You should have received a copy of the GNU General Public License
|
33 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
34 |
+
*
|
35 |
+
*/
|
36 |
+
|
37 |
+
namespace Linfo\Extension;
|
38 |
+
|
39 |
+
use Linfo\Linfo;
|
40 |
+
use Linfo\Common;
|
41 |
+
use Linfo\Meta\Errors;
|
42 |
+
|
43 |
+
/*
|
44 |
+
* Get status on soldat game servers
|
45 |
+
*/
|
46 |
+
class Soldat implements Extension
|
47 |
+
{
|
48 |
+
// Store these tucked away here
|
49 |
+
private
|
50 |
+
$_res,
|
51 |
+
$_servers;
|
52 |
+
|
53 |
+
// Localize important classes
|
54 |
+
public function __construct(Linfo $linfo)
|
55 |
+
{
|
56 |
+
$settings = $linfo->getSettings();
|
57 |
+
$this->_servers = (array) $settings['soldat_servers'];
|
58 |
+
}
|
59 |
+
|
60 |
+
// work it
|
61 |
+
private function _call()
|
62 |
+
{
|
63 |
+
$this->_res = array();
|
64 |
+
foreach ($this->_servers as $name => $path) {
|
65 |
+
$lines = Common::getLines($path);
|
66 |
+
if (count($lines) == 0) {
|
67 |
+
continue;
|
68 |
+
}
|
69 |
+
$info = self::readgamestat($lines);
|
70 |
+
$this->_res[] = array('name' => $name, 'info' => $info);
|
71 |
+
}
|
72 |
+
}
|
73 |
+
|
74 |
+
// Called to get working
|
75 |
+
public function work()
|
76 |
+
{
|
77 |
+
$this->_call();
|
78 |
+
}
|
79 |
+
|
80 |
+
// Get result. Essentially take results and make it usable by the Common::createTable function
|
81 |
+
public function result()
|
82 |
+
{
|
83 |
+
|
84 |
+
// Don't bother if it didn't go well
|
85 |
+
if ($this->_res == false) {
|
86 |
+
return false;
|
87 |
+
}
|
88 |
+
|
89 |
+
// Store rows here
|
90 |
+
$rows = array();
|
91 |
+
|
92 |
+
// Table header
|
93 |
+
$rows[] = array(
|
94 |
+
'type' => 'header',
|
95 |
+
'columns' => array(
|
96 |
+
'Name',
|
97 |
+
'Map',
|
98 |
+
'Time Left',
|
99 |
+
'Gametype',
|
100 |
+
'Players',
|
101 |
+
),
|
102 |
+
);
|
103 |
+
|
104 |
+
// Have we?
|
105 |
+
if (count($this->_res) == 0) {
|
106 |
+
$rows[] = array('type' => 'none', 'columns' => array(array(5, 'None found')));
|
107 |
+
}
|
108 |
+
|
109 |
+
// We do
|
110 |
+
else {
|
111 |
+
|
112 |
+
// Go through each server
|
113 |
+
foreach ($this->_res as $server) {
|
114 |
+
|
115 |
+
// No players? Set player column to 'none'
|
116 |
+
if ($server['info']['num_players'] == 0) {
|
117 |
+
$players = 'None';
|
118 |
+
}
|
119 |
+
|
120 |
+
// We do; populate a mini players table
|
121 |
+
else {
|
122 |
+
|
123 |
+
// Show team column?
|
124 |
+
$show_team = in_array($server['info']['mode'], array(
|
125 |
+
'Infiltration',
|
126 |
+
'Capture the Flag',
|
127 |
+
'Teammatch',
|
128 |
+
));
|
129 |
+
|
130 |
+
// Start table
|
131 |
+
$players = '
|
132 |
+
<table class="mini" style="text-align: center;">
|
133 |
+
<tr>
|
134 |
+
<th>Name</th>'.(
|
135 |
+
$show_team ? '
|
136 |
+
<th>Team</th>' : '').'
|
137 |
+
<th>Score</th>
|
138 |
+
<th>Deaths</th>
|
139 |
+
<th>Ping</th>
|
140 |
+
</tr>';
|
141 |
+
|
142 |
+
// Add each player to it
|
143 |
+
foreach ($server['info']['players'] as $player) {
|
144 |
+
$players .= '
|
145 |
+
<tr'.($show_team ? (' style="color: '.(
|
146 |
+
array_key_exists($player['team'], self::$team2color) ?
|
147 |
+
self::$team2color[$player['team']] : 'purple'
|
148 |
+
).';"') : '').'>
|
149 |
+
<td>'.htmlspecialchars($player['name']).'</td>'.(
|
150 |
+
$show_team ? '
|
151 |
+
<td>'.(array_key_exists($player['team'], self::$team2name) ?
|
152 |
+
self::$team2name[$player['team']] : 'None').'</td>' : '').'
|
153 |
+
<td>'.$player['kills'].'</td>
|
154 |
+
<td>'.$player['deaths'].'</td>
|
155 |
+
<td>'.$player['ping'].'</td>
|
156 |
+
</tr>';
|
157 |
+
}
|
158 |
+
|
159 |
+
// End table
|
160 |
+
$players .= '
|
161 |
+
</table>
|
162 |
+
';
|
163 |
+
}
|
164 |
+
|
165 |
+
// Save result in master table
|
166 |
+
$rows[] = array(
|
167 |
+
'type' => 'values',
|
168 |
+
'columns' => array(
|
169 |
+
$server['name'],
|
170 |
+
$server['info']['map'],
|
171 |
+
$server['info']['timeleft'],
|
172 |
+
$server['info']['mode'],
|
173 |
+
$players,
|
174 |
+
),
|
175 |
+
);
|
176 |
+
}
|
177 |
+
}
|
178 |
+
|
179 |
+
// Give info
|
180 |
+
return array(
|
181 |
+
'root_title' => 'Soldat Servers',
|
182 |
+
'rows' => $rows,
|
183 |
+
);
|
184 |
+
}
|
185 |
+
|
186 |
+
// Deal with team color
|
187 |
+
public static $team2color = array(
|
188 |
+
0 => '#333',
|
189 |
+
1 => 'red',
|
190 |
+
2 => 'blue',
|
191 |
+
3 => '#006600',
|
192 |
+
4 => '#FFD700',
|
193 |
+
);
|
194 |
+
|
195 |
+
// Deal with team name
|
196 |
+
public static $team2name = array(
|
197 |
+
0 => 'None',
|
198 |
+
1 => 'Alpha',
|
199 |
+
2 => 'Bravo',
|
200 |
+
3 => 'Charlie',
|
201 |
+
4 => 'Delta',
|
202 |
+
);
|
203 |
+
|
204 |
+
/*
|
205 |
+
gamestat.txt parser
|
206 |
+
Copyright (C) 2007 JRG Productions
|
207 |
+
http://soldat.jrgp.org/programs/gstp/gstp.phps
|
208 |
+
*/
|
209 |
+
public static function readgamestat($i)
|
210 |
+
{
|
211 |
+
//this array contains the info that will be returned
|
212 |
+
$info = array(
|
213 |
+
'num_players' => trim(str_replace('Players: ', '', $i[1])),
|
214 |
+
'map' => trim(str_replace('Map: ', '', $i[2])),
|
215 |
+
'mode' => trim(str_replace('Gamemode: ', '', $i[3])),
|
216 |
+
'timeleft' => trim(str_replace('Timeleft: ', '', $i[4])),
|
217 |
+
);
|
218 |
+
//support for the teambased gamemodes
|
219 |
+
if ($info['mode'] == 'Capture the Flag' || $info['mode'] == 'Infiltration' || $info['mode'] == 'Teammatch') {
|
220 |
+
$info['teams']['alpha'] = trim(str_replace('Team 1: ', '', $i[5]));
|
221 |
+
$info['teams']['bravo'] = trim(str_replace('Team 2: ', '', $i[6]));
|
222 |
+
$info['teams']['charlie'] = trim(str_replace('Team 3: ', '', $i[7]));
|
223 |
+
$info['teams']['delta'] = trim(str_replace('Team 4: ', '', $i[8]));
|
224 |
+
$players_line = 10;
|
225 |
+
} else {
|
226 |
+
$players_line = 6;
|
227 |
+
}
|
228 |
+
$pla = '';
|
229 |
+
//get the player info a string
|
230 |
+
for ($l = $players_line; $line = $i[$l], $l < count($i); ++$l) {
|
231 |
+
$pla .= $line;
|
232 |
+
}
|
233 |
+
//explode then chunk that string
|
234 |
+
$players_info = array_chunk(explode("\n", $pla), 5);
|
235 |
+
//kill the last element since its empty
|
236 |
+
array_pop($players_info);
|
237 |
+
//add each player to the new array
|
238 |
+
foreach ($players_info as $p) {
|
239 |
+
$info['players'][] = array(
|
240 |
+
'name' => $p[0],
|
241 |
+
'kills' => $p[1],
|
242 |
+
'deaths' => $p[2],
|
243 |
+
'team' => $p[3],
|
244 |
+
'ping' => $p[4],
|
245 |
+
);
|
246 |
+
}
|
247 |
+
//return the info
|
248 |
+
return $info;
|
249 |
+
}
|
250 |
+
}
|
lib/Linfo/Extension/Transmission.php
ADDED
@@ -0,0 +1,363 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
|
5 |
+
This implements a transmission-remote parsing extension which displays status of running torrents
|
6 |
+
|
7 |
+
Installation:
|
8 |
+
- The following lines must be added to your config.inc.php:
|
9 |
+
$settings['extensions']['transmission'] = true;
|
10 |
+
$settings['transmission_auth'] = array(
|
11 |
+
//'user' => 'jim', # Both of these must exist if you wish to use auth
|
12 |
+
//'pass' => 'pwnz!'
|
13 |
+
);
|
14 |
+
$settings['transmission_host'] = array(
|
15 |
+
// 'server' => 'localhost', # uncomment to set a specific host
|
16 |
+
// 'port' => 9091 # uncomment to set a specific port
|
17 |
+
);
|
18 |
+
|
19 |
+
|
20 |
+
// If you want download/upload/ratio/duration stats, make sure the web server user can
|
21 |
+
// read this folder, which is in the home directory of hteu ser that transmission is
|
22 |
+
// running as
|
23 |
+
$settings['transmission_folder'] = '/home/user/.config/transmission/';
|
24 |
+
|
25 |
+
*/
|
26 |
+
|
27 |
+
/**
|
28 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
29 |
+
*
|
30 |
+
* Linfo is free software: you can redistribute it and/or modify
|
31 |
+
* it under the terms of the GNU General Public License as published by
|
32 |
+
* the Free Software Foundation, either version 3 of the License, or
|
33 |
+
* (at your option) any later version.
|
34 |
+
*
|
35 |
+
* Linfo is distributed in the hope that it will be useful,
|
36 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
37 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
38 |
+
* GNU General Public License for more details.
|
39 |
+
*
|
40 |
+
* You should have received a copy of the GNU General Public License
|
41 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
42 |
+
*/
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Keep out hackers...
|
46 |
+
*/
|
47 |
+
namespace Linfo\Extension;
|
48 |
+
|
49 |
+
use Linfo\Linfo;
|
50 |
+
use Linfo\Common;
|
51 |
+
use Linfo\Meta\Errors;
|
52 |
+
use Linfo\Meta\Timer;
|
53 |
+
use Linfo\Parsers\CallExt;
|
54 |
+
use Exception;
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Get status on transmission torrents.
|
58 |
+
*/
|
59 |
+
class Transmission implements Extension
|
60 |
+
{
|
61 |
+
// Store these tucked away here
|
62 |
+
private $_CallExt,
|
63 |
+
$_res,
|
64 |
+
$_torrents = array(),
|
65 |
+
$_stats = false,
|
66 |
+
$_auth,
|
67 |
+
$_host;
|
68 |
+
|
69 |
+
/**
|
70 |
+
* localize important stuff.
|
71 |
+
* @param Linfo $linfo
|
72 |
+
*/
|
73 |
+
public function __construct(Linfo $linfo)
|
74 |
+
{
|
75 |
+
$settings = $linfo->getSettings();
|
76 |
+
|
77 |
+
// Classes we need
|
78 |
+
$this->_CallExt = new CallExt();
|
79 |
+
$this->_CallExt->setSearchPaths(array('/usr/bin', '/usr/local/bin'));
|
80 |
+
|
81 |
+
// Transmission specific settings
|
82 |
+
$this->_auth = array_key_exists('transmission_auth', $settings) ? (array) $settings['transmission_auth'] : array();
|
83 |
+
$this->_host = array_key_exists('transmission_host', $settings) ? (array) $settings['transmission_host'] : array();
|
84 |
+
|
85 |
+
// Path to home dir folder
|
86 |
+
$this->_folder = array_key_exists('transmission_folder', $settings) && is_dir($settings['transmission_folder']) && is_readable($settings['transmission_folder']) ? $settings['transmission_folder'] : false;
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Deal with it.
|
91 |
+
*/
|
92 |
+
private function _call()
|
93 |
+
{
|
94 |
+
// Time this
|
95 |
+
$t = new Timer('Transmission extension');
|
96 |
+
|
97 |
+
// Deal with stats, if possible
|
98 |
+
if ($this->_folder && ($stats_contents = Common::getContents($this->_folder.'stats.json', false)) && $stats_contents != false) {
|
99 |
+
$stats_vals = @json_decode($stats_contents, true);
|
100 |
+
if (is_array($stats_vals)) {
|
101 |
+
$this->_stats = $stats_vals;
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
// Deal with calling it
|
106 |
+
try {
|
107 |
+
// Start up args
|
108 |
+
$args = '';
|
109 |
+
|
110 |
+
// Specifc host/port?
|
111 |
+
if (array_key_exists('server', $this->_host) && array_key_exists('port', $this->_host) && is_numeric($this->_host['port'])) {
|
112 |
+
$args .= ' \''.$this->_host['server'].'\':'.$this->_host['port'];
|
113 |
+
}
|
114 |
+
|
115 |
+
// We need some auth?
|
116 |
+
if (array_key_exists('user', $this->_auth) && array_key_exists('pass', $this->_auth)) {
|
117 |
+
$args .= ' --auth=\''.$this->_auth['user'].'\':\''.$this->_auth['pass'].'\'';
|
118 |
+
}
|
119 |
+
|
120 |
+
// Rest of it, including result
|
121 |
+
$result = $this->_CallExt->exec('transmission-remote', $args.' -l');
|
122 |
+
} catch (Exception $e) {
|
123 |
+
// messed up somehow
|
124 |
+
Errors::add('Transmission extension: ', $e->getMessage());
|
125 |
+
$this->_res = false;
|
126 |
+
|
127 |
+
// Don't bother going any further
|
128 |
+
return;
|
129 |
+
}
|
130 |
+
|
131 |
+
$this->_res = true;
|
132 |
+
|
133 |
+
// Get first line
|
134 |
+
$first_line = reset(explode("\n", $result, 1));
|
135 |
+
|
136 |
+
// Invalid host?
|
137 |
+
if (strpos($first_line, 'Couldn\'t resolve host name') !== false) {
|
138 |
+
Errors::add('Transmission extension: Invalid Host');
|
139 |
+
$this->_res = false;
|
140 |
+
|
141 |
+
return;
|
142 |
+
}
|
143 |
+
|
144 |
+
// Invalid auth?
|
145 |
+
if (strpos($first_line, '401: Unauthorized') !== false) {
|
146 |
+
Errors::add('Transmission extension: Invalid Authentication');
|
147 |
+
$this->_res = false;
|
148 |
+
|
149 |
+
return;
|
150 |
+
}
|
151 |
+
|
152 |
+
// Match teh torrents!
|
153 |
+
if (preg_match_all('/^\s+(\d+)\*?\s+(\d+)\%\s+(\d+\.\d+ \w+|None)\s+((?:\d+ )?\w+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+|None)\s+(Up & Down|Seeding|Idle|Stopped)\s+(.+)$/m', $result, $matches, PREG_SET_ORDER) > 0) {
|
154 |
+
|
155 |
+
// Use this to sort them
|
156 |
+
$sort_done = array();
|
157 |
+
$sort_ratio = array();
|
158 |
+
$sort_name = array();
|
159 |
+
|
160 |
+
// Save the matches
|
161 |
+
for ($i = 0, $num = count($matches); $i < $num; ++$i) {
|
162 |
+
|
163 |
+
// Save this one
|
164 |
+
$this->_torrents[$i] = array(
|
165 |
+
'id' => $matches[$i][1],
|
166 |
+
'done' => $matches[$i][2],
|
167 |
+
'have' => $matches[$i][3],
|
168 |
+
'eta' => $matches[$i][4],
|
169 |
+
'up' => $matches[$i][5] * 1024, // always in KIB
|
170 |
+
'down' => $matches[$i][6] * 1024, // ^
|
171 |
+
'ratio' => $matches[$i][7],
|
172 |
+
'state' => $matches[$i][8],
|
173 |
+
'torrent' => $matches[$i][9],
|
174 |
+
);
|
175 |
+
|
176 |
+
// Use this for sorting
|
177 |
+
$sort_done[$i] = (int) $matches[$i][2];
|
178 |
+
$sort_ratio[$i] = (float) $matches[$i][7];
|
179 |
+
$sort_name[$i] = $matches[$i][9];
|
180 |
+
}
|
181 |
+
|
182 |
+
// Sort
|
183 |
+
array_multisort($sort_done, SORT_DESC, $sort_ratio, SORT_DESC, $sort_name, SORT_ASC, $this->_torrents);
|
184 |
+
}
|
185 |
+
}
|
186 |
+
|
187 |
+
/**
|
188 |
+
* Do the job.
|
189 |
+
*/
|
190 |
+
public function work()
|
191 |
+
{
|
192 |
+
$this->_call();
|
193 |
+
}
|
194 |
+
|
195 |
+
/**
|
196 |
+
* Return result.
|
197 |
+
*
|
198 |
+
* @return false on failure|array of the torrents
|
199 |
+
*/
|
200 |
+
public function result()
|
201 |
+
{
|
202 |
+
// Don't bother if it didn't go well
|
203 |
+
if ($this->_res === false) {
|
204 |
+
return false;
|
205 |
+
}
|
206 |
+
// it did; continue
|
207 |
+
|
208 |
+
// Store rows here
|
209 |
+
$rows = array();
|
210 |
+
|
211 |
+
// Start showing connections
|
212 |
+
$rows[] = array(
|
213 |
+
'type' => 'header',
|
214 |
+
'columns' => array(
|
215 |
+
'Torrent',
|
216 |
+
array(1, 'Done', '10%'),
|
217 |
+
'State',
|
218 |
+
'Have',
|
219 |
+
'Uploaded',
|
220 |
+
'Time Left',
|
221 |
+
'Ratio',
|
222 |
+
'Up',
|
223 |
+
'Down',
|
224 |
+
),
|
225 |
+
);
|
226 |
+
|
227 |
+
// No torrents?
|
228 |
+
if (count($this->_torrents) == 0) {
|
229 |
+
$rows[] = array(
|
230 |
+
'type' => 'none',
|
231 |
+
'columns' => array(
|
232 |
+
array(9, 'None found'),
|
233 |
+
),
|
234 |
+
);
|
235 |
+
} else {
|
236 |
+
|
237 |
+
// Store a total amount of certain torrents here:
|
238 |
+
$status_tally = array();
|
239 |
+
|
240 |
+
// As well as uploaded/downloaded
|
241 |
+
$status_tally['Downloaded'] = 0;
|
242 |
+
$status_tally['Uploaded'] = 0;
|
243 |
+
$status_tally['Ratio'] = '';
|
244 |
+
|
245 |
+
// Go through each torrent
|
246 |
+
foreach ($this->_torrents as $torrent) {
|
247 |
+
|
248 |
+
// Status count tally
|
249 |
+
$status_tally[$torrent['state']] = !array_key_exists($torrent['state'], $status_tally) ? 1 : $status_tally[$torrent['state']] + 1;
|
250 |
+
|
251 |
+
// Make some sense of the have so we can get it into bytes, which we can then have fun with
|
252 |
+
$have_bytes = false;
|
253 |
+
if ($torrent['have'] != 'None') {
|
254 |
+
$have_parts = explode(' ', $torrent['have'], 2);
|
255 |
+
if (is_numeric($have_parts[0]) && $have_parts[0] > 0) {
|
256 |
+
switch ($have_parts[1]) {
|
257 |
+
case 'TiB':
|
258 |
+
$have_bytes = (float) $have_parts[0] * 1099511627776;
|
259 |
+
break;
|
260 |
+
case 'GiB':
|
261 |
+
$have_bytes = (float) $have_parts[0] * 1073741824;
|
262 |
+
break;
|
263 |
+
case 'MiB':
|
264 |
+
$have_bytes = (float) $have_parts[0] * 1048576;
|
265 |
+
break;
|
266 |
+
case 'KiB':
|
267 |
+
$have_bytes = (float) $have_parts[0] * 1024;
|
268 |
+
break;
|
269 |
+
}
|
270 |
+
}
|
271 |
+
}
|
272 |
+
|
273 |
+
// Try getting amount uploaded, based upon ratio and exact amount downloaded above
|
274 |
+
$uploaded_bytes = false;
|
275 |
+
if (is_numeric($have_bytes) && $have_bytes > 0 && is_numeric($torrent['ratio']) && $torrent['ratio'] > 0) {
|
276 |
+
$uploaded_bytes = $torrent['ratio'] * $have_bytes;
|
277 |
+
}
|
278 |
+
|
279 |
+
// Save amount uploaded/downloaded tally
|
280 |
+
if (is_numeric($have_bytes) && $have_bytes > 0 && is_numeric($uploaded_bytes) && $uploaded_bytes > 0) {
|
281 |
+
$status_tally['Downloaded'] += $have_bytes;
|
282 |
+
$status_tally['Uploaded'] += $uploaded_bytes;
|
283 |
+
}
|
284 |
+
|
285 |
+
// Save result
|
286 |
+
$rows[] = array(
|
287 |
+
'type' => 'values',
|
288 |
+
'columns' => array(
|
289 |
+
wordwrap(htmlspecialchars($torrent['torrent']), 50, ' ', true),
|
290 |
+
'<div class="bar_chart">
|
291 |
+
<div class="bar_inner" style="width: '.(int) $torrent['done'].'%;">
|
292 |
+
<div class="bar_text">
|
293 |
+
'.($torrent['done'] ? $torrent['done'].'%' : '0%').'
|
294 |
+
</div>
|
295 |
+
</div>
|
296 |
+
</div>
|
297 |
+
',
|
298 |
+
$torrent['state'],
|
299 |
+
$have_bytes !== false ? Common::byteConvert($have_bytes) : $torrent['have'],
|
300 |
+
$uploaded_bytes !== false ? Common::byteConvert($uploaded_bytes) : 'None',
|
301 |
+
$torrent['eta'],
|
302 |
+
$torrent['ratio'],
|
303 |
+
Common::byteConvert($torrent['up']).'/s',
|
304 |
+
Common::byteConvert($torrent['down']).'/s',
|
305 |
+
),
|
306 |
+
);
|
307 |
+
}
|
308 |
+
|
309 |
+
// Finish the size totals
|
310 |
+
$status_tally['Ratio'] = $status_tally['Downloaded'] > 0 && $status_tally['Uploaded'] > 0 ? round($status_tally['Uploaded'] / $status_tally['Downloaded'], 2) : 'N/A';
|
311 |
+
$status_tally['Downloaded'] = $status_tally['Downloaded'] > 0 ? Common::byteConvert($status_tally['Downloaded']) : 'None';
|
312 |
+
$status_tally['Uploaded'] = $status_tally['Uploaded'] > 0 ? Common::byteConvert($status_tally['Uploaded']) : 'None';
|
313 |
+
|
314 |
+
// Create a row for the tally of statuses
|
315 |
+
if (count($status_tally) > 0) {
|
316 |
+
|
317 |
+
// Store list of k: v'ish values here
|
318 |
+
$tally_contents = array();
|
319 |
+
|
320 |
+
// Populate that
|
321 |
+
foreach ($status_tally as $state => $tally) {
|
322 |
+
$tally_contents[] = "$state: $tally";
|
323 |
+
}
|
324 |
+
|
325 |
+
// Save this final row
|
326 |
+
$rows[] = array(
|
327 |
+
'type' => 'values',
|
328 |
+
'columns' => array(
|
329 |
+
array(9, implode(', ', $tally_contents)),
|
330 |
+
),
|
331 |
+
);
|
332 |
+
}
|
333 |
+
}
|
334 |
+
|
335 |
+
// Handle stats which might not exist
|
336 |
+
if (
|
337 |
+
is_array($this->_stats) &&
|
338 |
+
array_key_exists('downloaded-bytes', $this->_stats) &&
|
339 |
+
array_key_exists('uploaded-bytes', $this->_stats) &&
|
340 |
+
array_key_exists('seconds-active', $this->_stats
|
341 |
+
)) {
|
342 |
+
$extra_vals = array(
|
343 |
+
'title' => 'Transmission Stats',
|
344 |
+
'values' => array(
|
345 |
+
array('Total Downloaded', Common::byteConvert($this->_stats['downloaded-bytes'])),
|
346 |
+
array('Total Uploaded', Common::byteConvert($this->_stats['uploaded-bytes'])),
|
347 |
+
$this->_stats['uploaded-bytes'] > 0 && $this->_stats['downloaded-bytes'] > 0 ? array('Total Ratio', round($this->_stats['uploaded-bytes'] / $this->_stats['downloaded-bytes'], 3)) : false,
|
348 |
+
array('Duration', Common::secondsConvert($this->_stats['seconds-active'])),
|
349 |
+
),
|
350 |
+
);
|
351 |
+
} else {
|
352 |
+
$extra_vals = false;
|
353 |
+
}
|
354 |
+
|
355 |
+
// Give it off
|
356 |
+
return array(
|
357 |
+
'root_title' => 'Transmission Torrents',
|
358 |
+
'rows' => $rows,
|
359 |
+
'extra_type' => 'k->v',
|
360 |
+
'extra_vals' => $extra_vals,
|
361 |
+
);
|
362 |
+
}
|
363 |
+
}
|
lib/Linfo/Extension/Truecrypt.php
ADDED
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
|
5 |
+
This implements a truecrypt mounted volume status shower
|
6 |
+
|
7 |
+
Installation:
|
8 |
+
- The following lines must be added to your config.inc.php:
|
9 |
+
$settings['extensions']['truecrypt'] = true;
|
10 |
+
|
11 |
+
*/
|
12 |
+
|
13 |
+
/*
|
14 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
15 |
+
*
|
16 |
+
* Linfo is free software: you can redistribute it and/or modify
|
17 |
+
* it under the terms of the GNU General Public License as published by
|
18 |
+
* the Free Software Foundation, either version 3 of the License, or
|
19 |
+
* (at your option) any later version.
|
20 |
+
*
|
21 |
+
* Linfo is distributed in the hope that it will be useful,
|
22 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
23 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
24 |
+
* GNU General Public License for more details.
|
25 |
+
*
|
26 |
+
* You should have received a copy of the GNU General Public License
|
27 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
28 |
+
*
|
29 |
+
*/
|
30 |
+
|
31 |
+
namespace Linfo\Extension;
|
32 |
+
|
33 |
+
use Linfo\Linfo;
|
34 |
+
use Linfo\Parsers\CallExt;
|
35 |
+
use Linfo\Meta\Errors;
|
36 |
+
use Linfo\Meta\Timer;
|
37 |
+
use Exception;
|
38 |
+
|
39 |
+
/*
|
40 |
+
* Get status on truecrypt volumes. very experimental
|
41 |
+
*/
|
42 |
+
class Truecrypt implements Extension
|
43 |
+
{
|
44 |
+
// Store these tucked away here
|
45 |
+
private $_CallExt,
|
46 |
+
$_res;
|
47 |
+
|
48 |
+
// Localize important classes
|
49 |
+
public function __construct(Linfo $linfo)
|
50 |
+
{
|
51 |
+
$this->_CallExt = new CallExt();
|
52 |
+
$this->_CallExt->setSearchPaths(array('/usr/bin', '/usr/local/bin', '/sbin', '/usr/local/sbin'));
|
53 |
+
}
|
54 |
+
|
55 |
+
// call truecrypt and parse it
|
56 |
+
private function _call()
|
57 |
+
{
|
58 |
+
|
59 |
+
// Time this
|
60 |
+
$t = new Timer('Truecrypt Extension');
|
61 |
+
|
62 |
+
// Deal with calling it
|
63 |
+
try {
|
64 |
+
$result = $this->_CallExt->exec('truecrypt', '-l -v');
|
65 |
+
} catch (Exception $e) {
|
66 |
+
// messed up somehow
|
67 |
+
Errors::add('Truecrypt Extension', $e->getMessage());
|
68 |
+
$this->_res = false;
|
69 |
+
|
70 |
+
// Don't bother going any further
|
71 |
+
return false;
|
72 |
+
}
|
73 |
+
|
74 |
+
// Store them here
|
75 |
+
$this->_res = array();
|
76 |
+
|
77 |
+
// Current one
|
78 |
+
$curr = false;
|
79 |
+
|
80 |
+
// Lines of output
|
81 |
+
$lines = explode("\n", $result);
|
82 |
+
|
83 |
+
// Go through each line
|
84 |
+
for ($i = 0, $num = count($lines); $i < $num; ++$i) {
|
85 |
+
|
86 |
+
// Extract juicy info
|
87 |
+
if (!preg_match('/^([^:]+): ([^$]+)$/', $lines[$i], $line_match)) {
|
88 |
+
continue;
|
89 |
+
}
|
90 |
+
|
91 |
+
// Decide what to do with that
|
92 |
+
switch ($line_match[1]) {
|
93 |
+
|
94 |
+
// It starts here
|
95 |
+
case 'Slot':
|
96 |
+
if ($curr === false) {
|
97 |
+
$curr = array('slot' => $line_match[2]);
|
98 |
+
} elseif (is_array($curr)) {
|
99 |
+
$this->_res[] = $curr;
|
100 |
+
$curr = false;
|
101 |
+
}
|
102 |
+
break;
|
103 |
+
|
104 |
+
// Volume.
|
105 |
+
case 'Volume':
|
106 |
+
if (is_array($curr)) {
|
107 |
+
$curr['volume'] = $line_match[2];
|
108 |
+
}
|
109 |
+
break;
|
110 |
+
|
111 |
+
// Virtual device
|
112 |
+
case 'Virtual Device':
|
113 |
+
if (is_array($curr)) {
|
114 |
+
$curr['virtual_device'] = $line_match[2];
|
115 |
+
}
|
116 |
+
break;
|
117 |
+
|
118 |
+
// Where it might be mounted
|
119 |
+
case 'Mount Directory':
|
120 |
+
if (is_array($curr)) {
|
121 |
+
$curr['mount_directory'] = $line_match[2];
|
122 |
+
}
|
123 |
+
break;
|
124 |
+
|
125 |
+
// Size of it
|
126 |
+
case 'Size':
|
127 |
+
if (is_array($curr)) {
|
128 |
+
$curr['size'] = $line_match[2];
|
129 |
+
}
|
130 |
+
break;
|
131 |
+
|
132 |
+
// Is it read only?
|
133 |
+
case 'Read-Only':
|
134 |
+
if (is_array($curr)) {
|
135 |
+
$curr['read_only'] = $line_match[2];
|
136 |
+
}
|
137 |
+
break;
|
138 |
+
|
139 |
+
// We deliberately ignore most keys for security reasons
|
140 |
+
default:
|
141 |
+
continue;
|
142 |
+
break;
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
+
// Save a remaining one
|
147 |
+
if (is_array($curr) && count($curr) > 0) {
|
148 |
+
$this->_res[] = $curr;
|
149 |
+
}
|
150 |
+
|
151 |
+
// Apparent success
|
152 |
+
return true;
|
153 |
+
}
|
154 |
+
|
155 |
+
// Called to get working
|
156 |
+
public function work()
|
157 |
+
{
|
158 |
+
$this->_call();
|
159 |
+
}
|
160 |
+
|
161 |
+
// Get result. Essentially take results and make it usable by the Common::createTable function
|
162 |
+
public function result()
|
163 |
+
{
|
164 |
+
|
165 |
+
// Don't bother if it didn't go well
|
166 |
+
if ($this->_res == false) {
|
167 |
+
return false;
|
168 |
+
}
|
169 |
+
|
170 |
+
// it did; continue
|
171 |
+
else {
|
172 |
+
|
173 |
+
// Store rows here
|
174 |
+
$rows = array();
|
175 |
+
|
176 |
+
// start off volume list
|
177 |
+
$rows[] = array(
|
178 |
+
'type' => 'header',
|
179 |
+
'columns' => array(
|
180 |
+
'Slot',
|
181 |
+
'Volume',
|
182 |
+
'Virtual Device',
|
183 |
+
'Mount Point',
|
184 |
+
'Size',
|
185 |
+
'Read Only',
|
186 |
+
),
|
187 |
+
);
|
188 |
+
|
189 |
+
// show volumes if we have them
|
190 |
+
if (count($this->_res) == 0) {
|
191 |
+
$rows[] = array('type' => 'none', 'columns' => array(array(6, 'None found')));
|
192 |
+
} else {
|
193 |
+
foreach ((array) $this->_res as $vol) {
|
194 |
+
$rows[] = array(
|
195 |
+
'type' => 'values',
|
196 |
+
'columns' => array(
|
197 |
+
$vol['slot'],
|
198 |
+
$vol['volume'],
|
199 |
+
$vol['virtual_device'],
|
200 |
+
$vol['mount_directory'],
|
201 |
+
$vol['size'],
|
202 |
+
$vol['read_only'],
|
203 |
+
),
|
204 |
+
);
|
205 |
+
}
|
206 |
+
}
|
207 |
+
|
208 |
+
// Give info
|
209 |
+
return array(
|
210 |
+
'root_title' => 'Truecrypt Volumes',
|
211 |
+
'rows' => $rows,
|
212 |
+
);
|
213 |
+
}
|
214 |
+
}
|
215 |
+
}
|
lib/Linfo/Extension/Utorrent.php
ADDED
@@ -0,0 +1,297 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
|
5 |
+
This connects to the web ui provided by utorrent headless for Linux. It works
|
6 |
+
by forging the HTTP requests, essentially pretending it's a web browser.
|
7 |
+
|
8 |
+
Requires libcurl extension. (apt-get install php5-curl)
|
9 |
+
|
10 |
+
To enable this extension, add/tweak the following to your config.inc.php
|
11 |
+
|
12 |
+
$settings['extensions']['utorrent'] = true;
|
13 |
+
$settings['utorrent_connection'] = array(
|
14 |
+
'host' => 'localhost',
|
15 |
+
'port' => 8080,
|
16 |
+
'user' => 'admin',
|
17 |
+
'pass' => ''
|
18 |
+
);
|
19 |
+
|
20 |
+
Optionally, you can add multiple regexes to filter torrents. Use something
|
21 |
+
like the following to strip out torrents with XXX in their name:
|
22 |
+
|
23 |
+
$settings['utorrent_filter'] = array(
|
24 |
+
'/XXX/i'
|
25 |
+
);
|
26 |
+
|
27 |
+
Set the following to not show torrent names and just show the hashes
|
28 |
+
|
29 |
+
$settings['utorrent_hide_name'] = true;
|
30 |
+
|
31 |
+
*/
|
32 |
+
|
33 |
+
/*
|
34 |
+
|
35 |
+
Known to work with this verson of uTorrent:
|
36 |
+
Product Version 3.3
|
37 |
+
Source Revision 30235
|
38 |
+
Build Date 2013-10-14 10:42:53 -0700
|
39 |
+
UI Revision 30235
|
40 |
+
|
41 |
+
*/
|
42 |
+
|
43 |
+
/**
|
44 |
+
* This file is part of Linfo (c) 2014 Joseph Gillotti.
|
45 |
+
*
|
46 |
+
* Linfo is free software: you can redistribute it and/or modify
|
47 |
+
* it under the terms of the GNU General Public License as published by
|
48 |
+
* the Free Software Foundation, either version 3 of the License, or
|
49 |
+
* (at your option) any later version.
|
50 |
+
*
|
51 |
+
* Linfo is distributed in the hope that it will be useful,
|
52 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
53 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
54 |
+
* GNU General Public License for more details.
|
55 |
+
*
|
56 |
+
* You should have received a copy of the GNU General Public License
|
57 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
58 |
+
*/
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Keep out hackers...
|
62 |
+
*/
|
63 |
+
namespace Linfo\Extension;
|
64 |
+
|
65 |
+
use Linfo\Linfo;
|
66 |
+
use Linfo\Common;
|
67 |
+
use Linfo\Meta\Errors;
|
68 |
+
use Linfo\Meta\Timer;
|
69 |
+
use Linfo\Output\Html;
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Get status on torrents running under uTorrent.
|
73 |
+
*/
|
74 |
+
class Utorrent implements Extension
|
75 |
+
{
|
76 |
+
private
|
77 |
+
$torrents = array(),
|
78 |
+
$connectionSettings = array(),
|
79 |
+
$stats = array('uploaded' => 0, 'downloaded' => 0),
|
80 |
+
$cookiefile = false,
|
81 |
+
$res = false;
|
82 |
+
|
83 |
+
// Keys corresponding to json array returned by utorrent.
|
84 |
+
// Ripped from utorrent/web/js/webui/constants.js. If this extension stops working
|
85 |
+
// they probably changed the keys in that file. Kindly fix this dictionary using that file plox and submit a patch ;)
|
86 |
+
protected static $torrent_keys = array(
|
87 |
+
'TORRENT_HASH' => 0,
|
88 |
+
'TORRENT_STATUS' => 1,
|
89 |
+
'TORRENT_NAME' => 2,
|
90 |
+
'TORRENT_SIZE' => 3, // bytes
|
91 |
+
'TORRENT_PROGRESS' => 4,
|
92 |
+
'TORRENT_DOWNLOADED' => 5, // bytes out of size
|
93 |
+
'TORRENT_UPLOADED' => 6,
|
94 |
+
'TORRENT_RATIO' => 7,
|
95 |
+
'TORRENT_UPSPEED' => 8,
|
96 |
+
'TORRENT_DOWNSPEED' => 9,
|
97 |
+
'TORRENT_ETA' => 10,
|
98 |
+
'TORRENT_LABEL' => 11,
|
99 |
+
'TORRENT_PEERS_CONNECTED' => 12,
|
100 |
+
'TORRENT_PEERS_SWARM' => 13,
|
101 |
+
'TORRENT_SEEDS_CONNECTED' => 14,
|
102 |
+
'TORRENT_SEEDS_SWARM' => 15,
|
103 |
+
'TORRENT_AVAILABILITY' => 16,
|
104 |
+
'TORRENT_QUEUE_POSITION' => 17,
|
105 |
+
'TORRENT_REMAINING' => 18,
|
106 |
+
'TORRENT_DOWNLOAD_URL' => 19,
|
107 |
+
'TORRENT_RSS_FEED_URL' => 20,
|
108 |
+
'TORRENT_STATUS_MESSAGE' => 21,
|
109 |
+
'TORRENT_STREAM_ID' => 22,
|
110 |
+
'TORRENT_DATE_ADDED' => 23,
|
111 |
+
'TORRENT_DATE_COMPLETED' => 24,
|
112 |
+
'TORRENT_APP_UPDATE_URL' => 25,
|
113 |
+
'TORRENT_SAVE_PATH' => 26,
|
114 |
+
);
|
115 |
+
|
116 |
+
// First we log in to token.html using our admin/password. This gives us a token hash and
|
117 |
+
// cookie used for subsequent requests. Then we use these details to access the json list of torrents
|
118 |
+
const
|
119 |
+
TOKEN_URL = 'http://%s:%s/gui/token.html',
|
120 |
+
LIST_URL = 'http://%s:%s/gui/?token=%s&list=%s';
|
121 |
+
|
122 |
+
public function __construct(Linfo $linfo)
|
123 |
+
{
|
124 |
+
$settings = $linfo->getSettings();
|
125 |
+
$this->connectionSettings = $settings['utorrent_connection'];
|
126 |
+
$this->regexFilters = isset($settings['utorrent_filter']) && is_array($settings['utorrent_filter']) ? $settings['utorrent_filter'] : array();
|
127 |
+
$this->hideName = isset($settings['utorrent_hide_name']) ? !empty($settings['utorrent_hide_name']) : false;
|
128 |
+
}
|
129 |
+
|
130 |
+
public function work()
|
131 |
+
{
|
132 |
+
$t = new Timer('utorrent extension');
|
133 |
+
|
134 |
+
$this->res = false;
|
135 |
+
|
136 |
+
if (!extension_loaded('curl')) {
|
137 |
+
Errors::add('utorrent extension', 'Curl PHP extension not installed');
|
138 |
+
|
139 |
+
return;
|
140 |
+
}
|
141 |
+
|
142 |
+
if (!isset($this->connectionSettings['host']) || !isset($this->connectionSettings['port']) || !isset($this->connectionSettings['user'])) {
|
143 |
+
Errors::add('utorrent extension', 'Missing $setting[\'utorrent_connection\'] details in config..');
|
144 |
+
|
145 |
+
return;
|
146 |
+
}
|
147 |
+
|
148 |
+
$token_url = sprintf(self::TOKEN_URL, $this->connectionSettings['host'], $this->connectionSettings['port']);
|
149 |
+
|
150 |
+
// Start up our curl session to be used for both requests. It is going to store the cookies utorrent
|
151 |
+
// uses
|
152 |
+
$curl = curl_init();
|
153 |
+
|
154 |
+
// For curl to actually process cokies we need to give it a filename. This should be filed as a
|
155 |
+
// bug to curl, especially since something like /dev/null works
|
156 |
+
$this->cookiefile = tempnam('/tmp', 'linfo_utorrent');
|
157 |
+
|
158 |
+
curl_setopt_array($curl, array(
|
159 |
+
CURLOPT_RETURNTRANSFER => true,
|
160 |
+
CURLOPT_USERPWD => $this->connectionSettings['user'].':',
|
161 |
+
CURLOPT_COOKIEJAR => $this->cookiefile ?: '/dev/null', // If tempnam fails this will fail on Windows
|
162 |
+
));
|
163 |
+
|
164 |
+
// Get token
|
165 |
+
curl_setopt($curl, CURLOPT_URL, $token_url);
|
166 |
+
$result = curl_exec($curl);
|
167 |
+
|
168 |
+
if (preg_match('/\>([^<]+)\</', $result, $m)) {
|
169 |
+
$token = $m[1];
|
170 |
+
} else {
|
171 |
+
Errors::add('utorrent extension', 'Failed parsing token');
|
172 |
+
$this->cleanup();
|
173 |
+
|
174 |
+
return;
|
175 |
+
}
|
176 |
+
|
177 |
+
// Get list of torrents? Do our best to forge this (ajax) request
|
178 |
+
curl_setopt_array($curl, array(
|
179 |
+
CURLOPT_HTTPHEADER => array(
|
180 |
+
'X-Requested-With: XMLHttpRequest',
|
181 |
+
'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:28.0) Gecko/20100101 Firefox/28.0',
|
182 |
+
'Host: '.$this->connectionSettings['host'].($this->connectionSettings['port'] != 80 ? ':'.$this->connectionSettings['port'] : ''),
|
183 |
+
'Referer: http://'.$this->connectionSettings['host'].($this->connectionSettings['port'] != 80 ? ':'.$this->connectionSettings['port'] : '').'/gui/web/index.html',
|
184 |
+
),
|
185 |
+
));
|
186 |
+
|
187 |
+
$list_url = sprintf(self::LIST_URL, $this->connectionSettings['host'], $this->connectionSettings['port'], $token, '1');
|
188 |
+
curl_setopt($curl, CURLOPT_URL, $list_url);
|
189 |
+
|
190 |
+
$result = curl_exec($curl);
|
191 |
+
|
192 |
+
if (!($response = @json_decode($result, true))) {
|
193 |
+
Errors::add('utorrent extension', 'Failed parsing json object');
|
194 |
+
$this->cleanup();
|
195 |
+
|
196 |
+
return;
|
197 |
+
}
|
198 |
+
|
199 |
+
// Not going to be needing curl again
|
200 |
+
curl_close($curl);
|
201 |
+
|
202 |
+
if (!isset($response['torrents']) || !is_array($response['torrents'])) {
|
203 |
+
Errors::add('utorrent extension', 'torrents array key not found in json response object');
|
204 |
+
$this->cleanup();
|
205 |
+
|
206 |
+
return;
|
207 |
+
}
|
208 |
+
|
209 |
+
$torrent_names = array();
|
210 |
+
$torrent_states = array();
|
211 |
+
|
212 |
+
foreach ($response['torrents'] as $torrent_src) {
|
213 |
+
$torrent = array();
|
214 |
+
foreach (self::$torrent_keys as $key => $index) {
|
215 |
+
$torrent[$key] = $torrent_src[$index];
|
216 |
+
}
|
217 |
+
|
218 |
+
foreach ($this->regexFilters as $regex) {
|
219 |
+
if (preg_match($regex, $torrent['TORRENT_NAME'])) {
|
220 |
+
continue 2;
|
221 |
+
}
|
222 |
+
}
|
223 |
+
|
224 |
+
$this->torrents[] = $torrent;
|
225 |
+
$torrent_names[] = $torrent['TORRENT_NAME'];
|
226 |
+
$torrent_states[] = $torrent['TORRENT_STATUS_MESSAGE'];
|
227 |
+
|
228 |
+
$this->stats['downloaded'] += $torrent['TORRENT_DOWNLOADED'];
|
229 |
+
$this->stats['uploaded'] += $torrent['TORRENT_UPLOADED'];
|
230 |
+
}
|
231 |
+
|
232 |
+
// Sort by state and then name ascending (show downloading/etc first)
|
233 |
+
array_multisort($torrent_states, SORT_ASC,
|
234 |
+
$torrent_names, SORT_ASC, $this->torrents);
|
235 |
+
|
236 |
+
$this->res = true;
|
237 |
+
$this->cleanup();
|
238 |
+
}
|
239 |
+
|
240 |
+
public function result()
|
241 |
+
{
|
242 |
+
if (!$this->res) {
|
243 |
+
return false;
|
244 |
+
}
|
245 |
+
|
246 |
+
$rows[] = array(
|
247 |
+
'type' => 'header',
|
248 |
+
'columns' => array(
|
249 |
+
'Torrent/hash'.($this->hideName ? ' (names hidden)' : ''),
|
250 |
+
'Size',
|
251 |
+
'Progress',
|
252 |
+
'Status',
|
253 |
+
'Seeds',
|
254 |
+
'Peers',
|
255 |
+
'Downloaded',
|
256 |
+
'Uploaded',
|
257 |
+
'Ratio',
|
258 |
+
'Speeds',
|
259 |
+
),
|
260 |
+
);
|
261 |
+
|
262 |
+
foreach ($this->torrents as $name => $info) {
|
263 |
+
$rows[] = array(
|
264 |
+
'type' => 'values',
|
265 |
+
'columns' => array(
|
266 |
+
($this->hideName ? '' : $info['TORRENT_NAME'].'<br />')
|
267 |
+
.'<span style="font-size: 80%; font-family: monaco, monospace, courier;">'.$info['TORRENT_HASH'].'</span>',
|
268 |
+
Common::byteConvert($info['TORRENT_SIZE']),
|
269 |
+
Html::generateBarChart($info['TORRENT_PROGRESS'] / 10),
|
270 |
+
$info['TORRENT_STATUS_MESSAGE'],
|
271 |
+
$info['TORRENT_SEEDS_CONNECTED'].'/'.$info['TORRENT_SEEDS_SWARM'],
|
272 |
+
$info['TORRENT_SEEDS_CONNECTED'].'/'.$info['TORRENT_PEERS_SWARM'],
|
273 |
+
Common::byteConvert($info['TORRENT_DOWNLOADED']),
|
274 |
+
Common::byteConvert($info['TORRENT_UPLOADED']),
|
275 |
+
$info['TORRENT_RATIO'] > 0 ? (round($info['TORRENT_RATIO'] / 1000, 2) ?: '0.0') : '0.0',
|
276 |
+
Common::byteConvert($info['TORRENT_DOWNSPEED']).'/s ↓ '.
|
277 |
+
Common::byteConvert($info['TORRENT_UPSPEED']).'/s ↑ ',
|
278 |
+
),
|
279 |
+
);
|
280 |
+
}
|
281 |
+
|
282 |
+
// Give it off
|
283 |
+
return array(
|
284 |
+
'root_title' => 'µTorrent <span style="font-size: 80%;">('.Common::byteConvert($this->stats['downloaded']).' ↓ '
|
285 |
+
.Common::byteConvert($this->stats['uploaded']).' ↑ '.round($this->stats['uploaded'] / $this->stats['downloaded'], 2).' ratio)</span>',
|
286 |
+
'rows' => $rows,
|
287 |
+
);
|
288 |
+
}
|
289 |
+
|
290 |
+
private function cleanup()
|
291 |
+
{
|
292 |
+
// If we succeeded creating that temp file kill it off
|
293 |
+
if ($this->cookiefile && is_file($this->cookiefile)) {
|
294 |
+
@unlink($this->cookiefile);
|
295 |
+
}
|
296 |
+
}
|
297 |
+
}
|
lib/Linfo/Lang/de.php
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Lang;
|
22 |
+
|
23 |
+
/*
|
24 |
+
* German translation
|
25 |
+
*/
|
26 |
+
|
27 |
+
return array(
|
28 |
+
'header' => 'Systeminformationen',
|
29 |
+
'core' => 'Kern',
|
30 |
+
'os' => 'OS',
|
31 |
+
'kernel' => 'Kernel',
|
32 |
+
'accessed_ip' => 'Adapter-IP',
|
33 |
+
'uptime' => 'Uptime',
|
34 |
+
'hostname' => 'Hostname',
|
35 |
+
'cpus' => 'CPUs',
|
36 |
+
'phpversion' => 'PHP-Version',
|
37 |
+
'webservice' => 'HTTP-Server',
|
38 |
+
'load' => 'Auslastung/Load',
|
39 |
+
'processes' => 'Prozesse',
|
40 |
+
'threads' => 'Threads',
|
41 |
+
'total' => 'Summe',
|
42 |
+
'memory' => 'Speicher',
|
43 |
+
'type' => 'Typ',
|
44 |
+
'free' => 'Frei',
|
45 |
+
'used' => 'Belegt',
|
46 |
+
'size' => 'Größe',
|
47 |
+
'physical' => 'Physikalisch',
|
48 |
+
'swap' => 'Auslagerungspartition',
|
49 |
+
'network_devices' => 'Netzwerkgeräte',
|
50 |
+
'device_name' => 'Gerätename',
|
51 |
+
'amount_sent' => 'Gesendet',
|
52 |
+
'amount_received' => 'Empfangen',
|
53 |
+
'state' => 'Zustand',
|
54 |
+
'temps_voltages' => 'Temperaturen / Spannungen',
|
55 |
+
'path' => 'Pfad',
|
56 |
+
'device' => 'Gerät',
|
57 |
+
'value' => 'Wert',
|
58 |
+
'hardware' => 'Hardware',
|
59 |
+
'vendor' => 'Hersteller',
|
60 |
+
'drives' => 'Festplatten',
|
61 |
+
'name' => 'Name',
|
62 |
+
'reads' => 'Lesezugriffe',
|
63 |
+
'writes' => 'Schreibzugriffe',
|
64 |
+
'filesystem_mounts' => 'Eingehängte Datenträger',
|
65 |
+
'mount_point' => 'Einhängepunkte',
|
66 |
+
'filesystem' => 'Dateisystem',
|
67 |
+
'percent_used' => 'Prozent belegt',
|
68 |
+
'raid_arrays' => 'RAID Arrays',
|
69 |
+
'level' => 'Level',
|
70 |
+
'status' => 'Status',
|
71 |
+
'devices' => 'Geräte',
|
72 |
+
'label' => 'Label',
|
73 |
+
'active' => 'Activ',
|
74 |
+
'batteries' => 'Batterien',
|
75 |
+
'charge' => 'Laden',
|
76 |
+
'unknown' => 'Unbekannt',
|
77 |
+
'footer_app' => 'Von %s in %s Sekunden generiert.',
|
78 |
+
'none_found' => 'Keine gefunden',
|
79 |
+
'sound_cards' => 'Soundkarten',
|
80 |
+
'number' => 'Nummer',
|
81 |
+
'card' => 'Karte',
|
82 |
+
'message' => 'Nachricht',
|
83 |
+
'from_where' => 'Quelle',
|
84 |
+
'mount_options' => 'Einhängeoptionen',
|
85 |
+
'error_head' => 'Fehler beim Sammeln der Daten',
|
86 |
+
'timer' => 'Timer',
|
87 |
+
'area' => 'Bereich',
|
88 |
+
'time_taken' => 'Zum Holen benötigte Zeit',
|
89 |
+
'days' => 'Tage',
|
90 |
+
'hours' => 'Stunden',
|
91 |
+
'minutes' => 'Minuten',
|
92 |
+
'seconds' => 'Sekunden',
|
93 |
+
'pid' => 'PID',
|
94 |
+
'service' => 'Dienst',
|
95 |
+
'services' => 'Dienste',
|
96 |
+
'memory_usage' => 'Speichernutzung',
|
97 |
+
'distro' => 'Distribution',
|
98 |
+
'cpu_arch' => 'Architektur',
|
99 |
+
'model' => 'Modell',
|
100 |
+
'numLoggedIn' => 'Aktive Benutzer',
|
101 |
+
);
|
lib/Linfo/Lang/en.php
ADDED
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Lang;
|
22 |
+
|
23 |
+
/*
|
24 |
+
* English translation
|
25 |
+
*/
|
26 |
+
|
27 |
+
return array(
|
28 |
+
'header' => 'System Health and Information',
|
29 |
+
'core' => 'Core',
|
30 |
+
'os' => 'OS',
|
31 |
+
'kernel' => 'Kernel',
|
32 |
+
'accessed_ip' => 'Accessed IP',
|
33 |
+
'uptime' => 'Uptime',
|
34 |
+
'hostname' => 'Hostname',
|
35 |
+
'cpus' => 'CPUs',
|
36 |
+
'phpversion' => 'PHP version',
|
37 |
+
'webservice' => 'HTTP server',
|
38 |
+
'load' => 'Load',
|
39 |
+
'processes' => 'Processes',
|
40 |
+
'threads' => 'Threads',
|
41 |
+
'total' => 'Total',
|
42 |
+
'memory' => 'Memory',
|
43 |
+
'type' => 'Type',
|
44 |
+
'free' => 'Free',
|
45 |
+
'used' => 'Used',
|
46 |
+
'size' => 'Size',
|
47 |
+
'physical' => 'Physical',
|
48 |
+
'swap' => 'Swap',
|
49 |
+
'network_devices' => 'Network Devices',
|
50 |
+
'device_name' => 'Device Name',
|
51 |
+
'amount_sent' => 'Amount Sent',
|
52 |
+
'amount_received' => 'Amount Received',
|
53 |
+
'state' => 'State',
|
54 |
+
'temps_voltages' => 'Temperatures / Voltages',
|
55 |
+
'path' => 'Path',
|
56 |
+
'device' => 'Device',
|
57 |
+
'value' => 'Value',
|
58 |
+
'hardware' => 'Hardware',
|
59 |
+
'vendor' => 'Vendor',
|
60 |
+
'drives' => 'Drives',
|
61 |
+
'name' => 'Name',
|
62 |
+
'reads' => 'Reads',
|
63 |
+
'writes' => 'Writes',
|
64 |
+
'filesystem_mounts' => 'Filesystem Mounts',
|
65 |
+
'mount_point' => 'Mount Point',
|
66 |
+
'filesystem' => 'Filesystem',
|
67 |
+
'percent_used' => 'Percent Used',
|
68 |
+
'raid_arrays' => 'RAID Arrays',
|
69 |
+
'level' => 'Level',
|
70 |
+
'status' => 'Status',
|
71 |
+
'devices' => 'Devices',
|
72 |
+
'label' => 'Label',
|
73 |
+
'active' => 'Active',
|
74 |
+
'batteries' => 'Batteries',
|
75 |
+
'charge' => 'Charge',
|
76 |
+
'unknown' => 'Unknown',
|
77 |
+
'footer_app' => 'Generated by %s in %s seconds.',
|
78 |
+
'none_found' => 'None Found',
|
79 |
+
'sound_cards' => 'Sound Cards',
|
80 |
+
'number' => 'Number',
|
81 |
+
'card' => 'Card',
|
82 |
+
'message' => 'Message',
|
83 |
+
'from_where' => 'Source',
|
84 |
+
'mount_options' => 'Mount Options',
|
85 |
+
'error_head' => 'Data Gathering Errors',
|
86 |
+
'timer' => 'Timer',
|
87 |
+
'area' => 'Area',
|
88 |
+
'time_taken' => 'Time taken to fetch',
|
89 |
+
'days' => 'days',
|
90 |
+
'years' => 'years',
|
91 |
+
'hours' => 'hours',
|
92 |
+
'minutes' => 'minutes',
|
93 |
+
'seconds' => 'seconds',
|
94 |
+
'pid' => 'PID',
|
95 |
+
'service' => 'Service',
|
96 |
+
'services' => 'Services',
|
97 |
+
'memory_usage' => 'Memory Usage',
|
98 |
+
'distro' => 'Distribution',
|
99 |
+
'cpu_arch' => 'Architecture',
|
100 |
+
'model' => 'Model',
|
101 |
+
'numLoggedIn' => 'Active Users',
|
102 |
+
'virtualization' => 'Virtualization',
|
103 |
+
'guest' => 'Guest',
|
104 |
+
'host' => 'Host',
|
105 |
+
'cpu_usage' => 'Overall CPU Usage',
|
106 |
+
'port_speed' => 'Port Speed',
|
107 |
+
);
|
lib/Linfo/Lang/fi.php
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Lang;
|
22 |
+
|
23 |
+
/*
|
24 |
+
* Finnish translation
|
25 |
+
*/
|
26 |
+
|
27 |
+
return array(
|
28 |
+
'header' => 'Järjestelmän kunto ja asetuksetn',
|
29 |
+
'core' => 'Perustiedot',
|
30 |
+
'os' => 'Käyttôjärjestelmä',
|
31 |
+
'kernel' => 'Kernel',
|
32 |
+
'accessed_ip' => 'IP osoite',
|
33 |
+
'uptime' => 'Käynnissä',
|
34 |
+
'hostname' => 'Nimi',
|
35 |
+
'cpus' => 'CPUt',
|
36 |
+
'phpversion' => 'PHP versio',
|
37 |
+
'webservice' => 'HTTP-palvelin',
|
38 |
+
'load' => 'Kuorma',
|
39 |
+
'processes' => 'Prosessit',
|
40 |
+
'threads' => 'Säikeitä',
|
41 |
+
'total' => 'Yhteensä',
|
42 |
+
'memory' => 'Muisti',
|
43 |
+
'type' => 'Tyyppi',
|
44 |
+
'free' => 'Vapaana',
|
45 |
+
'used' => 'Käytetty',
|
46 |
+
'size' => 'Koko',
|
47 |
+
'physical' => 'Fyysinen',
|
48 |
+
'swap' => 'Swap',
|
49 |
+
'network_devices' => 'Verkkolaitteet',
|
50 |
+
'device_name' => 'Laitenimi',
|
51 |
+
'amount_sent' => 'Lähetetty',
|
52 |
+
'amount_received' => 'Saapunut',
|
53 |
+
'state' => 'Tila',
|
54 |
+
'temps_voltages' => 'Lämpôtila / Jännitteet',
|
55 |
+
'path' => 'Polku',
|
56 |
+
'device' => 'Laite',
|
57 |
+
'value' => 'Arvo',
|
58 |
+
'hardware' => 'Kovo',
|
59 |
+
'vendor' => 'Valmistaja',
|
60 |
+
'type' => 'Tytppi',
|
61 |
+
'drives' => 'Asemat',
|
62 |
+
'name' => 'Nimi',
|
63 |
+
'reads' => 'Luettu',
|
64 |
+
'writes' => 'Kirjoitettu',
|
65 |
+
'size' => 'Koko',
|
66 |
+
'filesystem_mounts' => 'Tietojärjestelmät',
|
67 |
+
'mount_point' => 'Liitospiste',
|
68 |
+
'filesystem' => 'Tietojärjestelmä',
|
69 |
+
'used' => 'Käytetty',
|
70 |
+
'free' => 'Vapaana',
|
71 |
+
'percent_used' => 'Käytetty %',
|
72 |
+
'raid_arrays' => 'RAID pakat',
|
73 |
+
'level' => 'Taso',
|
74 |
+
'status' => 'Status',
|
75 |
+
'devices' => 'Asemat',
|
76 |
+
'label' => 'Label',
|
77 |
+
'active' => 'Aktivoitu',
|
78 |
+
'batteries' => 'Patterit',
|
79 |
+
'charge' => 'Lataus',
|
80 |
+
'unknown' => 'Tuntematon',
|
81 |
+
'footer_app' => 'Luotu: %s aika %s sekunttia.',
|
82 |
+
'none_found' => 'Ei osumia',
|
83 |
+
'sound_cards' => 'äänikortit',
|
84 |
+
'number' => 'Numero',
|
85 |
+
'card' => 'Kortti',
|
86 |
+
'message' => 'Viesti',
|
87 |
+
'from_where' => 'Lähde',
|
88 |
+
'mount_options' => 'Liitos optiot',
|
89 |
+
'error_head' => 'Virheet datan noudossa',
|
90 |
+
'timer' => 'Ajastin',
|
91 |
+
'area' => 'Area',
|
92 |
+
'time_taken' => 'Haun kesto',
|
93 |
+
'days' => 'päivää',
|
94 |
+
'minutes' => 'minuuttiat',
|
95 |
+
'seconds' => 'sekunttia',
|
96 |
+
'hours' => 'tuntia',
|
97 |
+
'pid' => 'PID',
|
98 |
+
'service' => 'Palvelu',
|
99 |
+
'services' => 'Palvelut',
|
100 |
+
'memory_usage' => 'Muistin käyttô',
|
101 |
+
'distro' => 'Jakelu',
|
102 |
+
'cpu_arch' => 'Arkkitektuuri',
|
103 |
+
'model' => 'Malli',
|
104 |
+
);
|
lib/Linfo/Lang/fr.php
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Lang;
|
22 |
+
|
23 |
+
/*
|
24 |
+
* Traduction française : Jean-Bernard Yata yata.jb@revolsys.fr
|
25 |
+
*/
|
26 |
+
|
27 |
+
return array(
|
28 |
+
'header' => 'Informations Générales du Système',
|
29 |
+
'core' => 'Principal',
|
30 |
+
'os' => 'Système d\'exploitation',
|
31 |
+
'kernel' => 'Noyau',
|
32 |
+
'accessed_ip' => 'Adresse IP utilisée',
|
33 |
+
'uptime' => 'Uptime',
|
34 |
+
'hostname' => 'Nom d\'hôte',
|
35 |
+
'cpus' => 'Processeur(s)',
|
36 |
+
'phpversion' => 'version de PHP',
|
37 |
+
'webservice' => 'serveur HTTP',
|
38 |
+
'load' => 'Charge',
|
39 |
+
'processes' => 'Processus',
|
40 |
+
'threads' => 'Opérations en cours',
|
41 |
+
'total' => 'Totale',
|
42 |
+
'memory' => 'Mémoire',
|
43 |
+
'type' => 'Type',
|
44 |
+
'free' => 'Libre',
|
45 |
+
'used' => 'Utilisée',
|
46 |
+
'size' => 'Taille',
|
47 |
+
'physical' => 'Physique',
|
48 |
+
'swap' => 'Echange',
|
49 |
+
'network_devices' => 'Interfaces réseau',
|
50 |
+
'device_name' => 'Interface',
|
51 |
+
'amount_sent' => 'Paquets envoyés',
|
52 |
+
'amount_received' => 'Paquets reçus',
|
53 |
+
'state' => 'Etat',
|
54 |
+
'temps_voltages' => 'Températures / Voltages',
|
55 |
+
'path' => 'Chemin système',
|
56 |
+
'device' => 'équipement',
|
57 |
+
'value' => 'Valeur',
|
58 |
+
'hardware' => 'Matériel',
|
59 |
+
'vendor' => 'Fabriquant',
|
60 |
+
'drives' => 'Lecteurs',
|
61 |
+
'name' => 'Nom',
|
62 |
+
'reads' => 'Cycles de lecture',
|
63 |
+
'writes' => 'Cycle d\'écriture',
|
64 |
+
'filesystem_mounts' => 'Points de montage',
|
65 |
+
'mount_point' => 'Point de montage',
|
66 |
+
'filesystem' => 'Système de fichiers',
|
67 |
+
'percent_used' => '% utilisé',
|
68 |
+
'raid_arrays' => 'Volumes RAID',
|
69 |
+
'level' => 'Niveau',
|
70 |
+
'status' => 'Etat',
|
71 |
+
'devices' => 'Périphériques',
|
72 |
+
'label' => 'Etiquette',
|
73 |
+
'active' => 'Active',
|
74 |
+
'batteries' => 'Batteries',
|
75 |
+
'charge' => 'Charge',
|
76 |
+
'unknown' => 'Non renseigné',
|
77 |
+
'footer_app' => 'Générée le %s en %s secondes.',
|
78 |
+
'none_found' => 'Introuvé',
|
79 |
+
'sound_cards' => 'Cartes son',
|
80 |
+
'number' => 'Nombre',
|
81 |
+
'card' => 'Carte',
|
82 |
+
'message' => 'Message',
|
83 |
+
'from_where' => 'Source',
|
84 |
+
'mount_options' => 'Options de montage',
|
85 |
+
'error_head' => 'Erreur lors de la collecte des informations',
|
86 |
+
'timer' => 'Horodateur',
|
87 |
+
'area' => 'Zone',
|
88 |
+
'time_taken' => 'Durée de collecte',
|
89 |
+
'days' => 'jours',
|
90 |
+
'hours' => 'heures',
|
91 |
+
'minutes' => 'minutes',
|
92 |
+
'seconds' => 'secondes',
|
93 |
+
'pid' => 'PID',
|
94 |
+
'service' => 'Service',
|
95 |
+
'services' => 'Services',
|
96 |
+
'memory_usage' => 'Utilisation mémoire',
|
97 |
+
'distro' => 'Distribution',
|
98 |
+
'cpu_arch' => 'Architecture',
|
99 |
+
'model' => 'Modèle',
|
100 |
+
'numLoggedIn' => 'Utilisateurs actifs',
|
101 |
+
);
|
lib/Linfo/Lang/it.php
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Lang;
|
22 |
+
|
23 |
+
/*
|
24 |
+
* Italian translation
|
25 |
+
* By mte90 - http://www.mte90.net
|
26 |
+
*/
|
27 |
+
|
28 |
+
return array(
|
29 |
+
'header' => 'Informazioni e Stato del Sistema',
|
30 |
+
'core' => 'Sistema',
|
31 |
+
'os' => 'SO',
|
32 |
+
'kernel' => 'Kernel',
|
33 |
+
'accessed_ip' => 'IP',
|
34 |
+
'uptime' => 'Uptime',
|
35 |
+
'hostname' => 'Hostname',
|
36 |
+
'cpus' => 'CPU',
|
37 |
+
'phpversion' => 'versione di PHP',
|
38 |
+
'webservice' => 'server HTTP',
|
39 |
+
'load' => 'Carico',
|
40 |
+
'processes' => 'Processi',
|
41 |
+
'threads' => 'Thread',
|
42 |
+
'total' => 'Totale',
|
43 |
+
'memory' => 'Memoria',
|
44 |
+
'type' => 'Tipo',
|
45 |
+
'free' => 'Libero',
|
46 |
+
'used' => 'Usato',
|
47 |
+
'size' => 'Dimensioni',
|
48 |
+
'physical' => 'Physical',
|
49 |
+
'swap' => 'Swap',
|
50 |
+
'network_devices' => 'Dispositivi di Rete',
|
51 |
+
'device_name' => 'Nome Dispositivo',
|
52 |
+
'amount_sent' => 'Totale Inviato',
|
53 |
+
'amount_received' => 'Totale Ricevuto',
|
54 |
+
'state' => 'Stato',
|
55 |
+
'temps_voltages' => 'Temperatura / Voltaggio',
|
56 |
+
'path' => 'Percorso',
|
57 |
+
'device' => 'Dispositivo',
|
58 |
+
'value' => 'Valore',
|
59 |
+
'hardware' => 'Hardware',
|
60 |
+
'vendor' => 'Produttore',
|
61 |
+
'type' => 'Tipo',
|
62 |
+
'drives' => 'Unità',
|
63 |
+
'name' => 'Nome',
|
64 |
+
'reads' => 'Letture',
|
65 |
+
'writes' => 'Scritture',
|
66 |
+
'size' => 'Dimensioni',
|
67 |
+
'filesystem_mounts' => 'Montaggio FileSystem',
|
68 |
+
'mount_point' => 'Punto di Montaggio',
|
69 |
+
'filesystem' => 'Filesystem',
|
70 |
+
'used' => 'Usato',
|
71 |
+
'free' => 'Libero',
|
72 |
+
'percent_used' => 'Percentuale Usata',
|
73 |
+
'raid_arrays' => 'RAID Array',
|
74 |
+
'level' => 'Livello',
|
75 |
+
'status' => 'Stato',
|
76 |
+
'devices' => 'Dispositivi',
|
77 |
+
'label' => 'Etichetta',
|
78 |
+
'active' => 'Attivo',
|
79 |
+
'batteries' => 'Batterie',
|
80 |
+
'charge' => 'Caricamento',
|
81 |
+
'unknown' => 'Sconosciuto',
|
82 |
+
'footer_app' => 'Generatato da %s in %s secondi.',
|
83 |
+
'none_found' => 'Nessun risultato',
|
84 |
+
'sound_cards' => 'Schede Audio',
|
85 |
+
'number' => 'Numero',
|
86 |
+
'card' => 'Scheda',
|
87 |
+
'message' => 'Messaggio',
|
88 |
+
'from_where' => 'Sorgente',
|
89 |
+
'mount_options' => 'opzioni di Montaggio',
|
90 |
+
'error_head' => 'Data Gathering Error',
|
91 |
+
'timer' => 'Timer',
|
92 |
+
'area' => 'Area',
|
93 |
+
'time_taken' => 'Tempo usato per la generazione',
|
94 |
+
'days' => 'giorni',
|
95 |
+
'minutes' => 'minuti',
|
96 |
+
'seconds' => 'secondi',
|
97 |
+
'hours' => 'ore',
|
98 |
+
'pid' => 'PID',
|
99 |
+
'service' => 'Servizio',
|
100 |
+
'services' => 'Servizi',
|
101 |
+
'memory_usage' => 'Uso della Memoria',
|
102 |
+
'distro' => 'Distribuzione',
|
103 |
+
'cpu_arch' => 'Architettura',
|
104 |
+
'model' => 'Modello',
|
105 |
+
);
|
lib/Linfo/Lang/pl.php
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Lang;
|
22 |
+
|
23 |
+
/*
|
24 |
+
* Polish translation
|
25 |
+
*/
|
26 |
+
|
27 |
+
return array(
|
28 |
+
'header' => 'Aktualny stan systemu i informacja',
|
29 |
+
'core' => 'Rdzeń',
|
30 |
+
'os' => 'OS',
|
31 |
+
'kernel' => 'Kernel',
|
32 |
+
'accessed_ip' => 'Przydzielone IP',
|
33 |
+
'uptime' => 'Działa',
|
34 |
+
'hostname' => 'Nazwa komputera',
|
35 |
+
'cpus' => 'CPUs',
|
36 |
+
'phpversion' => 'wersja PHP',
|
37 |
+
'webservice' => 'serwer HTTP',
|
38 |
+
'load' => 'Obciążenie',
|
39 |
+
'processes' => 'Procesy',
|
40 |
+
'threads' => 'Wątki',
|
41 |
+
'total' => 'Razem',
|
42 |
+
'memory' => 'Pamięci',
|
43 |
+
'type' => 'Typ',
|
44 |
+
'free' => 'Wolnych',
|
45 |
+
'used' => 'Używanego', //duplicate below
|
46 |
+
'size' => 'Rozmiar', //duplicate below
|
47 |
+
'physical' => 'Fizyczna',
|
48 |
+
'swap' => 'Swap',
|
49 |
+
'network_devices' => 'Urządzenia sieciowe',
|
50 |
+
'device_name' => 'Nazwa urządzenia',
|
51 |
+
'amount_sent' => 'Wysłane',
|
52 |
+
'amount_received' => 'Otrzymane',
|
53 |
+
'state' => 'Stan',
|
54 |
+
'temps_voltages' => 'Temperatura / Napięcie',
|
55 |
+
'path' => 'Ścieżka',
|
56 |
+
'device' => 'Urządzenie',
|
57 |
+
'value' => 'Wartość',
|
58 |
+
'hardware' => 'Sprzęt',
|
59 |
+
'vendor' => 'Dostawca',
|
60 |
+
'drives' => 'Dyski',
|
61 |
+
'name' => 'Nazwa',
|
62 |
+
'reads' => 'Odczytanych',
|
63 |
+
'writes' => 'Zapisanych',
|
64 |
+
'size' => 'Łącznie', //duplicate
|
65 |
+
'filesystem_mounts' => 'Zamonotwany system plików',
|
66 |
+
'mount_point' => 'Punkt montowania',
|
67 |
+
'filesystem' => 'System plików',
|
68 |
+
'used' => 'Użytych',//duplicate
|
69 |
+
'percent_used' => 'Procent zużycia',
|
70 |
+
'raid_arrays' => 'RAID Arrays',
|
71 |
+
'level' => 'Poziom',
|
72 |
+
'status' => 'Stan',
|
73 |
+
'devices' => 'Urządzenia',
|
74 |
+
'label' => 'Etykieta',
|
75 |
+
'active' => 'Aktywne',
|
76 |
+
'batteries' => 'Baterie',
|
77 |
+
'charge' => 'Naładowanie',
|
78 |
+
'unknown' => 'Nieznany',
|
79 |
+
'footer_app' => '%s Wygenerowane przez w sekund %s.',
|
80 |
+
'none_found' => 'Nieznalezione',
|
81 |
+
'sound_cards' => 'Karty dźwiękowe',
|
82 |
+
'number' => 'Numer',
|
83 |
+
'card' => 'Karta',
|
84 |
+
'from_where' => 'Źródło',
|
85 |
+
'message' => 'Wiadomość',
|
86 |
+
'mount_options' => 'Opcje montowania',
|
87 |
+
'error_head' => 'Błędy gromadzenia danych',
|
88 |
+
'timer' => 'Zegar',
|
89 |
+
'area' => 'Strefa',
|
90 |
+
'time_taken' => 'Czas potrzebny do pobierania',
|
91 |
+
'days' => 'dni',
|
92 |
+
'hours' => 'godzina',
|
93 |
+
'minutes' => 'minuta',
|
94 |
+
'seconds' => 'sekund',
|
95 |
+
'pid' => 'PID',
|
96 |
+
'service' => 'Usługa',
|
97 |
+
'services' => 'Usługi',
|
98 |
+
'memory_usage' => 'Zużycie pamięci',
|
99 |
+
'distro' => 'Dystrybucja',
|
100 |
+
'cpu_arch' => 'Architektura',
|
101 |
+
'model' => 'Model', //todo
|
102 |
+
'numLoggedIn' => 'Active Users', //todo
|
103 |
+
);
|
lib/Linfo/Lang/pt.php
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2012 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Lang;
|
22 |
+
|
23 |
+
/*
|
24 |
+
* Portuguese translation
|
25 |
+
* Fábio Diniz Rossi
|
26 |
+
* fdrossi@gmail.com
|
27 |
+
*/
|
28 |
+
|
29 |
+
return array(
|
30 |
+
'header' => 'Informações do Sistema',
|
31 |
+
'core' => 'Hardware',
|
32 |
+
'os' => 'Sistema Operacional',
|
33 |
+
'kernel' => 'Kernel',
|
34 |
+
'accessed_ip' => 'Endereço IP de acesso',
|
35 |
+
'uptime' => 'Tempo Ligado',
|
36 |
+
'hostname' => 'Nome da Máquina',
|
37 |
+
'cpus' => 'CPUs',
|
38 |
+
'phpversion' => 'versão PHP',
|
39 |
+
'webservice' => 'servidor HTTP',
|
40 |
+
'load' => 'Carregado',
|
41 |
+
'processes' => 'Processos',
|
42 |
+
'threads' => 'Threads',
|
43 |
+
'total' => 'Total',
|
44 |
+
'memory' => 'Memória',
|
45 |
+
'type' => 'Tipo',
|
46 |
+
'free' => 'Livre',
|
47 |
+
'used' => 'Usado',
|
48 |
+
'size' => 'Tamanho',
|
49 |
+
'physical' => 'Físico',
|
50 |
+
'swap' => 'Swap',
|
51 |
+
'network_devices' => 'Dispositivos de Rede',
|
52 |
+
'device_name' => 'Nome de Dispositivos',
|
53 |
+
'amount_sent' => 'Enviados',
|
54 |
+
'amount_received' => 'Recebidos',
|
55 |
+
'state' => 'Estado',
|
56 |
+
'temps_voltages' => 'Temperaturas / Voltagens',
|
57 |
+
'path' => 'Caminho',
|
58 |
+
'device' => 'Dispositivo',
|
59 |
+
'value' => 'Valor',
|
60 |
+
'hardware' => 'Hardware',
|
61 |
+
'vendor' => 'Fabricante',
|
62 |
+
'drives' => 'Drives',
|
63 |
+
'name' => 'Nome',
|
64 |
+
'reads' => 'Leituras',
|
65 |
+
'writes' => 'Escritas',
|
66 |
+
'filesystem_mounts' => 'Sistemas de Arquivos Montados',
|
67 |
+
'mount_point' => 'Ponto de Montagem',
|
68 |
+
'filesystem' => 'Sistema de Arquivos',
|
69 |
+
'percent_used' => 'Percentual Usado',
|
70 |
+
'raid_arrays' => 'RAID',
|
71 |
+
'level' => 'Nível',
|
72 |
+
'status' => 'Estado',
|
73 |
+
'devices' => 'Dispositivos',
|
74 |
+
'label' => 'Rótulo',
|
75 |
+
'active' => 'Ativo',
|
76 |
+
'batteries' => 'Baterias',
|
77 |
+
'charge' => 'Carga',
|
78 |
+
'unknown' => 'Desconhecido',
|
79 |
+
'footer_app' => 'Gerado por %s em %s segundos.',
|
80 |
+
'none_found' => 'Não Encontrado',
|
81 |
+
'sound_cards' => 'Placa de Som',
|
82 |
+
'number' => 'Numero',
|
83 |
+
'card' => 'Placa',
|
84 |
+
'message' => 'Mensagem',
|
85 |
+
'from_where' => 'Fonte',
|
86 |
+
'mount_options' => 'Opções de Montagem',
|
87 |
+
'error_head' => 'Erro de Dados',
|
88 |
+
'timer' => 'Tempo',
|
89 |
+
'area' => 'Area',
|
90 |
+
'time_taken' => 'Tempo de busca',
|
91 |
+
'days' => 'dias',
|
92 |
+
'years' => 'anos',
|
93 |
+
'hours' => 'horas',
|
94 |
+
'minutes' => 'minutos',
|
95 |
+
'seconds' => 'segundos',
|
96 |
+
'pid' => 'PID',
|
97 |
+
'service' => 'Serviço',
|
98 |
+
'services' => 'Serviços',
|
99 |
+
'memory_usage' => 'Uso da Memória',
|
100 |
+
'distro' => 'Distribuição',
|
101 |
+
'cpu_arch' => 'Arquitetura',
|
102 |
+
'model' => 'Modelo',
|
103 |
+
'numLoggedIn' => 'Usuários Ativos',
|
104 |
+
);
|
lib/Linfo/Lang/zh.php
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Lang;
|
22 |
+
|
23 |
+
/*
|
24 |
+
* Chinese translation
|
25 |
+
* 如果您有任何对翻译的建议请联系:Digimoncn@Gmail.com
|
26 |
+
*/
|
27 |
+
|
28 |
+
return array(
|
29 |
+
'header' => 'System Health and Information',
|
30 |
+
'core' => '核心信息',
|
31 |
+
'os' => '操作系统',
|
32 |
+
'kernel' => '内核版本',
|
33 |
+
'accessed_ip' => 'IP地址',
|
34 |
+
'uptime' => '在线时间',
|
35 |
+
'hostname' => '主机名',
|
36 |
+
'cpus' => 'CPU',
|
37 |
+
'phpversion' => 'PHP版本',
|
38 |
+
'webservice' => 'HTTP服務器',
|
39 |
+
'load' => '负载',
|
40 |
+
'processes' => '进程',
|
41 |
+
'threads' => '线程',
|
42 |
+
'total' => '总计',
|
43 |
+
'memory' => '内存',
|
44 |
+
'type' => '类型',
|
45 |
+
'free' => '可用',
|
46 |
+
'used' => '已用',
|
47 |
+
'size' => '总大小',
|
48 |
+
'physical' => '物理',
|
49 |
+
'swap' => 'Swap',
|
50 |
+
'network_devices' => '网络设备',
|
51 |
+
'device_name' => '设备名称',
|
52 |
+
'amount_sent' => '发送数据',
|
53 |
+
'amount_received' => '接收数据',
|
54 |
+
'state' => '状态',
|
55 |
+
'temps_voltages' => '温度 / 电压',
|
56 |
+
'path' => '地址',
|
57 |
+
'device' => '设备',
|
58 |
+
'value' => '值',
|
59 |
+
'hardware' => '硬件',
|
60 |
+
'vendor' => '制造商',
|
61 |
+
'type' => '类型',
|
62 |
+
'drives' => '硬盘',
|
63 |
+
'name' => '名称',
|
64 |
+
'reads' => '读取',
|
65 |
+
'writes' => '写入',
|
66 |
+
'size' => '总容量',
|
67 |
+
'filesystem_mounts' => '文件系统监控',
|
68 |
+
'mount_point' => '挂载点',
|
69 |
+
'filesystem' => '文件系统',
|
70 |
+
'used' => '已用',
|
71 |
+
'free' => '可用',
|
72 |
+
'percent_used' => '百分比',
|
73 |
+
'raid_arrays' => 'RAID阵列',
|
74 |
+
'level' => 'RAID类型',
|
75 |
+
'status' => '状态',
|
76 |
+
'devices' => '设备',
|
77 |
+
'label' => '标签',
|
78 |
+
'active' => '可用',
|
79 |
+
'batteries' => '电池',
|
80 |
+
'charge' => '剩余',
|
81 |
+
'unknown' => '未知',
|
82 |
+
'footer_app' => '由%s 生成,共花费 %s 秒.',
|
83 |
+
'none_found' => '未知',
|
84 |
+
'sound_cards' => '声卡',
|
85 |
+
'number' => '数量',
|
86 |
+
'card' => '卡片',
|
87 |
+
'message' => '消息',
|
88 |
+
'from_where' => '来源',
|
89 |
+
'mount_options' => '挂载设置',
|
90 |
+
'error_head' => '数据汇总错误',
|
91 |
+
'timer' => '计时器',
|
92 |
+
'area' => '区域',
|
93 |
+
'time_taken' => '获取用时',
|
94 |
+
'days' => '天',
|
95 |
+
'minutes' => '分钟',
|
96 |
+
'seconds' => '秒',
|
97 |
+
'hours' => '小时',
|
98 |
+
'pid' => 'PID',
|
99 |
+
'service' => '服务',
|
100 |
+
'services' => '服务',
|
101 |
+
'memory_usage' => '内存使用',
|
102 |
+
'distro' => '发行版',
|
103 |
+
'cpu_arch' => '架构',
|
104 |
+
'model' => '型号',
|
105 |
+
);
|
lib/Linfo/Linfo.php
ADDED
@@ -0,0 +1,504 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file is part of Linfo (c) 2014, 2015 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*/
|
19 |
+
namespace Linfo;
|
20 |
+
|
21 |
+
use Linfo\Parsers\CallExt;
|
22 |
+
use Linfo\Exceptions\FatalException;
|
23 |
+
use Linfo\Meta\Errors;
|
24 |
+
use ReflectionClass;
|
25 |
+
use ReflectionException;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Linfo.
|
29 |
+
*
|
30 |
+
* Serve as the script's "controller". Leverages other classes. Loads settings,
|
31 |
+
* outputs them in formats, runs extensions, etc.
|
32 |
+
*
|
33 |
+
* @throws FatalException
|
34 |
+
*/
|
35 |
+
class Linfo
|
36 |
+
{
|
37 |
+
protected $settings = array(),
|
38 |
+
$lang = array(),
|
39 |
+
$info = array(),
|
40 |
+
$parser = null,
|
41 |
+
|
42 |
+
$app_name = 'Linfo',
|
43 |
+
$version = '',
|
44 |
+
$time_start = 0,
|
45 |
+
$linfo_testdir = null,
|
46 |
+
$linfo_localdir = null;
|
47 |
+
|
48 |
+
public function __construct($settings = array())
|
49 |
+
{
|
50 |
+
|
51 |
+
// Time us
|
52 |
+
$this->time_start = microtime(true);
|
53 |
+
|
54 |
+
// Some paths..
|
55 |
+
$this->linfo_testdir = dirname(dirname(__DIR__)).'/tests';
|
56 |
+
$this->linfo_localdir = dirname(dirname(__DIR__)).'/';
|
57 |
+
|
58 |
+
// Get our version from git setattribs
|
59 |
+
$scm = '2016-01-30 18:17:52 -0800';
|
60 |
+
list($this->version) = strpos($scm, '$') !== false ? array('git') : explode(' ', $scm);
|
61 |
+
|
62 |
+
// Run through dependencies / sanity checking
|
63 |
+
if (!extension_loaded('pcre') && !function_exists('preg_match') && !function_exists('preg_match_all')) {
|
64 |
+
throw new FatalException($this->app_name.' needs the `pcre\' extension to be loaded. http://us2.php.net/manual/en/book.pcre.php');
|
65 |
+
}
|
66 |
+
|
67 |
+
// Warnings usually displayed to browser happen if date.timezone isn't set in php 5.3+
|
68 |
+
if (!ini_get('date.timezone')) {
|
69 |
+
@ini_set('date.timezone', 'Etc/UTC');
|
70 |
+
}
|
71 |
+
|
72 |
+
// Load our settings/language
|
73 |
+
$this->loadSettings($settings);
|
74 |
+
$this->loadLanguage();
|
75 |
+
|
76 |
+
// Some classes need our vars; config them
|
77 |
+
Common::config($this);
|
78 |
+
CallExt::config($this);
|
79 |
+
|
80 |
+
// Determine OS
|
81 |
+
$os = $this->getOS();
|
82 |
+
|
83 |
+
if (!$os) {
|
84 |
+
throw new FatalException('Unknown/unsupported operating system');
|
85 |
+
}
|
86 |
+
|
87 |
+
$distro_class = '\\Linfo\\OS\\'.$os;
|
88 |
+
$this->parser = new $distro_class($this->settings);
|
89 |
+
}
|
90 |
+
|
91 |
+
// Load everything, while obeying permissions...
|
92 |
+
public function scan()
|
93 |
+
{
|
94 |
+
$reflector = new ReflectionClass($this->parser);
|
95 |
+
|
96 |
+
// Prime parser. Do things not appropriate to do in constructor. Most OS classes
|
97 |
+
// don't have this.
|
98 |
+
if ($reflector->hasMethod('init') && ($method = $reflector->getMethod('init'))) {
|
99 |
+
$method->invoke($this->parser);
|
100 |
+
}
|
101 |
+
|
102 |
+
// Array fields, tied to method names and default values...
|
103 |
+
$fields = array(
|
104 |
+
'OS' => array(
|
105 |
+
'show' => !empty($this->settings['show']['os']),
|
106 |
+
'default' => '',
|
107 |
+
'method' => 'getOS',
|
108 |
+
),
|
109 |
+
|
110 |
+
'Kernel' => array(
|
111 |
+
'show' => !empty($this->settings['show']['kernel']),
|
112 |
+
'default' => '',
|
113 |
+
'method' => 'getKernel',
|
114 |
+
),
|
115 |
+
|
116 |
+
'AccessedIP' => array(
|
117 |
+
'show' => !isset($this->settings['show']['ip']) || !empty($this->settings['show']['ip']),
|
118 |
+
'default' => '',
|
119 |
+
'method' => 'getAccessedIP',
|
120 |
+
),
|
121 |
+
|
122 |
+
'Distro' => array(
|
123 |
+
'show' => !empty($this->settings['show']['distro']),
|
124 |
+
'default' => '',
|
125 |
+
'method' => 'getDistro',
|
126 |
+
),
|
127 |
+
|
128 |
+
'RAM' => array(
|
129 |
+
'show' => !empty($this->settings['show']['ram']),
|
130 |
+
'default' => array(),
|
131 |
+
'method' => 'getRam',
|
132 |
+
),
|
133 |
+
|
134 |
+
'HD' => array(
|
135 |
+
'show' => !empty($this->settings['show']['hd']),
|
136 |
+
'default' => array(),
|
137 |
+
'method' => 'getHD',
|
138 |
+
),
|
139 |
+
|
140 |
+
'Mounts' => array(
|
141 |
+
'show' => !empty($this->settings['show']['mounts']),
|
142 |
+
'default' => array(),
|
143 |
+
'method' => 'getMounts',
|
144 |
+
),
|
145 |
+
|
146 |
+
'Load' => array(
|
147 |
+
'show' => !empty($this->settings['show']['load']),
|
148 |
+
'default' => array(),
|
149 |
+
'method' => 'getLoad',
|
150 |
+
),
|
151 |
+
|
152 |
+
'HostName' => array(
|
153 |
+
'show' => !empty($this->settings['show']['hostname']),
|
154 |
+
'default' => '',
|
155 |
+
'method' => 'getHostName',
|
156 |
+
),
|
157 |
+
|
158 |
+
'UpTime' => array(
|
159 |
+
'show' => !empty($this->settings['show']['uptime']),
|
160 |
+
'default' => array(),
|
161 |
+
'method' => 'getUpTime',
|
162 |
+
),
|
163 |
+
|
164 |
+
'CPU' => array(
|
165 |
+
'show' => !empty($this->settings['show']['cpu']),
|
166 |
+
'default' => array(),
|
167 |
+
'method' => 'getCPU',
|
168 |
+
),
|
169 |
+
|
170 |
+
'Model' => array(
|
171 |
+
'show' => !empty($this->settings['show']['model']),
|
172 |
+
'default' => array(),
|
173 |
+
'method' => 'getModel',
|
174 |
+
),
|
175 |
+
|
176 |
+
'CPUArchitecture' => array(
|
177 |
+
'show' => !empty($this->settings['show']['cpu']),
|
178 |
+
'default' => '',
|
179 |
+
'method' => 'getCPUArchitecture',
|
180 |
+
),
|
181 |
+
|
182 |
+
'Network Devices' => array(
|
183 |
+
'show' => !empty($this->settings['show']['network']),
|
184 |
+
'default' => array(),
|
185 |
+
'method' => 'getNet',
|
186 |
+
),
|
187 |
+
|
188 |
+
'Devices' => array(
|
189 |
+
'show' => !empty($this->settings['show']['devices']),
|
190 |
+
'default' => array(),
|
191 |
+
'method' => 'getDevs',
|
192 |
+
),
|
193 |
+
|
194 |
+
'Temps' => array(
|
195 |
+
'show' => !empty($this->settings['show']['temps']),
|
196 |
+
'default' => array(),
|
197 |
+
'method' => 'getTemps',
|
198 |
+
),
|
199 |
+
|
200 |
+
'Battery' => array(
|
201 |
+
'show' => !empty($this->settings['show']['battery']),
|
202 |
+
'default' => array(),
|
203 |
+
'method' => 'getBattery',
|
204 |
+
),
|
205 |
+
|
206 |
+
'Raid' => array(
|
207 |
+
'show' => !empty($this->settings['show']['raid']),
|
208 |
+
'default' => array(),
|
209 |
+
'method' => 'getRAID',
|
210 |
+
),
|
211 |
+
|
212 |
+
'Wifi' => array(
|
213 |
+
'show' => !empty($this->settings['show']['wifi']),
|
214 |
+
'default' => array(),
|
215 |
+
'method' => 'getWifi',
|
216 |
+
),
|
217 |
+
|
218 |
+
'SoundCards' => array(
|
219 |
+
'show' => !empty($this->settings['show']['sound']),
|
220 |
+
'default' => array(),
|
221 |
+
'method' => 'getSoundCards',
|
222 |
+
),
|
223 |
+
|
224 |
+
'processStats' => array(
|
225 |
+
'show' => !empty($this->settings['show']['process_stats']),
|
226 |
+
'default' => array(),
|
227 |
+
'method' => 'getProcessStats',
|
228 |
+
),
|
229 |
+
|
230 |
+
'services' => array(
|
231 |
+
'show' => !empty($this->settings['show']['services']),
|
232 |
+
'default' => array(),
|
233 |
+
'method' => 'getServices',
|
234 |
+
),
|
235 |
+
|
236 |
+
'numLoggedIn' => array(
|
237 |
+
'show' => !empty($this->settings['show']['numLoggedIn']),
|
238 |
+
'default' => false,
|
239 |
+
'method' => 'getnumLoggedIn',
|
240 |
+
),
|
241 |
+
|
242 |
+
'virtualization' => array(
|
243 |
+
'show' => !empty($this->settings['show']['virtualization']),
|
244 |
+
'default' => array(),
|
245 |
+
'method' => 'getVirtualization',
|
246 |
+
),
|
247 |
+
|
248 |
+
'cpuUsage' => array(
|
249 |
+
'show' => !empty($this->settings['cpu_usage']),
|
250 |
+
'default' => false,
|
251 |
+
'method' => 'getCPUUsage',
|
252 |
+
),
|
253 |
+
|
254 |
+
'phpVersion' => array(
|
255 |
+
'show' => !empty($this->settings['show']['phpversion']),
|
256 |
+
'default' => false,
|
257 |
+
'method' => 'getPhpVersion',
|
258 |
+
),
|
259 |
+
|
260 |
+
'webService' => array(
|
261 |
+
'show' => !empty($this->settings['show']['webservice']),
|
262 |
+
'default' => false,
|
263 |
+
'method' => 'getWebService',
|
264 |
+
),
|
265 |
+
|
266 |
+
// Extra info such as which fields to not show
|
267 |
+
'contains' => array(
|
268 |
+
'show' => true,
|
269 |
+
'default' => array(),
|
270 |
+
'method' => 'getContains',
|
271 |
+
),
|
272 |
+
);
|
273 |
+
|
274 |
+
foreach ($fields as $key => $data) {
|
275 |
+
if (!$data['show']) {
|
276 |
+
$this->info[$key] = $data['default'];
|
277 |
+
continue;
|
278 |
+
}
|
279 |
+
|
280 |
+
try {
|
281 |
+
$method = $reflector->getMethod($data['method']);
|
282 |
+
$this->info[$key] = $method->invoke($this->parser);
|
283 |
+
} catch (ReflectionException $e) {
|
284 |
+
$this->info[$key] = $data['default'];
|
285 |
+
}
|
286 |
+
}
|
287 |
+
|
288 |
+
// Add a timestamp
|
289 |
+
$this->info['timestamp'] = date('c');
|
290 |
+
|
291 |
+
// Run extra extensions
|
292 |
+
$this->runExtensions();
|
293 |
+
}
|
294 |
+
|
295 |
+
protected function loadSettings($settings = array())
|
296 |
+
{
|
297 |
+
|
298 |
+
// Running unit tests?
|
299 |
+
if (defined('LINFO_TESTING')) {
|
300 |
+
$this->settings = Common::getVarFromFile($this->linfo_testdir.'/test_settings.php', 'settings');
|
301 |
+
if (!is_array($this->settings)) {
|
302 |
+
throw new FatalException('Failed getting test-specific settings');
|
303 |
+
}
|
304 |
+
|
305 |
+
return;
|
306 |
+
}
|
307 |
+
|
308 |
+
// Don't just blindly assume we have the ob_* functions...
|
309 |
+
if (!function_exists('ob_start')) {
|
310 |
+
$settings['compress_content'] = false;
|
311 |
+
}
|
312 |
+
|
313 |
+
if (!isset($settings['hide'])) {
|
314 |
+
$settings['hide'] = array(
|
315 |
+
'filesystems' => array(),
|
316 |
+
'storage_devices' => array(),
|
317 |
+
);
|
318 |
+
}
|
319 |
+
|
320 |
+
// Make sure these are arrays
|
321 |
+
$settings['hide']['filesystems'] = is_array($settings['hide']['filesystems']) ? $settings['hide']['filesystems'] : array();
|
322 |
+
$settings['hide']['storage_devices'] = is_array($settings['hide']['storage_devices']) ? $settings['hide']['storage_devices'] : array();
|
323 |
+
|
324 |
+
// Make sure these are always hidden
|
325 |
+
$settings['hide']['filesystems'][] = 'rootfs';
|
326 |
+
$settings['hide']['filesystems'][] = 'binfmt_misc';
|
327 |
+
|
328 |
+
// Default timeformat
|
329 |
+
$settings['dates'] = array_key_exists('dates', $settings) ? $settings['dates'] : 'm/d/y h:i A (T)';
|
330 |
+
|
331 |
+
// Default to english translation if garbage is passed
|
332 |
+
if (empty($settings['language']) || !preg_match('/^[a-z]{2}$/', $settings['language'])) {
|
333 |
+
$settings['language'] = 'en';
|
334 |
+
}
|
335 |
+
|
336 |
+
// If it can't be found default to english
|
337 |
+
if (!is_file($this->linfo_localdir.'src/Linfo/Lang/'.$settings['language'].'.php')) {
|
338 |
+
$settings['language'] = 'en';
|
339 |
+
}
|
340 |
+
|
341 |
+
$this->settings = $settings;
|
342 |
+
}
|
343 |
+
|
344 |
+
protected function loadLanguage()
|
345 |
+
{
|
346 |
+
|
347 |
+
// Running unit tests?
|
348 |
+
if (defined('LINFO_TESTING')) {
|
349 |
+
$this->lang = require $this->linfo_testdir.'/test_lang.php';
|
350 |
+
if (!is_array($this->lang)) {
|
351 |
+
throw new FatalException('Failed getting test-specific language');
|
352 |
+
}
|
353 |
+
|
354 |
+
return;
|
355 |
+
}
|
356 |
+
|
357 |
+
// Load translation, defaulting to english of keys are missing (assuming
|
358 |
+
// we're not using english anyway and the english translation indeed exists)
|
359 |
+
if (is_file($this->linfo_localdir.'src/Linfo/Lang/en.php') && $this->settings['language'] != 'en') {
|
360 |
+
$this->lang = array_merge(require($this->linfo_localdir.'src/Linfo/Lang/en.php'),
|
361 |
+
require($this->linfo_localdir.'src/Linfo/Lang/'.$this->settings['language'].'.php'));
|
362 |
+
}
|
363 |
+
|
364 |
+
// Otherwise snag desired translation, be it english or a non-english without english to fall back on
|
365 |
+
else {
|
366 |
+
$this->lang = require $this->linfo_localdir.'src/Linfo/Lang/'.$this->settings['language'].'.php';
|
367 |
+
}
|
368 |
+
}
|
369 |
+
|
370 |
+
protected function getOS()
|
371 |
+
{
|
372 |
+
list($os) = explode('_', PHP_OS, 2);
|
373 |
+
|
374 |
+
// This magical constant knows all
|
375 |
+
switch ($os) {
|
376 |
+
|
377 |
+
// These are supported
|
378 |
+
case 'Linux':
|
379 |
+
case 'FreeBSD':
|
380 |
+
case 'DragonFly':
|
381 |
+
case 'OpenBSD':
|
382 |
+
case 'NetBSD':
|
383 |
+
case 'Minix':
|
384 |
+
case 'Darwin':
|
385 |
+
case 'SunOS':
|
386 |
+
return PHP_OS;
|
387 |
+
break;
|
388 |
+
case 'WINNT':
|
389 |
+
return 'Windows';
|
390 |
+
break;
|
391 |
+
}
|
392 |
+
|
393 |
+
// So anything else isn't
|
394 |
+
return false;
|
395 |
+
}
|
396 |
+
|
397 |
+
/*
|
398 |
+
* getInfo()
|
399 |
+
*
|
400 |
+
* Returning reference so extensions can modify result
|
401 |
+
*/
|
402 |
+
public function &getInfo()
|
403 |
+
{
|
404 |
+
return $this->info;
|
405 |
+
}
|
406 |
+
|
407 |
+
protected function runExtensions()
|
408 |
+
{
|
409 |
+
$this->info['extensions'] = array();
|
410 |
+
|
411 |
+
if (!array_key_exists('extensions', $this->settings) || count($this->settings['extensions']) == 0) {
|
412 |
+
return;
|
413 |
+
}
|
414 |
+
|
415 |
+
// Go through each enabled extension
|
416 |
+
foreach ((array) $this->settings['extensions'] as $ext => $enabled) {
|
417 |
+
|
418 |
+
// Is it really enabled?
|
419 |
+
if (empty($enabled)) {
|
420 |
+
continue;
|
421 |
+
}
|
422 |
+
|
423 |
+
// Anti hack
|
424 |
+
if (!preg_match('/^[a-z0-9-_]+$/i', $ext)) {
|
425 |
+
Errors::add('Extension Loader', 'Not going to load "'.$ext.'" extension as only characters allowed in name are letters/numbers/-_');
|
426 |
+
continue;
|
427 |
+
}
|
428 |
+
|
429 |
+
// Support older config files with lowercase
|
430 |
+
if (preg_match('/^[a-z]/', $ext)) {
|
431 |
+
$ext = ucfirst($ext);
|
432 |
+
}
|
433 |
+
|
434 |
+
// Try loading our class..
|
435 |
+
try {
|
436 |
+
$reflector = new ReflectionClass('\\Linfo\\Extension\\'.$ext);
|
437 |
+
$ext_class = $reflector->newInstance($this);
|
438 |
+
} catch (ReflectionException $e) {
|
439 |
+
Errors::add('Extension Loader', 'Cannot instantiate class for "'.$ext.'" extension: '.$e->getMessage());
|
440 |
+
continue;
|
441 |
+
}
|
442 |
+
|
443 |
+
// Deal with it
|
444 |
+
$ext_class->work();
|
445 |
+
|
446 |
+
// Does this edit the $info directly, instead of creating a separate output table type thing?
|
447 |
+
if (!$reflector->hasConstant('LINFO_INTEGRATE')) {
|
448 |
+
|
449 |
+
// Result
|
450 |
+
$result = $ext_class->result();
|
451 |
+
|
452 |
+
// Save result if it's good
|
453 |
+
if ($result != false) {
|
454 |
+
$this->info['extensions'][$ext] = $result;
|
455 |
+
}
|
456 |
+
}
|
457 |
+
}
|
458 |
+
}
|
459 |
+
|
460 |
+
public function getLang()
|
461 |
+
{
|
462 |
+
return $this->lang;
|
463 |
+
}
|
464 |
+
|
465 |
+
public function getSettings()
|
466 |
+
{
|
467 |
+
return $this->settings;
|
468 |
+
}
|
469 |
+
|
470 |
+
public function getAppName()
|
471 |
+
{
|
472 |
+
return $this->app_name;
|
473 |
+
}
|
474 |
+
|
475 |
+
public function getVersion()
|
476 |
+
{
|
477 |
+
return $this->version;
|
478 |
+
}
|
479 |
+
|
480 |
+
public function getTimeStart()
|
481 |
+
{
|
482 |
+
return $this->time_start;
|
483 |
+
}
|
484 |
+
|
485 |
+
public function getParser()
|
486 |
+
{
|
487 |
+
return $this->parser;
|
488 |
+
}
|
489 |
+
|
490 |
+
public function getLocalDir()
|
491 |
+
{
|
492 |
+
return $this->linfo_localdir;
|
493 |
+
}
|
494 |
+
|
495 |
+
public function getTestDir()
|
496 |
+
{
|
497 |
+
return $this->linfo_testdir;
|
498 |
+
}
|
499 |
+
|
500 |
+
public function getCacheDir()
|
501 |
+
{
|
502 |
+
return dirname(dirname(__DIR__)).'/cache/';
|
503 |
+
}
|
504 |
+
}
|
lib/Linfo/Meta/Errors.php
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*/
|
19 |
+
namespace Linfo\Meta;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Use this class for all error handling.
|
23 |
+
*/
|
24 |
+
class Errors
|
25 |
+
{
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Store error messages here.
|
29 |
+
*
|
30 |
+
* @var array
|
31 |
+
*/
|
32 |
+
private static $errors = array();
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Add an error message.
|
36 |
+
*
|
37 |
+
* @static
|
38 |
+
* @param string $whence name of error message source
|
39 |
+
* @param string $message error message text
|
40 |
+
*/
|
41 |
+
public static function add($whence, $message)
|
42 |
+
{
|
43 |
+
self::$errors[] = array($whence, $message);
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Get all error messages.
|
48 |
+
*
|
49 |
+
* @static
|
50 |
+
* @return array of errors
|
51 |
+
*/
|
52 |
+
public static function show()
|
53 |
+
{
|
54 |
+
return self::$errors;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* How many are there?
|
59 |
+
*
|
60 |
+
* @static
|
61 |
+
* @return int number of errors
|
62 |
+
*/
|
63 |
+
public static function num()
|
64 |
+
{
|
65 |
+
return count(self::$errors);
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Used mainly for unit tests.
|
70 |
+
*
|
71 |
+
* @static
|
72 |
+
*/
|
73 |
+
public static function clear()
|
74 |
+
{
|
75 |
+
self::$errors = array();
|
76 |
+
}
|
77 |
+
}
|
lib/Linfo/Meta/Timer.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Linfo\Meta;
|
4 |
+
|
5 |
+
class Timer
|
6 |
+
{
|
7 |
+
protected static $timers = array();
|
8 |
+
protected $id = null;
|
9 |
+
protected $start = null;
|
10 |
+
|
11 |
+
public static function getResults()
|
12 |
+
{
|
13 |
+
return self::$timers;
|
14 |
+
}
|
15 |
+
|
16 |
+
public static function clear()
|
17 |
+
{
|
18 |
+
self::$timers = array();
|
19 |
+
}
|
20 |
+
|
21 |
+
public function __construct($id)
|
22 |
+
{
|
23 |
+
$this->id = $id;
|
24 |
+
$this->start = microtime(true);
|
25 |
+
}
|
26 |
+
|
27 |
+
public function __destruct()
|
28 |
+
{
|
29 |
+
$duration = microtime(true) - $this->start;
|
30 |
+
self::$timers[] = array(
|
31 |
+
'id' => $this->id,
|
32 |
+
'duration' => $duration,
|
33 |
+
);
|
34 |
+
}
|
35 |
+
}
|
lib/Linfo/OS/BSDcommon.php
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\OS;
|
22 |
+
|
23 |
+
use Linfo\Common;
|
24 |
+
use Linfo\Parsers\CallExt;
|
25 |
+
use Exception;
|
26 |
+
|
27 |
+
/*
|
28 |
+
* The BSD os's are largely similar and thus draw from this class.
|
29 |
+
*/
|
30 |
+
|
31 |
+
abstract class BSDcommon extends Unixcommon
|
32 |
+
{
|
33 |
+
// Store these
|
34 |
+
protected $settings,
|
35 |
+
$exec,
|
36 |
+
$dmesg,
|
37 |
+
$sysctl = array();
|
38 |
+
|
39 |
+
// Start us off
|
40 |
+
protected function __construct($settings)
|
41 |
+
{
|
42 |
+
|
43 |
+
// Localize settings
|
44 |
+
$this->settings = $settings;
|
45 |
+
|
46 |
+
// Exec running
|
47 |
+
$this->exec = new CallExt();
|
48 |
+
|
49 |
+
// Get dmesg
|
50 |
+
$this->loadDmesg();
|
51 |
+
}
|
52 |
+
|
53 |
+
// Save dmesg
|
54 |
+
protected function loadDmesg()
|
55 |
+
{
|
56 |
+
$this->dmesg = Common::getContents('/var/run/dmesg.boot');
|
57 |
+
}
|
58 |
+
|
59 |
+
// Use sysctl to get something, and cache result.
|
60 |
+
// Also allow getting multiple keys at once, in which case sysctl
|
61 |
+
// will only be called once instead of multiple times (assuming it doesn't break)
|
62 |
+
protected function getSysCTL($keys, $do_return = true)
|
63 |
+
{
|
64 |
+
|
65 |
+
// Get the keys as an array, so we can treat it as an array of keys
|
66 |
+
$keys = (array) $keys;
|
67 |
+
|
68 |
+
// Store the results of which here
|
69 |
+
$results = array();
|
70 |
+
|
71 |
+
// Go through each
|
72 |
+
foreach ($keys as $k => $v) {
|
73 |
+
$keys[$k] = escapeshellarg($v);
|
74 |
+
|
75 |
+
// Check and see if we have any of these already. If so, use previous
|
76 |
+
// values and don't retrive them again
|
77 |
+
if (array_key_exists($v, $this->sysctl)) {
|
78 |
+
unset($keys[$k]);
|
79 |
+
$results[$v] = $this->sysctl[$v];
|
80 |
+
}
|
81 |
+
}
|
82 |
+
|
83 |
+
// Try running sysctl to get all the values together
|
84 |
+
try {
|
85 |
+
// Result of sysctl
|
86 |
+
$command = $this->exec->exec('sysctl', implode(' ', $keys));
|
87 |
+
|
88 |
+
// Place holder
|
89 |
+
$current_key = false;
|
90 |
+
|
91 |
+
// Go through each line
|
92 |
+
foreach (explode("\n", $command) as $line) {
|
93 |
+
|
94 |
+
// If this is the beginning of one of the keys' values
|
95 |
+
if (preg_match('/^([a-z0-9\.\-\_]+)\s*(?:\:|=)(.+)/', $line, $line_match) == 1) {
|
96 |
+
if ($line_match[1] != $current_key) {
|
97 |
+
$current_key = $line_match[1];
|
98 |
+
$results[$line_match[1]] = trim($line_match[2]);
|
99 |
+
}
|
100 |
+
}
|
101 |
+
|
102 |
+
// If this line is a continuation of one of the keys' values
|
103 |
+
elseif ($current_key != false) {
|
104 |
+
$results[$current_key] .= "\n".trim($line);
|
105 |
+
}
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
// Something broke with that sysctl call; try getting
|
110 |
+
// all the values separately (slower)
|
111 |
+
catch (Exception $e) {
|
112 |
+
|
113 |
+
// Go through each
|
114 |
+
foreach ($keys as $v) {
|
115 |
+
|
116 |
+
// Try it
|
117 |
+
try {
|
118 |
+
$results[$v] = $this->exec->exec('sysctl', $v);
|
119 |
+
}
|
120 |
+
|
121 |
+
// Didn't work again... just forget it and set value to empty string
|
122 |
+
catch (Exception $e) {
|
123 |
+
$results[$v] = '';
|
124 |
+
}
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
// Cache these incase they're called upon again
|
129 |
+
$this->sysctl = array_merge($results, $this->sysctl);
|
130 |
+
|
131 |
+
// Return an array of all values retrieved, or if just one was
|
132 |
+
// requested, then that one as a string
|
133 |
+
if ($do_return) {
|
134 |
+
return count($results) == 1 ? reset($results) : $results;
|
135 |
+
}
|
136 |
+
else {
|
137 |
+
return null;
|
138 |
+
}
|
139 |
+
}
|
140 |
+
|
141 |
+
|
142 |
+
// System load averages
|
143 |
+
public function getLoad()
|
144 |
+
{
|
145 |
+
if (!empty($this->settings['timer'])) {
|
146 |
+
$t = new Timer('Load Averages');
|
147 |
+
}
|
148 |
+
|
149 |
+
$parts = explode(' ', trim($this->sysctl['vm.loadavg']));
|
150 |
+
|
151 |
+
if (!$parts) {
|
152 |
+
return array();
|
153 |
+
}
|
154 |
+
|
155 |
+
return array_combine(array('now', '5min', '15min'), $parts);
|
156 |
+
}
|
157 |
+
}
|
lib/Linfo/OS/Darwin.php
ADDED
@@ -0,0 +1,622 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010, 2012 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\OS;
|
22 |
+
|
23 |
+
use Exception;
|
24 |
+
use Linfo\Meta\Timer;
|
25 |
+
use Linfo\Meta\Errors;
|
26 |
+
use Linfo\Common;
|
27 |
+
|
28 |
+
/*
|
29 |
+
* Alpha osx class
|
30 |
+
* Differs very slightly from the FreeBSD, especially in the fact that
|
31 |
+
* only root can access dmesg
|
32 |
+
*/
|
33 |
+
|
34 |
+
class Darwin extends BSDcommon
|
35 |
+
{
|
36 |
+
// Encapsulate these
|
37 |
+
protected $settings,
|
38 |
+
$exec,
|
39 |
+
$dmesg;
|
40 |
+
|
41 |
+
// Start us off
|
42 |
+
public function __construct($settings)
|
43 |
+
{
|
44 |
+
|
45 |
+
// Instantiate parent
|
46 |
+
parent::__construct($settings);
|
47 |
+
|
48 |
+
// We search these folders for our commands
|
49 |
+
$this->exec->setSearchPaths(array('/sbin', '/bin', '/usr/bin', '/usr/sbin'));
|
50 |
+
|
51 |
+
// We need these sysctl values
|
52 |
+
$this->GetSysCTL(array(
|
53 |
+
'machdep.cpu.vendor',
|
54 |
+
'machdep.cpu.brand_string',
|
55 |
+
'hw.cpufrequency',
|
56 |
+
'hw.ncpu',
|
57 |
+
'vm.swapusage',
|
58 |
+
'hw.memsize',
|
59 |
+
'hw.usermem',
|
60 |
+
'kern.boottime',
|
61 |
+
'vm.loadavg',
|
62 |
+
'hw.model',
|
63 |
+
), false);
|
64 |
+
|
65 |
+
// And get this info for when the above fails
|
66 |
+
try {
|
67 |
+
$this->systemProfiler = $this->exec->exec('system_profiler', 'SPHardwareDataType SPSoftwareDataType SPPowerDataType');
|
68 |
+
} catch (Exception $e) {
|
69 |
+
// Meh
|
70 |
+
Errors::add('Linfo Mac OS 10', 'Error using system_profiler');
|
71 |
+
}
|
72 |
+
}
|
73 |
+
|
74 |
+
// What we should leave out
|
75 |
+
public function getContains()
|
76 |
+
{
|
77 |
+
return array(
|
78 |
+
'hw_vendor' => false,
|
79 |
+
'drives_rw_stats' => false,
|
80 |
+
'drives_vendor' => false,
|
81 |
+
'nic_type' => false,
|
82 |
+
'nic_port_speed' => false,
|
83 |
+
);
|
84 |
+
}
|
85 |
+
|
86 |
+
// Operating system
|
87 |
+
public function getOS()
|
88 |
+
{
|
89 |
+
return 'Darwin ('.(preg_match('/^\s+System Version: ([^\(]+)/m', $this->systemProfiler, $m) ? $m[1] : 'Mac OS X').')';
|
90 |
+
}
|
91 |
+
|
92 |
+
// Hostname
|
93 |
+
public function getHostname()
|
94 |
+
{
|
95 |
+
return preg_match('/^\s*Computer Name:\s+(.+)\s*$/m', $this->systemProfiler, $m) ? $m[1] : php_uname('n');
|
96 |
+
}
|
97 |
+
|
98 |
+
// Get mounted file systems
|
99 |
+
public function getMounts()
|
100 |
+
{
|
101 |
+
// Time?
|
102 |
+
if (!empty($this->settings['timer'])) {
|
103 |
+
$t = new Timer('Mounted file systems');
|
104 |
+
}
|
105 |
+
|
106 |
+
// Get result of mount command
|
107 |
+
try {
|
108 |
+
$res = $this->exec->exec('mount');
|
109 |
+
} catch (Exception $e) {
|
110 |
+
Errors::add('Linfo Core', 'Error running `mount` command');
|
111 |
+
|
112 |
+
return array();
|
113 |
+
}
|
114 |
+
|
115 |
+
// Parse it
|
116 |
+
if (preg_match_all('/(.+)\s+on\s+(.+)\s+\((\w+).*\)\n/i', $res, $m, PREG_SET_ORDER) == 0) {
|
117 |
+
return array();
|
118 |
+
}
|
119 |
+
|
120 |
+
// Store them here
|
121 |
+
$mounts = array();
|
122 |
+
|
123 |
+
// Deal with each entry
|
124 |
+
foreach ($m as $mount) {
|
125 |
+
|
126 |
+
// Should we not show this?
|
127 |
+
if (in_array($mount[1], $this->settings['hide']['storage_devices']) || in_array($mount[3], $this->settings['hide']['filesystems'])) {
|
128 |
+
continue;
|
129 |
+
}
|
130 |
+
|
131 |
+
// Get these
|
132 |
+
$size = @disk_total_space($mount[2]);
|
133 |
+
$free = @disk_free_space($mount[2]);
|
134 |
+
$used = $size - $free;
|
135 |
+
|
136 |
+
// Might be good, go for it
|
137 |
+
$mounts[] = array(
|
138 |
+
'device' => $mount[1],
|
139 |
+
'mount' => $mount[2],
|
140 |
+
'type' => $mount[3],
|
141 |
+
'size' => $size ,
|
142 |
+
'used' => $used,
|
143 |
+
'free' => $free,
|
144 |
+
'free_percent' => ((bool) $free != false && (bool) $size != false ? round($free / $size, 2) * 100 : false),
|
145 |
+
'used_percent' => ((bool) $used != false && (bool) $size != false ? round($used / $size, 2) * 100 : false),
|
146 |
+
);
|
147 |
+
}
|
148 |
+
|
149 |
+
// Give it
|
150 |
+
return $mounts;
|
151 |
+
}
|
152 |
+
|
153 |
+
// Get network interfaces
|
154 |
+
public function getNet()
|
155 |
+
{
|
156 |
+
// Time?
|
157 |
+
if (!empty($this->settings['timer'])) {
|
158 |
+
$t = new Timer('Network Devices');
|
159 |
+
}
|
160 |
+
|
161 |
+
// Store return vals here
|
162 |
+
$return = array();
|
163 |
+
|
164 |
+
// Use netstat to get info
|
165 |
+
try {
|
166 |
+
$netstat = $this->exec->exec('netstat', '-nbdi');
|
167 |
+
} catch (Exception $e) {
|
168 |
+
Errors::add('Linfo Core', 'Error using `netstat` to get network info');
|
169 |
+
|
170 |
+
return $return;
|
171 |
+
}
|
172 |
+
|
173 |
+
// Initially get interfaces themselves along with numerical stats
|
174 |
+
//
|
175 |
+
// Example output:
|
176 |
+
// Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll Drop
|
177 |
+
// lo0 16384 <Link#1> 1945 0 429565 1945 0 429565 0
|
178 |
+
// en0 1500 <Link#4> 58:b0:35:f9:fd:2b 0 0 0 0 0 59166 0
|
179 |
+
// fw0 4078 <Link#6> d8:30:62:ff:fe:f5:c8:9c 0 0 0 0 0 346 0
|
180 |
+
if (preg_match_all(
|
181 |
+
'/^
|
182 |
+
([a-z0-9*]+)\s* # Name
|
183 |
+
\w+\s+ # Mtu
|
184 |
+
<Link\#\w+> # Network
|
185 |
+
(?:\D+|\s+\w+:\w+:\w+:\w+:\w+:\w+\s+) # MAC address
|
186 |
+
(\w+)\s+ # Ipkts
|
187 |
+
(\w+)\s+ # Ierrs
|
188 |
+
(\w+)\s+ # Ibytes
|
189 |
+
(\w+)\s+ # Opkts
|
190 |
+
(\w+)\s+ # Oerrs
|
191 |
+
(\w+)\s+ # Obytes
|
192 |
+
(\w+)\s+ # Coll
|
193 |
+
(\w+)?\s* # Drop
|
194 |
+
$/mx', $netstat, $netstat_match, PREG_SET_ORDER) == 0) {
|
195 |
+
return $return;
|
196 |
+
}
|
197 |
+
|
198 |
+
// Try using ifconfig to get states of the network interfaces
|
199 |
+
$statuses = array();
|
200 |
+
try {
|
201 |
+
// Output of ifconfig command
|
202 |
+
$ifconfig = $this->exec->exec('ifconfig', '-a');
|
203 |
+
|
204 |
+
// Set this to false to prevent wasted regexes
|
205 |
+
$current_nic = false;
|
206 |
+
|
207 |
+
// Go through each line
|
208 |
+
foreach ((array) explode("\n", $ifconfig) as $line) {
|
209 |
+
|
210 |
+
// Approachign new nic def
|
211 |
+
if (preg_match('/^(\w+):/', $line, $m) == 1) {
|
212 |
+
$current_nic = $m[1];
|
213 |
+
}
|
214 |
+
|
215 |
+
// Hopefully match its status
|
216 |
+
elseif ($current_nic && preg_match('/status: (\w+)$/', $line, $m) == 1) {
|
217 |
+
$statuses[$current_nic] = $m[1];
|
218 |
+
$current_nic = false;
|
219 |
+
}
|
220 |
+
}
|
221 |
+
} catch (Exception $e) {
|
222 |
+
}
|
223 |
+
|
224 |
+
// Save info
|
225 |
+
foreach ($netstat_match as $net) {
|
226 |
+
|
227 |
+
// Determine status
|
228 |
+
switch (array_key_exists($net[1], $statuses) ? $statuses[$net[1]] : 'unknown') {
|
229 |
+
|
230 |
+
case 'active':
|
231 |
+
$state = 'up';
|
232 |
+
break;
|
233 |
+
|
234 |
+
case 'inactive':
|
235 |
+
$state = 'down';
|
236 |
+
break;
|
237 |
+
|
238 |
+
default:
|
239 |
+
$state = 'unknown';
|
240 |
+
break;
|
241 |
+
}
|
242 |
+
|
243 |
+
// Save info
|
244 |
+
$return[$net[1]] = array(
|
245 |
+
|
246 |
+
// These came from netstat
|
247 |
+
'recieved' => array(
|
248 |
+
'bytes' => $net[4],
|
249 |
+
'errors' => $net[3],
|
250 |
+
'packets' => $net[2],
|
251 |
+
),
|
252 |
+
'sent' => array(
|
253 |
+
'bytes' => $net[7],
|
254 |
+
'errors' => $net[6],
|
255 |
+
'packets' => $net[5],
|
256 |
+
),
|
257 |
+
|
258 |
+
// This came from ifconfig -a
|
259 |
+
'state' => $state,
|
260 |
+
|
261 |
+
// Not sure where to get his
|
262 |
+
'type' => '?',
|
263 |
+
);
|
264 |
+
}
|
265 |
+
|
266 |
+
// Return it
|
267 |
+
return $return;
|
268 |
+
}
|
269 |
+
|
270 |
+
// Get uptime
|
271 |
+
public function getUpTime()
|
272 |
+
{
|
273 |
+
|
274 |
+
// Time?
|
275 |
+
if (!empty($this->settings['timer'])) {
|
276 |
+
$t = new Timer('Uptime');
|
277 |
+
}
|
278 |
+
|
279 |
+
// Extract boot part of it
|
280 |
+
if (preg_match('/^\{ sec \= (\d+).+$/', $this->sysctl['kern.boottime'], $m) == 0) {
|
281 |
+
return '';
|
282 |
+
}
|
283 |
+
|
284 |
+
return array(
|
285 |
+
'text' => Common::secondsConvert(time() - $m[1]),
|
286 |
+
'bootedTimestamp' => $m[1],
|
287 |
+
);
|
288 |
+
}
|
289 |
+
|
290 |
+
// Get stats on processes
|
291 |
+
public function getProcessStats()
|
292 |
+
{
|
293 |
+
|
294 |
+
// Time?
|
295 |
+
if (!empty($this->settings['timer'])) {
|
296 |
+
$t = new Timer('Process Stats');
|
297 |
+
}
|
298 |
+
|
299 |
+
// We'll return this after stuffing it with useful info
|
300 |
+
$result = array(
|
301 |
+
'exists' => true,
|
302 |
+
'totals' => array(
|
303 |
+
'running' => 0,
|
304 |
+
'zombie' => 0,
|
305 |
+
'sleeping' => 0,
|
306 |
+
'stopped' => 0,
|
307 |
+
'idle' => 0,
|
308 |
+
),
|
309 |
+
'proc_total' => 0,
|
310 |
+
'threads' => false, // I'm not sure how to get this
|
311 |
+
);
|
312 |
+
|
313 |
+
// Use ps
|
314 |
+
try {
|
315 |
+
// Get it
|
316 |
+
$ps = $this->exec->exec('ps', 'ax');
|
317 |
+
|
318 |
+
// Match them
|
319 |
+
preg_match_all('/^\s*\d+\s+[\w?]+\s+([A-Z])\S*\s+.+$/m', $ps, $processes, PREG_SET_ORDER);
|
320 |
+
|
321 |
+
// Get total
|
322 |
+
$result['proc_total'] = count($processes);
|
323 |
+
|
324 |
+
// Go through
|
325 |
+
foreach ($processes as $process) {
|
326 |
+
switch ($process[1]) {
|
327 |
+
case 'S':
|
328 |
+
case 'I':
|
329 |
+
$result['totals']['sleeping']++;
|
330 |
+
break;
|
331 |
+
case 'Z':
|
332 |
+
$result['totals']['zombie']++;
|
333 |
+
break;
|
334 |
+
case 'R':
|
335 |
+
case 'D':
|
336 |
+
$result['totals']['running']++;
|
337 |
+
break;
|
338 |
+
case 'T':
|
339 |
+
$result['totals']['stopped']++;
|
340 |
+
break;
|
341 |
+
case 'W':
|
342 |
+
$result['totals']['idle']++;
|
343 |
+
break;
|
344 |
+
}
|
345 |
+
}
|
346 |
+
} catch (Exception $e) {
|
347 |
+
Errors::add('Linfo Core', 'Error using `ps` to get process info');
|
348 |
+
}
|
349 |
+
|
350 |
+
// Give
|
351 |
+
return $result;
|
352 |
+
}
|
353 |
+
|
354 |
+
// Get cpus
|
355 |
+
public function getCPU()
|
356 |
+
{
|
357 |
+
// Time?
|
358 |
+
if (!empty($this->settings['timer'])) {
|
359 |
+
$t = new Timer('CPUs');
|
360 |
+
}
|
361 |
+
|
362 |
+
// Was machdep mean to us? Likely on ppc macs
|
363 |
+
if (empty($this->sysctl['machdep.cpu.brand_string']) && preg_match('/^\s+Processor Name:\s+(.+)(?= \([\d\.]+\))/m', $this->systemProfiler, $m)) {
|
364 |
+
$this->sysctl['machdep.cpu.brand_string'] = $m[1];
|
365 |
+
}
|
366 |
+
|
367 |
+
if (empty($this->sysctl['machdep.cpu.vendor'])) {
|
368 |
+
$this->sysctl['machdep.cpu.vendor'] = false;
|
369 |
+
}
|
370 |
+
|
371 |
+
// Store them here
|
372 |
+
$cpus = array();
|
373 |
+
|
374 |
+
// The same one multiple times
|
375 |
+
for ($i = 0; $i < $this->sysctl['hw.ncpu']; ++$i) {
|
376 |
+
$cpus[] = array(
|
377 |
+
'Model' => $this->sysctl['machdep.cpu.brand_string'],
|
378 |
+
'MHz' => $this->sysctl['hw.cpufrequency'] / 1000000,
|
379 |
+
'Vendor' => $this->sysctl['machdep.cpu.vendor'],
|
380 |
+
|
381 |
+
);
|
382 |
+
}
|
383 |
+
|
384 |
+
return $cpus;
|
385 |
+
}
|
386 |
+
|
387 |
+
// Get ram usage
|
388 |
+
public function getRam()
|
389 |
+
{
|
390 |
+
|
391 |
+
// Time?
|
392 |
+
if (!empty($this->settings['timer'])) {
|
393 |
+
$t = new Timer('Memory');
|
394 |
+
}
|
395 |
+
|
396 |
+
// Start us off
|
397 |
+
$return = array();
|
398 |
+
$return['type'] = 'Physical';
|
399 |
+
$return['total'] = $this->sysctl['hw.memsize'];
|
400 |
+
$return['free'] = $this->sysctl['hw.memsize'] - $this->sysctl['hw.usermem'];
|
401 |
+
$return['swapTotal'] = 0;
|
402 |
+
$return['swapFree'] = 0;
|
403 |
+
$return['swapInfo'] = array();
|
404 |
+
|
405 |
+
// Sort out swap
|
406 |
+
if (preg_match('/total = ([\d\.]+)M\s+used = ([\d\.]+)M\s+free = ([\d\.]+)M/', $this->sysctl['vm.swapusage'], $swap_match)) {
|
407 |
+
list(, $swap_total, $swap_used, $swap_free) = $swap_match;
|
408 |
+
$return['swapTotal'] = $swap_total * 1000000;
|
409 |
+
$return['swapFree'] = $swap_free * 1000000;
|
410 |
+
}
|
411 |
+
|
412 |
+
// Return ram info
|
413 |
+
return $return;
|
414 |
+
}
|
415 |
+
|
416 |
+
// Model of mac
|
417 |
+
public function getModel()
|
418 |
+
{
|
419 |
+
if (preg_match('/^\s+Model Name:\s+(.+)/m', $this->systemProfiler, $m)) {
|
420 |
+
return $m[1];
|
421 |
+
}
|
422 |
+
|
423 |
+
if (preg_match('/^([a-zA-Z]+)/', $this->sysctl['hw.model'], $m)) {
|
424 |
+
return $m[1];
|
425 |
+
} else {
|
426 |
+
return $this->sysctl['hw.model'];
|
427 |
+
}
|
428 |
+
}
|
429 |
+
|
430 |
+
// Battery
|
431 |
+
public function getBattery()
|
432 |
+
{
|
433 |
+
// Time?
|
434 |
+
if (!empty($this->settings['timer'])) {
|
435 |
+
$t = new Timer('Battery');
|
436 |
+
}
|
437 |
+
|
438 |
+
// Store any we find here
|
439 |
+
$batteries = array();
|
440 |
+
|
441 |
+
// Lines
|
442 |
+
$lines = explode("\n", $this->systemProfiler);
|
443 |
+
|
444 |
+
// Hunt
|
445 |
+
$bat = array();
|
446 |
+
$in_bat_field = false;
|
447 |
+
|
448 |
+
foreach ($lines as $line) {
|
449 |
+
if (preg_match('/^\s+Battery Information/', $line)) {
|
450 |
+
$in_bat_field = true;
|
451 |
+
continue;
|
452 |
+
} elseif (preg_match('/^\s+System Power Settings/', $line)) {
|
453 |
+
$in_bat_field = false;
|
454 |
+
break;
|
455 |
+
} elseif ($in_bat_field && preg_match('/^\s+Fully charged: ([a-zA-Z]+)/i', $line, $m)) {
|
456 |
+
$bat['charged'] = $m[1] == 'Yes';
|
457 |
+
} elseif ($in_bat_field && preg_match('/^\s+Charging: ([a-zA-Z]+)/i', $line, $m)) {
|
458 |
+
$bat['charging'] = $m[1] == 'Yes';
|
459 |
+
} elseif ($in_bat_field && preg_match('/^\s+Charge remaining \(mAh\): (\d+)/i', $line, $m)) {
|
460 |
+
$bat['charge_now'] = (int) $m[1];
|
461 |
+
} elseif ($in_bat_field && preg_match('/^\s+Full charge capacity \(mAh\): (\d+)/i', $line, $m)) {
|
462 |
+
$bat['charge_full'] = (int) $m[1];
|
463 |
+
} elseif ($in_bat_field && preg_match('/^\s+Serial Number: ([A-Z0-9]+)/i', $line, $m)) {
|
464 |
+
$bat['serial'] = $m[1];
|
465 |
+
} elseif ($in_bat_field && preg_match('/^\s+Manufacturer: (\w+)/i', $line, $m)) {
|
466 |
+
$bat['vendor'] = $m[1];
|
467 |
+
} elseif ($in_bat_field && preg_match('/^\s+Device name: (\w+)/i', $line, $m)) {
|
468 |
+
$bat['name'] = $m[1];
|
469 |
+
}
|
470 |
+
}
|
471 |
+
|
472 |
+
// If we have what we need, append
|
473 |
+
if (isset($bat['charge_full']) && isset($bat['charge_now']) && isset($bat['charged']) && isset($bat['charging'])) {
|
474 |
+
$batteries[] = array(
|
475 |
+
'charge_full' => $bat['charge_full'],
|
476 |
+
'charge_now' => $bat['charge_now'],
|
477 |
+
'percentage' => $bat['charge_full'] > 0 && $bat['charge_now'] > 0 ? round($bat['charge_now'] / $bat['charge_full'], 4) * 100 .'%' : '?',
|
478 |
+
'device' => $bat['vendor'].' - '.$bat['name'],
|
479 |
+
'state' => $bat['charging'] ? 'Charging' : ($bat['charged'] ? 'Fully Charged' : 'Discharging'),
|
480 |
+
);
|
481 |
+
}
|
482 |
+
|
483 |
+
// Give
|
484 |
+
return $batteries;
|
485 |
+
}
|
486 |
+
|
487 |
+
// drives
|
488 |
+
public function getHD()
|
489 |
+
{
|
490 |
+
// Time?
|
491 |
+
if (!empty($this->settings['timer'])) {
|
492 |
+
$t = new Timer('Drives');
|
493 |
+
}
|
494 |
+
|
495 |
+
// Use system profiler to get info
|
496 |
+
try {
|
497 |
+
$res = $this->exec->exec('diskutil', ' list');
|
498 |
+
} catch (Exception $e) {
|
499 |
+
Errors::add('Linfo drives', 'Error using `diskutil list` to get drives');
|
500 |
+
|
501 |
+
return array();
|
502 |
+
}
|
503 |
+
|
504 |
+
// Get it into lines
|
505 |
+
$lines = explode("\n", $res);
|
506 |
+
|
507 |
+
// Keep drives here
|
508 |
+
$drives = array();
|
509 |
+
|
510 |
+
// Work on tmp drive here
|
511 |
+
$tmp = false;
|
512 |
+
|
513 |
+
for ($i = 0, $num_lines = count($lines); $i < $num_lines; ++$i) {
|
514 |
+
|
515 |
+
// A drive or partition entry
|
516 |
+
if (preg_match('/^\s+(\d+):\s+([a-zA-Z0-9\_]+)\s+([\s\w]*) \*?(\d+(?:\.\d+)? [A-Z])B\s+([a-z0-9]+)/', $lines[$i], $m)) {
|
517 |
+
|
518 |
+
// Get size sorted out
|
519 |
+
$size_parts = explode(' ', $m[4]);
|
520 |
+
switch ($size_parts[1]) {
|
521 |
+
case 'K':
|
522 |
+
$size = $size_parts[0] * 1000;
|
523 |
+
break;
|
524 |
+
case 'M':
|
525 |
+
$size = $size_parts[0] * 1000000;
|
526 |
+
break;
|
527 |
+
case 'G':
|
528 |
+
$size = $size_parts[0] * 1000000000;
|
529 |
+
break;
|
530 |
+
case 'T':
|
531 |
+
$size = $size_parts[0] * 1000000000000;
|
532 |
+
break;
|
533 |
+
case 'P':
|
534 |
+
$size = $size_parts[0] * 1000000000000000;
|
535 |
+
break;
|
536 |
+
default:
|
537 |
+
$size = false;
|
538 |
+
break;
|
539 |
+
}
|
540 |
+
|
541 |
+
// A drive?
|
542 |
+
if ($m[1] == 0) {
|
543 |
+
|
544 |
+
// Finish prior drive
|
545 |
+
if (is_array($tmp)) {
|
546 |
+
$drives[] = $tmp;
|
547 |
+
}
|
548 |
+
|
549 |
+
// Try getting the name
|
550 |
+
$drive_name = false; // I'm pessimistic
|
551 |
+
try {
|
552 |
+
$drive_res = $this->exec->exec('diskutil', ' info /dev/'.$m[5]);
|
553 |
+
if (preg_match('/^\s+Device \/ Media Name:\s+(.+)/m', $drive_res, $drive_m)) {
|
554 |
+
$drive_name = $drive_m[1];
|
555 |
+
}
|
556 |
+
} catch (Exception $e) {
|
557 |
+
}
|
558 |
+
|
559 |
+
// Start this one off
|
560 |
+
$tmp = array(
|
561 |
+
'name' => $drive_name,
|
562 |
+
'vendor' => 'Unknown',
|
563 |
+
'device' => '/dev/'.$m[5],
|
564 |
+
'reads' => false,
|
565 |
+
'writes' => false,
|
566 |
+
'size' => $size,
|
567 |
+
'partitions' => array(),
|
568 |
+
);
|
569 |
+
}
|
570 |
+
|
571 |
+
// Or a partition
|
572 |
+
elseif ($m[1] > 0) {
|
573 |
+
|
574 |
+
// Save it
|
575 |
+
$tmp['partitions'][] = array(
|
576 |
+
'size' => $size,
|
577 |
+
'name' => '/dev/'.$m[5],
|
578 |
+
);
|
579 |
+
}
|
580 |
+
}
|
581 |
+
}
|
582 |
+
|
583 |
+
// Save a drive
|
584 |
+
if (is_array($tmp)) {
|
585 |
+
$drives[] = $tmp;
|
586 |
+
}
|
587 |
+
|
588 |
+
// Give
|
589 |
+
return $drives;
|
590 |
+
}
|
591 |
+
|
592 |
+
public function getVirtualization()
|
593 |
+
{
|
594 |
+
|
595 |
+
// Time?
|
596 |
+
if (!empty($this->settings['timer'])) {
|
597 |
+
$t = new Timer('Determining virtualization type');
|
598 |
+
}
|
599 |
+
|
600 |
+
// All results on google show this file only being present and related to VMware Fusion
|
601 |
+
if (file_exists('/dev/vmmon')) {
|
602 |
+
return array('type' => 'host', 'method' => 'VMWare');
|
603 |
+
}
|
604 |
+
|
605 |
+
return false;
|
606 |
+
}
|
607 |
+
|
608 |
+
public function getLoad()
|
609 |
+
{
|
610 |
+
if (!empty($this->settings['timer'])) {
|
611 |
+
$t = new Timer('Load Averages');
|
612 |
+
}
|
613 |
+
|
614 |
+
$loads = $this->sysctl['vm.loadavg'];
|
615 |
+
|
616 |
+
if (preg_match('/([\d\.]+) ([\d\.]+) ([\d\.]+)/', $loads, $m)) {
|
617 |
+
return array_combine(array('now', '5min', '15min'), array_slice($m, 1, 3));
|
618 |
+
} else {
|
619 |
+
return array();
|
620 |
+
}
|
621 |
+
}
|
622 |
+
}
|
lib/Linfo/OS/DragonFly.php
ADDED
@@ -0,0 +1,415 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2011 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\OS;
|
22 |
+
|
23 |
+
use Exception;
|
24 |
+
use Linfo\Meta\Timer;
|
25 |
+
use Linfo\Meta\Errors;
|
26 |
+
use Linfo\Common;
|
27 |
+
use Linfo\Parsers\Hwpci;
|
28 |
+
|
29 |
+
class DragonFly extends BSDcommon
|
30 |
+
{
|
31 |
+
// Encapsulate these
|
32 |
+
protected $settings,
|
33 |
+
$exec,
|
34 |
+
$dmesg;
|
35 |
+
|
36 |
+
// Start us off
|
37 |
+
public function __construct($settings)
|
38 |
+
{
|
39 |
+
|
40 |
+
// Initiate parent
|
41 |
+
parent::__construct($settings);
|
42 |
+
|
43 |
+
// We search these folders for our commands
|
44 |
+
$this->exec->setSearchPaths(array('/sbin', '/bin', '/usr/bin', '/usr/local/bin', '/usr/sbin'));
|
45 |
+
|
46 |
+
// sysctl values we'll access below
|
47 |
+
$this->GetSysCTL(array(
|
48 |
+
'kern.boottime',
|
49 |
+
'vm.loadavg',
|
50 |
+
'hw.model',
|
51 |
+
'hw.ncpu',
|
52 |
+
'hw.clockrate',
|
53 |
+
), false);
|
54 |
+
}
|
55 |
+
|
56 |
+
// What we should leave out
|
57 |
+
public function getContains()
|
58 |
+
{
|
59 |
+
return array(
|
60 |
+
'drives_rw_stats' => false,
|
61 |
+
'nic_type' => false,
|
62 |
+
);
|
63 |
+
}
|
64 |
+
|
65 |
+
// Return OS type
|
66 |
+
public function getOS()
|
67 |
+
{
|
68 |
+
|
69 |
+
// Obviously
|
70 |
+
return 'DragonFly BSD';
|
71 |
+
}
|
72 |
+
|
73 |
+
// Get mounted file systems
|
74 |
+
public function getMounts()
|
75 |
+
{
|
76 |
+
|
77 |
+
// Time?
|
78 |
+
if (!empty($this->settings['timer'])) {
|
79 |
+
$t = new Timer('Mounted file systems');
|
80 |
+
}
|
81 |
+
|
82 |
+
// Get result of mount command
|
83 |
+
try {
|
84 |
+
$res = $this->exec->exec('mount');
|
85 |
+
} catch (Exception $e) {
|
86 |
+
Errors::add('Linfo Core', 'Error running `mount` command');
|
87 |
+
|
88 |
+
return array();
|
89 |
+
}
|
90 |
+
|
91 |
+
// Parse it
|
92 |
+
if (preg_match_all('/^(\S+) on (\S+) \((\w+)(?:, (.+))?\)/m', $res, $m, PREG_SET_ORDER) == 0) {
|
93 |
+
return array();
|
94 |
+
}
|
95 |
+
|
96 |
+
// Store them here
|
97 |
+
$mounts = array();
|
98 |
+
|
99 |
+
// Deal with each entry
|
100 |
+
foreach ($m as $mount) {
|
101 |
+
|
102 |
+
// Should we not show this?
|
103 |
+
if (in_array($mount[1], $this->settings['hide']['storage_devices']) || in_array($mount[3], $this->settings['hide']['filesystems'])) {
|
104 |
+
continue;
|
105 |
+
}
|
106 |
+
|
107 |
+
// Get these
|
108 |
+
$size = @disk_total_space($mount[2]);
|
109 |
+
$free = @disk_free_space($mount[2]);
|
110 |
+
$used = $size - $free;
|
111 |
+
|
112 |
+
// Optionally get mount options
|
113 |
+
if (
|
114 |
+
$this->settings['show']['mounts_options'] &&
|
115 |
+
!in_array($mount[3], (array) $this->settings['hide']['fs_mount_options']) &&
|
116 |
+
isset($mount[4])
|
117 |
+
) {
|
118 |
+
$mount_options = explode(', ', $mount[4]);
|
119 |
+
} else {
|
120 |
+
$mount_options = array();
|
121 |
+
}
|
122 |
+
|
123 |
+
// Might be good, go for it
|
124 |
+
$mounts[] = array(
|
125 |
+
'device' => $mount[1],
|
126 |
+
'mount' => $mount[2],
|
127 |
+
'type' => $mount[3],
|
128 |
+
'size' => $size ,
|
129 |
+
'used' => $used,
|
130 |
+
'free' => $free,
|
131 |
+
'free_percent' => ((bool) $free != false && (bool) $size != false ? round($free / $size, 2) * 100 : false),
|
132 |
+
'used_percent' => ((bool) $used != false && (bool) $size != false ? round($used / $size, 2) * 100 : false),
|
133 |
+
'options' => $mount_options,
|
134 |
+
);
|
135 |
+
}
|
136 |
+
|
137 |
+
// Give it
|
138 |
+
return $mounts;
|
139 |
+
}
|
140 |
+
|
141 |
+
// Get ram usage
|
142 |
+
public function getRam()
|
143 |
+
{
|
144 |
+
|
145 |
+
// Time?
|
146 |
+
if (!empty($this->settings['timer'])) {
|
147 |
+
$t = new Timer('Memory');
|
148 |
+
}
|
149 |
+
|
150 |
+
// We'll return the contents of this
|
151 |
+
$return = array();
|
152 |
+
|
153 |
+
// Start us off at zilch
|
154 |
+
$return['type'] = 'Virtual';
|
155 |
+
$return['total'] = 0;
|
156 |
+
$return['free'] = 0;
|
157 |
+
$return['swapTotal'] = 0;
|
158 |
+
$return['swapFree'] = 0;
|
159 |
+
$return['swapInfo'] = array();
|
160 |
+
|
161 |
+
// Get swap
|
162 |
+
|
163 |
+
// Return it
|
164 |
+
return $return;
|
165 |
+
}
|
166 |
+
|
167 |
+
// Get uptime
|
168 |
+
public function getUpTime()
|
169 |
+
{
|
170 |
+
|
171 |
+
// Time?
|
172 |
+
if (!empty($this->settings['timer'])) {
|
173 |
+
$t = new Timer('Uptime');
|
174 |
+
}
|
175 |
+
|
176 |
+
// Use sysctl to get unix timestamp of boot. Very elegant!
|
177 |
+
if (preg_match('/^\{ sec \= (\d+).+$/', $this->sysctl['kern.boottime'], $m) == 0) {
|
178 |
+
return '';
|
179 |
+
}
|
180 |
+
|
181 |
+
// Boot unix timestamp
|
182 |
+
$booted = $m[1];
|
183 |
+
|
184 |
+
// Get it textual, as in days/minutes/hours/etc
|
185 |
+
return array(
|
186 |
+
'text' => Common::secondsConvert(time() - $booted),
|
187 |
+
'bootedTimestamp' => $booted,
|
188 |
+
);
|
189 |
+
}
|
190 |
+
|
191 |
+
// RAID Stats
|
192 |
+
public function getRAID()
|
193 |
+
{
|
194 |
+
}
|
195 |
+
|
196 |
+
// Done
|
197 |
+
public function getNet()
|
198 |
+
{
|
199 |
+
|
200 |
+
// Time?
|
201 |
+
if (!empty($this->settings['timer'])) {
|
202 |
+
$t = new Timer('Network Devices');
|
203 |
+
}
|
204 |
+
|
205 |
+
// Use netstat to get nic names and stats
|
206 |
+
try {
|
207 |
+
$netstat = $this->exec->exec('netstat', '-nibd');
|
208 |
+
} catch (Exception $e) {
|
209 |
+
Errors::add('Linfo Core', 'error using netstat');
|
210 |
+
|
211 |
+
return array();
|
212 |
+
}
|
213 |
+
|
214 |
+
// Store nics here
|
215 |
+
$nets = array();
|
216 |
+
|
217 |
+
// Match that up
|
218 |
+
if (!preg_match_all('/^([\da-z]+\*?)\s+\d+\s+<Link#\d+>(?:\s+[a-z0-9:]+)?\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/m', $netstat, $netstat_m, PREG_SET_ORDER)) {
|
219 |
+
return array();
|
220 |
+
}
|
221 |
+
|
222 |
+
// Go through each match
|
223 |
+
foreach ($netstat_m as $m) {
|
224 |
+
$nets[$m[1]] = array(
|
225 |
+
'recieved' => array(
|
226 |
+
'bytes' => $m[4],
|
227 |
+
'errors' => $m[3],
|
228 |
+
'packets' => $m[2],
|
229 |
+
),
|
230 |
+
'sent' => array(
|
231 |
+
'bytes' => $m[7],
|
232 |
+
'errors' => $m[6],
|
233 |
+
'packets' => $m[5],
|
234 |
+
),
|
235 |
+
'state' => 'unknown',
|
236 |
+
'type' => 'N/A',
|
237 |
+
);
|
238 |
+
}
|
239 |
+
|
240 |
+
// Try getting the statuses with ifconfig
|
241 |
+
try {
|
242 |
+
|
243 |
+
// Store current nic here
|
244 |
+
$current_nic = false;
|
245 |
+
|
246 |
+
$ifconfig = $this->exec->exec('ifconfig', '-a');
|
247 |
+
|
248 |
+
// Go through each line
|
249 |
+
foreach (explode("\n", $ifconfig) as $line) {
|
250 |
+
|
251 |
+
// Approaching new nic?
|
252 |
+
if (preg_match('/^([a-z0-9]+):/', $line, $m)) {
|
253 |
+
if (array_key_exists($m[1], $nets)) {
|
254 |
+
$current_nic = $m[1];
|
255 |
+
} else {
|
256 |
+
$current_nic = false;
|
257 |
+
}
|
258 |
+
}
|
259 |
+
|
260 |
+
// In a nick and found a status entry
|
261 |
+
elseif ($current_nic && preg_match('/^\s+status: ([^$]+)$/', $line, $m)) {
|
262 |
+
|
263 |
+
// Decide what it is and save it
|
264 |
+
switch ($m[1]) {
|
265 |
+
case 'active':
|
266 |
+
$nets[$current_nic]['state'] = 'up';
|
267 |
+
break;
|
268 |
+
case 'inactive':
|
269 |
+
case 'no carrier':
|
270 |
+
$nets[$current_nic]['state'] = 'down';
|
271 |
+
break;
|
272 |
+
default:
|
273 |
+
$nets[$current_nic]['state'] = 'unknown';
|
274 |
+
break;
|
275 |
+
}
|
276 |
+
|
277 |
+
// Don't waste further time until we find another nic entry
|
278 |
+
$current_nic = false;
|
279 |
+
}
|
280 |
+
}
|
281 |
+
} catch (Exception $e) {
|
282 |
+
Errors::add('Linfo Core', 'error using ifconfig to get nic statuses');
|
283 |
+
}
|
284 |
+
|
285 |
+
// Give nets
|
286 |
+
return $nets;
|
287 |
+
}
|
288 |
+
|
289 |
+
// Get CPU's
|
290 |
+
// I still don't really like how this is done
|
291 |
+
public function getCPU()
|
292 |
+
{
|
293 |
+
|
294 |
+
// Time?
|
295 |
+
if (!empty($this->settings['timer'])) {
|
296 |
+
$t = new Timer('CPUs');
|
297 |
+
}
|
298 |
+
|
299 |
+
// Store them here
|
300 |
+
$cpus = array();
|
301 |
+
|
302 |
+
// Stuff it with identical cpus
|
303 |
+
for ($i = 0; $i < $this->sysctl['hw.ncpu']; ++$i) {
|
304 |
+
|
305 |
+
// Save each
|
306 |
+
$cpus[] = array(
|
307 |
+
'Model' => $this->sysctl['hw.model'],
|
308 |
+
'MHz' => $this->sysctl['hw.clockrate'],
|
309 |
+
);
|
310 |
+
}
|
311 |
+
|
312 |
+
// Return
|
313 |
+
return $cpus;
|
314 |
+
}
|
315 |
+
|
316 |
+
// Parse dmesg boot log
|
317 |
+
public function getDevs()
|
318 |
+
{
|
319 |
+
|
320 |
+
// Time?
|
321 |
+
if (!empty($this->settings['timer'])) {
|
322 |
+
$t = new Timer('Hardware Devices');
|
323 |
+
}
|
324 |
+
|
325 |
+
$hw = new Hwpci(null, '/usr/share/misc/pci_vendors');
|
326 |
+
$hw->work('dragonfly');
|
327 |
+
|
328 |
+
return $hw->result();
|
329 |
+
}
|
330 |
+
|
331 |
+
// APM? Seems to only support either one battery of them all collectively
|
332 |
+
public function getBattery()
|
333 |
+
{
|
334 |
+
|
335 |
+
// Time?
|
336 |
+
if (!empty($this->settings['timer'])) {
|
337 |
+
$t = new Timer('Batteries');
|
338 |
+
}
|
339 |
+
|
340 |
+
return array();
|
341 |
+
}
|
342 |
+
|
343 |
+
// Get stats on processes
|
344 |
+
public function getProcessStats()
|
345 |
+
{
|
346 |
+
|
347 |
+
// Time?
|
348 |
+
if (!empty($this->settings['timer'])) {
|
349 |
+
$t = new Timer('Process Stats');
|
350 |
+
}
|
351 |
+
|
352 |
+
// We'll return this after stuffing it with useful info
|
353 |
+
$result = array(
|
354 |
+
'exists' => true,
|
355 |
+
'totals' => array(
|
356 |
+
'running' => 0,
|
357 |
+
'zombie' => 0,
|
358 |
+
'sleeping' => 0,
|
359 |
+
'stopped' => 0,
|
360 |
+
'idle' => 0,
|
361 |
+
),
|
362 |
+
'proc_total' => 0,
|
363 |
+
'threads' => false, // I'm not sure how to get this
|
364 |
+
);
|
365 |
+
|
366 |
+
// Use ps
|
367 |
+
try {
|
368 |
+
// Get it
|
369 |
+
$ps = $this->exec->exec('ps', 'ax');
|
370 |
+
|
371 |
+
// Match them
|
372 |
+
preg_match_all('/^\s*\d+\s+[\w?]+\s+([A-Z])\S*\s+.+$/m', $ps, $processes, PREG_SET_ORDER);
|
373 |
+
|
374 |
+
// Get total
|
375 |
+
$result['proc_total'] = count($processes);
|
376 |
+
|
377 |
+
// Go through
|
378 |
+
foreach ($processes as $process) {
|
379 |
+
switch ($process[1]) {
|
380 |
+
case 'S':
|
381 |
+
case 'I':
|
382 |
+
$result['totals']['sleeping']++;
|
383 |
+
break;
|
384 |
+
case 'Z':
|
385 |
+
$result['totals']['zombie']++;
|
386 |
+
break;
|
387 |
+
case 'R':
|
388 |
+
case 'D':
|
389 |
+
$result['totals']['running']++;
|
390 |
+
break;
|
391 |
+
case 'T':
|
392 |
+
$result['totals']['stopped']++;
|
393 |
+
break;
|
394 |
+
case 'W':
|
395 |
+
$result['totals']['idle']++;
|
396 |
+
break;
|
397 |
+
}
|
398 |
+
}
|
399 |
+
} catch (Exception $e) {
|
400 |
+
Errors::add('Linfo Core', 'Error using `ps` to get process info');
|
401 |
+
}
|
402 |
+
|
403 |
+
// Give
|
404 |
+
return $result;
|
405 |
+
}
|
406 |
+
|
407 |
+
// idk
|
408 |
+
public function getTemps()
|
409 |
+
{
|
410 |
+
// Time?
|
411 |
+
if (!empty($this->settings['timer'])) {
|
412 |
+
$t = new Timer('Temperature');
|
413 |
+
}
|
414 |
+
}
|
415 |
+
}
|
lib/Linfo/OS/FreeBSD.php
ADDED
@@ -0,0 +1,729 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\OS;
|
22 |
+
|
23 |
+
use Exception;
|
24 |
+
use Linfo\Meta\Timer;
|
25 |
+
use Linfo\Meta\Errors;
|
26 |
+
use Linfo\Common;
|
27 |
+
use Linfo\Parsers\Hwpci;
|
28 |
+
|
29 |
+
/*
|
30 |
+
* Mostly complete FreeBSD info class.
|
31 |
+
*
|
32 |
+
* Note: When Linux compatibility is enabled and /proc is mounted, it only
|
33 |
+
* contains process info; none of the hardware/system/network status that Linux /proc has.
|
34 |
+
*/
|
35 |
+
|
36 |
+
class FreeBSD extends BSDcommon
|
37 |
+
{
|
38 |
+
// Encapsulate these
|
39 |
+
protected $settings,
|
40 |
+
$exec,
|
41 |
+
$dmesg,
|
42 |
+
$version;
|
43 |
+
|
44 |
+
// Start us off
|
45 |
+
public function __construct($settings)
|
46 |
+
{
|
47 |
+
|
48 |
+
// Initiate parent
|
49 |
+
parent::__construct($settings);
|
50 |
+
|
51 |
+
// We search these folders for our commands
|
52 |
+
$this->exec->setSearchPaths(array('/sbin', '/bin', '/usr/bin', '/usr/local/bin', '/usr/sbin'));
|
53 |
+
|
54 |
+
// sysctl values we'll access below
|
55 |
+
$this->GetSysCTL(array(
|
56 |
+
|
57 |
+
// Has unix timestamp of boot time
|
58 |
+
'kern.boottime',
|
59 |
+
|
60 |
+
// Ram stuff
|
61 |
+
'vm.vmtotal',
|
62 |
+
'vm.loadavg',
|
63 |
+
|
64 |
+
// CPU related
|
65 |
+
'hw.model',
|
66 |
+
'hw.ncpu',
|
67 |
+
'hw.clockrate',
|
68 |
+
), false);
|
69 |
+
|
70 |
+
// Save version
|
71 |
+
if (preg_match('/^([\d\.]+)/', php_uname('r'), $vm) != 0) {
|
72 |
+
$this->version = (float) $vm[1];
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Return a list of things to hide from view..
|
78 |
+
*
|
79 |
+
* @return array
|
80 |
+
*/
|
81 |
+
public function getContains()
|
82 |
+
{
|
83 |
+
return array(
|
84 |
+
'drives_rw_stats' => false,
|
85 |
+
'nic_port_speed' => false,
|
86 |
+
);
|
87 |
+
}
|
88 |
+
|
89 |
+
// Get mounted file systems
|
90 |
+
public function getMounts()
|
91 |
+
{
|
92 |
+
|
93 |
+
// Time?
|
94 |
+
if (!empty($this->settings['timer'])) {
|
95 |
+
$t = new Timer('Mounted file systems');
|
96 |
+
}
|
97 |
+
|
98 |
+
// Get result of mount command
|
99 |
+
try {
|
100 |
+
$res = $this->exec->exec('mount');
|
101 |
+
} catch (Exception $e) {
|
102 |
+
Errors::add('Linfo Core', 'Error running `mount` command');
|
103 |
+
|
104 |
+
return array();
|
105 |
+
}
|
106 |
+
|
107 |
+
// Parse it
|
108 |
+
if (preg_match_all('/^(\S+) on (\S+) \((\w+)(?:, (.+))?\)/m', $res, $m, PREG_SET_ORDER) == 0) {
|
109 |
+
return array();
|
110 |
+
}
|
111 |
+
|
112 |
+
// Store them here
|
113 |
+
$mounts = array();
|
114 |
+
|
115 |
+
// Deal with each entry
|
116 |
+
foreach ($m as $mount) {
|
117 |
+
|
118 |
+
// Should we not show this?
|
119 |
+
if (in_array($mount[1], $this->settings['hide']['storage_devices']) || in_array($mount[3], $this->settings['hide']['filesystems'])) {
|
120 |
+
continue;
|
121 |
+
}
|
122 |
+
|
123 |
+
// Get these
|
124 |
+
$size = @disk_total_space($mount[2]);
|
125 |
+
$free = @disk_free_space($mount[2]);
|
126 |
+
$used = $size - $free;
|
127 |
+
|
128 |
+
// Optionally get mount options
|
129 |
+
if (
|
130 |
+
$this->settings['show']['mounts_options'] &&
|
131 |
+
!in_array($mount[3], (array) $this->settings['hide']['fs_mount_options']) &&
|
132 |
+
isset($mount[4])
|
133 |
+
) {
|
134 |
+
$mount_options = explode(', ', $mount[4]);
|
135 |
+
} else {
|
136 |
+
$mount_options = array();
|
137 |
+
}
|
138 |
+
|
139 |
+
// Might be good, go for it
|
140 |
+
$mounts[] = array(
|
141 |
+
'device' => $mount[1],
|
142 |
+
'mount' => $mount[2],
|
143 |
+
'type' => $mount[3],
|
144 |
+
'size' => $size ,
|
145 |
+
'used' => $used,
|
146 |
+
'free' => $free,
|
147 |
+
'free_percent' => ((bool) $free != false && (bool) $size != false ? round($free / $size, 2) * 100 : false),
|
148 |
+
'used_percent' => ((bool) $used != false && (bool) $size != false ? round($used / $size, 2) * 100 : false),
|
149 |
+
'options' => $mount_options,
|
150 |
+
);
|
151 |
+
}
|
152 |
+
|
153 |
+
// Give it
|
154 |
+
return $mounts;
|
155 |
+
}
|
156 |
+
|
157 |
+
// Get ram usage
|
158 |
+
public function getRam()
|
159 |
+
{
|
160 |
+
|
161 |
+
// Time?
|
162 |
+
if (!empty($this->settings['timer'])) {
|
163 |
+
$t = new Timer('Memory');
|
164 |
+
}
|
165 |
+
|
166 |
+
// We'll return the contents of this
|
167 |
+
$return = array();
|
168 |
+
|
169 |
+
// Start us off at zilch
|
170 |
+
$return['type'] = 'Virtual';
|
171 |
+
$return['total'] = 0;
|
172 |
+
$return['free'] = 0;
|
173 |
+
$return['swapTotal'] = 0;
|
174 |
+
$return['swapFree'] = 0;
|
175 |
+
$return['swapInfo'] = array();
|
176 |
+
|
177 |
+
// Parse the vm.vmtotal sysctl entry
|
178 |
+
if (!preg_match_all('/([a-z\ ]+):\s*\(Total: (\d+)\w,? Active:? (\d+)\w\)\n/i', $this->sysctl['vm.vmtotal'], $rm, PREG_SET_ORDER)) {
|
179 |
+
return $return;
|
180 |
+
}
|
181 |
+
|
182 |
+
// Parse each entry
|
183 |
+
foreach ($rm as $r) {
|
184 |
+
if ($r[1] == 'Real Memory') {
|
185 |
+
$return['total'] = $r[2] * 1024;
|
186 |
+
$return['free'] = ($r[2] - $r[3]) * 1024;
|
187 |
+
}
|
188 |
+
}
|
189 |
+
|
190 |
+
// Swap info
|
191 |
+
try {
|
192 |
+
$swapinfo = $this->exec->exec('swapinfo', '-k');
|
193 |
+
// Parse swap info
|
194 |
+
@preg_match_all('/^(\S+)\s+(\d+)\s+(\d+)\s+(\d+)/m', $swapinfo, $sm, PREG_SET_ORDER);
|
195 |
+
foreach ($sm as $swap) {
|
196 |
+
$return['swapTotal'] += $swap[2] * 1024;
|
197 |
+
$return['swapFree'] += (($swap[2] - $swap[3]) * 1024);
|
198 |
+
$ft = @filetype($swap[1]); // TODO: I'd rather it be Partition or File
|
199 |
+
$return['swapInfo'][] = array(
|
200 |
+
'device' => $swap[1],
|
201 |
+
'size' => $swap[2] * 1024,
|
202 |
+
'used' => $swap[3] * 1024,
|
203 |
+
'type' => ucfirst($ft),
|
204 |
+
);
|
205 |
+
}
|
206 |
+
} catch (Exception $e) {
|
207 |
+
Errors::add('Linfo Core', 'Error using `swapinfo` to get swap usage');
|
208 |
+
// meh
|
209 |
+
}
|
210 |
+
|
211 |
+
// Return it
|
212 |
+
return $return;
|
213 |
+
}
|
214 |
+
|
215 |
+
// Get uptime
|
216 |
+
public function getUpTime()
|
217 |
+
{
|
218 |
+
|
219 |
+
// Time?
|
220 |
+
if (!empty($this->settings['timer'])) {
|
221 |
+
$t = new Timer('Uptime');
|
222 |
+
}
|
223 |
+
|
224 |
+
// Use sysctl to get unix timestamp of boot. Very elegant!
|
225 |
+
if (preg_match('/^\{ sec \= (\d+).+$/', $this->sysctl['kern.boottime'], $m) == 0) {
|
226 |
+
return '';
|
227 |
+
}
|
228 |
+
|
229 |
+
// Boot unix timestamp
|
230 |
+
$booted = $m[1];
|
231 |
+
|
232 |
+
// Give it
|
233 |
+
return array(
|
234 |
+
'text' => Common::secondsConvert(time() - $booted),
|
235 |
+
'bootedTimestamp' => $booted,
|
236 |
+
);
|
237 |
+
}
|
238 |
+
|
239 |
+
// RAID Stats
|
240 |
+
public function getRAID()
|
241 |
+
{
|
242 |
+
|
243 |
+
// Time?
|
244 |
+
if (!empty($this->settings['timer'])) {
|
245 |
+
$t = new Timer('RAID');
|
246 |
+
}
|
247 |
+
|
248 |
+
// Store raid arrays here
|
249 |
+
$return = array();
|
250 |
+
|
251 |
+
// Counter for each raid array
|
252 |
+
$i = 0;
|
253 |
+
|
254 |
+
// Gmirror?
|
255 |
+
if (array_key_exists('gmirror', $this->settings['raid']) && !empty($this->settings['raid']['gmirror'])) {
|
256 |
+
try {
|
257 |
+
// Run gmirror status program to get raid array status
|
258 |
+
$res = $this->exec->exec('gmirror', 'status');
|
259 |
+
|
260 |
+
// Divide that into lines
|
261 |
+
$lines = explode("\n", $res);
|
262 |
+
|
263 |
+
// First is worthless
|
264 |
+
unset($lines[0]);
|
265 |
+
|
266 |
+
// Parse the remaining ones
|
267 |
+
foreach ($lines as $line => $content) {
|
268 |
+
|
269 |
+
// Hitting a new raid definition
|
270 |
+
if (preg_match('/^(\w+)\/(\w+)\s+(\w+)\s+(\w+)$/', $content, $m)) {
|
271 |
+
++$i;
|
272 |
+
|
273 |
+
switch ($m[1]) {
|
274 |
+
case 'mirror':
|
275 |
+
$m[1] = 1;
|
276 |
+
break;
|
277 |
+
case 'stripe':
|
278 |
+
$m[1] = 0;
|
279 |
+
break;
|
280 |
+
default:
|
281 |
+
$m[1] = 'unknown';
|
282 |
+
break;
|
283 |
+
}
|
284 |
+
|
285 |
+
switch ($m[3]) {
|
286 |
+
case 'COMPLETE':
|
287 |
+
$m[3] = 'normal';
|
288 |
+
break;
|
289 |
+
case 'DEGRADED':
|
290 |
+
$m[3] = 'failed';
|
291 |
+
break;
|
292 |
+
default:
|
293 |
+
$m[3] = 'unknown';
|
294 |
+
break;
|
295 |
+
}
|
296 |
+
|
297 |
+
// Save result set
|
298 |
+
$return[$i] = array(
|
299 |
+
'device' => $m[2],
|
300 |
+
'level' => $m[1],
|
301 |
+
'status' => $m[3],
|
302 |
+
'drives' => array(array('drive' => $m[4], 'state' => 'unknown')),
|
303 |
+
'size' => 'unknown',
|
304 |
+
'count' => '?/?',
|
305 |
+
);
|
306 |
+
}
|
307 |
+
|
308 |
+
// Hitting a new device in a raid definition
|
309 |
+
elseif (preg_match('/^ (\w+)$/', $content, $m)) {
|
310 |
+
|
311 |
+
// This migh be part of a raid dev; save it if it is
|
312 |
+
if (array_key_exists($i, $return)) {
|
313 |
+
$return[$i]['drives'][] = array('drive' => $m[1], 'state' => 'unknown');
|
314 |
+
}
|
315 |
+
}
|
316 |
+
}
|
317 |
+
} catch (Exception $e) {
|
318 |
+
Errors::add('RAID', 'Error using gmirror to get raid info');
|
319 |
+
// Don't jump out; allow potential more raid array
|
320 |
+
// mechanisms to be gathered and outputted
|
321 |
+
}
|
322 |
+
}
|
323 |
+
|
324 |
+
// Give off raid info
|
325 |
+
return $return;
|
326 |
+
}
|
327 |
+
|
328 |
+
// Done
|
329 |
+
public function getNet()
|
330 |
+
{
|
331 |
+
|
332 |
+
// Time?
|
333 |
+
if (!empty($this->settings['timer'])) {
|
334 |
+
$t = new Timer('Network Devices');
|
335 |
+
}
|
336 |
+
|
337 |
+
// Store return vals here
|
338 |
+
$return = array();
|
339 |
+
|
340 |
+
// Use netstat to get info
|
341 |
+
try {
|
342 |
+
$netstat = $this->exec->exec('netstat', '-nbdi');
|
343 |
+
} catch (Exception $e) {
|
344 |
+
Errors::add('Linfo Core', 'Error using `netstat` to get network info');
|
345 |
+
|
346 |
+
return $return;
|
347 |
+
}
|
348 |
+
|
349 |
+
// Initially get interfaces themselves along with numerical stats
|
350 |
+
if (preg_match_all('/^(\w+\w)\*?\s*\w+\s+<Link\#\w+>(?:\D+|\s+\w+:\w+:\w+:\w+:\w+:\w+\s+)(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+/m', $netstat, $netstat_match, PREG_SET_ORDER) == 0) {
|
351 |
+
return $return;
|
352 |
+
}
|
353 |
+
|
354 |
+
// Try using ifconfig to get states of the network interfaces
|
355 |
+
$statuses = array();
|
356 |
+
try {
|
357 |
+
// Output of ifconfig command
|
358 |
+
$ifconfig = $this->exec->exec('ifconfig', '-a');
|
359 |
+
|
360 |
+
// Set this to false to prevent wasted regexes
|
361 |
+
$current_nic = false;
|
362 |
+
|
363 |
+
// Go through each line
|
364 |
+
foreach ((array) explode("\n", $ifconfig) as $line) {
|
365 |
+
|
366 |
+
// Approachign new nic def
|
367 |
+
if (preg_match('/^(\w+):/', $line, $m) == 1) {
|
368 |
+
$current_nic = $m[1];
|
369 |
+
}
|
370 |
+
|
371 |
+
// Hopefully match its status
|
372 |
+
elseif ($current_nic && preg_match('/^\s+status: ([^\$]+)/', $line, $m) == 1) {
|
373 |
+
$statuses[$current_nic] = $m[1];
|
374 |
+
$current_nic = false;
|
375 |
+
}
|
376 |
+
}
|
377 |
+
} catch (Exception $e) {
|
378 |
+
}
|
379 |
+
|
380 |
+
// Get type from dmesg boot
|
381 |
+
$type = array();
|
382 |
+
$type_nics = array();
|
383 |
+
|
384 |
+
// Store the to-be detected nics here
|
385 |
+
foreach ($netstat_match as $net) {
|
386 |
+
$type_nics[] = $net[1];
|
387 |
+
}
|
388 |
+
|
389 |
+
// Go through dmesg looking for them
|
390 |
+
if (preg_match_all('/^(\w+): <.+>.+on ([a-z]+)\d+/m', $this->dmesg, $type_match, PREG_SET_ORDER)) {
|
391 |
+
|
392 |
+
// Go through each
|
393 |
+
foreach ($type_match as $type_nic_match) {
|
394 |
+
|
395 |
+
// Is this one of our detected nics?
|
396 |
+
if (in_array($type_nic_match[1], $type_nics)) {
|
397 |
+
|
398 |
+
// Yes; save status
|
399 |
+
$type[$type_nic_match[1]] = $type_nic_match[2];
|
400 |
+
}
|
401 |
+
}
|
402 |
+
}
|
403 |
+
|
404 |
+
// Save info
|
405 |
+
foreach ($netstat_match as $net) {
|
406 |
+
|
407 |
+
// Determine status
|
408 |
+
switch (array_key_exists($net[1], $statuses) ? $statuses[$net[1]] : 'unknown') {
|
409 |
+
|
410 |
+
case 'active':
|
411 |
+
$state = 'up';
|
412 |
+
break;
|
413 |
+
|
414 |
+
case 'inactive':
|
415 |
+
case 'no carrier':
|
416 |
+
$state = 'down';
|
417 |
+
break;
|
418 |
+
|
419 |
+
default:
|
420 |
+
$state = 'unknown';
|
421 |
+
break;
|
422 |
+
}
|
423 |
+
|
424 |
+
// Save info
|
425 |
+
$return[$net[1]] = array(
|
426 |
+
|
427 |
+
// These came from netstat
|
428 |
+
'recieved' => array(
|
429 |
+
'bytes' => (int) $net[$this->version >= 8 ? 5 : 4],
|
430 |
+
'errors' => $net[3],
|
431 |
+
'packets' => $net[2],
|
432 |
+
),
|
433 |
+
'sent' => array(
|
434 |
+
'bytes' => (int) $net[$this->version >= 8 ? 8 : 7],
|
435 |
+
'errors' => $net[6],
|
436 |
+
'packets' => $net[5],
|
437 |
+
),
|
438 |
+
|
439 |
+
// This came from ifconfig -a
|
440 |
+
'state' => $state,
|
441 |
+
|
442 |
+
// And this came from dmeg.
|
443 |
+
// TODO: Value for following is usually vague
|
444 |
+
'type' => array_key_exists($net[1], $type) ? strtoupper($type[$net[1]]) : 'N/A',
|
445 |
+
);
|
446 |
+
}
|
447 |
+
|
448 |
+
// Return it
|
449 |
+
return $return;
|
450 |
+
}
|
451 |
+
|
452 |
+
// Get CPU's
|
453 |
+
// I still don't really like how this is done
|
454 |
+
// todo: support multiple non-identical cpu's
|
455 |
+
public function getCPU()
|
456 |
+
{
|
457 |
+
|
458 |
+
// Time?
|
459 |
+
if (!empty($this->settings['timer'])) {
|
460 |
+
$t = new Timer('CPUs');
|
461 |
+
}
|
462 |
+
|
463 |
+
// Store them here
|
464 |
+
$cpus = array();
|
465 |
+
|
466 |
+
// Stuff it with identical cpus
|
467 |
+
for ($i = 0; $i < $this->sysctl['hw.ncpu']; ++$i) {
|
468 |
+
|
469 |
+
// Save each
|
470 |
+
$cpus[] = array(
|
471 |
+
'Model' => $this->sysctl['hw.model'],
|
472 |
+
'MHz' => (int) trim($this->sysctl['hw.clockrate']),
|
473 |
+
);
|
474 |
+
}
|
475 |
+
|
476 |
+
// Return
|
477 |
+
return $cpus;
|
478 |
+
}
|
479 |
+
|
480 |
+
// TODO: Get reads/writes and partitions for the drives
|
481 |
+
public function getHD()
|
482 |
+
{
|
483 |
+
|
484 |
+
// Time?
|
485 |
+
if (!empty($this->settings['timer'])) {
|
486 |
+
$t = new Timer('Drives');
|
487 |
+
}
|
488 |
+
|
489 |
+
// Keep them here
|
490 |
+
$drives = array();
|
491 |
+
|
492 |
+
// Must they change the format of everything with each release?!?!?!?!
|
493 |
+
switch ($this->version) {
|
494 |
+
|
495 |
+
case 8.2:
|
496 |
+
$cur = false;
|
497 |
+
|
498 |
+
// Each line of dmesg boot log
|
499 |
+
foreach ((array) explode("\n", $this->dmesg) as $line) {
|
500 |
+
|
501 |
+
// Start of a drive entry which spans multiple lines
|
502 |
+
if (preg_match('/^((?:ad|da|acd|cd)\d+) at/', $line, $m)) {
|
503 |
+
$cur = array('device' => '/dev/'.$m[1]);
|
504 |
+
}
|
505 |
+
|
506 |
+
// Branding of this drive
|
507 |
+
elseif ($cur && preg_match('/^((?:ad|da|acd|cd)\d+): \<([^>]+)\>/', $line, $m)) {
|
508 |
+
if ('/dev/'.$m[1] != $cur['device']) {
|
509 |
+
continue;
|
510 |
+
}
|
511 |
+
$halves = explode(' ', $m[2]);
|
512 |
+
if (count($halves) > 1) {
|
513 |
+
$cur['vendor'] = $halves[0];
|
514 |
+
$cur['name'] = $halves[1];
|
515 |
+
} else {
|
516 |
+
$cur['vendor'] = false;
|
517 |
+
$cur['name'] = $m[1];
|
518 |
+
}
|
519 |
+
}
|
520 |
+
|
521 |
+
// Lastly the size; gather it and save it
|
522 |
+
elseif ($cur && preg_match('/^((?:ad|da|acd|cd)\d+): (\d+)MB/', $line, $m)) {
|
523 |
+
if ('/dev/'.$m[1] != $cur['device']) {
|
524 |
+
$cur = false;
|
525 |
+
continue;
|
526 |
+
}
|
527 |
+
$cur['size'] = $m[2] * 1048576;
|
528 |
+
$drives[] = $cur;
|
529 |
+
$cur = false;
|
530 |
+
}
|
531 |
+
}
|
532 |
+
break;
|
533 |
+
|
534 |
+
default:
|
535 |
+
if (preg_match_all('/^((?:ad|da|acd|cd)\d+)\: ((?:\w+|\d+\w+)) \<(\S+)\s+([^>]+)\>/m', $this->dmesg, $m, PREG_SET_ORDER) > 0) {
|
536 |
+
foreach ($m as $drive) {
|
537 |
+
$drives[] = array(
|
538 |
+
'name' => $drive[4],
|
539 |
+
'vendor' => $drive[3],
|
540 |
+
'device' => '/dev/'.$drive[1],
|
541 |
+
'size' => preg_match('/^(\d+)MB$/', $drive[2], $m) == 1 ? $m[1] * 1048576 : false,
|
542 |
+
'reads' => false,
|
543 |
+
'writes' => false,
|
544 |
+
);
|
545 |
+
}
|
546 |
+
}
|
547 |
+
break;
|
548 |
+
}
|
549 |
+
|
550 |
+
// Return
|
551 |
+
return $drives;
|
552 |
+
}
|
553 |
+
|
554 |
+
// Parse dmesg boot log
|
555 |
+
public function getDevs()
|
556 |
+
{
|
557 |
+
|
558 |
+
// Time?
|
559 |
+
if (!empty($this->settings['timer'])) {
|
560 |
+
$t = new Timer('Hardware Devices');
|
561 |
+
}
|
562 |
+
|
563 |
+
// Class that does it
|
564 |
+
$hw = new Hwpci(false, '/usr/share/misc/pci_vendors');
|
565 |
+
$hw->work('freebsd');
|
566 |
+
|
567 |
+
return $hw->result();
|
568 |
+
}
|
569 |
+
|
570 |
+
// APM? Seems to only support either one battery of them all collectively
|
571 |
+
public function getBattery()
|
572 |
+
{
|
573 |
+
|
574 |
+
// Time?
|
575 |
+
if (!empty($this->settings['timer'])) {
|
576 |
+
$t = new Timer('Batteries');
|
577 |
+
}
|
578 |
+
|
579 |
+
// Store them here
|
580 |
+
$batts = array();
|
581 |
+
|
582 |
+
// Get result of program
|
583 |
+
try {
|
584 |
+
$res = $this->exec->exec('apm', '-abl');
|
585 |
+
} catch (Exception $e) {
|
586 |
+
Errors::add('Linfo Core', 'Error using `apm` battery info');
|
587 |
+
|
588 |
+
return $batts;
|
589 |
+
}
|
590 |
+
|
591 |
+
// Values from program
|
592 |
+
list(, $bat_status, $percentage) = explode("\n", $res);
|
593 |
+
|
594 |
+
// Interpret status code
|
595 |
+
switch ($bat_status) {
|
596 |
+
case 0:
|
597 |
+
$status = 'High';
|
598 |
+
break;
|
599 |
+
case 1:
|
600 |
+
$status = 'Low';
|
601 |
+
break;
|
602 |
+
case 2:
|
603 |
+
$status = 'Critical';
|
604 |
+
break;
|
605 |
+
case 3:
|
606 |
+
$status = 'Charging';
|
607 |
+
break;
|
608 |
+
default:
|
609 |
+
$status = 'Unknown';
|
610 |
+
break;
|
611 |
+
}
|
612 |
+
|
613 |
+
// Save battery
|
614 |
+
$batts[] = array(
|
615 |
+
'percentage' => $percentage.'%',
|
616 |
+
'state' => $status,
|
617 |
+
'device' => 'battery',
|
618 |
+
);
|
619 |
+
|
620 |
+
// Return
|
621 |
+
return $batts;
|
622 |
+
}
|
623 |
+
|
624 |
+
// Get stats on processes
|
625 |
+
public function getProcessStats()
|
626 |
+
{
|
627 |
+
|
628 |
+
// Time?
|
629 |
+
if (!empty($this->settings['timer'])) {
|
630 |
+
$t = new Timer('Process Stats');
|
631 |
+
}
|
632 |
+
|
633 |
+
// We'll return this after stuffing it with useful info
|
634 |
+
$result = array(
|
635 |
+
'exists' => true,
|
636 |
+
'totals' => array(
|
637 |
+
'running' => 0,
|
638 |
+
'zombie' => 0,
|
639 |
+
'sleeping' => 0,
|
640 |
+
'stopped' => 0,
|
641 |
+
'idle' => 0,
|
642 |
+
),
|
643 |
+
'proc_total' => 0,
|
644 |
+
'threads' => false, // I'm not sure how to get this
|
645 |
+
);
|
646 |
+
|
647 |
+
// Use ps
|
648 |
+
try {
|
649 |
+
// Get it
|
650 |
+
$ps = $this->exec->exec('ps', 'ax');
|
651 |
+
|
652 |
+
// Match them
|
653 |
+
preg_match_all('/^\s*\d+\s+[\w?]+\s+([A-Z])\S*\s+.+$/m', $ps, $processes, PREG_SET_ORDER);
|
654 |
+
|
655 |
+
// Get total
|
656 |
+
$result['proc_total'] = count($processes);
|
657 |
+
|
658 |
+
// Go through
|
659 |
+
foreach ($processes as $process) {
|
660 |
+
switch ($process[1]) {
|
661 |
+
case 'S':
|
662 |
+
case 'I':
|
663 |
+
$result['totals']['sleeping']++;
|
664 |
+
break;
|
665 |
+
case 'Z':
|
666 |
+
$result['totals']['zombie']++;
|
667 |
+
break;
|
668 |
+
case 'R':
|
669 |
+
case 'D':
|
670 |
+
$result['totals']['running']++;
|
671 |
+
break;
|
672 |
+
case 'T':
|
673 |
+
$result['totals']['stopped']++;
|
674 |
+
break;
|
675 |
+
case 'W':
|
676 |
+
$result['totals']['idle']++;
|
677 |
+
break;
|
678 |
+
}
|
679 |
+
}
|
680 |
+
} catch (Exception $e) {
|
681 |
+
Errors::add('Linfo Core', 'Error using `ps` to get process info');
|
682 |
+
}
|
683 |
+
|
684 |
+
// Give
|
685 |
+
return $result;
|
686 |
+
}
|
687 |
+
|
688 |
+
// idk
|
689 |
+
public function getTemps()
|
690 |
+
{
|
691 |
+
// Time?
|
692 |
+
if (!empty($this->settings['timer'])) {
|
693 |
+
$t = new Timer('Temperature');
|
694 |
+
}
|
695 |
+
}
|
696 |
+
|
697 |
+
public function getLoad()
|
698 |
+
{
|
699 |
+
if (!empty($this->settings['timer'])) {
|
700 |
+
$t = new Timer('Load Averages');
|
701 |
+
}
|
702 |
+
|
703 |
+
$loads = $this->sysctl['vm.loadavg'];
|
704 |
+
|
705 |
+
if (preg_match('/([\d\.]+) ([\d\.]+) ([\d\.]+)/', $loads, $m)) {
|
706 |
+
return array_combine(array('now', '5min', '15min'), array_slice($m, 1, 3));
|
707 |
+
} else {
|
708 |
+
return array();
|
709 |
+
}
|
710 |
+
}
|
711 |
+
|
712 |
+
public function getVirtualization()
|
713 |
+
{
|
714 |
+
|
715 |
+
// Time?
|
716 |
+
if (!empty($this->settings['timer'])) {
|
717 |
+
$t = new Timer('Determining virtualization type');
|
718 |
+
}
|
719 |
+
|
720 |
+
// KVM guest? Try to expand this with support for other hypervisors..
|
721 |
+
if (preg_match('/^Hypervisor:\s+Origin\s+=\s+"([^"]+)"/m', $this->dmesg, $m)) {
|
722 |
+
if (strpos($m[1], 'KVM') !== false) {
|
723 |
+
return array('type' => 'guest', 'method' => 'KVM');
|
724 |
+
}
|
725 |
+
}
|
726 |
+
|
727 |
+
return false;
|
728 |
+
}
|
729 |
+
}
|
lib/Linfo/OS/Linux.php
ADDED
@@ -0,0 +1,1729 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*/
|
19 |
+
namespace Linfo\OS;
|
20 |
+
|
21 |
+
use Linfo\Meta\Timer;
|
22 |
+
use Linfo\Meta\Errors;
|
23 |
+
use Linfo\Common;
|
24 |
+
use Linfo\Exceptions\FatalException;
|
25 |
+
use Linfo\Parsers\Hwpci;
|
26 |
+
use Linfo\Parsers\Sensord;
|
27 |
+
use Linfo\Parsers\Hddtemp;
|
28 |
+
use Linfo\Parsers\Mbmon;
|
29 |
+
use Exception;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Get info on a usual linux system
|
33 |
+
* Works by exclusively looking around /proc and /sys
|
34 |
+
* Totally ignores CallExt class, very deliberately
|
35 |
+
* Also deliberately ignores trying to find out the distro.
|
36 |
+
*/
|
37 |
+
class Linux extends Unixcommon
|
38 |
+
{
|
39 |
+
// Keep these tucked away
|
40 |
+
protected $settings;
|
41 |
+
|
42 |
+
// Generally disabled as it's slowww
|
43 |
+
protected $cpu_percent = array('overall' => false, 'cpus' => array());
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Constructor. Localizes settings.
|
47 |
+
*
|
48 |
+
* @param array $settings of linfo settings
|
49 |
+
* @throws FatalException
|
50 |
+
*/
|
51 |
+
public function __construct($settings)
|
52 |
+
{
|
53 |
+
|
54 |
+
// Localize settings
|
55 |
+
$this->settings = $settings;
|
56 |
+
|
57 |
+
// Make sure we have what we need
|
58 |
+
if (!is_dir('/sys') || !is_dir('/proc')) {
|
59 |
+
throw new FatalException('This needs access to /proc and /sys to work.');
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
public function init()
|
64 |
+
{
|
65 |
+
if (isset($this->settings['cpu_usage']) && !empty($this->settings['cpu_usage'])) {
|
66 |
+
$this->determineCPUPercentage();
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* getKernel.
|
72 |
+
*
|
73 |
+
* @return string kernel version
|
74 |
+
*/
|
75 |
+
public function getKernel()
|
76 |
+
{
|
77 |
+
|
78 |
+
// Time?
|
79 |
+
if (!empty($this->settings['timer'])) {
|
80 |
+
$t = new Timer('Kernel');
|
81 |
+
}
|
82 |
+
|
83 |
+
// File containing info
|
84 |
+
$file = '/proc/version';
|
85 |
+
|
86 |
+
// Make sure we can use it
|
87 |
+
if (!is_file($file) || !is_readable($file)) {
|
88 |
+
Errors::add('Linfo Core', '/proc/version not found');
|
89 |
+
|
90 |
+
return 'Unknown';
|
91 |
+
}
|
92 |
+
|
93 |
+
// Get it
|
94 |
+
$contents = Common::getContents($file);
|
95 |
+
|
96 |
+
// Parse it
|
97 |
+
if (preg_match('/^Linux version (\S+).+$/', $contents, $match) != 1) {
|
98 |
+
Errors::add('Linfo Core', 'Error parsing /proc/version');
|
99 |
+
|
100 |
+
return 'Unknown';
|
101 |
+
}
|
102 |
+
|
103 |
+
// Return it
|
104 |
+
return $match[1];
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* getHostName.
|
109 |
+
*
|
110 |
+
* @return string the host name
|
111 |
+
*/
|
112 |
+
public function getHostName()
|
113 |
+
{
|
114 |
+
|
115 |
+
// Time?
|
116 |
+
if (!empty($this->settings['timer'])) {
|
117 |
+
$t = new Timer('Hostname');
|
118 |
+
}
|
119 |
+
|
120 |
+
// File containing info
|
121 |
+
$file = '/proc/sys/kernel/hostname';
|
122 |
+
|
123 |
+
// Get it
|
124 |
+
$hostname = Common::getContents($file, false);
|
125 |
+
|
126 |
+
// Failed?
|
127 |
+
if ($hostname === false) {
|
128 |
+
Errors::add('Linfo Core', 'Error getting /proc/sys/kernel/hostname');
|
129 |
+
|
130 |
+
return 'Unknown';
|
131 |
+
}
|
132 |
+
|
133 |
+
// Didn't fail; return it
|
134 |
+
return $this->ensureFQDN($hostname);
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* getRam.
|
139 |
+
*
|
140 |
+
* @return array the memory information
|
141 |
+
*/
|
142 |
+
public function getRam()
|
143 |
+
{
|
144 |
+
|
145 |
+
// Time?
|
146 |
+
if (!empty($this->settings['timer'])) {
|
147 |
+
$t = new Timer('Memory');
|
148 |
+
}
|
149 |
+
|
150 |
+
// We'll return the contents of this
|
151 |
+
$return = array();
|
152 |
+
|
153 |
+
// Files containing juicy info
|
154 |
+
$procFileSwap = '/proc/swaps';
|
155 |
+
$procFileMem = '/proc/meminfo';
|
156 |
+
|
157 |
+
// First off, these need to exist..
|
158 |
+
if (!is_readable($procFileSwap) || !is_readable($procFileMem)) {
|
159 |
+
Errors::add('Linfo Core', '/proc/swaps and/or /proc/meminfo are not readable');
|
160 |
+
|
161 |
+
return array();
|
162 |
+
}
|
163 |
+
|
164 |
+
// To hold their values
|
165 |
+
$memVals = array();
|
166 |
+
$swapVals = array();
|
167 |
+
|
168 |
+
// Get memContents
|
169 |
+
@preg_match_all('/^([^:]+)\:\s+(\d+)\s*(?:k[bB])?\s*/m', Common::getContents($procFileMem), $matches, PREG_SET_ORDER);
|
170 |
+
|
171 |
+
// Deal with it
|
172 |
+
foreach ((array) $matches as $memInfo) {
|
173 |
+
$memVals[$memInfo[1]] = $memInfo[2];
|
174 |
+
}
|
175 |
+
|
176 |
+
// Get swapContents
|
177 |
+
@preg_match_all('/^(\S+)\s+(\S+)\s+(\d+)\s(\d+)/m', Common::getContents($procFileSwap), $matches, PREG_SET_ORDER);
|
178 |
+
foreach ((array) $matches as $swapDevice) {
|
179 |
+
|
180 |
+
// Append each swap device
|
181 |
+
$swapVals[] = array(
|
182 |
+
'device' => $swapDevice[1],
|
183 |
+
'type' => $swapDevice[2],
|
184 |
+
'size' => $swapDevice[3] * 1024,
|
185 |
+
'used' => $swapDevice[4] * 1024,
|
186 |
+
);
|
187 |
+
}
|
188 |
+
|
189 |
+
// Get individual vals
|
190 |
+
$return['type'] = 'Physical';
|
191 |
+
$return['total'] = @$memVals['MemTotal'] * 1024;
|
192 |
+
$return['free'] = @$memVals['MemFree'] * 1024 + @$memVals['Cached'] * 1024 + @$memVals['Buffers'] * 1024;
|
193 |
+
$return['swapTotal'] = @$memVals['SwapTotal'] * 1024;
|
194 |
+
$return['swapFree'] = @$memVals['SwapFree'] * 1024 + @$memVals['SwapCached'] * 1024;
|
195 |
+
$return['swapCached'] = @$memVals['SwapCached'] * 1024;
|
196 |
+
$return['swapInfo'] = @$swapVals;
|
197 |
+
|
198 |
+
// Return it
|
199 |
+
return $return;
|
200 |
+
}
|
201 |
+
|
202 |
+
/**
|
203 |
+
* getCPU.
|
204 |
+
*
|
205 |
+
* @return array of cpu info
|
206 |
+
*/
|
207 |
+
public function getCPU()
|
208 |
+
{
|
209 |
+
|
210 |
+
// Time?
|
211 |
+
if (!empty($this->settings['timer'])) {
|
212 |
+
$t = new Timer('CPUs');
|
213 |
+
}
|
214 |
+
|
215 |
+
// File that has it
|
216 |
+
$file = '/proc/cpuinfo';
|
217 |
+
|
218 |
+
// Not there?
|
219 |
+
if (!is_file($file) || !is_readable($file)) {
|
220 |
+
Errors::add('Linfo Core', '/proc/cpuinfo not readable');
|
221 |
+
|
222 |
+
return array();
|
223 |
+
}
|
224 |
+
|
225 |
+
/*
|
226 |
+
* Get all info for all CPUs from the cpuinfo file
|
227 |
+
*/
|
228 |
+
|
229 |
+
// Get contents
|
230 |
+
$contents = Common::getContents($file);
|
231 |
+
|
232 |
+
// Lines
|
233 |
+
$lines = explode("\n", $contents);
|
234 |
+
|
235 |
+
// Store CPUs here
|
236 |
+
$cpus = array();
|
237 |
+
|
238 |
+
// Holder for current CPU info
|
239 |
+
$cur_cpu = array();
|
240 |
+
|
241 |
+
// Go through lines in file
|
242 |
+
$num_lines = count($lines);
|
243 |
+
|
244 |
+
// We use the key of the first line to separate CPUs
|
245 |
+
$first_line = substr($lines[0], 0, strpos($lines[0], ' '));
|
246 |
+
|
247 |
+
for ($i = 0; $i < $num_lines; ++$i) {
|
248 |
+
|
249 |
+
// Approaching new CPU? Save current and start new info for this
|
250 |
+
if (strpos($lines[$i], $first_line) === 0 && count($cur_cpu) > 0) {
|
251 |
+
$cpus[] = $cur_cpu;
|
252 |
+
$cur_cpu = array();
|
253 |
+
|
254 |
+
// Default to unknown
|
255 |
+
$cur_cpu['Model'] = 'Unknown';
|
256 |
+
}
|
257 |
+
|
258 |
+
// Info here
|
259 |
+
$line = explode(':', $lines[$i], 2);
|
260 |
+
|
261 |
+
if (!array_key_exists(1, $line)) {
|
262 |
+
continue;
|
263 |
+
}
|
264 |
+
|
265 |
+
$key = trim($line[0]);
|
266 |
+
$value = trim($line[1]);
|
267 |
+
|
268 |
+
// What we want are MHZ, Vendor, and Model.
|
269 |
+
switch ($key) {
|
270 |
+
|
271 |
+
// CPU model
|
272 |
+
case 'model name':
|
273 |
+
case 'cpu':
|
274 |
+
case 'Processor':
|
275 |
+
$cur_cpu['Model'] = $value;
|
276 |
+
break;
|
277 |
+
|
278 |
+
// Speed in MHz
|
279 |
+
case 'cpu MHz':
|
280 |
+
$cur_cpu['MHz'] = $value;
|
281 |
+
break;
|
282 |
+
|
283 |
+
case 'Cpu0ClkTck': // Old sun boxes
|
284 |
+
$cur_cpu['MHz'] = hexdec($value) / 1000000;
|
285 |
+
break;
|
286 |
+
|
287 |
+
// Brand/vendor
|
288 |
+
case 'vendor_id':
|
289 |
+
$cur_cpu['Vendor'] = $value;
|
290 |
+
break;
|
291 |
+
|
292 |
+
// ID. Corresponds to percentage if enabled below
|
293 |
+
case 'processor':
|
294 |
+
if (isset($this->cpu_percent['cpus'][$value])) {
|
295 |
+
$cur_cpu['usage_percentage'] = $this->cpu_percent['cpus'][$value];
|
296 |
+
}
|
297 |
+
break;
|
298 |
+
}
|
299 |
+
}
|
300 |
+
|
301 |
+
// Save remaining one
|
302 |
+
if (count($cur_cpu) > 0) {
|
303 |
+
$cpus[] = $cur_cpu;
|
304 |
+
}
|
305 |
+
|
306 |
+
// Return them
|
307 |
+
return $cpus;
|
308 |
+
}
|
309 |
+
|
310 |
+
// Famously interesting uptime
|
311 |
+
public function getUpTime()
|
312 |
+
{
|
313 |
+
|
314 |
+
// Time?
|
315 |
+
if (!empty($this->settings['timer'])) {
|
316 |
+
$t = new Timer('Uptime');
|
317 |
+
}
|
318 |
+
|
319 |
+
// Get contents
|
320 |
+
$contents = Common::getContents('/proc/uptime', false);
|
321 |
+
|
322 |
+
// eh?
|
323 |
+
if ($contents === false) {
|
324 |
+
Errors::add('Linfo Core', '/proc/uptime does not exist.');
|
325 |
+
|
326 |
+
return 'Unknown';
|
327 |
+
}
|
328 |
+
|
329 |
+
// Seconds
|
330 |
+
list($seconds) = explode(' ', $contents, 1);
|
331 |
+
|
332 |
+
// Get it textual, as in days/minutes/hours/etc
|
333 |
+
$uptime = Common::secondsConvert(ceil($seconds));
|
334 |
+
|
335 |
+
// Now find out when the system was booted
|
336 |
+
$contents = Common::getContents('/proc/stat', false);
|
337 |
+
|
338 |
+
// Ugh
|
339 |
+
if ($contents === false) {
|
340 |
+
return $uptime;
|
341 |
+
} // Settle for just uptime
|
342 |
+
|
343 |
+
// Get date of boot
|
344 |
+
if (preg_match('/^btime (\d+)$/m', $contents, $boot) != 1) {
|
345 |
+
return $uptime;
|
346 |
+
}
|
347 |
+
|
348 |
+
// Okay?
|
349 |
+
list(, $boot) = $boot;
|
350 |
+
|
351 |
+
return array(
|
352 |
+
'text' => $uptime,
|
353 |
+
'bootedTimestamp' => $boot,
|
354 |
+
);
|
355 |
+
}
|
356 |
+
|
357 |
+
/**
|
358 |
+
* getHD.
|
359 |
+
*
|
360 |
+
* @return array the hard drive info
|
361 |
+
*/
|
362 |
+
public function getHD()
|
363 |
+
{
|
364 |
+
|
365 |
+
// Time?
|
366 |
+
if (!empty($this->settings['timer'])) {
|
367 |
+
$t = new Timer('Drives');
|
368 |
+
}
|
369 |
+
|
370 |
+
// Get partitions
|
371 |
+
$partitions = array();
|
372 |
+
$partitions_contents = Common::getContents('/proc/partitions');
|
373 |
+
if (@preg_match_all('/(\d+)\s+([a-z]{3})(\d+)$/m', $partitions_contents, $partitions_match, PREG_SET_ORDER) > 0) {
|
374 |
+
// Go through each match
|
375 |
+
foreach ($partitions_match as $partition) {
|
376 |
+
$partitions[$partition[2]][] = array(
|
377 |
+
'size' => $partition[1] * 1024,
|
378 |
+
'number' => $partition[3],
|
379 |
+
);
|
380 |
+
}
|
381 |
+
}
|
382 |
+
|
383 |
+
// Store drives here
|
384 |
+
$drives = array();
|
385 |
+
|
386 |
+
// Get actual drives
|
387 |
+
foreach ((array) @glob('/sys/block/*/device/model', GLOB_NOSORT) as $path) {
|
388 |
+
|
389 |
+
// Parts of the path
|
390 |
+
$parts = explode('/', $path);
|
391 |
+
|
392 |
+
// Attempt getting read/write stats
|
393 |
+
if (preg_match('/^(\d+)\s+\d+\s+\d+\s+\d+\s+(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+$/', Common::getContents(dirname(dirname($path)).'/stat'), $statMatches) !== 1) {
|
394 |
+
// Didn't get it
|
395 |
+
$reads = false;
|
396 |
+
$writes = false;
|
397 |
+
} else {
|
398 |
+
// Got it, save it
|
399 |
+
list(, $reads, $writes) = $statMatches;
|
400 |
+
}
|
401 |
+
|
402 |
+
// Append this drive on
|
403 |
+
$drives[] = array(
|
404 |
+
'name' => Common::getContents($path, 'Unknown').(Common::getContents(dirname(dirname($path)).'/queue/rotational') == 0 ? ' (SSD)' : ''),
|
405 |
+
'vendor' => Common::getContents(dirname($path).'/vendor', 'Unknown'),
|
406 |
+
'device' => '/dev/'.$parts[3],
|
407 |
+
'reads' => $reads,
|
408 |
+
'writes' => $writes,
|
409 |
+
'size' => Common::getContents(dirname(dirname($path)).'/size', 0) * 512,
|
410 |
+
'partitions' => array_key_exists($parts[3], $partitions) && is_array($partitions[$parts[3]]) ? $partitions[$parts[3]] : false,
|
411 |
+
);
|
412 |
+
}
|
413 |
+
|
414 |
+
// Return drives
|
415 |
+
return $drives;
|
416 |
+
}
|
417 |
+
|
418 |
+
/**
|
419 |
+
* getTemps.
|
420 |
+
*
|
421 |
+
* @return array the temps
|
422 |
+
*/
|
423 |
+
public function getTemps()
|
424 |
+
{
|
425 |
+
|
426 |
+
// Time?
|
427 |
+
if (!empty($this->settings['timer'])) {
|
428 |
+
$t = new Timer('Temperature');
|
429 |
+
}
|
430 |
+
|
431 |
+
// Hold them here
|
432 |
+
$return = array();
|
433 |
+
|
434 |
+
// hddtemp?
|
435 |
+
if (array_key_exists('hddtemp', (array) $this->settings['temps']) && !empty($this->settings['temps']['hddtemp']) && isset($this->settings['hddtemp'])) {
|
436 |
+
try {
|
437 |
+
// Initiate class
|
438 |
+
$hddtemp = new Hddtemp($this->settings);
|
439 |
+
|
440 |
+
// Set mode, as in either daemon or syslog
|
441 |
+
$hddtemp->setMode($this->settings['hddtemp']['mode']);
|
442 |
+
|
443 |
+
// If we're daemon, save host and port
|
444 |
+
if ($this->settings['hddtemp']['mode'] == 'daemon') {
|
445 |
+
$hddtemp->setAddress(
|
446 |
+
$this->settings['hddtemp']['address']['host'],
|
447 |
+
$this->settings['hddtemp']['address']['port']);
|
448 |
+
}
|
449 |
+
|
450 |
+
// Result after working it
|
451 |
+
$hddtemp_res = $hddtemp->work();
|
452 |
+
|
453 |
+
// If it's an array, it worked
|
454 |
+
if (is_array($hddtemp_res)) {
|
455 |
+
// Save result
|
456 |
+
$return = array_merge($return, $hddtemp_res);
|
457 |
+
}
|
458 |
+
}
|
459 |
+
|
460 |
+
// There was an issue
|
461 |
+
catch (\Exception $e) {
|
462 |
+
Errors::add('hddtemp parser', $e->getMessage());
|
463 |
+
}
|
464 |
+
}
|
465 |
+
|
466 |
+
// mbmon?
|
467 |
+
if (array_key_exists('mbmon', (array) $this->settings['temps']) && !empty($this->settings['temps']['mbmon']) && isset($this->settings['mbmon'])) {
|
468 |
+
try {
|
469 |
+
// Initiate class
|
470 |
+
$mbmon = new Mbmon();
|
471 |
+
|
472 |
+
// Set host and port
|
473 |
+
$mbmon->setAddress(
|
474 |
+
$this->settings['mbmon']['address']['host'],
|
475 |
+
$this->settings['mbmon']['address']['port']);
|
476 |
+
|
477 |
+
// Get result after working it
|
478 |
+
$mbmon_res = $mbmon->work();
|
479 |
+
|
480 |
+
// If it's an array, it worked
|
481 |
+
if (is_array($mbmon_res)) {
|
482 |
+
// Save result
|
483 |
+
$return = array_merge($return, $mbmon_res);
|
484 |
+
}
|
485 |
+
} catch (Exception $e) {
|
486 |
+
Errors::add('mbmon parser', $e->getMessage());
|
487 |
+
}
|
488 |
+
}
|
489 |
+
|
490 |
+
// sensord? (part of lm-sensors)
|
491 |
+
if (array_key_exists('sensord', (array) $this->settings['temps']) && !empty($this->settings['temps']['sensord'])) {
|
492 |
+
try {
|
493 |
+
// Iniatate class
|
494 |
+
$sensord = new Sensord();
|
495 |
+
|
496 |
+
// Work it
|
497 |
+
$sensord_res = $sensord->work();
|
498 |
+
|
499 |
+
// If it's an array, it worked
|
500 |
+
if (is_array($sensord_res)) {
|
501 |
+
// Save result
|
502 |
+
$return = array_merge($return, $sensord_res);
|
503 |
+
}
|
504 |
+
} catch (Exception $e) {
|
505 |
+
Errors::add('sensord parser', $e->getMessage());
|
506 |
+
}
|
507 |
+
}
|
508 |
+
|
509 |
+
// hwmon? (probably the fastest of what's here)
|
510 |
+
// too simple to be in its own class
|
511 |
+
if (array_key_exists('hwmon', (array) $this->settings['temps']) && !empty($this->settings['temps']['hwmon'])) {
|
512 |
+
|
513 |
+
// Store them here
|
514 |
+
$hwmon_vals = array();
|
515 |
+
|
516 |
+
// Wacky location
|
517 |
+
foreach ((array) @glob('/sys/class/hwmon/hwmon*/{,device/}*_input', GLOB_NOSORT | GLOB_BRACE) as $path) {
|
518 |
+
$initpath = rtrim($path, 'input');
|
519 |
+
$value = Common::getContents($path);
|
520 |
+
$base = basename($path);
|
521 |
+
$labelpath = $initpath.'label';
|
522 |
+
$showemptyfans = isset($this->settings['temps_show0rpmfans']) ? $this->settings['temps_show0rpmfans'] : false;
|
523 |
+
$drivername = @basename(@readlink(dirname($path).'/driver')) ?: false;
|
524 |
+
|
525 |
+
// Temperatures
|
526 |
+
if (is_file($labelpath) && strpos($base, 'temp') === 0) {
|
527 |
+
$label = Common::getContents($labelpath);
|
528 |
+
$value /= $value > 10000 ? 1000 : 1;
|
529 |
+
$unit = 'C'; // I don't think this is ever going to be in F
|
530 |
+
}
|
531 |
+
|
532 |
+
// Fan RPMs
|
533 |
+
elseif (preg_match('/^fan(\d+)_/', $base, $m)) {
|
534 |
+
$label = 'fan'.$m[1];
|
535 |
+
$unit = 'RPM';
|
536 |
+
|
537 |
+
if ($value == 0 && !$showemptyfans) {
|
538 |
+
continue;
|
539 |
+
}
|
540 |
+
}
|
541 |
+
|
542 |
+
// Volts
|
543 |
+
elseif (preg_match('/^in(\d+)_/', $base, $m)) {
|
544 |
+
$unit = 'V';
|
545 |
+
$value /= 1000;
|
546 |
+
$label = Common::getContents($labelpath) ?: 'in'.$m[1];
|
547 |
+
} else {
|
548 |
+
continue;
|
549 |
+
}
|
550 |
+
|
551 |
+
// Append values
|
552 |
+
$hwmon_vals[] = array(
|
553 |
+
'path' => '',
|
554 |
+
'name' => $label.($drivername ? ' <span class="faded">('.$drivername.')</span>' : ''),
|
555 |
+
'temp' => $value,
|
556 |
+
'unit' => $unit,
|
557 |
+
);
|
558 |
+
}
|
559 |
+
|
560 |
+
// Save any if we have any
|
561 |
+
if (count($hwmon_vals) > 0) {
|
562 |
+
$return = array_merge($return, $hwmon_vals);
|
563 |
+
}
|
564 |
+
}
|
565 |
+
|
566 |
+
// Laptop backlight percentage
|
567 |
+
foreach ((array) @glob('/sys/{devices/virtual,class}/backlight/*/max_brightness', GLOB_NOSORT | GLOB_BRACE) as $bl) {
|
568 |
+
$dir = dirname($bl);
|
569 |
+
if (!is_file($dir.'/actual_brightness')) {
|
570 |
+
continue;
|
571 |
+
}
|
572 |
+
$max = Common::getIntFromFile($bl);
|
573 |
+
$cur = Common::getIntFromFile($dir.'/actual_brightness');
|
574 |
+
if ($max < 0 || $cur < 0) {
|
575 |
+
continue;
|
576 |
+
}
|
577 |
+
$return[] = array(
|
578 |
+
'name' => 'Backlight brightness',
|
579 |
+
'temp' => round($cur / $max, 2) * 100,
|
580 |
+
'unit' => '%',
|
581 |
+
'path' => 'N/A',
|
582 |
+
'bar' => true,
|
583 |
+
);
|
584 |
+
}
|
585 |
+
|
586 |
+
// Done
|
587 |
+
return $return;
|
588 |
+
}
|
589 |
+
|
590 |
+
/**
|
591 |
+
* getMounts.
|
592 |
+
*
|
593 |
+
* @return array the mounted the file systems
|
594 |
+
*/
|
595 |
+
public function getMounts()
|
596 |
+
{
|
597 |
+
|
598 |
+
// Time?
|
599 |
+
if (!empty($this->settings['timer'])) {
|
600 |
+
$t = new Timer('Mounted file systems');
|
601 |
+
}
|
602 |
+
|
603 |
+
// File
|
604 |
+
$contents = Common::getContents('/proc/mounts', false);
|
605 |
+
|
606 |
+
// Can't?
|
607 |
+
if ($contents == false) {
|
608 |
+
Errors::add('Linfo Core', '/proc/mounts does not exist');
|
609 |
+
}
|
610 |
+
|
611 |
+
// Parse
|
612 |
+
if (@preg_match_all('/^(\S+) (\S+) (\S+) (.+) \d \d$/m', $contents, $match, PREG_SET_ORDER) === false) {
|
613 |
+
Errors::add('Linfo Core', 'Error parsing /proc/mounts');
|
614 |
+
}
|
615 |
+
|
616 |
+
// Return these
|
617 |
+
$mounts = array();
|
618 |
+
|
619 |
+
// Populate
|
620 |
+
foreach ($match as $mount) {
|
621 |
+
|
622 |
+
// Should we not show this?
|
623 |
+
if (in_array($mount[1], $this->settings['hide']['storage_devices']) || in_array($mount[3], $this->settings['hide']['filesystems'])) {
|
624 |
+
continue;
|
625 |
+
}
|
626 |
+
|
627 |
+
// Should we not show this? (regex)
|
628 |
+
if (isset($this->settings['hide']['mountpoints_regex']) && is_array($this->settings['hide']['mountpoints_regex'])) {
|
629 |
+
foreach ($this->settings['hide']['mountpoints_regex'] as $regex) {
|
630 |
+
if (@preg_match($regex, $mount[2])) {
|
631 |
+
continue 2;
|
632 |
+
}
|
633 |
+
}
|
634 |
+
}
|
635 |
+
|
636 |
+
// Spaces and other things in the mount path are escaped C style. Fix that.
|
637 |
+
$mount[2] = stripcslashes($mount[2]);
|
638 |
+
|
639 |
+
// Get these
|
640 |
+
$size = @disk_total_space($mount[2]);
|
641 |
+
$free = @disk_free_space($mount[2]);
|
642 |
+
$used = $size != false && $free != false ? $size - $free : false;
|
643 |
+
|
644 |
+
// If it's a symlink, find out where it really goes.
|
645 |
+
// (using realpath instead of readlink because the former gives absolute paths)
|
646 |
+
$symlink = is_link($mount[1]) ? realpath($mount[1]) : false;
|
647 |
+
|
648 |
+
// Optionally get mount options
|
649 |
+
if ($this->settings['show']['mounts_options'] && !in_array($mount[3], (array) $this->settings['hide']['fs_mount_options'])) {
|
650 |
+
$mount_options = explode(',', $mount[4]);
|
651 |
+
} else {
|
652 |
+
$mount_options = array();
|
653 |
+
}
|
654 |
+
|
655 |
+
// Might be good, go for it
|
656 |
+
$mounts[] = array(
|
657 |
+
'device' => $symlink != false ? $symlink : $mount[1],
|
658 |
+
'mount' => $mount[2],
|
659 |
+
'type' => $mount[3],
|
660 |
+
'size' => $size,
|
661 |
+
'used' => $used,
|
662 |
+
'free' => $free,
|
663 |
+
'free_percent' => ((bool) $free != false && (bool) $size != false ? round($free / $size, 2) * 100 : false),
|
664 |
+
'used_percent' => ((bool) $used != false && (bool) $size != false ? round($used / $size, 2) * 100 : false),
|
665 |
+
'options' => $mount_options,
|
666 |
+
);
|
667 |
+
}
|
668 |
+
|
669 |
+
// Return
|
670 |
+
return $mounts;
|
671 |
+
}
|
672 |
+
|
673 |
+
/**
|
674 |
+
* getDevs.
|
675 |
+
*
|
676 |
+
* @return array of devices
|
677 |
+
*/
|
678 |
+
public function getDevs()
|
679 |
+
{
|
680 |
+
|
681 |
+
// Time?
|
682 |
+
if (!empty($this->settings['timer'])) {
|
683 |
+
$t = new Timer('Hardware Devices');
|
684 |
+
}
|
685 |
+
|
686 |
+
// Location of useful paths
|
687 |
+
$pci_ids = Common::locateActualPath(array(
|
688 |
+
'/usr/share/misc/pci.ids', // debian/ubuntu
|
689 |
+
'/usr/share/pci.ids', // opensuse
|
690 |
+
'/usr/share/hwdata/pci.ids', // centos. maybe also redhat/fedora
|
691 |
+
));
|
692 |
+
$usb_ids = Common::locateActualPath(array(
|
693 |
+
'/usr/share/misc/usb.ids', // debian/ubuntu
|
694 |
+
'/usr/share/usb.ids', // opensuse
|
695 |
+
'/usr/share/hwdata/usb.ids', // centos. maybe also redhat/fedora
|
696 |
+
));
|
697 |
+
|
698 |
+
// Did we not get them?
|
699 |
+
$pci_ids || Errors::add('Linux Device Finder', 'Cannot find pci.ids; ensure pciutils is installed.');
|
700 |
+
$usb_ids || Errors::add('Linux Device Finder', 'Cannot find usb.ids; ensure usbutils is installed.');
|
701 |
+
|
702 |
+
// Class that does it
|
703 |
+
$hw = new Hwpci($usb_ids, $pci_ids);
|
704 |
+
$hw->work('linux');
|
705 |
+
|
706 |
+
return $hw->result();
|
707 |
+
}
|
708 |
+
|
709 |
+
/**
|
710 |
+
* getRAID.
|
711 |
+
*
|
712 |
+
* @return array of raid arrays
|
713 |
+
*/
|
714 |
+
public function getRAID()
|
715 |
+
{
|
716 |
+
|
717 |
+
// Time?
|
718 |
+
if (!empty($this->settings['timer'])) {
|
719 |
+
$t = new Timer('RAID');
|
720 |
+
}
|
721 |
+
|
722 |
+
// Store it here
|
723 |
+
$raidinfo = array();
|
724 |
+
|
725 |
+
// mdadm?
|
726 |
+
if (array_key_exists('mdadm', (array) $this->settings['raid']) && !empty($this->settings['raid']['mdadm'])) {
|
727 |
+
|
728 |
+
// Try getting contents
|
729 |
+
$mdadm_contents = Common::getContents('/proc/mdstat', false);
|
730 |
+
|
731 |
+
// No?
|
732 |
+
if ($mdadm_contents === false) {
|
733 |
+
Errors::add('Linux softraid mdstat parser', '/proc/mdstat does not exist.');
|
734 |
+
}
|
735 |
+
|
736 |
+
// Parse
|
737 |
+
@preg_match_all('/(\S+)\s*:\s*(\w+)\s*raid(\d+)\s*([\w+\[\d+\] (\(\w\))?]+)\n\s+(\d+) blocks[^[]+\[(\d\/\d)\] \[([U\_]+)\]/mi', (string) $mdadm_contents, $match, PREG_SET_ORDER);
|
738 |
+
|
739 |
+
// Store them here
|
740 |
+
$mdadm_arrays = array();
|
741 |
+
|
742 |
+
// Deal with entries
|
743 |
+
foreach ((array) $match as $array) {
|
744 |
+
|
745 |
+
// Temporarily store drives here
|
746 |
+
$drives = array();
|
747 |
+
|
748 |
+
// Parse drives
|
749 |
+
foreach (explode(' ', $array[4]) as $drive) {
|
750 |
+
|
751 |
+
// Parse?
|
752 |
+
if (preg_match('/([\w\d]+)\[\d+\](\(\w\))?/', $drive, $match_drive) == 1) {
|
753 |
+
|
754 |
+
// Determine a status other than normal, like if it failed or is a spare
|
755 |
+
if (array_key_exists(2, $match_drive)) {
|
756 |
+
switch ($match_drive[2]) {
|
757 |
+
case '(S)':
|
758 |
+
$drive_state = 'spare';
|
759 |
+
break;
|
760 |
+
case '(F)':
|
761 |
+
$drive_state = 'failed';
|
762 |
+
break;
|
763 |
+
case null:
|
764 |
+
$drive_state = 'normal';
|
765 |
+
break;
|
766 |
+
|
767 |
+
// I'm not sure if there are status codes other than the above
|
768 |
+
default:
|
769 |
+
$drive_state = 'unknown';
|
770 |
+
break;
|
771 |
+
}
|
772 |
+
} else {
|
773 |
+
$drive_state = 'normal';
|
774 |
+
}
|
775 |
+
|
776 |
+
// Append this drive to the temp drives array
|
777 |
+
$drives[] = array(
|
778 |
+
'drive' => '/dev/'.$match_drive[1],
|
779 |
+
'state' => $drive_state,
|
780 |
+
);
|
781 |
+
}
|
782 |
+
}
|
783 |
+
|
784 |
+
// Add record of this array to arrays list
|
785 |
+
$mdadm_arrays[] = array(
|
786 |
+
'device' => '/dev/'.$array[1],
|
787 |
+
'status' => $array[2],
|
788 |
+
'level' => $array[3],
|
789 |
+
'drives' => $drives,
|
790 |
+
'size' => Common::byteConvert($array[5] * 1024),
|
791 |
+
'count' => $array[6],
|
792 |
+
'chart' => $array[7],
|
793 |
+
);
|
794 |
+
}
|
795 |
+
|
796 |
+
// Append MD arrays to main raidinfo if it's good
|
797 |
+
if (is_array($mdadm_arrays) && count($mdadm_arrays) > 0) {
|
798 |
+
$raidinfo = array_merge($raidinfo, $mdadm_arrays);
|
799 |
+
}
|
800 |
+
}
|
801 |
+
|
802 |
+
// Return info
|
803 |
+
return $raidinfo;
|
804 |
+
}
|
805 |
+
|
806 |
+
/**
|
807 |
+
* getLoad.
|
808 |
+
*
|
809 |
+
* @return array of current system load values
|
810 |
+
*/
|
811 |
+
public function getLoad()
|
812 |
+
{
|
813 |
+
|
814 |
+
// Time?
|
815 |
+
if (!empty($this->settings['timer'])) {
|
816 |
+
$t = new Timer('Load Averages');
|
817 |
+
}
|
818 |
+
|
819 |
+
// File that has it
|
820 |
+
$file = '/proc/loadavg';
|
821 |
+
|
822 |
+
// Get contents
|
823 |
+
$contents = Common::getContents($file, false);
|
824 |
+
|
825 |
+
// ugh
|
826 |
+
if ($contents === false) {
|
827 |
+
Errors::add('Linfo Core', '/proc/loadavg unreadable');
|
828 |
+
return array();
|
829 |
+
}
|
830 |
+
|
831 |
+
// Parts
|
832 |
+
$parts = array_slice(explode(' ', $contents), 0, 3);
|
833 |
+
|
834 |
+
if (!$parts) {
|
835 |
+
return array();
|
836 |
+
}
|
837 |
+
|
838 |
+
return array_combine(array('now', '5min', '15min'), $parts);
|
839 |
+
}
|
840 |
+
|
841 |
+
/**
|
842 |
+
* getNet.
|
843 |
+
*
|
844 |
+
* @return array of network devices
|
845 |
+
*/
|
846 |
+
public function getNet()
|
847 |
+
{
|
848 |
+
|
849 |
+
// Time?
|
850 |
+
if (!empty($this->settings['timer'])) {
|
851 |
+
$t = new Timer('Network Devices');
|
852 |
+
}
|
853 |
+
|
854 |
+
// Hold our return values
|
855 |
+
$return = array();
|
856 |
+
|
857 |
+
// Get values for each device
|
858 |
+
foreach ((array) @glob('/sys/class/net/*', GLOB_NOSORT) as $path) {
|
859 |
+
$nic = basename($path);
|
860 |
+
|
861 |
+
// States
|
862 |
+
$operstate_contents = Common::getContents($path.'/operstate');
|
863 |
+
switch ($operstate_contents) {
|
864 |
+
case 'down':
|
865 |
+
case 'up':
|
866 |
+
case 'unknown':
|
867 |
+
$state = $operstate_contents;
|
868 |
+
break;
|
869 |
+
|
870 |
+
default:
|
871 |
+
$state = 'unknown';
|
872 |
+
break;
|
873 |
+
}
|
874 |
+
|
875 |
+
if ($state = 'unknown' && file_exists($path.'/carrier')) {
|
876 |
+
$carrier = Common::getContents($path.'/carrier', false);
|
877 |
+
if (!empty($carrier)) {
|
878 |
+
$state = 'up';
|
879 |
+
} else {
|
880 |
+
$state = 'down';
|
881 |
+
}
|
882 |
+
}
|
883 |
+
|
884 |
+
// Try the weird ways of getting type (https://stackoverflow.com/a/16060638)
|
885 |
+
$type = false;
|
886 |
+
$typeCode = Common::getIntFromFile($path.'/type');
|
887 |
+
|
888 |
+
if ($typeCode == 772) {
|
889 |
+
$type = 'Loopback';
|
890 |
+
} elseif ($typeCode == 65534) {
|
891 |
+
$type = 'Tunnel';
|
892 |
+
} elseif ($typeCode == 776) {
|
893 |
+
$type = 'IPv6 in IPv4';
|
894 |
+
}
|
895 |
+
|
896 |
+
if (!$type) {
|
897 |
+
$type_contents = strtoupper(Common::getContents($path.'/device/modalias'));
|
898 |
+
list($type_match) = explode(':', $type_contents, 2);
|
899 |
+
|
900 |
+
if (in_array($type_match, array('PCI', 'USB'))) {
|
901 |
+
$type = 'Ethernet ('.$type_match.')';
|
902 |
+
|
903 |
+
// Driver maybe?
|
904 |
+
if (($uevent_contents = @parse_ini_file($path.'/device/uevent')) && isset($uevent_contents['DRIVER'])) {
|
905 |
+
$type .= ' ('.$uevent_contents['DRIVER'].')';
|
906 |
+
}
|
907 |
+
} elseif ($type_match == 'VIRTIO') {
|
908 |
+
$type = 'VirtIO';
|
909 |
+
} elseif ($type_contents == 'XEN:VIF') {
|
910 |
+
$type = 'Xen (VIF)';
|
911 |
+
} elseif ($type_contents == 'XEN-BACKEND:VIF') {
|
912 |
+
$type = 'Xen Backend (VIF)';
|
913 |
+
} elseif (is_dir($path.'/bridge')) {
|
914 |
+
$type = 'Bridge';
|
915 |
+
} elseif (is_dir($path.'/bonding')) {
|
916 |
+
$type = 'Bond';
|
917 |
+
}
|
918 |
+
|
919 |
+
// TODO find some way of finding out what provides the virt-specific kvm vnet devices
|
920 |
+
}
|
921 |
+
|
922 |
+
$speed = Common::getIntFromFile($path.'/speed');
|
923 |
+
|
924 |
+
// Save and get info for each
|
925 |
+
$return[$nic] = array(
|
926 |
+
|
927 |
+
// Stats are stored in simple files just containing the number
|
928 |
+
'recieved' => array(
|
929 |
+
'bytes' => Common::getIntFromFile($path.'/statistics/rx_bytes'),
|
930 |
+
'errors' => Common::getIntFromFile($path.'/statistics/rx_errors'),
|
931 |
+
'packets' => Common::getIntFromFile($path.'/statistics/rx_packets'),
|
932 |
+
),
|
933 |
+
'sent' => array(
|
934 |
+
'bytes' => Common::getIntFromFile($path.'/statistics/tx_bytes'),
|
935 |
+
'errors' => Common::getIntFromFile($path.'/statistics/tx_errors'),
|
936 |
+
'packets' => Common::getIntFromFile($path.'/statistics/rx_packets'),
|
937 |
+
),
|
938 |
+
|
939 |
+
// These were determined above
|
940 |
+
'state' => $state,
|
941 |
+
'type' => $type ?: 'N/A',
|
942 |
+
'port_speed' => $speed > 0 ? $speed : false,
|
943 |
+
);
|
944 |
+
}
|
945 |
+
|
946 |
+
// Return array of info
|
947 |
+
return $return;
|
948 |
+
}
|
949 |
+
|
950 |
+
/**
|
951 |
+
* getBattery.
|
952 |
+
*
|
953 |
+
* @return array of battery status
|
954 |
+
*/
|
955 |
+
public function getBattery()
|
956 |
+
{
|
957 |
+
|
958 |
+
// Time?
|
959 |
+
if (!empty($this->settings['timer'])) {
|
960 |
+
$t = new Timer('Batteries');
|
961 |
+
}
|
962 |
+
|
963 |
+
// Return values
|
964 |
+
$return = array();
|
965 |
+
|
966 |
+
// Here they should be
|
967 |
+
$bats = (array) @glob('/sys/class/power_supply/BAT*', GLOB_NOSORT);
|
968 |
+
|
969 |
+
// Get vals for each battery
|
970 |
+
foreach ($bats as $b) {
|
971 |
+
foreach (array($b.'/manufacturer', $b.'/status') as $f) {
|
972 |
+
if (!is_file($f)) {
|
973 |
+
continue 2;
|
974 |
+
}
|
975 |
+
}
|
976 |
+
|
977 |
+
// Get these from the simple text files
|
978 |
+
switch (true) {
|
979 |
+
case is_file($b.'/energy_full'):
|
980 |
+
$charge_full = Common::getIntFromFile($b.'/energy_full');
|
981 |
+
$charge_now = Common::getIntFromFile($b.'/energy_now');
|
982 |
+
break;
|
983 |
+
case is_file($b.'/charge_full'):
|
984 |
+
$charge_full = Common::getIntFromFile($b.'/charge_full');
|
985 |
+
$charge_now = Common::getIntFromFile($b.'/charge_now');
|
986 |
+
break;
|
987 |
+
default:
|
988 |
+
continue;
|
989 |
+
break;
|
990 |
+
}
|
991 |
+
|
992 |
+
// Alleged percentage
|
993 |
+
$percentage = $charge_now != 0 && $charge_full != 0 ? (round($charge_now / $charge_full, 4) * 100) : '?';
|
994 |
+
|
995 |
+
// Save result set
|
996 |
+
$return[] = array(
|
997 |
+
'charge_full' => $charge_full,
|
998 |
+
'charge_now' => $charge_now,
|
999 |
+
'percentage' => (is_numeric($percentage) && $percentage > 100 ? 100 : $percentage),
|
1000 |
+
'device' => Common::getContents($b.'/manufacturer').' '.Common::getContents($b.'/model_name', 'Unknown'),
|
1001 |
+
'state' => Common::getContents($b.'/status', 'Unknown'),
|
1002 |
+
);
|
1003 |
+
}
|
1004 |
+
|
1005 |
+
// Give it
|
1006 |
+
return $return;
|
1007 |
+
}
|
1008 |
+
|
1009 |
+
/**
|
1010 |
+
* getWifi.
|
1011 |
+
*
|
1012 |
+
* @return array of wifi devices
|
1013 |
+
*/
|
1014 |
+
public function getWifi()
|
1015 |
+
{
|
1016 |
+
|
1017 |
+
// Time?
|
1018 |
+
if (!empty($this->settings['timer'])) {
|
1019 |
+
$t = new Timer('Wifi');
|
1020 |
+
}
|
1021 |
+
|
1022 |
+
// Return these
|
1023 |
+
$return = array();
|
1024 |
+
|
1025 |
+
// In here
|
1026 |
+
$contents = Common::getContents('/proc/net/wireless');
|
1027 |
+
|
1028 |
+
// Oi
|
1029 |
+
if ($contents == false) {
|
1030 |
+
Errors::add('Linux WiFi info parser', '/proc/net/wireless does not exist');
|
1031 |
+
|
1032 |
+
return $return;
|
1033 |
+
}
|
1034 |
+
|
1035 |
+
// Parse
|
1036 |
+
@preg_match_all('/^ (\S+)\:\s*(\d+)\s*(\S+)\s*(\S+)\s*(\S+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*$/m', $contents, $match, PREG_SET_ORDER);
|
1037 |
+
|
1038 |
+
// Match
|
1039 |
+
foreach ($match as $wlan) {
|
1040 |
+
$return[] = array(
|
1041 |
+
'device' => $wlan[1],
|
1042 |
+
'status' => $wlan[2],
|
1043 |
+
'quality_link' => $wlan[3],
|
1044 |
+
'quality_level' => $wlan[4],
|
1045 |
+
'quality_noise' => $wlan[5],
|
1046 |
+
'dis_nwid' => $wlan[6],
|
1047 |
+
'dis_crypt' => $wlan[7],
|
1048 |
+
'dis_frag' => $wlan[8],
|
1049 |
+
'dis_retry' => $wlan[9],
|
1050 |
+
'dis_misc' => $wlan[10],
|
1051 |
+
'mis_beac' => $wlan[11],
|
1052 |
+
);
|
1053 |
+
}
|
1054 |
+
|
1055 |
+
// Done
|
1056 |
+
return $return;
|
1057 |
+
}
|
1058 |
+
|
1059 |
+
/**
|
1060 |
+
* getSoundCards.
|
1061 |
+
*
|
1062 |
+
* @return array of soundcards
|
1063 |
+
*/
|
1064 |
+
public function getSoundCards()
|
1065 |
+
{
|
1066 |
+
|
1067 |
+
// Time?
|
1068 |
+
if (!empty($this->settings['timer'])) {
|
1069 |
+
$t = new Timer('Sound cards');
|
1070 |
+
}
|
1071 |
+
|
1072 |
+
// This should be it
|
1073 |
+
$file = '/proc/asound/cards';
|
1074 |
+
|
1075 |
+
// eh?
|
1076 |
+
if (!is_file($file)) {
|
1077 |
+
Errors::add('Linux sound card detector', '/proc/asound/cards does not exist');
|
1078 |
+
}
|
1079 |
+
|
1080 |
+
// Get contents and parse
|
1081 |
+
$contents = Common::getContents($file);
|
1082 |
+
|
1083 |
+
// Parse
|
1084 |
+
if (preg_match_all('/^\s*(\d+)\s\[[\s\w]+\]:\s(.+)$/m', $contents, $matches, PREG_SET_ORDER) == 0) {
|
1085 |
+
return array();
|
1086 |
+
}
|
1087 |
+
|
1088 |
+
// eh?
|
1089 |
+
$cards = array();
|
1090 |
+
|
1091 |
+
// Deal with results
|
1092 |
+
foreach ($matches as $card) {
|
1093 |
+
$cards[] = array(
|
1094 |
+
'number' => $card[1],
|
1095 |
+
'card' => $card[2],
|
1096 |
+
);
|
1097 |
+
}
|
1098 |
+
|
1099 |
+
// Give cards
|
1100 |
+
return $cards;
|
1101 |
+
}
|
1102 |
+
|
1103 |
+
/**
|
1104 |
+
* getProcessStats.
|
1105 |
+
*
|
1106 |
+
* @return array of process stats
|
1107 |
+
*/
|
1108 |
+
public function getProcessStats()
|
1109 |
+
{
|
1110 |
+
|
1111 |
+
// Time?
|
1112 |
+
if (!empty($this->settings['timer'])) {
|
1113 |
+
$t = new Timer('Process Stats');
|
1114 |
+
}
|
1115 |
+
|
1116 |
+
// We'll return this after stuffing it with useful info
|
1117 |
+
$result = array(
|
1118 |
+
'exists' => true,
|
1119 |
+
'totals' => array(
|
1120 |
+
'running' => 0,
|
1121 |
+
'zombie' => 0,
|
1122 |
+
'sleeping' => 0,
|
1123 |
+
'stopped' => 0,
|
1124 |
+
),
|
1125 |
+
'proc_total' => 0,
|
1126 |
+
'threads' => 0,
|
1127 |
+
);
|
1128 |
+
|
1129 |
+
// Get all the paths to each process' status file
|
1130 |
+
$processes = (array) @glob('/proc/*/status', GLOB_NOSORT);
|
1131 |
+
|
1132 |
+
// Total
|
1133 |
+
$result['proc_total'] = count($processes);
|
1134 |
+
|
1135 |
+
// Go through each
|
1136 |
+
foreach ($processes as $process) {
|
1137 |
+
|
1138 |
+
// Don't waste time if we can't use it
|
1139 |
+
if (!is_readable($process)) {
|
1140 |
+
continue;
|
1141 |
+
}
|
1142 |
+
|
1143 |
+
// Get that file's contents
|
1144 |
+
$status_contents = Common::getContents($process);
|
1145 |
+
|
1146 |
+
// Try getting state
|
1147 |
+
@preg_match('/^State:\s+(\w)/m', $status_contents, $state_match);
|
1148 |
+
|
1149 |
+
// Well? Determine state
|
1150 |
+
switch ($state_match[1]) {
|
1151 |
+
case 'D': // disk sleep? wtf?
|
1152 |
+
case 'S':
|
1153 |
+
$result['totals']['sleeping']++;
|
1154 |
+
break;
|
1155 |
+
case 'Z':
|
1156 |
+
$result['totals']['zombie']++;
|
1157 |
+
break;
|
1158 |
+
case 'R':
|
1159 |
+
$result['totals']['running']++;
|
1160 |
+
break;
|
1161 |
+
case 'T':
|
1162 |
+
$result['totals']['stopped']++;
|
1163 |
+
break;
|
1164 |
+
}
|
1165 |
+
|
1166 |
+
// Try getting number of threads
|
1167 |
+
@preg_match('/^Threads:\s+(\d+)/m', $status_contents, $threads_match);
|
1168 |
+
|
1169 |
+
// Well?
|
1170 |
+
if ($threads_match) {
|
1171 |
+
list(, $threads) = $threads_match;
|
1172 |
+
}
|
1173 |
+
|
1174 |
+
// Append it on if it's good
|
1175 |
+
if (is_numeric($threads)) {
|
1176 |
+
$result['threads'] = $result['threads'] + $threads;
|
1177 |
+
}
|
1178 |
+
}
|
1179 |
+
|
1180 |
+
// Give off result
|
1181 |
+
return $result;
|
1182 |
+
}
|
1183 |
+
|
1184 |
+
/**
|
1185 |
+
* getServices.
|
1186 |
+
*
|
1187 |
+
* @return array the services
|
1188 |
+
*/
|
1189 |
+
public function getServices()
|
1190 |
+
{
|
1191 |
+
|
1192 |
+
// Time?
|
1193 |
+
if (!empty($this->settings['timer'])) {
|
1194 |
+
$t = new Timer('Services');
|
1195 |
+
}
|
1196 |
+
|
1197 |
+
// We allowed?
|
1198 |
+
if (empty($this->settings['show']['services']) || !is_array($this->settings['services']) || count($this->settings['services']) == 0) {
|
1199 |
+
return array();
|
1200 |
+
}
|
1201 |
+
|
1202 |
+
// Temporarily keep statuses here
|
1203 |
+
$statuses = array();
|
1204 |
+
|
1205 |
+
$this->settings['services']['executables'] = (array) $this->settings['services']['executables'];
|
1206 |
+
$this->settings['services']['pidFiles'] = (array) $this->settings['services']['pidFiles'];
|
1207 |
+
|
1208 |
+
// Convert paths of executables to PID files
|
1209 |
+
$pids = array();
|
1210 |
+
$do_process_search = false;
|
1211 |
+
if (count($this->settings['services']['executables']) > 0) {
|
1212 |
+
$potential_paths = @glob('/proc/*/cmdline');
|
1213 |
+
if (is_array($potential_paths)) {
|
1214 |
+
$num_paths = count($potential_paths);
|
1215 |
+
$do_process_search = true;
|
1216 |
+
}
|
1217 |
+
}
|
1218 |
+
|
1219 |
+
// Should we go ahead and do the PID search based on executables?
|
1220 |
+
if ($do_process_search) {
|
1221 |
+
// Precache all process cmdlines
|
1222 |
+
for ($i = 0; $i < $num_paths; ++$i) {
|
1223 |
+
$cmdline_cache[$i] = explode("\x00", Common::getContents($potential_paths[$i]));
|
1224 |
+
}
|
1225 |
+
|
1226 |
+
// Go through the list of executables to search for
|
1227 |
+
foreach ($this->settings['services']['executables'] as $service => $exec) {
|
1228 |
+
// Go through pid file list. for loops are faster than foreach
|
1229 |
+
for ($i = 0; $i < $num_paths; ++$i) {
|
1230 |
+
$cmdline = $cmdline_cache[$i];
|
1231 |
+
$match = false;
|
1232 |
+
if (is_array($exec)) {
|
1233 |
+
$match = true;
|
1234 |
+
foreach ($exec as $argn => $argv) {
|
1235 |
+
if (isset($cmdline[$argn]) && $cmdline[$argn] != $argv) {
|
1236 |
+
$match = false;
|
1237 |
+
}
|
1238 |
+
}
|
1239 |
+
} elseif ($cmdline[0] == $exec) {
|
1240 |
+
$match = true;
|
1241 |
+
}
|
1242 |
+
// If this one matches, stop here and save it
|
1243 |
+
if ($match) {
|
1244 |
+
// Get pid out of path to cmdline file
|
1245 |
+
$pids[$service] = substr($potential_paths[$i], 6 /*strlen('/proc/')*/,
|
1246 |
+
strpos($potential_paths[$i], '/', 7) - 6);
|
1247 |
+
break;
|
1248 |
+
}
|
1249 |
+
}
|
1250 |
+
}
|
1251 |
+
}
|
1252 |
+
|
1253 |
+
// PID files
|
1254 |
+
foreach ($this->settings['services']['pidFiles'] as $service => $file) {
|
1255 |
+
$pid = Common::getContents($file, false);
|
1256 |
+
if ($pid != false && is_numeric($pid)) {
|
1257 |
+
$pids[$service] = $pid;
|
1258 |
+
}
|
1259 |
+
}
|
1260 |
+
|
1261 |
+
// Deal with PIDs
|
1262 |
+
foreach ($pids as $service => $pid) {
|
1263 |
+
$path = '/proc/'.$pid.'/status';
|
1264 |
+
$status_contents = Common::getContents($path, false);
|
1265 |
+
if ($status_contents == false) {
|
1266 |
+
$statuses[$service] = array('state' => 'Down', 'threads' => 'N/A', 'pid' => $pid);
|
1267 |
+
continue;
|
1268 |
+
}
|
1269 |
+
|
1270 |
+
// Attempt getting info out of it
|
1271 |
+
if (!preg_match_all('/^(\w+):\s+(\w+)/m', $status_contents, $status_matches, PREG_SET_ORDER)) {
|
1272 |
+
continue;
|
1273 |
+
}
|
1274 |
+
|
1275 |
+
// Initially set these as pointless
|
1276 |
+
$state = false;
|
1277 |
+
$threads = false;
|
1278 |
+
$mem = false;
|
1279 |
+
|
1280 |
+
// Go through
|
1281 |
+
for ($i = 0, $num = count($status_matches); $i < $num; ++$i) {
|
1282 |
+
|
1283 |
+
// What have we here?
|
1284 |
+
switch ($status_matches[$i][1]) {
|
1285 |
+
|
1286 |
+
// State section
|
1287 |
+
case 'State':
|
1288 |
+
switch ($status_matches[$i][2]) {
|
1289 |
+
case 'D': // disk sleep? wtf?
|
1290 |
+
case 'S':
|
1291 |
+
$state = 'Up (Sleeping)';
|
1292 |
+
break;
|
1293 |
+
case 'Z':
|
1294 |
+
$state = 'Zombie';
|
1295 |
+
break;
|
1296 |
+
// running
|
1297 |
+
case 'R':
|
1298 |
+
$state = 'Up (Running)';
|
1299 |
+
break;
|
1300 |
+
// stopped
|
1301 |
+
case 'T':
|
1302 |
+
$state = 'Up (Stopped)';
|
1303 |
+
break;
|
1304 |
+
default:
|
1305 |
+
continue;
|
1306 |
+
break;
|
1307 |
+
}
|
1308 |
+
break;
|
1309 |
+
|
1310 |
+
// Mem usage
|
1311 |
+
case 'VmRSS':
|
1312 |
+
if (is_numeric($status_matches[$i][2])) {
|
1313 |
+
$mem = $status_matches[$i][2] * 1024;
|
1314 |
+
} // Measured in kilobytes; we want bytes
|
1315 |
+
break;
|
1316 |
+
|
1317 |
+
// Thread count
|
1318 |
+
case 'Threads':
|
1319 |
+
if (is_numeric($status_matches[$i][2])) {
|
1320 |
+
$threads = $status_matches[$i][2];
|
1321 |
+
}
|
1322 |
+
|
1323 |
+
// Thread count should be last. Stop here to possibly save time assuming we have the other values
|
1324 |
+
if ($state !== false && $mem !== false && $threads !== false) {
|
1325 |
+
break;
|
1326 |
+
}
|
1327 |
+
break;
|
1328 |
+
}
|
1329 |
+
}
|
1330 |
+
|
1331 |
+
// Save info
|
1332 |
+
$statuses[$service] = array(
|
1333 |
+
'state' => $state ? $state : '?',
|
1334 |
+
'threads' => $threads,
|
1335 |
+
'pid' => $pid,
|
1336 |
+
'memory_usage' => $mem,
|
1337 |
+
);
|
1338 |
+
}
|
1339 |
+
|
1340 |
+
return $statuses;
|
1341 |
+
}
|
1342 |
+
|
1343 |
+
/**
|
1344 |
+
* getDistro.
|
1345 |
+
*
|
1346 |
+
* @return array the distro,version or false
|
1347 |
+
*/
|
1348 |
+
public function getDistro()
|
1349 |
+
{
|
1350 |
+
|
1351 |
+
// Time?
|
1352 |
+
if (!empty($this->settings['timer'])) {
|
1353 |
+
$t = new Timer('Determining Distrobution');
|
1354 |
+
}
|
1355 |
+
|
1356 |
+
// Seems the best way of doing it, as opposed to calling 'lsb_release -a', parsing /etc/issue, or
|
1357 |
+
// just checking if distro specific version files exist without actually parsing them:
|
1358 |
+
// - Allows multiple files of the same name for different distros/versions of distros, provided each
|
1359 |
+
// - uses different regular expression syntax.
|
1360 |
+
// - Also permits files that contain only the distro release version and nothing else,
|
1361 |
+
// - in which case passing false instead of a regex string snags the contents.
|
1362 |
+
// - And even also supports empty files, and just uses said file to identify the distro and ignore version
|
1363 |
+
|
1364 |
+
$contents_distros = array(
|
1365 |
+
array(
|
1366 |
+
'file' => '/etc/redhat-release',
|
1367 |
+
'regex' => '/^CentOS.+release (?P<version>[\d\.]+) \((?P<codename>[^)]+)\)$/i',
|
1368 |
+
'distro' => 'CentOS',
|
1369 |
+
),
|
1370 |
+
array(
|
1371 |
+
'file' => '/etc/redhat-release',
|
1372 |
+
'regex' => '/^Red Hat.+release (?P<version>\S+) \((?P<codename>[^)]+)\)$/i',
|
1373 |
+
'distro' => 'RedHat',
|
1374 |
+
),
|
1375 |
+
array(
|
1376 |
+
'file' => '/etc/lsb-release',
|
1377 |
+
'closure' => function ($ini) {
|
1378 |
+
return ($info = @parse_ini_string($ini)) &&
|
1379 |
+
isset($info['DISTRIB_ID']) &&
|
1380 |
+
isset($info['DISTRIB_RELEASE']) &&
|
1381 |
+
isset($info['DISTRIB_CODENAME']) ? array(
|
1382 |
+
'distro' => $info['DISTRIB_ID'],
|
1383 |
+
'version' => $info['DISTRIB_RELEASE'],
|
1384 |
+
'codename' => $info['DISTRIB_CODENAME'],
|
1385 |
+
) : false;
|
1386 |
+
}
|
1387 |
+
),
|
1388 |
+
array(
|
1389 |
+
'file' => '/etc/os-release',
|
1390 |
+
'closure' => function ($ini) {
|
1391 |
+
return ($info = @parse_ini_string($ini)) &&
|
1392 |
+
isset($info['ID']) &&
|
1393 |
+
isset($info['VERSION']) ? array(
|
1394 |
+
'distro' => $info['ID'],
|
1395 |
+
'version' => $info['VERSION']
|
1396 |
+
) : false;
|
1397 |
+
},
|
1398 |
+
),
|
1399 |
+
array(
|
1400 |
+
'file' => '/etc/fedora-release',
|
1401 |
+
'regex' => '/^Fedora(?: Core)? release (?P<version>\d+) \((?P<codename>[^)]+)\)$/',
|
1402 |
+
'distro' => 'Fedora',
|
1403 |
+
),
|
1404 |
+
array(
|
1405 |
+
'file' => '/etc/gentoo-release',
|
1406 |
+
'regex' => '/(?P<version>[\d\.]+)$/',
|
1407 |
+
'distro' => 'Gentoo',
|
1408 |
+
),
|
1409 |
+
array(
|
1410 |
+
'file' => '/etc/SuSE-release',
|
1411 |
+
'regex' => '/^VERSION = (?P<version>[\d\.]+)$/m',
|
1412 |
+
'distro' => 'openSUSE',
|
1413 |
+
),
|
1414 |
+
array(
|
1415 |
+
'file' => '/etc/slackware-version',
|
1416 |
+
'regex' => '/(?P<version>[\d\.]+)$/',
|
1417 |
+
'distro' => 'Slackware',
|
1418 |
+
),
|
1419 |
+
array(
|
1420 |
+
'file' => '/etc/debian_version',
|
1421 |
+
'distro' => 'Debian',
|
1422 |
+
),
|
1423 |
+
);
|
1424 |
+
|
1425 |
+
foreach ($contents_distros as $distro) {
|
1426 |
+
if (!($contents = Common::getContents($distro['file'], false))) {
|
1427 |
+
continue;
|
1428 |
+
}
|
1429 |
+
if (isset($distro['closure']) && ($info = $distro['closure']($contents))) {
|
1430 |
+
return array(
|
1431 |
+
'name' => ucfirst($info['distro']),
|
1432 |
+
'version' => $info['version'].(isset($info['codename']) ? ' ('.ucfirst($info['codename']).')' : ''),
|
1433 |
+
);
|
1434 |
+
} elseif (isset($distro['regex']) && preg_match($distro['regex'], $contents, $info)) {
|
1435 |
+
return array(
|
1436 |
+
'name' => $distro['distro'],
|
1437 |
+
'version' => $info['version'].(isset($info['codename']) ? ' ('.ucfirst($info['codename']).')' : ''),
|
1438 |
+
);
|
1439 |
+
} elseif (isset($distro['distro'])) {
|
1440 |
+
return array(
|
1441 |
+
'name' => $distro['distro'],
|
1442 |
+
'version' => $contents,
|
1443 |
+
);
|
1444 |
+
}
|
1445 |
+
}
|
1446 |
+
|
1447 |
+
$existence_distros = array(
|
1448 |
+
'/etc/arch-release' => 'Arch',
|
1449 |
+
'/etc/mklinux-release' => 'MkLinux',
|
1450 |
+
'/etc/tinysofa-release ' => 'TinySofa',
|
1451 |
+
'/etc/turbolinux-release ' => 'TurboLinux',
|
1452 |
+
'/etc/yellowdog-release ' => 'YellowDog',
|
1453 |
+
'/etc/annvix-release ' => 'Annvix',
|
1454 |
+
'/etc/arklinux-release ' => 'Arklinux',
|
1455 |
+
'/etc/aurox-release ' => 'AuroxLinux',
|
1456 |
+
'/etc/blackcat-release ' => 'BlackCat',
|
1457 |
+
'/etc/cobalt-release ' => 'Cobalt',
|
1458 |
+
'/etc/immunix-release ' => 'Immunix',
|
1459 |
+
'/etc/lfs-release ' => 'Linux-From-Scratch',
|
1460 |
+
'/etc/linuxppc-release ' => 'Linux-PPC',
|
1461 |
+
'/etc/mklinux-release ' => 'MkLinux',
|
1462 |
+
'/etc/nld-release ' => 'NovellLinuxDesktop',
|
1463 |
+
);
|
1464 |
+
|
1465 |
+
foreach ($existence_distros as $file => $distro) {
|
1466 |
+
if (is_file($file)) {
|
1467 |
+
return array(
|
1468 |
+
'name' => $distro,
|
1469 |
+
'version' => false,
|
1470 |
+
);
|
1471 |
+
}
|
1472 |
+
}
|
1473 |
+
|
1474 |
+
// Return lack of result if we didn't find it
|
1475 |
+
return false;
|
1476 |
+
}
|
1477 |
+
|
1478 |
+
/**
|
1479 |
+
* getNumLoggedIn.
|
1480 |
+
*
|
1481 |
+
* @return number of logged in users with shells
|
1482 |
+
*/
|
1483 |
+
public function getNumLoggedIn()
|
1484 |
+
{
|
1485 |
+
|
1486 |
+
// Snag command line of every process in system
|
1487 |
+
$procs = glob('/proc/*/cmdline', GLOB_NOSORT);
|
1488 |
+
|
1489 |
+
// Store unqiue users here
|
1490 |
+
$users = array();
|
1491 |
+
|
1492 |
+
// Each process
|
1493 |
+
foreach ($procs as $proc) {
|
1494 |
+
|
1495 |
+
// Does the process match a popular shell, such as bash, csh, etc?
|
1496 |
+
if (preg_match('/(?:bash|csh|zsh|ksh)$/', Common::getContents($proc, ''))) {
|
1497 |
+
|
1498 |
+
// Who owns it, anyway?
|
1499 |
+
$owner = fileowner(dirname($proc));
|
1500 |
+
|
1501 |
+
// Careful..
|
1502 |
+
if (!is_numeric($owner)) {
|
1503 |
+
continue;
|
1504 |
+
}
|
1505 |
+
|
1506 |
+
// Have we not seen this user before?
|
1507 |
+
if (!in_array($owner, $users)) {
|
1508 |
+
$users[] = $owner;
|
1509 |
+
}
|
1510 |
+
}
|
1511 |
+
}
|
1512 |
+
|
1513 |
+
// Give number of unique users with shells running
|
1514 |
+
return count($users);
|
1515 |
+
}
|
1516 |
+
|
1517 |
+
/**
|
1518 |
+
* getVirtualization. Potentially not very accurate especially since you can virtualize hypervisors,
|
1519 |
+
* kernel module names change frequently, you can load (some of) these modules if you aren't a host/guest, etc.
|
1520 |
+
*
|
1521 |
+
* @return array('type' => 'guest', 'method' => kvm or vmware or xen or openvz) or array('type' => 'host', 'methods' = ['intel', 'amd'])
|
1522 |
+
*/
|
1523 |
+
public function getVirtualization()
|
1524 |
+
{
|
1525 |
+
|
1526 |
+
// Time?
|
1527 |
+
if (!empty($this->settings['timer'])) {
|
1528 |
+
$t = new Timer('Determining virtualization type');
|
1529 |
+
}
|
1530 |
+
|
1531 |
+
// OpenVZ host?
|
1532 |
+
if (is_file('/proc/vz/version')) {
|
1533 |
+
return array('type' => 'host', 'method' => 'OpenVZ');
|
1534 |
+
}
|
1535 |
+
|
1536 |
+
// OpenVZ guest?
|
1537 |
+
elseif (is_file('/proc/vz/veinfo')) {
|
1538 |
+
return array('type' => 'guest', 'method' => 'OpenVZ');
|
1539 |
+
}
|
1540 |
+
|
1541 |
+
// Try getting kernel modules
|
1542 |
+
$modules = array();
|
1543 |
+
if (preg_match_all('/^(\S+)/m', Common::getContents('/proc/modules', ''), $matches, PREG_SET_ORDER)) {
|
1544 |
+
foreach ($matches as $match) {
|
1545 |
+
$modules[] = $match[1];
|
1546 |
+
}
|
1547 |
+
}
|
1548 |
+
|
1549 |
+
// Sometimes /proc/modules is missing what is in this dir on VMs
|
1550 |
+
foreach (@glob('/sys/bus/pci/drivers/*') as $name) {
|
1551 |
+
$modules[] = basename($name);
|
1552 |
+
}
|
1553 |
+
|
1554 |
+
// VMware guest. Tested on debian under vmware fusion for mac...
|
1555 |
+
if (Common::anyInArray(array('vmw_balloon', 'vmwgfx', 'vmw_vmci'), $modules)) {
|
1556 |
+
return array('type' => 'guest', 'method' => 'VMWare');
|
1557 |
+
}
|
1558 |
+
|
1559 |
+
// VMware Host! tested on rhel6 running vmware..workstation?
|
1560 |
+
if (Common::anyInArray(array('vmnet', 'vmci', 'vmmon'), $modules)) {
|
1561 |
+
return array('type' => 'host', 'method' => 'VMWare');
|
1562 |
+
}
|
1563 |
+
|
1564 |
+
// Looks like it might be xen...
|
1565 |
+
if (Common::anyInArray(array('xenfs', 'xen_gntdev', 'xen_evtchn', 'xen_blkfront', 'xen_netfront'), $modules) || is_dir('/proc/xen')) {
|
1566 |
+
|
1567 |
+
// Guest or host?
|
1568 |
+
if (Common::anyInArray(array('xen-netback', 'xen_blkback'), $modules) || strpos('control_d', Common::getContents('/proc/xen/capabilities', '')) !== false) {
|
1569 |
+
return array('type' => 'host', 'method' => 'Xen');
|
1570 |
+
} else {
|
1571 |
+
return array('type' => 'guest', 'method' => 'Xen');
|
1572 |
+
}
|
1573 |
+
}
|
1574 |
+
|
1575 |
+
// VirtualBox Host! Tested on lucid running vbox..
|
1576 |
+
if (in_array('vboxdrv', $modules)) {
|
1577 |
+
return array('type' => 'host', 'method' => 'VirtualBox');
|
1578 |
+
}
|
1579 |
+
|
1580 |
+
// VirtualBox Guest! Tested on wheezy under mac vbox
|
1581 |
+
if (in_array('vboxguest', $modules)) {
|
1582 |
+
return array('type' => 'guest', 'method' => 'VirtualBox');
|
1583 |
+
}
|
1584 |
+
|
1585 |
+
// Looks like it might be KVM HOST!
|
1586 |
+
if (Common::anyInArray(array('kvm_intel', 'kvm_amd'), $modules)) {
|
1587 |
+
return array('type' => 'host', 'method' => 'KVM');
|
1588 |
+
}
|
1589 |
+
|
1590 |
+
// Looks like it might be a KVM or QEMU guest! This is a bit lame since Xen can also use virtio but its less likely (?)
|
1591 |
+
if (Common::anyInArray(array('virtio', 'virtio_balloon', 'virtio_pci', 'virtio-pci', 'virtio_blk', 'virtio_net'), $modules)) {
|
1592 |
+
return array('type' => 'guest', 'method' => 'Qemu/KVM');
|
1593 |
+
}
|
1594 |
+
|
1595 |
+
// idk
|
1596 |
+
return false;
|
1597 |
+
}
|
1598 |
+
|
1599 |
+
/**
|
1600 |
+
* Get overall CPU usage. Depends on determineCPUPercentage() being called prior.
|
1601 |
+
*/
|
1602 |
+
public function getCPUUsage()
|
1603 |
+
{
|
1604 |
+
return $this->cpu_percent['overall'] === false ? false : $this->cpu_percent['overall'];
|
1605 |
+
}
|
1606 |
+
|
1607 |
+
/**
|
1608 |
+
* Parse lines from /proc/stat. Used by determineCPUPercentage function.
|
1609 |
+
* @param $key
|
1610 |
+
* @param $line
|
1611 |
+
* @return float
|
1612 |
+
*/
|
1613 |
+
private function cpuPercent($key, $line)
|
1614 |
+
{
|
1615 |
+
|
1616 |
+
// With each iteration we compare what we got to last time's version
|
1617 |
+
// as the file changes every milisecond or something
|
1618 |
+
static $prev = array();
|
1619 |
+
|
1620 |
+
// Using regex/explode is excessive here, not unlike rest of linfo :/
|
1621 |
+
$ret = sscanf($line, '%Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu');
|
1622 |
+
|
1623 |
+
// Negative? That's crazy talk now
|
1624 |
+
foreach ($ret as $k => $v) {
|
1625 |
+
if ($v < 0) {
|
1626 |
+
$ret[$k] = 0;
|
1627 |
+
}
|
1628 |
+
}
|
1629 |
+
|
1630 |
+
// First time; set our vals
|
1631 |
+
if (!isset($prev[$key])) {
|
1632 |
+
$prev[$key] = $ret;
|
1633 |
+
}
|
1634 |
+
|
1635 |
+
// Subsequent time; difference with last time
|
1636 |
+
else {
|
1637 |
+
$orig = $ret;
|
1638 |
+
foreach ($ret as $k => $v) {
|
1639 |
+
$ret[$k] -= $prev[$key][$k];
|
1640 |
+
}
|
1641 |
+
$prev[$key] = $orig;
|
1642 |
+
}
|
1643 |
+
|
1644 |
+
// Refer back to top.c for the reasoning here. I just copied the algorithm without
|
1645 |
+
// trying to understand why.
|
1646 |
+
$scale = 100.0 / (float) array_sum($ret);
|
1647 |
+
$cpu_percent = $ret[0] * $scale;
|
1648 |
+
|
1649 |
+
return round($cpu_percent, 2);
|
1650 |
+
}
|
1651 |
+
|
1652 |
+
/**
|
1653 |
+
* Most controersial and different function in linfo. Updates $this->cpu_percent array. Sleeps 1 second
|
1654 |
+
* to do this which is how it gets accurate details. Code stolen from procps' source for the Linux top command.
|
1655 |
+
*
|
1656 |
+
* @void
|
1657 |
+
*/
|
1658 |
+
public function determineCPUPercentage()
|
1659 |
+
{
|
1660 |
+
// Time?
|
1661 |
+
if (!empty($this->settings['timer'])) {
|
1662 |
+
$t = new Timer('Determining CPU usage');
|
1663 |
+
}
|
1664 |
+
|
1665 |
+
$iterations = 2;
|
1666 |
+
|
1667 |
+
// Probably only inline function here. Only used once so it makes sense.
|
1668 |
+
|
1669 |
+
for ($i = 0; $i < $iterations; ++$i) {
|
1670 |
+
$contents = Common::getContents('/proc/stat', false);
|
1671 |
+
|
1672 |
+
// Yay we can't read it so we won't sleep below!
|
1673 |
+
if (!$contents) {
|
1674 |
+
continue;
|
1675 |
+
}
|
1676 |
+
|
1677 |
+
// Overall system CPU usage
|
1678 |
+
if (preg_match('/^cpu\s+(.+)/', $contents, $m)) {
|
1679 |
+
$this->cpu_percent['overall'] = $this->cpuPercent('overall', $m[1]);
|
1680 |
+
}
|
1681 |
+
|
1682 |
+
// CPU usage per CPU
|
1683 |
+
if (preg_match_all('/^cpu(\d+)\s+(.+)/m', $contents, $cpus, PREG_SET_ORDER)) {
|
1684 |
+
foreach ($cpus as $cpu) {
|
1685 |
+
$this->cpu_percent['cpus'][$cpu[1]] = $this->cpuPercent('c'.$cpu[1], $cpu[2]);
|
1686 |
+
}
|
1687 |
+
}
|
1688 |
+
|
1689 |
+
// Following two lines make me want to puke as they go against everything linfo stands for
|
1690 |
+
// this functionality will always be disabled by default
|
1691 |
+
// Sleep *between* iterations and only if we're doing at least two of them
|
1692 |
+
if ($iterations > 1 && $i != $iterations - 1) {
|
1693 |
+
sleep(1);
|
1694 |
+
}
|
1695 |
+
}
|
1696 |
+
}
|
1697 |
+
|
1698 |
+
/**
|
1699 |
+
* Get brand/name of motherboard/server through /sys' interface to dmidecode.
|
1700 |
+
*/
|
1701 |
+
public function getModel()
|
1702 |
+
{
|
1703 |
+
$info = array();
|
1704 |
+
$vendor = Common::getContents('/sys/devices/virtual/dmi/id/board_vendor', false);
|
1705 |
+
$name = Common::getContents('/sys/devices/virtual/dmi/id/board_name', false);
|
1706 |
+
$product = Common::getContents('/sys/devices/virtual/dmi/id/product_name', false);
|
1707 |
+
|
1708 |
+
if (!$name) {
|
1709 |
+
return false;
|
1710 |
+
}
|
1711 |
+
|
1712 |
+
// Don't add vendor to the mix if the name starts with it
|
1713 |
+
if ($vendor && strpos($name, $vendor) !== 0) {
|
1714 |
+
$info[] = $vendor;
|
1715 |
+
}
|
1716 |
+
|
1717 |
+
$info[] = $name;
|
1718 |
+
|
1719 |
+
$infostr = implode(' ', $info);
|
1720 |
+
|
1721 |
+
// product name is usually bullshit, but *occasionally* it's a useful name of the computer, such as
|
1722 |
+
// dell latitude e6500 or hp z260
|
1723 |
+
if ($product && strpos($name, $product) === false && strpos($product, 'Filled') === false) {
|
1724 |
+
return $product.' ('.$infostr.')';
|
1725 |
+
} else {
|
1726 |
+
return $infostr;
|
1727 |
+
}
|
1728 |
+
}
|
1729 |
+
}
|
lib/Linfo/OS/Minix.php
ADDED
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\OS;
|
22 |
+
|
23 |
+
use Exception;
|
24 |
+
use Linfo\Parsers\CallExt;
|
25 |
+
|
26 |
+
/*
|
27 |
+
* Get info on a Minix system
|
28 |
+
* ---
|
29 |
+
* Note: the cli tools on minix are so meager that getting real detail
|
30 |
+
* out of it (like nic stats / fs types / etc) is either difficult or
|
31 |
+
* impossible. Nevertheless, this is my attempt at doing so.
|
32 |
+
*/
|
33 |
+
|
34 |
+
class Minix extends OS
|
35 |
+
{
|
36 |
+
// Store these here
|
37 |
+
protected $settings,
|
38 |
+
$exec;
|
39 |
+
|
40 |
+
// Start us off by localizing the settings and initializing the external
|
41 |
+
// application running class
|
42 |
+
public function __construct($settings)
|
43 |
+
{
|
44 |
+
|
45 |
+
// Localize settings
|
46 |
+
$this->settings = $settings;
|
47 |
+
|
48 |
+
// Start up external app loader
|
49 |
+
$this->exec = new CallExt();
|
50 |
+
|
51 |
+
// Have it look in these places
|
52 |
+
$this->exec->setSearchPaths(array('/usr/bin', '/usr/local/bin', '/bin'));
|
53 |
+
}
|
54 |
+
|
55 |
+
// Mounted file systems
|
56 |
+
// ---
|
57 |
+
// Note: the `mount` command does not have file system type
|
58 |
+
// and php's disk_free_space/disk_total_space functions don't seem
|
59 |
+
// to work here
|
60 |
+
public function getMounts()
|
61 |
+
{
|
62 |
+
|
63 |
+
// Try using the `mount` command to get mounted file systems
|
64 |
+
try {
|
65 |
+
$res = $this->exec->exec('mount');
|
66 |
+
} catch (Exception $e) {
|
67 |
+
return array();
|
68 |
+
}
|
69 |
+
|
70 |
+
// Try matching up the output
|
71 |
+
if (preg_match_all('/^(\S+) is .+ mounted on (\S+) \(.+\)$/m', $res, $mount_matches, PREG_SET_ORDER) == 0) {
|
72 |
+
return array();
|
73 |
+
}
|
74 |
+
|
75 |
+
// Store them here
|
76 |
+
$mounts = array();
|
77 |
+
|
78 |
+
// Go through each match
|
79 |
+
foreach ($mount_matches as $mount) {
|
80 |
+
|
81 |
+
// These might be a waste
|
82 |
+
$size = @disk_total_space($mount[2]);
|
83 |
+
$free = @disk_free_space($mount[2]);
|
84 |
+
$used = $size - $free;
|
85 |
+
|
86 |
+
// Save it
|
87 |
+
$mounts[] = array(
|
88 |
+
'device' => $mount[1],
|
89 |
+
'mount' => $mount[2],
|
90 |
+
'type' => '?', // Haven't a clue on how to get this on minix
|
91 |
+
'size' => $size,
|
92 |
+
'used' => $used,
|
93 |
+
'free' => $free,
|
94 |
+
'free_percent' => ((bool) $free != false && (bool) $size != false ? round($free / $size, 2) * 100 : false),
|
95 |
+
'used_percent' => ((bool) $used != false && (bool) $size != false ? round($used / $size, 2) * 100 : false),
|
96 |
+
);
|
97 |
+
}
|
98 |
+
|
99 |
+
// Return them
|
100 |
+
return $mounts;
|
101 |
+
}
|
102 |
+
|
103 |
+
// Get network interfaces
|
104 |
+
// ---
|
105 |
+
// netstat isn't installed by default and ifconfig doesn't have
|
106 |
+
// much functionality for viewing status, so I can't seem to get
|
107 |
+
// more than just name of interface
|
108 |
+
public function getNet()
|
109 |
+
{
|
110 |
+
|
111 |
+
// Try getting it.
|
112 |
+
try {
|
113 |
+
$res = $this->exec->exec('ifconfig', '-a');
|
114 |
+
} catch (Exception $e) {
|
115 |
+
return array();
|
116 |
+
}
|
117 |
+
|
118 |
+
// Match up the entries
|
119 |
+
if (preg_match_all('/^([^:]+)/m', $res, $net_matches, PREG_SET_ORDER) == 0) {
|
120 |
+
return array();
|
121 |
+
}
|
122 |
+
|
123 |
+
// Store them here
|
124 |
+
$nets = array();
|
125 |
+
|
126 |
+
// Go through each
|
127 |
+
foreach ($net_matches as $net) {
|
128 |
+
|
129 |
+
// Save this one
|
130 |
+
$nets[$net[1]] = array(
|
131 |
+
'state' => '?',
|
132 |
+
'type' => '?',
|
133 |
+
);
|
134 |
+
}
|
135 |
+
|
136 |
+
// Give them
|
137 |
+
return $nets;
|
138 |
+
}
|
139 |
+
}
|
lib/Linfo/OS/NetBSD.php
ADDED
@@ -0,0 +1,498 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\OS;
|
22 |
+
|
23 |
+
use Exception;
|
24 |
+
use Linfo\Meta\Timer;
|
25 |
+
use Linfo\Meta\Errors;
|
26 |
+
use Linfo\Common;
|
27 |
+
|
28 |
+
/*
|
29 |
+
* NetBSD info class. Differs slightly from FreeBSD's
|
30 |
+
* TODO: netbsd's /proc contains really useful info
|
31 |
+
* possibly get some stuff from it if it exists
|
32 |
+
*/
|
33 |
+
|
34 |
+
class NetBSD extends BSDcommon
|
35 |
+
{
|
36 |
+
// Encapsulate these
|
37 |
+
protected $settings,
|
38 |
+
$exec,
|
39 |
+
$error,
|
40 |
+
$dmesg;
|
41 |
+
|
42 |
+
// Start us off
|
43 |
+
public function __construct($settings)
|
44 |
+
{
|
45 |
+
|
46 |
+
// Initiate parent
|
47 |
+
parent::__construct($settings);
|
48 |
+
|
49 |
+
// We search these folders for our commands
|
50 |
+
$this->exec->setSearchPaths(array('/sbin', '/bin', '/usr/bin', '/usr/pkg/bin', '/usr/sbin'));
|
51 |
+
|
52 |
+
// sysctl values we'll access below
|
53 |
+
$this->GetSysCTL(array('kern.boottime', 'vm.loadavg'), false);
|
54 |
+
}
|
55 |
+
|
56 |
+
// Mounted file systems
|
57 |
+
public function getMounts()
|
58 |
+
{
|
59 |
+
|
60 |
+
// Time it
|
61 |
+
if (!empty($this->settings['timer'])) {
|
62 |
+
$t = new Timer('Mounted file systems');
|
63 |
+
}
|
64 |
+
|
65 |
+
// Try getting mount command
|
66 |
+
try {
|
67 |
+
$res = $this->exec->exec('mount');
|
68 |
+
} catch (Exception $e) {
|
69 |
+
Errors::add('Linfo Core', 'Error running `mount` command');
|
70 |
+
|
71 |
+
return array();
|
72 |
+
}
|
73 |
+
|
74 |
+
// Match the file systems
|
75 |
+
if (@preg_match_all('/^(\S+) on (\S+) type (\S+)/m', $res, $mount_match, PREG_SET_ORDER) == 0) {
|
76 |
+
return array();
|
77 |
+
}
|
78 |
+
|
79 |
+
// Store them here
|
80 |
+
$mounts = array();
|
81 |
+
|
82 |
+
// Go through each
|
83 |
+
foreach ($mount_match as $mount) {
|
84 |
+
// Should we not show this?
|
85 |
+
if (in_array($mount[1], $this->settings['hide']['storage_devices']) || in_array($mount[3], $this->settings['hide']['filesystems'])) {
|
86 |
+
continue;
|
87 |
+
}
|
88 |
+
|
89 |
+
// Get these
|
90 |
+
$size = @disk_total_space($mount[2]);
|
91 |
+
$free = @disk_free_space($mount[2]);
|
92 |
+
$used = $size - $free;
|
93 |
+
|
94 |
+
// Might be good, go for it
|
95 |
+
$mounts[] = array(
|
96 |
+
'device' => $mount[1],
|
97 |
+
'mount' => $mount[2],
|
98 |
+
'type' => $mount[3],
|
99 |
+
'size' => $size ,
|
100 |
+
'used' => $used,
|
101 |
+
'free' => $free,
|
102 |
+
'free_percent' => ((bool) $free != false && (bool) $size != false ? round($free / $size, 2) * 100 : false),
|
103 |
+
'used_percent' => ((bool) $used != false && (bool) $size != false ? round($used / $size, 2) * 100 : false),
|
104 |
+
);
|
105 |
+
}
|
106 |
+
|
107 |
+
// Give them
|
108 |
+
return $mounts;
|
109 |
+
}
|
110 |
+
|
111 |
+
// Get the always gloatable uptime
|
112 |
+
public function getUpTime()
|
113 |
+
{
|
114 |
+
// Time?
|
115 |
+
if (!empty($this->settings['timer'])) {
|
116 |
+
$t = new Timer('Uptime');
|
117 |
+
}
|
118 |
+
|
119 |
+
// Use sysctl
|
120 |
+
$booted = strtotime($this->sysctl['kern.boottime']);
|
121 |
+
|
122 |
+
// Give it
|
123 |
+
return array(
|
124 |
+
'text' => Common::secondsConvert(time() - $booted),
|
125 |
+
'bootedTimestamp' => $booted,
|
126 |
+
);
|
127 |
+
}
|
128 |
+
|
129 |
+
// Get network devices
|
130 |
+
public function getNet()
|
131 |
+
{
|
132 |
+
// Time?
|
133 |
+
if (!empty($this->settings['timer'])) {
|
134 |
+
$t = new Timer('Network Devices');
|
135 |
+
}
|
136 |
+
|
137 |
+
// Try using netstat
|
138 |
+
try {
|
139 |
+
$res = $this->exec->exec('netstat', '-nbdi');
|
140 |
+
} catch (Exception $e) {
|
141 |
+
Errors::add('Linfo Core', 'Error using `netstat` to get network info');
|
142 |
+
|
143 |
+
return array();
|
144 |
+
}
|
145 |
+
|
146 |
+
// Match the interfaces themselves
|
147 |
+
if (preg_match_all('/^(\S+)\s+\d+\s+<Link>\s+[a-z0-9\:]+\s+(\d+)\s+(\d+)\s+\d+$/m', $res, $net_matches, PREG_SET_ORDER) == 0) {
|
148 |
+
return array();
|
149 |
+
}
|
150 |
+
|
151 |
+
// Store statuses for each here
|
152 |
+
$statuses = array();
|
153 |
+
|
154 |
+
// Try using ifconfig to get statuses for each interface
|
155 |
+
try {
|
156 |
+
$ifconfig = $this->exec->exec('ifconfig', '-a');
|
157 |
+
$current_nic = false;
|
158 |
+
foreach ((array) explode("\n", $ifconfig) as $line) {
|
159 |
+
if (preg_match('/^(\w+):/m', $line, $m) == 1) {
|
160 |
+
$current_nic = $m[1];
|
161 |
+
} elseif ($current_nic != false && preg_match('/^\s+status: (\w+)$/m', $line, $m) == 1) {
|
162 |
+
$statuses[$current_nic] = $m[1];
|
163 |
+
$current_nic = false;
|
164 |
+
}
|
165 |
+
}
|
166 |
+
} catch (Exception $e) {
|
167 |
+
}
|
168 |
+
|
169 |
+
// Store interfaces here
|
170 |
+
$nets = array();
|
171 |
+
|
172 |
+
// Go through each
|
173 |
+
foreach ($net_matches as $net) {
|
174 |
+
|
175 |
+
// See if we successfully found a status, and use it if so
|
176 |
+
switch (array_key_exists($net[1], $statuses) ? $statuses[$net[1]] : 'unknown') {
|
177 |
+
case 'active':
|
178 |
+
$state = 'up';
|
179 |
+
break;
|
180 |
+
case 'inactive':
|
181 |
+
$state = 'down';
|
182 |
+
break;
|
183 |
+
default:
|
184 |
+
$state = 'unknown';
|
185 |
+
break;
|
186 |
+
}
|
187 |
+
|
188 |
+
// Save this interface
|
189 |
+
$nets[$net[1]] = array(
|
190 |
+
'recieved' => array(
|
191 |
+
'bytes' => $net[2],
|
192 |
+
),
|
193 |
+
'sent' => array(
|
194 |
+
'bytes' => $net[3],
|
195 |
+
),
|
196 |
+
'state' => $state,
|
197 |
+
'type' => 'Unknown', // TODO
|
198 |
+
);
|
199 |
+
}
|
200 |
+
|
201 |
+
// Give it
|
202 |
+
return $nets;
|
203 |
+
}
|
204 |
+
|
205 |
+
// Get drives
|
206 |
+
public function getHD()
|
207 |
+
{
|
208 |
+
|
209 |
+
// Time?
|
210 |
+
if (!empty($this->settings['timer'])) {
|
211 |
+
$t = new Timer('CPU');
|
212 |
+
}
|
213 |
+
|
214 |
+
$drives = array();
|
215 |
+
$curr_hd = false;
|
216 |
+
|
217 |
+
// Parse dmesg
|
218 |
+
foreach (explode("\n", $this->dmesg) as $dmesg_line) {
|
219 |
+
|
220 |
+
// Beginning of a drive entry
|
221 |
+
if (preg_match('/^([a-z]{2}\d) at [^:]+: <([^>]+)> (\w+)/', $dmesg_line, $init_match)) {
|
222 |
+
|
223 |
+
// If it's a cdrom just stop here and save it.
|
224 |
+
if ($init_match[3] == 'cdrom') {
|
225 |
+
|
226 |
+
// Save entry
|
227 |
+
$drives[] = array(
|
228 |
+
'name' => preg_match('/^([^,]+)/', $init_match[2], $cd_match) ? $cd_match[1] : $init_match[2],
|
229 |
+
'vendor' => false, // I don't know if this is possible
|
230 |
+
'device' => '/dev/'.$init_match[1],
|
231 |
+
|
232 |
+
// Not sure how to get the following:
|
233 |
+
'size' => false,
|
234 |
+
'reads' => false,
|
235 |
+
'writes' => false,
|
236 |
+
);
|
237 |
+
}
|
238 |
+
|
239 |
+
// Otherwise prep for further info on a later line
|
240 |
+
elseif ($init_match[3] == 'disk') {
|
241 |
+
$curr_hd = array($init_match[1], $init_match[2], $init_match[3]);
|
242 |
+
}
|
243 |
+
|
244 |
+
// Don't go any farther with this line
|
245 |
+
continue;
|
246 |
+
}
|
247 |
+
|
248 |
+
// A hard drive setting line, that has size and stuff
|
249 |
+
elseif ($curr_hd != false && preg_match('/^'.preg_quote($curr_hd[0]).': (\d+) MB/', $dmesg_line, $drive_match)) {
|
250 |
+
|
251 |
+
// Try getting vendor or name
|
252 |
+
$make = preg_match('/^([^,]+), ([^,]+)/', $curr_hd[1], $v_match) ? array($v_match[1], $v_match[2]) : false;
|
253 |
+
|
254 |
+
// Save entry
|
255 |
+
$drives[] = array(
|
256 |
+
'name' => $make ? $make[1] : $curr_hd[1],
|
257 |
+
'vendor' => $make ? $make[0] : false,
|
258 |
+
'device' => '/dev/'.$curr_hd[0],
|
259 |
+
'size' => $drive_match[1] * 1048576,
|
260 |
+
|
261 |
+
// Not sure how to get the following:
|
262 |
+
'reads' => false,
|
263 |
+
'writes' => false,
|
264 |
+
);
|
265 |
+
|
266 |
+
// We're done with this drive
|
267 |
+
$curr_hd = false;
|
268 |
+
|
269 |
+
// Don't go any farther with this line
|
270 |
+
continue;
|
271 |
+
}
|
272 |
+
}
|
273 |
+
|
274 |
+
// Give drives
|
275 |
+
return $drives;
|
276 |
+
}
|
277 |
+
|
278 |
+
// Get cpu's
|
279 |
+
public function getCPU()
|
280 |
+
{
|
281 |
+
|
282 |
+
// Time?
|
283 |
+
if (!empty($this->settings['timer'])) {
|
284 |
+
$t = new Timer('CPU');
|
285 |
+
}
|
286 |
+
|
287 |
+
// Parse dmesg
|
288 |
+
if (preg_match_all('/^cpu\d+ at [^:]+: (\S+) ([^,]+), (\d+)MHz/m', $this->dmesg, $cpu_matches, PREG_SET_ORDER) == 0) {
|
289 |
+
return array();
|
290 |
+
}
|
291 |
+
|
292 |
+
// Store them here
|
293 |
+
$cpus = array();
|
294 |
+
|
295 |
+
// Store as many as possible
|
296 |
+
foreach ($cpu_matches as $cpu_m) {
|
297 |
+
$cpus[] = array(
|
298 |
+
'Model' => $cpu_m[2],
|
299 |
+
'MHz' => $cpu_m[3],
|
300 |
+
'Vendor' => $cpu_m[1],
|
301 |
+
);
|
302 |
+
}
|
303 |
+
|
304 |
+
// Give them
|
305 |
+
return $cpus;
|
306 |
+
}
|
307 |
+
|
308 |
+
// Get ram usage
|
309 |
+
public function getRam()
|
310 |
+
{
|
311 |
+
|
312 |
+
// Time?
|
313 |
+
if (!empty($this->settings['timer'])) {
|
314 |
+
$t = new Timer('Memory');
|
315 |
+
}
|
316 |
+
|
317 |
+
// Start us off at zilch
|
318 |
+
$return = array();
|
319 |
+
$return['type'] = 'Virtual';
|
320 |
+
$return['total'] = 0;
|
321 |
+
$return['free'] = 0;
|
322 |
+
$return['swapTotal'] = 0;
|
323 |
+
$return['swapFree'] = 0;
|
324 |
+
$return['swapInfo'] = array();
|
325 |
+
|
326 |
+
// Get virtual memory usage with vmstat
|
327 |
+
try {
|
328 |
+
// Get result of vmstat
|
329 |
+
$vmstat = $this->exec->exec('vmstat', '-s');
|
330 |
+
|
331 |
+
// Get bytes per page
|
332 |
+
preg_match('/^\s+(\d+) bytes per page$/m', $vmstat, $bytes_per_page);
|
333 |
+
|
334 |
+
// Did we?
|
335 |
+
if (!is_numeric($bytes_per_page[1]) || $bytes_per_page[1] < 0) {
|
336 |
+
throw new Exception('Error parsing page size out of `vmstat`');
|
337 |
+
} else {
|
338 |
+
list(, $bytes_per_page) = $bytes_per_page;
|
339 |
+
}
|
340 |
+
|
341 |
+
// Get available ram
|
342 |
+
preg_match('/^\s+(\d+) pages managed$/m', $vmstat, $available_ram);
|
343 |
+
|
344 |
+
// Did we?
|
345 |
+
if (!is_numeric($available_ram[1])) {
|
346 |
+
throw new Exception('Error parsing managed pages out of `vmstat`');
|
347 |
+
} else {
|
348 |
+
list(, $available_ram) = $available_ram;
|
349 |
+
}
|
350 |
+
|
351 |
+
// Get free ram
|
352 |
+
preg_match('/^\s+(\d+) pages free$/m', $vmstat, $free_ram);
|
353 |
+
|
354 |
+
// Did we?
|
355 |
+
if (!is_numeric($free_ram[1])) {
|
356 |
+
throw new Exception('Error parsing free pages out of `vmstat`');
|
357 |
+
} else {
|
358 |
+
list(, $free_ram) = $free_ram;
|
359 |
+
}
|
360 |
+
|
361 |
+
// Okay, cool. Total them up
|
362 |
+
$return['total'] = $available_ram * $bytes_per_page;
|
363 |
+
$return['free'] = $free_ram * $bytes_per_page;
|
364 |
+
} catch (Exception $e) {
|
365 |
+
Errors::add('Linfo Core', 'Error using `vmstat` to get memory usage');
|
366 |
+
}
|
367 |
+
|
368 |
+
// Get swap
|
369 |
+
try {
|
370 |
+
$swapinfo = $this->exec->exec('swapctl', '-l');
|
371 |
+
@preg_match_all('/^(\S+)\s+(\d+)\s+(\d+)\s+(\d+)/m', $swapinfo, $sm, PREG_SET_ORDER);
|
372 |
+
foreach ($sm as $swap) {
|
373 |
+
$return['swapTotal'] += $swap[2] * 1024;
|
374 |
+
$return['swapFree'] += (($swap[2] - $swap[3]) * 1024);
|
375 |
+
$ft = is_file($swap[1]) ? @filetype($swap[1]) : 'Unknown'; // TODO: I'd rather it be Partition or File
|
376 |
+
$return['swapInfo'][] = array(
|
377 |
+
'device' => $swap[1],
|
378 |
+
'size' => $swap[2] * 1024,
|
379 |
+
'used' => $swap[3] * 1024,
|
380 |
+
'type' => ucfirst($ft),
|
381 |
+
);
|
382 |
+
}
|
383 |
+
} catch (Exception $e) {
|
384 |
+
Errors::add('Linfo Core', 'Error using `swapctl` to get swap usage');
|
385 |
+
}
|
386 |
+
|
387 |
+
// Give it off
|
388 |
+
return $return;
|
389 |
+
}
|
390 |
+
|
391 |
+
// Get devices
|
392 |
+
public function getDevs()
|
393 |
+
{
|
394 |
+
|
395 |
+
// Time?
|
396 |
+
if (!empty($this->settings['timer'])) {
|
397 |
+
$t = new Timer('Hardware Devices');
|
398 |
+
}
|
399 |
+
|
400 |
+
// Get them
|
401 |
+
if (preg_match_all('/^([a-z]+\d+) at ([a-z]+)\d+[^:]+:(.+)/m', $this->dmesg, $devices_match, PREG_SET_ORDER) == 0) {
|
402 |
+
return array();
|
403 |
+
}
|
404 |
+
|
405 |
+
// Keep them here
|
406 |
+
$devices = array();
|
407 |
+
|
408 |
+
// Store the type column for each key
|
409 |
+
$sort_type = array();
|
410 |
+
|
411 |
+
// Stuff it
|
412 |
+
foreach ($devices_match as $device) {
|
413 |
+
if ($device[2] == 'ppb' || strpos($device[3], 'vendor') !== false) {
|
414 |
+
continue;
|
415 |
+
}
|
416 |
+
|
417 |
+
// Only call this once
|
418 |
+
$type = strtoupper($device[2]);
|
419 |
+
|
420 |
+
// Stuff entry
|
421 |
+
$devices[] = array(
|
422 |
+
'vendor' => false, // Maybe todo?
|
423 |
+
'device' => $device[3],
|
424 |
+
'type' => $type,
|
425 |
+
);
|
426 |
+
|
427 |
+
// For the sorting of this entry
|
428 |
+
$sort_type[] = $type;
|
429 |
+
}
|
430 |
+
|
431 |
+
// Sort
|
432 |
+
array_multisort($devices, SORT_STRING, $sort_type);
|
433 |
+
|
434 |
+
// Give them
|
435 |
+
return $devices;
|
436 |
+
}
|
437 |
+
|
438 |
+
// Get stats on processes
|
439 |
+
public function getProcessStats()
|
440 |
+
{
|
441 |
+
|
442 |
+
// Time?
|
443 |
+
if (!empty($this->settings['timer'])) {
|
444 |
+
$t = new Timer('Process Stats');
|
445 |
+
}
|
446 |
+
|
447 |
+
// We'll return this after stuffing it with useful info
|
448 |
+
$result = array(
|
449 |
+
'exists' => true,
|
450 |
+
'totals' => array(
|
451 |
+
'running' => 0,
|
452 |
+
'zombie' => 0,
|
453 |
+
'sleeping' => 0,
|
454 |
+
'stopped' => 0,
|
455 |
+
),
|
456 |
+
'proc_total' => 0,
|
457 |
+
'threads' => false, // I'm not sure how to get this
|
458 |
+
);
|
459 |
+
|
460 |
+
// Use ps
|
461 |
+
try {
|
462 |
+
// Get it
|
463 |
+
$ps = $this->exec->exec('ps', 'ax');
|
464 |
+
|
465 |
+
// Match them
|
466 |
+
preg_match_all('/^\s*\d+\s+[\w?]+\s+([A-Z])\S*\s+.+$/m', $ps, $processes, PREG_SET_ORDER);
|
467 |
+
|
468 |
+
// Get total
|
469 |
+
$result['proc_total'] = count($processes);
|
470 |
+
|
471 |
+
// Go through
|
472 |
+
foreach ($processes as $process) {
|
473 |
+
switch ($process[1]) {
|
474 |
+
case 'S':
|
475 |
+
case 'I':
|
476 |
+
$result['totals']['sleeping']++;
|
477 |
+
break;
|
478 |
+
case 'Z':
|
479 |
+
$result['totals']['zombie']++;
|
480 |
+
break;
|
481 |
+
case 'R':
|
482 |
+
case 'D':
|
483 |
+
case 'O':
|
484 |
+
$result['totals']['running']++;
|
485 |
+
break;
|
486 |
+
case 'T':
|
487 |
+
$result['totals']['stopped']++;
|
488 |
+
break;
|
489 |
+
}
|
490 |
+
}
|
491 |
+
} catch (Exception $e) {
|
492 |
+
Errors::add('Linfo Core', 'Error using `ps` to get process info');
|
493 |
+
}
|
494 |
+
|
495 |
+
// Give
|
496 |
+
return $result;
|
497 |
+
}
|
498 |
+
}
|
lib/Linfo/OS/OS.php
ADDED
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file is part of Linfo (c) 2014 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*/
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Keep out hackers...
|
22 |
+
*/
|
23 |
+
namespace Linfo\OS;
|
24 |
+
|
25 |
+
use Linfo\Exceptions\FatalException;
|
26 |
+
|
27 |
+
abstract class OS
|
28 |
+
{
|
29 |
+
public function __call($name, $args)
|
30 |
+
{
|
31 |
+
throw new FatalException('Method '.$name.' not present.');
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* getAccessedIP
|
36 |
+
*
|
37 |
+
* @return string SERVER_ADDR or LOCAL_ADDR key in $_SERVER superglobal or Unknown
|
38 |
+
*/
|
39 |
+
public function getAccessedIP()
|
40 |
+
{
|
41 |
+
return isset($_SERVER['SERVER_ADDR']) && $_SERVER['SERVER_ADDR'] ? $_SERVER['SERVER_ADDR'] : (isset($_SERVER['LOCAL_ADDR']) && $_SERVER['LOCAL_ADDR'] ? $_SERVER['LOCAL_ADDR'] : 'Unknown');
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* getWebService
|
46 |
+
*
|
47 |
+
* @return string SERVER_SOFTWARE key in $_SERVER superglobal or Unknown
|
48 |
+
*/
|
49 |
+
public function getWebService()
|
50 |
+
{
|
51 |
+
return isset($_SERVER['SERVER_SOFTWARE']) && $_SERVER['SERVER_SOFTWARE'] ? $_SERVER['SERVER_SOFTWARE'] : 'Unknown';
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* getPhpVersion
|
56 |
+
*
|
57 |
+
* @return string the version of php
|
58 |
+
*/
|
59 |
+
public function getPhpVersion()
|
60 |
+
{
|
61 |
+
return phpversion();
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* getCPUArchitecture
|
66 |
+
*
|
67 |
+
* @return string the arch and bits
|
68 |
+
*/
|
69 |
+
public function getCPUArchitecture()
|
70 |
+
{
|
71 |
+
return php_uname('m');
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* getKernel
|
76 |
+
*
|
77 |
+
* @return string the OS kernel. A few OS classes override this.
|
78 |
+
*/
|
79 |
+
public function getKernel()
|
80 |
+
{
|
81 |
+
return php_uname('r');
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* getHostName
|
86 |
+
*
|
87 |
+
* @return string the OS' hostname A few OS classes override this.
|
88 |
+
*/
|
89 |
+
public function getHostName()
|
90 |
+
{
|
91 |
+
|
92 |
+
// Take advantage of that function again
|
93 |
+
return php_uname('n');
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* getOS
|
98 |
+
*
|
99 |
+
* @return string the OS' name.
|
100 |
+
*/
|
101 |
+
public function getOS()
|
102 |
+
{
|
103 |
+
$parts = explode('\\', get_class($this));
|
104 |
+
return array_pop($parts);
|
105 |
+
}
|
106 |
+
}
|
lib/Linfo/OS/OpenBSD.php
ADDED
@@ -0,0 +1,469 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010, 2012 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\OS;
|
22 |
+
|
23 |
+
use Exception;
|
24 |
+
use Linfo\Meta\Timer;
|
25 |
+
use Linfo\Meta\Errors;
|
26 |
+
use Linfo\Common;
|
27 |
+
|
28 |
+
/*
|
29 |
+
* OpenBSD info class.
|
30 |
+
* todo: as much functionality as the freebsd version
|
31 |
+
*/
|
32 |
+
|
33 |
+
class OpenBSD extends BSDcommon
|
34 |
+
{
|
35 |
+
// Encapsulate these
|
36 |
+
protected $settings,
|
37 |
+
$exec,
|
38 |
+
$dmesg;
|
39 |
+
|
40 |
+
// Start us off
|
41 |
+
public function __construct($settings)
|
42 |
+
{
|
43 |
+
|
44 |
+
// Initiate parent
|
45 |
+
parent::__construct($settings);
|
46 |
+
|
47 |
+
// We search these folders for our commands
|
48 |
+
$this->exec->setSearchPaths(array('/sbin', '/bin', '/usr/bin', '/usr/local/bin', '/usr/sbin'));
|
49 |
+
|
50 |
+
// sysctl values we'll access below
|
51 |
+
$this->GetSysCTL(array(
|
52 |
+
|
53 |
+
// Has unix timestamp of boot time
|
54 |
+
'kern.boottime',
|
55 |
+
|
56 |
+
// Ram stuff
|
57 |
+
'hw.physmem',
|
58 |
+
|
59 |
+
// CPU related
|
60 |
+
'hw.model',
|
61 |
+
'hw.ncpu',
|
62 |
+
'hw.cpuspeed',
|
63 |
+
|
64 |
+
'vm.loadavg',
|
65 |
+
), false);
|
66 |
+
}
|
67 |
+
|
68 |
+
// What we should leave out
|
69 |
+
public function getContains()
|
70 |
+
{
|
71 |
+
return array(
|
72 |
+
'drives_rw_stats' => false,
|
73 |
+
'hw_vendor' => false,
|
74 |
+
'drives_vendor' => false,
|
75 |
+
);
|
76 |
+
}
|
77 |
+
|
78 |
+
// Get mounted file systems and their disk usage stats
|
79 |
+
public function getMounts()
|
80 |
+
{
|
81 |
+
// Time?
|
82 |
+
if (!empty($this->settings['timer'])) {
|
83 |
+
$t = new Timer('Mounted file systems');
|
84 |
+
}
|
85 |
+
|
86 |
+
// Get result of mount command
|
87 |
+
try {
|
88 |
+
$mount_res = $this->exec->exec('mount');
|
89 |
+
} catch (Exception $e) {
|
90 |
+
Errors::add('Linfo Core', 'Error running `mount` command');
|
91 |
+
|
92 |
+
return array();
|
93 |
+
}
|
94 |
+
|
95 |
+
// Match that up
|
96 |
+
if (preg_match_all('/^(\S+) on (\S+) type (\S+) \(.+\)$/m', $mount_res, $mount_matches, PREG_SET_ORDER) == 0) {
|
97 |
+
return array();
|
98 |
+
}
|
99 |
+
|
100 |
+
// Store them here
|
101 |
+
$mounts = array();
|
102 |
+
|
103 |
+
// Go through
|
104 |
+
foreach ($mount_matches as $mount) {
|
105 |
+
// Should we not show this?
|
106 |
+
if (in_array($mount[1], $this->settings['hide']['storage_devices']) || in_array($mount[3], $this->settings['hide']['filesystems'])) {
|
107 |
+
continue;
|
108 |
+
}
|
109 |
+
|
110 |
+
// Get these
|
111 |
+
$size = @disk_total_space($mount[2]);
|
112 |
+
$free = @disk_free_space($mount[2]);
|
113 |
+
$used = $size - $free;
|
114 |
+
|
115 |
+
// Might be good, go for it
|
116 |
+
$mounts[] = array(
|
117 |
+
'device' => $mount[1],
|
118 |
+
'mount' => $mount[2],
|
119 |
+
'type' => $mount[3],
|
120 |
+
'size' => $size ,
|
121 |
+
'used' => $used,
|
122 |
+
'free' => $free,
|
123 |
+
'free_percent' => ((bool) $free != false && (bool) $size != false ? round($free / $size, 2) * 100 : false),
|
124 |
+
'used_percent' => ((bool) $used != false && (bool) $size != false ? round($used / $size, 2) * 100 : false),
|
125 |
+
);
|
126 |
+
}
|
127 |
+
|
128 |
+
// Give it
|
129 |
+
return $mounts;
|
130 |
+
}
|
131 |
+
|
132 |
+
// Get memory usage statistics
|
133 |
+
public function getRam()
|
134 |
+
{
|
135 |
+
$return = array();
|
136 |
+
$return['swapTotal'] = 0;
|
137 |
+
$return['swapFree'] = 0;
|
138 |
+
$return['swapInfo'] = array();
|
139 |
+
|
140 |
+
// Get amount of real hard ram, in bytes
|
141 |
+
$return['total'] = $this->sysctl['hw.physmem'];
|
142 |
+
|
143 |
+
// Get real
|
144 |
+
try {
|
145 |
+
$vmstat = $this->exec->exec('vmstat');
|
146 |
+
if (preg_match('/\s\d\s\d\s\d\s+\d+\s+(\d+)/', $vmstat, $vmstat_match)) {
|
147 |
+
$hard_ram_free = $vmstat_match[1];
|
148 |
+
$return['type'] = 'Physical';
|
149 |
+
$return['free'] = $return['total'] - ($hard_ram_free * 1024);
|
150 |
+
}
|
151 |
+
} catch (Exception $e) {
|
152 |
+
Errors::add('Linfo Core', 'Error using `vmstat` to get memory usage usage');
|
153 |
+
}
|
154 |
+
|
155 |
+
// Get swap
|
156 |
+
try {
|
157 |
+
$swapinfo = $this->exec->exec('swapctl', '-k');
|
158 |
+
@preg_match_all('/^(\S+)\s+(\d+)\s+(\d+)\s+(\d+)/m', $swapinfo, $sm, PREG_SET_ORDER);
|
159 |
+
foreach ($sm as $swap) {
|
160 |
+
$return['swapTotal'] += $swap[2] * 1024;
|
161 |
+
$return['swapFree'] += (($swap[2] - $swap[3]) * 1024);
|
162 |
+
$ft = is_file($swap[1]) ? @filetype($swap[1]) : 'Unknown'; // TODO: I'd rather it be Partition or File
|
163 |
+
$return['swapInfo'][] = array(
|
164 |
+
'device' => $swap[1],
|
165 |
+
'size' => $swap[2] * 1024,
|
166 |
+
'used' => $swap[3] * 1024,
|
167 |
+
'type' => ucfirst($ft),
|
168 |
+
);
|
169 |
+
}
|
170 |
+
} catch (Exception $e) {
|
171 |
+
Errors::add('Linfo Core', 'Error using `swapctl` to get swap usage');
|
172 |
+
}
|
173 |
+
|
174 |
+
// Give it
|
175 |
+
return $return;
|
176 |
+
}
|
177 |
+
|
178 |
+
// Get hardware devices
|
179 |
+
public function getDevs()
|
180 |
+
{
|
181 |
+
// Time?
|
182 |
+
if (!empty($this->settings['timer'])) {
|
183 |
+
$t = new Timer('Hardware Devices');
|
184 |
+
}
|
185 |
+
|
186 |
+
// Match them
|
187 |
+
if (preg_match_all('/([a-z]+\d+) at ([a-z]+)\d*.+ "(.+)"/m', $this->dmesg, $devices_match, PREG_SET_ORDER) == 0) {
|
188 |
+
return array();
|
189 |
+
}
|
190 |
+
|
191 |
+
// Store them here
|
192 |
+
$devices = array();
|
193 |
+
|
194 |
+
// Stuff them
|
195 |
+
foreach ($devices_match as $match) {
|
196 |
+
$type = strtoupper($match[2]);
|
197 |
+
|
198 |
+
$devices[] = array(
|
199 |
+
'vendor' => false, // hmm
|
200 |
+
'device' => $match[3],
|
201 |
+
'type' => $type,
|
202 |
+
|
203 |
+
);
|
204 |
+
}
|
205 |
+
|
206 |
+
// Give them
|
207 |
+
return $devices;
|
208 |
+
}
|
209 |
+
|
210 |
+
// Get hard disk drives and the like
|
211 |
+
public function getHD()
|
212 |
+
{
|
213 |
+
|
214 |
+
// Time?
|
215 |
+
if (!empty($this->settings['timer'])) {
|
216 |
+
$t = new Timer('CPU');
|
217 |
+
}
|
218 |
+
|
219 |
+
$drives = array();
|
220 |
+
$curr_hd = false;
|
221 |
+
|
222 |
+
// Parse dmesg
|
223 |
+
foreach (explode("\n", $this->dmesg) as $dmesg_line) {
|
224 |
+
if (preg_match('/^(\w+) at .+<([^>]+)>/', $dmesg_line, $hd_start_match)) {
|
225 |
+
$curr_hd = $hd_start_match;
|
226 |
+
} elseif ($curr_hd !== false && preg_match('/^'.preg_quote($curr_hd[1]).':.*\b(\d+)MB/', $dmesg_line, $hd_spec_match)) {
|
227 |
+
$drives[] = array(
|
228 |
+
'name' => trim($curr_hd[2], ', '),
|
229 |
+
'vendor' => false,
|
230 |
+
'device' => '/dev/'.$curr_hd[1],
|
231 |
+
'size' => $hd_spec_match[1] * 1048576,
|
232 |
+
|
233 |
+
// Not sure how to get the following:
|
234 |
+
'reads' => false,
|
235 |
+
'writes' => false,
|
236 |
+
|
237 |
+
);
|
238 |
+
$curr_hd = false;
|
239 |
+
} else {
|
240 |
+
$curr_hd = false;
|
241 |
+
}
|
242 |
+
}
|
243 |
+
|
244 |
+
// give it
|
245 |
+
return $drives;
|
246 |
+
}
|
247 |
+
|
248 |
+
// Get uptime
|
249 |
+
public function getUpTime()
|
250 |
+
{
|
251 |
+
|
252 |
+
// Time?
|
253 |
+
if (!empty($this->settings['timer'])) {
|
254 |
+
$t = new Timer('Uptime');
|
255 |
+
}
|
256 |
+
|
257 |
+
// Short and sweet
|
258 |
+
$booted = $this->sysctl['kern.boottime'];
|
259 |
+
|
260 |
+
if ($booted == false) {
|
261 |
+
return 'Unknown';
|
262 |
+
}
|
263 |
+
|
264 |
+
// Is it not a timestamp?
|
265 |
+
if (!is_numeric($booted)) {
|
266 |
+
$booted = strtotime($booted);
|
267 |
+
}
|
268 |
+
|
269 |
+
// Give it
|
270 |
+
return array(
|
271 |
+
'text' => Common::secondsConvert(time() - $booted),
|
272 |
+
'bootedTimestamp' => $booted,
|
273 |
+
);
|
274 |
+
}
|
275 |
+
|
276 |
+
// Get network devices, their stats, status, and type
|
277 |
+
public function getNet()
|
278 |
+
{
|
279 |
+
|
280 |
+
// Time?
|
281 |
+
if (!empty($this->settings['timer'])) {
|
282 |
+
$t = new Timer('Network Devices');
|
283 |
+
}
|
284 |
+
|
285 |
+
// Get result of netstat command
|
286 |
+
try {
|
287 |
+
$res = $this->exec->exec('netstat', '-nbi');
|
288 |
+
} catch (Exception $e) {
|
289 |
+
Errors::add('Linfo Core', 'Error using `netstat` to get network info');
|
290 |
+
|
291 |
+
return array();
|
292 |
+
}
|
293 |
+
|
294 |
+
// Get initial matches
|
295 |
+
if (preg_match_all('/^([a-z0-9]+)\*?\s+\d+\s+<Link>(?:\s+[a-z0-9\:]+)?\s+(\d+)\s+(\d+)$/m', $res, $net_matches, PREG_SET_ORDER) == 0) {
|
296 |
+
return array();
|
297 |
+
}
|
298 |
+
|
299 |
+
// Store statuses for each here
|
300 |
+
$statuses = array();
|
301 |
+
|
302 |
+
// Try using ifconfig to get statuses for each interface
|
303 |
+
try {
|
304 |
+
$ifconfig = $this->exec->exec('ifconfig', '-a');
|
305 |
+
$current_nic = false;
|
306 |
+
foreach ((array) explode("\n", $ifconfig) as $line) {
|
307 |
+
if (preg_match('/^(\w+):/m', $line, $m) == 1) {
|
308 |
+
$current_nic = $m[1];
|
309 |
+
} elseif ($current_nic != false && preg_match('/^\s+status: ([^$]+)$/m', $line, $m) == 1) {
|
310 |
+
$statuses[$current_nic] = $m[1];
|
311 |
+
$current_nic = false;
|
312 |
+
}
|
313 |
+
}
|
314 |
+
} catch (Exception $e) {
|
315 |
+
}
|
316 |
+
|
317 |
+
// Get type from dmesg boot
|
318 |
+
$type = array();
|
319 |
+
$type_nics = array();
|
320 |
+
|
321 |
+
// Store the to-be detected nics here
|
322 |
+
foreach ($net_matches as $net) {
|
323 |
+
$type_nics[] = $net[1];
|
324 |
+
}
|
325 |
+
|
326 |
+
// Go through dmesg looking for them
|
327 |
+
if (preg_match_all('/^(\w+) at ([a-zA-Z]+)\d*.+address [\w\:]+.+/m', $this->dmesg, $type_match, PREG_SET_ORDER)) {
|
328 |
+
|
329 |
+
// Go through each
|
330 |
+
foreach ($type_match as $type_nic_match) {
|
331 |
+
|
332 |
+
// Is this one of our detected nics?
|
333 |
+
if (in_array($type_nic_match[1], $type_nics)) {
|
334 |
+
|
335 |
+
// Yes; save status
|
336 |
+
$type[$type_nic_match[1]] = $type_nic_match[2];
|
337 |
+
}
|
338 |
+
}
|
339 |
+
}
|
340 |
+
|
341 |
+
// Save them here
|
342 |
+
$nets = array();
|
343 |
+
|
344 |
+
// Go through each
|
345 |
+
foreach ($net_matches as $net) {
|
346 |
+
|
347 |
+
// See if we successfully found a status, and use it if so
|
348 |
+
switch (array_key_exists($net[1], $statuses) ? $statuses[$net[1]] : 'unknown') {
|
349 |
+
case 'active':
|
350 |
+
$state = 'up';
|
351 |
+
break;
|
352 |
+
case 'inactive':
|
353 |
+
case 'no carrier':
|
354 |
+
$state = 'down';
|
355 |
+
break;
|
356 |
+
default:
|
357 |
+
$state = 'unknown';
|
358 |
+
break;
|
359 |
+
}
|
360 |
+
|
361 |
+
// Save this interface
|
362 |
+
$nets[$net[1]] = array(
|
363 |
+
|
364 |
+
// pulled from netstat
|
365 |
+
'recieved' => array(
|
366 |
+
'bytes' => $net[2],
|
367 |
+
),
|
368 |
+
'sent' => array(
|
369 |
+
'bytes' => $net[3],
|
370 |
+
),
|
371 |
+
|
372 |
+
// pulled from ifconfig
|
373 |
+
'state' => $state,
|
374 |
+
|
375 |
+
// pulled from dmesg
|
376 |
+
'type' => array_key_exists($net[1], $type) ? strtoupper($type[$net[1]]) : 'N/A',
|
377 |
+
);
|
378 |
+
}
|
379 |
+
|
380 |
+
// Give them
|
381 |
+
return $nets;
|
382 |
+
}
|
383 |
+
|
384 |
+
// processors...
|
385 |
+
public function getCPU()
|
386 |
+
{
|
387 |
+
|
388 |
+
// Time?
|
389 |
+
if (!empty($this->settings['timer'])) {
|
390 |
+
$t = new Timer('CPUs');
|
391 |
+
}
|
392 |
+
|
393 |
+
// Store them here
|
394 |
+
$cpus = array();
|
395 |
+
|
396 |
+
// Stuff it with identical cpus
|
397 |
+
for ($i = 0; $i < $this->sysctl['hw.ncpu']; ++$i) {
|
398 |
+
|
399 |
+
// Save each
|
400 |
+
$cpus[] = array(
|
401 |
+
'Model' => $this->sysctl['hw.model'],
|
402 |
+
'MHz' => $this->sysctl['hw.cpuspeed'],
|
403 |
+
);
|
404 |
+
}
|
405 |
+
|
406 |
+
// Return
|
407 |
+
return $cpus;
|
408 |
+
}
|
409 |
+
|
410 |
+
// Get process stats
|
411 |
+
public function getProcessStats()
|
412 |
+
{
|
413 |
+
// Time?
|
414 |
+
if (!empty($this->settings['timer'])) {
|
415 |
+
$t = new Timer('Process Stats');
|
416 |
+
}
|
417 |
+
|
418 |
+
// We'll return this after stuffing it with useful info
|
419 |
+
$result = array(
|
420 |
+
'exists' => true,
|
421 |
+
'totals' => array(
|
422 |
+
'running' => 0,
|
423 |
+
'zombie' => 0,
|
424 |
+
'sleeping' => 0,
|
425 |
+
'stopped' => 0,
|
426 |
+
),
|
427 |
+
'proc_total' => 0,
|
428 |
+
'threads' => false, // I'm not sure how to get this
|
429 |
+
);
|
430 |
+
|
431 |
+
// Use ps
|
432 |
+
try {
|
433 |
+
// Get it
|
434 |
+
$ps = $this->exec->exec('ps', 'ax');
|
435 |
+
|
436 |
+
// Match them
|
437 |
+
preg_match_all('/^\s*\d+\s+[\w?]+\s+([A-Z])\S*\s+.+$/m', $ps, $processes, PREG_SET_ORDER);
|
438 |
+
|
439 |
+
// Get total
|
440 |
+
$result['proc_total'] = count($processes);
|
441 |
+
|
442 |
+
// Go through
|
443 |
+
foreach ($processes as $process) {
|
444 |
+
switch ($process[1]) {
|
445 |
+
case 'S':
|
446 |
+
case 'I':
|
447 |
+
$result['totals']['sleeping']++;
|
448 |
+
break;
|
449 |
+
case 'Z':
|
450 |
+
$result['totals']['zombie']++;
|
451 |
+
break;
|
452 |
+
case 'R':
|
453 |
+
case 'D':
|
454 |
+
case 'O':
|
455 |
+
$result['totals']['running']++;
|
456 |
+
break;
|
457 |
+
case 'T':
|
458 |
+
$result['totals']['stopped']++;
|
459 |
+
break;
|
460 |
+
}
|
461 |
+
}
|
462 |
+
} catch (Exception $e) {
|
463 |
+
Errors::add('Linfo Core', 'Error using `ps` to get process info');
|
464 |
+
}
|
465 |
+
|
466 |
+
// Give
|
467 |
+
return $result;
|
468 |
+
}
|
469 |
+
}
|
lib/Linfo/OS/SunOS.php
ADDED
@@ -0,0 +1,456 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\OS;
|
22 |
+
|
23 |
+
use Exception;
|
24 |
+
use Linfo\Meta\Timer;
|
25 |
+
use Linfo\Meta\Errors;
|
26 |
+
use Linfo\Common;
|
27 |
+
use Linfo\Parsers\CallExt;
|
28 |
+
|
29 |
+
class SunOS extends OS
|
30 |
+
{
|
31 |
+
// Encapsulate these
|
32 |
+
protected $settings,
|
33 |
+
$exec,
|
34 |
+
$kstat = array();
|
35 |
+
|
36 |
+
// Start us off
|
37 |
+
public function __construct($settings)
|
38 |
+
{
|
39 |
+
|
40 |
+
// Localize settings
|
41 |
+
$this->settings = $settings;
|
42 |
+
|
43 |
+
// External exec runnign
|
44 |
+
$this->exec = new CallExt();
|
45 |
+
|
46 |
+
// We search these folders for our commands
|
47 |
+
$this->exec->setSearchPaths(array('/sbin', '/bin', '/usr/bin', '/usr/local/bin', '/usr/sbin'));
|
48 |
+
|
49 |
+
// Used multpile times so might as well just get it once. here
|
50 |
+
$this->release = php_uname('r');
|
51 |
+
|
52 |
+
// Get multiple kstat values at once and store them here. It seems kstat is SunOS' version of BSD's sysctl
|
53 |
+
$this->loadkstat(array(
|
54 |
+
|
55 |
+
// unix time stamp of system boot
|
56 |
+
'unix:0:system_misc:boot_time',
|
57 |
+
|
58 |
+
// usual 3 system load values
|
59 |
+
'unix:0:system_misc:avenrun_1min',
|
60 |
+
'unix:0:system_misc:avenrun_5min',
|
61 |
+
'unix:0:system_misc:avenrun_15min',
|
62 |
+
|
63 |
+
// physical ram info
|
64 |
+
'unix:0:seg_cache:slab_size',
|
65 |
+
'unix:0:system_pages:pagestotal',
|
66 |
+
'unix:0:system_pages:pagesfree',
|
67 |
+
|
68 |
+
// Info on all CPUs
|
69 |
+
'cpu_info:0:',
|
70 |
+
|
71 |
+
// Network interface stats
|
72 |
+
'link:0:',
|
73 |
+
));
|
74 |
+
}
|
75 |
+
|
76 |
+
// Get kstat values. *extremely* similar in practice to the sysctl nature of the bsd's
|
77 |
+
// -
|
78 |
+
// Use kstat to get something, and cache result.
|
79 |
+
// Also allow getting multiple keys at once, in which case sysctl
|
80 |
+
// will only be called once instead of multiple times (assuming it doesn't break)
|
81 |
+
protected function loadkstat($keys)
|
82 |
+
{
|
83 |
+
|
84 |
+
// Time?
|
85 |
+
if (!empty($this->settings['timer'])) {
|
86 |
+
$t = new Timer('Solaris Kstat Parsing');
|
87 |
+
}
|
88 |
+
|
89 |
+
$results = array();
|
90 |
+
|
91 |
+
foreach ($keys as $k => $v) {
|
92 |
+
if (array_key_exists($v, $this->kstat)) {
|
93 |
+
unset($keys[$k]);
|
94 |
+
}
|
95 |
+
}
|
96 |
+
|
97 |
+
try {
|
98 |
+
$command = $this->exec->exec('kstat', ' -p '.implode(' ', array_map('escapeshellarg', $keys)));
|
99 |
+
$lines = explode("\n", $command);
|
100 |
+
} catch (Exception $e) {
|
101 |
+
Errors::add('Solaris Core', 'Failed running kstat.');
|
102 |
+
}
|
103 |
+
|
104 |
+
if (!is_array($lines)) {
|
105 |
+
return;
|
106 |
+
}
|
107 |
+
|
108 |
+
// Not very efficient as it loops over each line for every key that exists, but it is
|
109 |
+
// very effective and thorough
|
110 |
+
foreach ($keys as $key) {
|
111 |
+
foreach ($lines as $line) {
|
112 |
+
$line = trim($line);
|
113 |
+
|
114 |
+
if (strpos($line, $key) !== 0) {
|
115 |
+
continue;
|
116 |
+
}
|
117 |
+
|
118 |
+
$value = ltrim(substr($line, strlen($key)));
|
119 |
+
if (isset($results[$key])) {
|
120 |
+
$results[$key] .= "\n".$value;
|
121 |
+
} else {
|
122 |
+
$results[$key] = $value;
|
123 |
+
}
|
124 |
+
}
|
125 |
+
}
|
126 |
+
|
127 |
+
$this->kstat = array_merge($results, $this->kstat);
|
128 |
+
}
|
129 |
+
|
130 |
+
// Return OS type
|
131 |
+
public function getOS()
|
132 |
+
{
|
133 |
+
|
134 |
+
// Get SunOS version
|
135 |
+
$v = reset(explode('.', $this->release, 2));
|
136 |
+
|
137 |
+
// Stuff 4 and under is SunOS. 5 and up is Solaris
|
138 |
+
switch ($v) {
|
139 |
+
case ($v > 4):
|
140 |
+
return 'Solaris';
|
141 |
+
break;
|
142 |
+
default:
|
143 |
+
return 'SunOS';
|
144 |
+
break;
|
145 |
+
}
|
146 |
+
|
147 |
+
// What's next is determining what variant of Solaris,
|
148 |
+
// eg: opensolaris (R.I.P.), nexenta, illumos, etc
|
149 |
+
}
|
150 |
+
|
151 |
+
// Get kernel version
|
152 |
+
public function getKernel()
|
153 |
+
{
|
154 |
+
return $this->release;
|
155 |
+
}
|
156 |
+
|
157 |
+
// Mounted file systems
|
158 |
+
public function getMounts()
|
159 |
+
{
|
160 |
+
|
161 |
+
// Time?
|
162 |
+
if (!empty($this->settings['timer'])) {
|
163 |
+
$t = new Timer('Mounted file systems');
|
164 |
+
}
|
165 |
+
|
166 |
+
// Run mount command
|
167 |
+
try {
|
168 |
+
$res = $this->exec->exec('mount', '-p');
|
169 |
+
} catch (Exception $e) {
|
170 |
+
Errors::add('Linfo Core', 'Error running `mount` command');
|
171 |
+
|
172 |
+
return array();
|
173 |
+
}
|
174 |
+
|
175 |
+
// Parse it
|
176 |
+
if (!preg_match_all('/^(\S+) - (\S+) (\w+).+/m', $res, $mount_matches, PREG_SET_ORDER)) {
|
177 |
+
return array();
|
178 |
+
}
|
179 |
+
|
180 |
+
// Store them here
|
181 |
+
$mounts = array();
|
182 |
+
|
183 |
+
// Deal with each entry
|
184 |
+
foreach ($mount_matches as $mount) {
|
185 |
+
|
186 |
+
// Should we not show this?
|
187 |
+
if (in_array($mount[1], $this->settings['hide']['storage_devices']) || in_array($mount[3], $this->settings['hide']['filesystems'])) {
|
188 |
+
continue;
|
189 |
+
}
|
190 |
+
|
191 |
+
// Get these
|
192 |
+
$size = @disk_total_space($mount[2]);
|
193 |
+
$free = @disk_free_space($mount[2]);
|
194 |
+
$used = $size - $free;
|
195 |
+
|
196 |
+
// Might be good, go for it
|
197 |
+
$mounts[] = array(
|
198 |
+
'device' => $mount[1],
|
199 |
+
'mount' => $mount[2],
|
200 |
+
'type' => $mount[3],
|
201 |
+
'size' => $size ,
|
202 |
+
'used' => $used,
|
203 |
+
'free' => $free,
|
204 |
+
'free_percent' => ((bool) $free != false && (bool) $size != false ? round($free / $size, 2) * 100 : false),
|
205 |
+
'used_percent' => ((bool) $used != false && (bool) $size != false ? round($used / $size, 2) * 100 : false),
|
206 |
+
);
|
207 |
+
}
|
208 |
+
|
209 |
+
// Give it
|
210 |
+
return $mounts;
|
211 |
+
}
|
212 |
+
|
213 |
+
// Get ram stats
|
214 |
+
public function getRAM()
|
215 |
+
{
|
216 |
+
|
217 |
+
// Time?
|
218 |
+
if (!empty($this->settings['timer'])) {
|
219 |
+
$t = new Timer('Memory');
|
220 |
+
}
|
221 |
+
|
222 |
+
// Give
|
223 |
+
return array(
|
224 |
+
'type' => 'Physical',
|
225 |
+
'total' => $this->kstat['unix:0:system_pages:pagestotal'] * $this->kstat['unix:0:seg_cache:slab_size'],
|
226 |
+
'free' => $this->kstat['unix:0:system_pages:pagesfree'] * $this->kstat['unix:0:seg_cache:slab_size'],
|
227 |
+
'swapInfo' => array(),
|
228 |
+
);
|
229 |
+
}
|
230 |
+
|
231 |
+
public function getProcessStats()
|
232 |
+
{
|
233 |
+
|
234 |
+
// Time?
|
235 |
+
if (!empty($this->settings['timer'])) {
|
236 |
+
$t = new Timer('Process Stats');
|
237 |
+
}
|
238 |
+
|
239 |
+
// We'll return this after stuffing it with useful info
|
240 |
+
$result = array(
|
241 |
+
'exists' => true,
|
242 |
+
'totals' => array(
|
243 |
+
'running' => 0,
|
244 |
+
'zombie' => 0,
|
245 |
+
'sleeping' => 0,
|
246 |
+
'stopped' => 0,
|
247 |
+
'idle' => 0,
|
248 |
+
),
|
249 |
+
'proc_total' => 0,
|
250 |
+
'threads' => false, // I'm not sure how to get this
|
251 |
+
);
|
252 |
+
|
253 |
+
// Use ps
|
254 |
+
try {
|
255 |
+
// Get it
|
256 |
+
$ps = $this->exec->exec('ps', '-fe -o s');
|
257 |
+
|
258 |
+
// Go through it
|
259 |
+
foreach (explode("\n", trim($ps)) as $process) {
|
260 |
+
|
261 |
+
// Decide what this is
|
262 |
+
switch ($process) {
|
263 |
+
case 'S':
|
264 |
+
$result['totals']['sleeping']++;
|
265 |
+
break;
|
266 |
+
case 'Z':
|
267 |
+
$result['totals']['zombie']++;
|
268 |
+
break;
|
269 |
+
case 'R':
|
270 |
+
case 'O':
|
271 |
+
$result['totals']['running']++;
|
272 |
+
break;
|
273 |
+
case 'T':
|
274 |
+
$result['totals']['stopped']++;
|
275 |
+
break;
|
276 |
+
}
|
277 |
+
|
278 |
+
// Increment total
|
279 |
+
++$result['proc_total'];
|
280 |
+
}
|
281 |
+
}
|
282 |
+
|
283 |
+
// Something bad happened
|
284 |
+
catch (Exception $e) {
|
285 |
+
Errors::add('Linfo Core', 'Error using `ps` to get process info');
|
286 |
+
}
|
287 |
+
|
288 |
+
// Give
|
289 |
+
return $result;
|
290 |
+
}
|
291 |
+
|
292 |
+
// uptime
|
293 |
+
public function getUpTime()
|
294 |
+
{
|
295 |
+
$booted = $this->kstat['unix:0:system_misc:boot_time'];
|
296 |
+
|
297 |
+
return array(
|
298 |
+
'text' => Common::secondsConvert(time() - $booted),
|
299 |
+
'bootedTimestamp' => $booted,
|
300 |
+
);
|
301 |
+
}
|
302 |
+
|
303 |
+
// load
|
304 |
+
public function getLoad()
|
305 |
+
{
|
306 |
+
// Give
|
307 |
+
return array(
|
308 |
+
'now' => round($this->kstat['unix:0:system_misc:avenrun_1min'] / 256, 2),
|
309 |
+
'5min' => round($this->kstat['unix:0:system_misc:avenrun_5min'] / 256, 2),
|
310 |
+
'15min' => round($this->kstat['unix:0:system_misc:avenrun_10min'] / 256, 2),
|
311 |
+
);
|
312 |
+
}
|
313 |
+
|
314 |
+
public function getCPU()
|
315 |
+
{
|
316 |
+
$cpus = array();
|
317 |
+
|
318 |
+
foreach (explode("\n", $this->kstat['cpu_info:0:']) as $line) {
|
319 |
+
if (!preg_match('/^cpu_info(\d+):(\S+)\s+(.+)/', trim($line), $m)) {
|
320 |
+
continue;
|
321 |
+
}
|
322 |
+
if (!isset($cpus[$m[1]])) {
|
323 |
+
$cpus[$m[1]] = array();
|
324 |
+
}
|
325 |
+
|
326 |
+
$cur_cpu = &$cpus[$m[1]];
|
327 |
+
|
328 |
+
$value = trim($m[3]);
|
329 |
+
switch ($m[2]) {
|
330 |
+
case 'vendor_id':
|
331 |
+
$cur_cpu['Vendor'] = $value;
|
332 |
+
break;
|
333 |
+
|
334 |
+
case 'clock_MHz':
|
335 |
+
$cur_cpu['MHz'] = $value;
|
336 |
+
break;
|
337 |
+
|
338 |
+
case 'brand':
|
339 |
+
$cur_cpu['Model'] = $value;
|
340 |
+
break;
|
341 |
+
}
|
342 |
+
}
|
343 |
+
|
344 |
+
return $cpus;
|
345 |
+
}
|
346 |
+
|
347 |
+
public function getNet()
|
348 |
+
{
|
349 |
+
$nets = array();
|
350 |
+
|
351 |
+
// ifconfig for nics/statuses
|
352 |
+
try {
|
353 |
+
$ifconfig = $this->exec->exec('ifconfig', '-a');
|
354 |
+
} catch (Exception $e) {
|
355 |
+
Errors::add('Solaris Core', 'Failed running ifconfig -a.');
|
356 |
+
|
357 |
+
return array();
|
358 |
+
}
|
359 |
+
|
360 |
+
foreach (explode("\n", $ifconfig) as $line) {
|
361 |
+
if (!preg_match('/^([^:]+):[^<]+<([^>]+)>/', trim($line), $m)) {
|
362 |
+
continue;
|
363 |
+
}
|
364 |
+
|
365 |
+
$nic = $m[1];
|
366 |
+
$flags = explode(',', strtolower($m[2]));
|
367 |
+
|
368 |
+
if (isset($nets[$nic])) {
|
369 |
+
continue;
|
370 |
+
}
|
371 |
+
|
372 |
+
$type = null;
|
373 |
+
|
374 |
+
if (in_array('loopback', $flags)) {
|
375 |
+
$type = 'Loopback';
|
376 |
+
}
|
377 |
+
|
378 |
+
$nets[$nic] = array(
|
379 |
+
|
380 |
+
// To be filled in later
|
381 |
+
'recieved' => array(
|
382 |
+
'bytes' => null,
|
383 |
+
'packets' => null,
|
384 |
+
'errors' => null,
|
385 |
+
),
|
386 |
+
'sent' => array(
|
387 |
+
'bytes' => null,
|
388 |
+
'bytes' => null,
|
389 |
+
'errors' => null,
|
390 |
+
),
|
391 |
+
|
392 |
+
// Should find a better way of getting these
|
393 |
+
'state' => in_array('up', $flags) ? 'up' : 'Unknown',
|
394 |
+
'type' => $type,
|
395 |
+
);
|
396 |
+
}
|
397 |
+
|
398 |
+
// kstat for more stats
|
399 |
+
foreach (explode("\n", $this->kstat['link:0:']) as $line) {
|
400 |
+
if (!preg_match('/^([^:]+):(\S+)\s+(\S+)/', trim($line), $m)) {
|
401 |
+
continue;
|
402 |
+
}
|
403 |
+
|
404 |
+
list(, $nic, $key, $value) = $m;
|
405 |
+
|
406 |
+
if (!isset($nets[$nic])) {
|
407 |
+
continue;
|
408 |
+
}
|
409 |
+
|
410 |
+
$cur_nic = &$nets[$nic];
|
411 |
+
|
412 |
+
switch ($key) {
|
413 |
+
case 'ipackets64':
|
414 |
+
$cur_nic['recieved']['packets'] = $value;
|
415 |
+
break;
|
416 |
+
case 'opackets64':
|
417 |
+
$cur_nic['sent']['packets'] = $value;
|
418 |
+
break;
|
419 |
+
case 'rbytes64':
|
420 |
+
$cur_nic['recieved']['bytes'] = $value;
|
421 |
+
break;
|
422 |
+
case 'obytes64':
|
423 |
+
$cur_nic['sent']['bytes'] = $value;
|
424 |
+
break;
|
425 |
+
}
|
426 |
+
}
|
427 |
+
|
428 |
+
// dladm for more stats...
|
429 |
+
try {
|
430 |
+
$dladm = $this->exec->exec('dladm', 'show-link');
|
431 |
+
foreach (explode("\n", $dladm) as $line) {
|
432 |
+
if (!preg_match('/^(\S+)\s+(\S+)\s+\d+\s+(\S+)/', $line, $m)) {
|
433 |
+
continue;
|
434 |
+
}
|
435 |
+
|
436 |
+
if (!isset($nets[$m[1]])) {
|
437 |
+
continue;
|
438 |
+
}
|
439 |
+
|
440 |
+
if (!$nets[$m[1]]['type'] && $m[2] == 'phys') {
|
441 |
+
$nets[$m[1]]['type'] = 'Physical';
|
442 |
+
}
|
443 |
+
|
444 |
+
if (!$nets[$m[1]]['state'] || $nets[$m[1]]['state'] == 'unknown') {
|
445 |
+
$nets[$m[1]]['state'] = $m[3];
|
446 |
+
}
|
447 |
+
}
|
448 |
+
} catch (Exception $e) {
|
449 |
+
Errors::add('Solaris Core', 'Failed running dladm show-link.');
|
450 |
+
|
451 |
+
return array();
|
452 |
+
}
|
453 |
+
|
454 |
+
return $nets;
|
455 |
+
}
|
456 |
+
}
|
lib/Linfo/OS/Unixcommon.php
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file is part of Linfo (c) 2014 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*/
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Keep out hackers...
|
22 |
+
*/
|
23 |
+
namespace Linfo\OS;
|
24 |
+
|
25 |
+
use Linfo\Common;
|
26 |
+
|
27 |
+
/*
|
28 |
+
* The Unix os's are largely similar and thus draw from this class.
|
29 |
+
*/
|
30 |
+
abstract class Unixcommon extends OS
|
31 |
+
{
|
32 |
+
public function ensureFQDN($hostname)
|
33 |
+
{
|
34 |
+
$parts = explode('.', $hostname);
|
35 |
+
$num_parts = count($parts);
|
36 |
+
|
37 |
+
// Already FQDN, like a boss..
|
38 |
+
if ($num_parts >= 2) {
|
39 |
+
return $hostname;
|
40 |
+
}
|
41 |
+
|
42 |
+
// Don't bother trying to expand on .local
|
43 |
+
if ($num_parts > 0 && $parts[$num_parts - 1] == '.local') {
|
44 |
+
return $hostname;
|
45 |
+
}
|
46 |
+
|
47 |
+
// This relies on reading /etc/hosts.
|
48 |
+
if (!($contents = Common::getContents('/etc/hosts', false))) {
|
49 |
+
return $hostname;
|
50 |
+
}
|
51 |
+
|
52 |
+
preg_match_all('/^[^\s#]+\s+(.+)/m', $contents, $matches, PREG_SET_ORDER);
|
53 |
+
|
54 |
+
// Lets see if we can do some magic with /etc/hosts..
|
55 |
+
foreach ($matches as $match) {
|
56 |
+
if (!preg_match_all('/(\S+)/', $match[1], $hosts, PREG_SET_ORDER)) {
|
57 |
+
continue;
|
58 |
+
}
|
59 |
+
|
60 |
+
foreach ($hosts as $host) {
|
61 |
+
|
62 |
+
// I don't want to expand on localhost as it's pointlesss
|
63 |
+
if (strpos('localhost', $host[1]) !== false) {
|
64 |
+
continue;
|
65 |
+
}
|
66 |
+
|
67 |
+
$entry_parts = explode('.', $host[1]);
|
68 |
+
if (count($entry_parts) > 1 && $entry_parts[0] == $hostname) {
|
69 |
+
return $host[1];
|
70 |
+
}
|
71 |
+
}
|
72 |
+
}
|
73 |
+
|
74 |
+
// Couldn't make it better :/
|
75 |
+
return $hostname;
|
76 |
+
}
|
77 |
+
}
|
lib/Linfo/OS/Windows.php
ADDED
@@ -0,0 +1,769 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\OS;
|
22 |
+
|
23 |
+
use Linfo\Meta\Timer;
|
24 |
+
use Linfo\Common;
|
25 |
+
use Linfo\Exceptions\FatalException;
|
26 |
+
use COM;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Get info on Windows systems
|
30 |
+
* Written and maintained by Oliver Kuckertz (mologie).
|
31 |
+
*/
|
32 |
+
class Windows extends OS
|
33 |
+
{
|
34 |
+
// Keep these tucked away
|
35 |
+
protected $settings;
|
36 |
+
|
37 |
+
private $wmi, $windows_version;
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Constructor. Localizes settings.
|
41 |
+
*
|
42 |
+
* @param array $settings of linfo settings
|
43 |
+
* @throws FatalException
|
44 |
+
*/
|
45 |
+
public function __construct($settings)
|
46 |
+
{
|
47 |
+
|
48 |
+
// Localize settings
|
49 |
+
$this->settings = $settings;
|
50 |
+
|
51 |
+
// Get WMI instance
|
52 |
+
$this->wmi = new COM('winmgmts:{impersonationLevel=impersonate}//./root/cimv2');
|
53 |
+
|
54 |
+
if (!is_object($this->wmi)) {
|
55 |
+
throw new FatalException('This needs access to WMI. Please enable DCOM in php.ini and allow the current user to access the WMI DCOM object.');
|
56 |
+
}
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Return a list of things to hide from view..
|
61 |
+
*
|
62 |
+
* @return array
|
63 |
+
*/
|
64 |
+
public function getContains()
|
65 |
+
{
|
66 |
+
return array(
|
67 |
+
'drives_rw_stats' => false,
|
68 |
+
'nic_port_speed' => false,
|
69 |
+
);
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* getOS.
|
74 |
+
*
|
75 |
+
* @return string current windows version
|
76 |
+
*/
|
77 |
+
public function getOS()
|
78 |
+
{
|
79 |
+
foreach ($this->wmi->ExecQuery('SELECT Caption FROM Win32_OperatingSystem') as $os) {
|
80 |
+
return $os->Caption;
|
81 |
+
}
|
82 |
+
|
83 |
+
return 'Windows';
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* getKernel.
|
88 |
+
*
|
89 |
+
* @return string kernel version
|
90 |
+
*/
|
91 |
+
public function getKernel()
|
92 |
+
{
|
93 |
+
|
94 |
+
// Time?
|
95 |
+
if (!empty($this->settings['timer'])) {
|
96 |
+
$t = new Timer('Kernel');
|
97 |
+
}
|
98 |
+
|
99 |
+
foreach ($this->wmi->ExecQuery('SELECT WindowsVersion FROM Win32_Process WHERE Handle = 0') as $process) {
|
100 |
+
$this->windows_version = $process->WindowsVersion;
|
101 |
+
|
102 |
+
return $process->WindowsVersion;
|
103 |
+
}
|
104 |
+
|
105 |
+
return 'Unknown';
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* getHostName.
|
110 |
+
*
|
111 |
+
* @return string the host name
|
112 |
+
*/
|
113 |
+
public function getHostName()
|
114 |
+
{
|
115 |
+
|
116 |
+
// Time?
|
117 |
+
if (!empty($this->settings['timer'])) {
|
118 |
+
$t = new Timer('Hostname');
|
119 |
+
}
|
120 |
+
|
121 |
+
foreach ($this->wmi->ExecQuery('SELECT Name FROM Win32_ComputerSystem') as $cs) {
|
122 |
+
return $cs->Name;
|
123 |
+
}
|
124 |
+
|
125 |
+
return 'Unknown';
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* getRam.
|
130 |
+
*
|
131 |
+
* @return array the memory information
|
132 |
+
*/
|
133 |
+
public function getRam()
|
134 |
+
{
|
135 |
+
|
136 |
+
// Time?
|
137 |
+
if (!empty($this->settings['timer'])) {
|
138 |
+
$t = new Timer('Memory');
|
139 |
+
}
|
140 |
+
|
141 |
+
$total_memory = 0;
|
142 |
+
$free_memory = 0;
|
143 |
+
|
144 |
+
foreach ($this->wmi->ExecQuery('SELECT TotalPhysicalMemory FROM Win32_ComputerSystem') as $cs) {
|
145 |
+
$total_memory = $cs->TotalPhysicalMemory;
|
146 |
+
break;
|
147 |
+
}
|
148 |
+
|
149 |
+
foreach ($this->wmi->ExecQuery('SELECT FreePhysicalMemory FROM Win32_OperatingSystem') as $os) {
|
150 |
+
$free_memory = $os->FreePhysicalMemory;
|
151 |
+
break;
|
152 |
+
}
|
153 |
+
|
154 |
+
return array(
|
155 |
+
'type' => 'Physical',
|
156 |
+
'total' => $total_memory,
|
157 |
+
'free' => $free_memory * 1024,
|
158 |
+
);
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* getCPU.
|
163 |
+
*
|
164 |
+
* @return array of cpu info
|
165 |
+
*/
|
166 |
+
public function getCPU()
|
167 |
+
{
|
168 |
+
|
169 |
+
// Time?
|
170 |
+
if (!empty($this->settings['timer'])) {
|
171 |
+
$t = new Timer('CPUs');
|
172 |
+
}
|
173 |
+
|
174 |
+
$cpus = array();
|
175 |
+
$alt = false;
|
176 |
+
$object = $this->wmi->ExecQuery('SELECT Name, Manufacturer, CurrentClockSpeed, NumberOfLogicalProcessors,LoadPercentage FROM Win32_Processor');
|
177 |
+
|
178 |
+
if (!is_object($object)) {
|
179 |
+
$object = $this->wmi->ExecQuery('SELECT Name, Manufacturer, CurrentClockSpeed,LoadPercentage FROM Win32_Processor');
|
180 |
+
$alt = true;
|
181 |
+
}
|
182 |
+
|
183 |
+
foreach ($object as $cpu) {
|
184 |
+
$curr = array(
|
185 |
+
'Model' => $cpu->Name,
|
186 |
+
'Vendor' => $cpu->Manufacturer,
|
187 |
+
'MHz' => $cpu->CurrentClockSpeed,
|
188 |
+
);
|
189 |
+
|
190 |
+
if ($cpu->LoadPercentage != '') {
|
191 |
+
$curr['usage_percentage'] = $cpu->LoadPercentage;
|
192 |
+
}
|
193 |
+
|
194 |
+
if (!$alt) {
|
195 |
+
for ($i = 0; $i < $cpu->NumberOfLogicalProcessors; ++$i) {
|
196 |
+
$cpus[] = $curr;
|
197 |
+
}
|
198 |
+
} else {
|
199 |
+
$cpus[] = $curr;
|
200 |
+
}
|
201 |
+
}
|
202 |
+
|
203 |
+
return $cpus;
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* getUpTime.
|
208 |
+
*
|
209 |
+
* @return string uptime
|
210 |
+
*/
|
211 |
+
public function getUpTime()
|
212 |
+
{
|
213 |
+
|
214 |
+
// Time?
|
215 |
+
if (!empty($this->settings['timer'])) {
|
216 |
+
$t = new Timer('Uptime');
|
217 |
+
}
|
218 |
+
|
219 |
+
$booted_str = '';
|
220 |
+
|
221 |
+
foreach ($this->wmi->ExecQuery('SELECT LastBootUpTime FROM Win32_OperatingSystem') as $os) {
|
222 |
+
$booted_str = $os->LastBootUpTime;
|
223 |
+
break;
|
224 |
+
}
|
225 |
+
|
226 |
+
$booted = array(
|
227 |
+
'year' => substr($booted_str, 0, 4),
|
228 |
+
'month' => substr($booted_str, 4, 2),
|
229 |
+
'day' => substr($booted_str, 6, 2),
|
230 |
+
'hour' => substr($booted_str, 8, 2),
|
231 |
+
'minute' => substr($booted_str, 10, 2),
|
232 |
+
'second' => substr($booted_str, 12, 2),
|
233 |
+
);
|
234 |
+
$booted_ts = mktime($booted['hour'], $booted['minute'], $booted['second'], $booted['month'], $booted['day'], $booted['year']);
|
235 |
+
|
236 |
+
return array(
|
237 |
+
'text' => Common::secondsConvert(time() - $booted_ts),
|
238 |
+
'bootedTimestamp' => $booted_ts,
|
239 |
+
);
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* getHD.
|
244 |
+
*
|
245 |
+
* @return array the hard drive info
|
246 |
+
*/
|
247 |
+
public function getHD()
|
248 |
+
{
|
249 |
+
|
250 |
+
// Time?
|
251 |
+
if (!empty($this->settings['timer'])) {
|
252 |
+
$t = new Timer('Drives');
|
253 |
+
}
|
254 |
+
|
255 |
+
$drives = array();
|
256 |
+
$partitions = array();
|
257 |
+
|
258 |
+
foreach ($this->wmi->ExecQuery('SELECT DiskIndex, Size, DeviceID, Type FROM Win32_DiskPartition') as $partition) {
|
259 |
+
$partitions[$partition->DiskIndex][] = array(
|
260 |
+
'size' => $partition->Size,
|
261 |
+
'name' => $partition->DeviceID.' ('.$partition->Type.')',
|
262 |
+
);
|
263 |
+
}
|
264 |
+
|
265 |
+
foreach ($this->wmi->ExecQuery('SELECT Caption, DeviceID, Index, Size FROM Win32_DiskDrive') as $drive) {
|
266 |
+
$caption = explode(' ', $drive->Caption);
|
267 |
+
$drives[] = array(
|
268 |
+
'name' => $drive->Caption,
|
269 |
+
'vendor' => reset($caption),
|
270 |
+
'device' => $drive->DeviceID,
|
271 |
+
'reads' => false,
|
272 |
+
'writes' => false,
|
273 |
+
'size' => $drive->Size,
|
274 |
+
'partitions' => array_key_exists($drive->Index, $partitions) && is_array($partitions[$drive->Index]) ? $partitions[$drive->Index] : false,
|
275 |
+
);
|
276 |
+
}
|
277 |
+
|
278 |
+
usort($drives, array('Linfo\OS\Windows', 'compare_drives'));
|
279 |
+
|
280 |
+
return $drives;
|
281 |
+
}
|
282 |
+
|
283 |
+
/**
|
284 |
+
* getTemps.
|
285 |
+
*
|
286 |
+
* @return array the temps
|
287 |
+
*/
|
288 |
+
public function getTemps()
|
289 |
+
{
|
290 |
+
|
291 |
+
// Time?
|
292 |
+
if (!empty($this->settings['timer'])) {
|
293 |
+
$t = new Timer('Temperature');
|
294 |
+
}
|
295 |
+
|
296 |
+
return array(); // TODO
|
297 |
+
}
|
298 |
+
|
299 |
+
/**
|
300 |
+
* getMounts.
|
301 |
+
*
|
302 |
+
* @return array the mounted the file systems
|
303 |
+
*/
|
304 |
+
public function getMounts()
|
305 |
+
{
|
306 |
+
|
307 |
+
// Time?
|
308 |
+
if (!empty($this->settings['timer'])) {
|
309 |
+
$t = new Timer('Mounted file systems');
|
310 |
+
}
|
311 |
+
|
312 |
+
$volumes = array();
|
313 |
+
|
314 |
+
if ($this->windows_version > '6.1.0000') {
|
315 |
+
$object = $this->wmi->ExecQuery('SELECT Automount, BootVolume, Compressed, IndexingEnabled, Label, Caption, FileSystem, Capacity, FreeSpace, DriveType FROM Win32_Volume');
|
316 |
+
} else {
|
317 |
+
$object = $this->wmi->ExecQuery('SELECT Compressed, Name, FileSystem, Size, FreeSpace, DriveType FROM Win32_LogicalDisk');
|
318 |
+
}
|
319 |
+
|
320 |
+
foreach ($object as $volume) {
|
321 |
+
$options = array();
|
322 |
+
if ($this->windows_version > '6.1.0000') {
|
323 |
+
if ($volume->Automount) {
|
324 |
+
$options[] = 'automount';
|
325 |
+
}
|
326 |
+
if ($volume->BootVolume) {
|
327 |
+
$options[] = 'boot';
|
328 |
+
}
|
329 |
+
if ($volume->IndexingEnabled) {
|
330 |
+
$options[] = 'indexed';
|
331 |
+
}
|
332 |
+
}
|
333 |
+
if ($volume->Compressed) {
|
334 |
+
$options[] = 'compressed';
|
335 |
+
}
|
336 |
+
$capacity = ($this->windows_version > '6.1.0000') ? $volume->Capacity : $volume->Size;
|
337 |
+
$label = ($this->windows_version > '6.1.0000') ? $volume->Label : $volume->Name;
|
338 |
+
$mount = ($this->windows_version > '6.1.0000') ? $volume->Caption : $label.'\\';
|
339 |
+
$a = array(
|
340 |
+
'device' => false,
|
341 |
+
'label' => $label,
|
342 |
+
'devtype' => '',
|
343 |
+
'mount' => $mount,
|
344 |
+
'type' => $volume->FileSystem,
|
345 |
+
'size' => $capacity,
|
346 |
+
'used' => $capacity - $volume->FreeSpace,
|
347 |
+
'free' => $volume->FreeSpace,
|
348 |
+
'free_percent' => 0,
|
349 |
+
'used_percent' => 0,
|
350 |
+
'options' => $options,
|
351 |
+
);
|
352 |
+
|
353 |
+
switch ($volume->DriveType) {
|
354 |
+
case 2:
|
355 |
+
$a['devtype'] = 'Removable drive';
|
356 |
+
break;
|
357 |
+
case 3:
|
358 |
+
$a['devtype'] = 'Fixed drive';
|
359 |
+
break;
|
360 |
+
case 4:
|
361 |
+
$a['devtype'] = 'Remote drive';
|
362 |
+
break;
|
363 |
+
case 5:
|
364 |
+
$a['devtype'] = 'CD-ROM';
|
365 |
+
break;
|
366 |
+
case 6:
|
367 |
+
$a['devtype'] = 'RAM disk';
|
368 |
+
break;
|
369 |
+
default:
|
370 |
+
$a['devtype'] = 'Unknown';
|
371 |
+
break;
|
372 |
+
}
|
373 |
+
|
374 |
+
if ($capacity != 0) {
|
375 |
+
$a['free_percent'] = round($volume->FreeSpace / $capacity, 2) * 100;
|
376 |
+
$a['used_percent'] = round(($capacity - $volume->FreeSpace) / $capacity, 2) * 100;
|
377 |
+
}
|
378 |
+
|
379 |
+
$volumes[] = $a;
|
380 |
+
}
|
381 |
+
|
382 |
+
usort($volumes, array('Linfo\OS\Windows', 'compare_mounts'));
|
383 |
+
|
384 |
+
return $volumes;
|
385 |
+
}
|
386 |
+
|
387 |
+
/**
|
388 |
+
* getDevs.
|
389 |
+
*
|
390 |
+
* @return array of devices
|
391 |
+
*/
|
392 |
+
public function getDevs()
|
393 |
+
{
|
394 |
+
|
395 |
+
// Time?
|
396 |
+
if (!empty($this->settings['timer'])) {
|
397 |
+
$t = new Timer('Hardware Devices');
|
398 |
+
}
|
399 |
+
|
400 |
+
$devs = array();
|
401 |
+
|
402 |
+
foreach ($this->wmi->ExecQuery('SELECT DeviceID, Caption, Manufacturer FROM Win32_PnPEntity') as $pnpdev) {
|
403 |
+
$devId = explode('\\', $pnpdev->DeviceID);
|
404 |
+
$type = reset($devId);
|
405 |
+
if (($type != 'USB' && $type != 'PCI') || (empty($pnpdev->Caption) || $pnpdev->Manufacturer[0] == '(')) {
|
406 |
+
continue;
|
407 |
+
}
|
408 |
+
$manufacturer = $pnpdev->Manufacturer;
|
409 |
+
$caption = $pnpdev->Caption;
|
410 |
+
if (function_exists('iconv')) {
|
411 |
+
$manufacturer = iconv('Windows-1252', 'UTF-8//TRANSLIT', $manufacturer);
|
412 |
+
$caption = iconv('Windows-1252', 'UTF-8//TRANSLIT', $caption);
|
413 |
+
}
|
414 |
+
$devs[] = array(
|
415 |
+
'vendor' => $manufacturer,
|
416 |
+
'device' => $caption,
|
417 |
+
'type' => $type,
|
418 |
+
);
|
419 |
+
}
|
420 |
+
|
421 |
+
// Sort by 1. Type, 2. Vendor
|
422 |
+
usort($devs, array('Linfo\OS\Windows', 'compare_devices'));
|
423 |
+
|
424 |
+
return $devs;
|
425 |
+
}
|
426 |
+
|
427 |
+
/**
|
428 |
+
* getRAID.
|
429 |
+
*
|
430 |
+
* @return array of raid arrays
|
431 |
+
*/
|
432 |
+
public function getRAID()
|
433 |
+
{
|
434 |
+
|
435 |
+
// Time?
|
436 |
+
if (!empty($this->settings['timer'])) {
|
437 |
+
$t = new Timer('RAID');
|
438 |
+
}
|
439 |
+
|
440 |
+
return array();
|
441 |
+
}
|
442 |
+
|
443 |
+
/**
|
444 |
+
* getLoad.
|
445 |
+
*
|
446 |
+
* @return array of current system load values
|
447 |
+
*/
|
448 |
+
public function getLoad()
|
449 |
+
{
|
450 |
+
|
451 |
+
// Time?
|
452 |
+
if (!empty($this->settings['timer'])) {
|
453 |
+
$t = new Timer('Load Averages');
|
454 |
+
}
|
455 |
+
|
456 |
+
$load = array();
|
457 |
+
foreach ($this->wmi->ExecQuery('SELECT LoadPercentage FROM Win32_Processor') as $cpu) {
|
458 |
+
$load[] = $cpu->LoadPercentage;
|
459 |
+
}
|
460 |
+
|
461 |
+
return round(array_sum($load) / count($load), 2).'%';
|
462 |
+
}
|
463 |
+
|
464 |
+
/**
|
465 |
+
* getNet.
|
466 |
+
*
|
467 |
+
* @return array of network devices
|
468 |
+
*/
|
469 |
+
public function getNet()
|
470 |
+
{
|
471 |
+
|
472 |
+
// Time?
|
473 |
+
if (!empty($this->settings['timer'])) {
|
474 |
+
$t = new Timer('Network Devices');
|
475 |
+
}
|
476 |
+
|
477 |
+
$return = array();
|
478 |
+
$i = 0;
|
479 |
+
|
480 |
+
if ($this->windows_version > '6.1.0000') {
|
481 |
+
$object = $this->wmi->ExecQuery('SELECT AdapterType, Name, NetConnectionStatus, GUID FROM Win32_NetworkAdapter WHERE PhysicalAdapter = TRUE');
|
482 |
+
} else {
|
483 |
+
$object = $this->wmi->ExecQuery('SELECT AdapterType, Name, NetConnectionStatus FROM Win32_NetworkAdapter WHERE NetConnectionStatus != NULL');
|
484 |
+
}
|
485 |
+
|
486 |
+
foreach ($object as $net) {
|
487 |
+
// Save and get info for each
|
488 |
+
$return[$net->Name] = array(
|
489 |
+
'recieved' => array(
|
490 |
+
'bytes' => 0,
|
491 |
+
'errors' => 0,
|
492 |
+
'packets' => 0,
|
493 |
+
),
|
494 |
+
'sent' => array(
|
495 |
+
'bytes' => 0,
|
496 |
+
'errors' => 0,
|
497 |
+
'packets' => 0,
|
498 |
+
),
|
499 |
+
'state' => 0,
|
500 |
+
'type' => $net->AdapterType,
|
501 |
+
);
|
502 |
+
switch ($net->NetConnectionStatus) {
|
503 |
+
case 0:
|
504 |
+
$return[$net->Name]['state'] = 'down';
|
505 |
+
break;
|
506 |
+
case 1:
|
507 |
+
$return[$net->Name]['state'] = 'Connecting';
|
508 |
+
break;
|
509 |
+
case 2:
|
510 |
+
$return[$net->Name]['state'] = 'up';
|
511 |
+
break;
|
512 |
+
case 3:
|
513 |
+
$return[$net->Name]['state'] = 'Disconnecting';
|
514 |
+
break;
|
515 |
+
case 4:
|
516 |
+
$return[$net->Name]['state'] = 'down'; // MSDN 'Hardware not present'
|
517 |
+
break;
|
518 |
+
case 5:
|
519 |
+
$return[$net->Name]['state'] = 'Hardware disabled';
|
520 |
+
break;
|
521 |
+
case 6:
|
522 |
+
$return[$net->Name]['state'] = 'Hardware malfunction';
|
523 |
+
break;
|
524 |
+
case 7:
|
525 |
+
$return[$net->Name]['state'] = 'Media disconnected';
|
526 |
+
break;
|
527 |
+
case 8:
|
528 |
+
$return[$net->Name]['state'] = 'Authenticating';
|
529 |
+
break;
|
530 |
+
case 9:
|
531 |
+
$return[$net->Name]['state'] = 'Authentication succeeded';
|
532 |
+
break;
|
533 |
+
case 10:
|
534 |
+
$return[$net->Name]['state'] = 'Authentication failed';
|
535 |
+
break;
|
536 |
+
case 11:
|
537 |
+
$return[$net->Name]['state'] = 'Invalid address';
|
538 |
+
break;
|
539 |
+
case 12:
|
540 |
+
$return[$net->Name]['state'] = 'Credentials required';
|
541 |
+
break;
|
542 |
+
default:
|
543 |
+
$return[$net->Name]['state'] = 'unknown';
|
544 |
+
break;
|
545 |
+
}
|
546 |
+
// @Microsoft: An index would be nice here indeed.
|
547 |
+
if ($this->windows_version > '6.1.0000') {
|
548 |
+
$canonname = preg_replace('/[^A-Za-z0-9- ]/', '_', $net->Name);
|
549 |
+
$isatapname = 'isatap.'.$net->GUID;
|
550 |
+
$result = $this->wmi->ExecQuery("SELECT BytesReceivedPersec, PacketsReceivedErrors, PacketsReceivedPersec, BytesSentPersec, PacketsSentPersec FROM Win32_PerfRawData_Tcpip_NetworkInterface WHERE Name = '$canonname' OR Name = '$isatapname'");
|
551 |
+
} else {
|
552 |
+
$canonname = preg_replace('/[^A-Za-z0-9- ]/', '_', $net->Name);
|
553 |
+
$result = $this->wmi->ExecQuery("SELECT BytesReceivedPersec, PacketsReceivedErrors, PacketsReceivedPersec, BytesSentPersec, PacketsSentPersec FROM Win32_PerfRawData_Tcpip_NetworkInterface WHERE Name = '$canonname'");
|
554 |
+
}
|
555 |
+
foreach ($result as $netspeed) {
|
556 |
+
$return[$net->Name]['recieved'] = array(
|
557 |
+
'bytes' => (int) $netspeed->BytesReceivedPersec,
|
558 |
+
'errors' => (int) $netspeed->PacketsReceivedErrors,
|
559 |
+
'packets' => (int) $netspeed->PacketsReceivedPersec,
|
560 |
+
);
|
561 |
+
$return[$net->Name]['sent'] = array(
|
562 |
+
'bytes' => (int) $netspeed->BytesSentPersec,
|
563 |
+
'erros' => 0,
|
564 |
+
'packets' => (int) $netspeed->PacketsSentPersec,
|
565 |
+
);
|
566 |
+
}
|
567 |
+
++$i;
|
568 |
+
}
|
569 |
+
|
570 |
+
return $return;
|
571 |
+
}
|
572 |
+
|
573 |
+
/**
|
574 |
+
* getBattery.
|
575 |
+
*
|
576 |
+
* @return array of battery status
|
577 |
+
*/
|
578 |
+
public function getBattery()
|
579 |
+
{
|
580 |
+
|
581 |
+
// Time?
|
582 |
+
if (!empty($this->settings['timer'])) {
|
583 |
+
$t = new Timer('Batteries');
|
584 |
+
}
|
585 |
+
|
586 |
+
return array(); // TODO
|
587 |
+
}
|
588 |
+
|
589 |
+
/**
|
590 |
+
* getWifi.
|
591 |
+
*
|
592 |
+
* @return array of wifi devices
|
593 |
+
*/
|
594 |
+
public function getWifi()
|
595 |
+
{
|
596 |
+
|
597 |
+
// Time?
|
598 |
+
if (!empty($this->settings['timer'])) {
|
599 |
+
$t = new Timer('Wifi');
|
600 |
+
}
|
601 |
+
}
|
602 |
+
|
603 |
+
/**
|
604 |
+
* getSoundCards.
|
605 |
+
*
|
606 |
+
* @return array of soundcards
|
607 |
+
*/
|
608 |
+
public function getSoundCards()
|
609 |
+
{
|
610 |
+
|
611 |
+
// Time?
|
612 |
+
if (!empty($this->settings['timer'])) {
|
613 |
+
$t = new Timer('Sound cards');
|
614 |
+
}
|
615 |
+
|
616 |
+
$cards = array();
|
617 |
+
$i = 1;
|
618 |
+
|
619 |
+
foreach ($this->wmi->ExecQuery('SELECT Caption, Manufacturer FROM Win32_SoundDevice') as $card) {
|
620 |
+
$manufacturer = $card->Manufacturer;
|
621 |
+
$caption = $card->Caption;
|
622 |
+
if (function_exists('iconv')) {
|
623 |
+
$manufacturer = iconv('Windows-1252', 'UTF-8//TRANSLIT', $manufacturer);
|
624 |
+
$caption = iconv('Windows-1252', 'UTF-8//TRANSLIT', $caption);
|
625 |
+
}
|
626 |
+
$cards[] = array(
|
627 |
+
'number' => $i,
|
628 |
+
'vendor' => $manufacturer,
|
629 |
+
'card' => $caption,
|
630 |
+
);
|
631 |
+
++$i;
|
632 |
+
}
|
633 |
+
|
634 |
+
return $cards;
|
635 |
+
}
|
636 |
+
|
637 |
+
/**
|
638 |
+
* getProcessStats.
|
639 |
+
*
|
640 |
+
* @return array of process stats
|
641 |
+
*/
|
642 |
+
public function getProcessStats()
|
643 |
+
{
|
644 |
+
|
645 |
+
// Time?
|
646 |
+
if (!empty($this->settings['timer'])) {
|
647 |
+
$t = new Timer('Process Stats');
|
648 |
+
}
|
649 |
+
|
650 |
+
$result = array(
|
651 |
+
'exists' => true,
|
652 |
+
'proc_total' => 0,
|
653 |
+
'threads' => 0,
|
654 |
+
);
|
655 |
+
|
656 |
+
foreach ($this->wmi->ExecQuery('SELECT ThreadCount FROM Win32_Process') as $proc) {
|
657 |
+
$result['threads'] += (int) $proc->ThreadCount;
|
658 |
+
++$result['proc_total'];
|
659 |
+
}
|
660 |
+
|
661 |
+
return $result;
|
662 |
+
}
|
663 |
+
|
664 |
+
/**
|
665 |
+
* getServices.
|
666 |
+
*
|
667 |
+
* @return array the services
|
668 |
+
*/
|
669 |
+
public function getServices()
|
670 |
+
{
|
671 |
+
return array(); // TODO
|
672 |
+
}
|
673 |
+
|
674 |
+
/**
|
675 |
+
* getDistro.
|
676 |
+
*
|
677 |
+
* @return array the distro,version or false
|
678 |
+
*/
|
679 |
+
public function getDistro()
|
680 |
+
{
|
681 |
+
return false;
|
682 |
+
}
|
683 |
+
|
684 |
+
/**
|
685 |
+
* getCPUArchitecture.
|
686 |
+
*
|
687 |
+
* @return string the arch and bits
|
688 |
+
*/
|
689 |
+
public function getCPUArchitecture()
|
690 |
+
{
|
691 |
+
|
692 |
+
// Time?
|
693 |
+
if (!empty($this->settings['timer'])) {
|
694 |
+
$t = new Timer('CPU architecture');
|
695 |
+
}
|
696 |
+
|
697 |
+
foreach ($this->wmi->ExecQuery('SELECT Architecture FROM Win32_Processor') as $cpu) {
|
698 |
+
switch ($cpu->Architecture) {
|
699 |
+
case 0:
|
700 |
+
return 'x86';
|
701 |
+
case 1:
|
702 |
+
return 'MIPS';
|
703 |
+
case 2:
|
704 |
+
return 'Alpha';
|
705 |
+
case 3:
|
706 |
+
return 'PowerPC';
|
707 |
+
case 6:
|
708 |
+
return 'Itanium-based systems';
|
709 |
+
case 9:
|
710 |
+
return 'x64';
|
711 |
+
}
|
712 |
+
}
|
713 |
+
|
714 |
+
return 'Unknown';
|
715 |
+
}
|
716 |
+
|
717 |
+
/**
|
718 |
+
* @ignore
|
719 |
+
* @param $a
|
720 |
+
* @param $b
|
721 |
+
* @return int
|
722 |
+
*/
|
723 |
+
public static function compare_devices($a, $b)
|
724 |
+
{
|
725 |
+
if ($a['type'] == $b['type']) {
|
726 |
+
if ($a['vendor'] == $b['vendor']) {
|
727 |
+
if ($a['device'] == $b['device']) {
|
728 |
+
return 0;
|
729 |
+
}
|
730 |
+
|
731 |
+
return ($a['device'] > $b['device']) ? 1 : -1;
|
732 |
+
}
|
733 |
+
|
734 |
+
return ($a['vendor'] > $b['vendor']) ? 1 : -1;
|
735 |
+
}
|
736 |
+
|
737 |
+
return ($a['type'] > $b['type']) ? 1 : -1;
|
738 |
+
}
|
739 |
+
|
740 |
+
/**
|
741 |
+
* @ignore
|
742 |
+
* @param $a
|
743 |
+
* @param $b
|
744 |
+
* @return int
|
745 |
+
*/
|
746 |
+
public static function compare_drives($a, $b)
|
747 |
+
{
|
748 |
+
if ($a['device'] == $b['device']) {
|
749 |
+
return 0;
|
750 |
+
}
|
751 |
+
|
752 |
+
return ($a['device'] > $b['device']) ? 1 : -1;
|
753 |
+
}
|
754 |
+
|
755 |
+
/**
|
756 |
+
* @ignore
|
757 |
+
* @param $a
|
758 |
+
* @param $b
|
759 |
+
* @return int
|
760 |
+
*/
|
761 |
+
public static function compare_mounts($a, $b)
|
762 |
+
{
|
763 |
+
if ($a['mount'] == $b['mount']) {
|
764 |
+
return 0;
|
765 |
+
}
|
766 |
+
|
767 |
+
return ($a['mount'] > $b['mount']) ? 1 : -1;
|
768 |
+
}
|
769 |
+
}
|
lib/Linfo/Output/Html.php
ADDED
@@ -0,0 +1,1006 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Linfo\Output;
|
4 |
+
|
5 |
+
use Linfo\Linfo;
|
6 |
+
use Linfo\Common;
|
7 |
+
use Linfo\Meta\Errors;
|
8 |
+
use Linfo\Meta\Timer;
|
9 |
+
|
10 |
+
class Html implements Output
|
11 |
+
{
|
12 |
+
protected $linfo;
|
13 |
+
|
14 |
+
public function __construct(Linfo $linfo)
|
15 |
+
{
|
16 |
+
$this->linfo = $linfo;
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Create a progress bar looking thingy. Put into a function here
|
21 |
+
* as its being increasingly used elsewhere. TODO refactor linfo and
|
22 |
+
* stop leaving functions in global namespace.
|
23 |
+
* @param $percent
|
24 |
+
* @param bool $text
|
25 |
+
* @return string
|
26 |
+
*/
|
27 |
+
public static function generateBarChart($percent, $text = false)
|
28 |
+
{
|
29 |
+
return '
|
30 |
+
<div class="new_bar_outer">
|
31 |
+
<div class="new_bar_bg" style="width: '.$percent.'%; "></div>
|
32 |
+
<div class="new_bar_text">'.($text ?: $percent.'%').'</div>
|
33 |
+
</div>
|
34 |
+
';
|
35 |
+
}
|
36 |
+
|
37 |
+
public static function fadedText($text)
|
38 |
+
{
|
39 |
+
return '<span class="faded">'.$text.'</span>';
|
40 |
+
}
|
41 |
+
|
42 |
+
// Create a table out of an array. Mostly used by extensions
|
43 |
+
/*
|
44 |
+
Example array structure:
|
45 |
+
|
46 |
+
$structure = array(
|
47 |
+
'root_title' => 'Name',
|
48 |
+
'rows' => array(
|
49 |
+
01 = array(
|
50 |
+
'type' => 'header',
|
51 |
+
'columns' => array(
|
52 |
+
'Column 1',
|
53 |
+
'Column 2',
|
54 |
+
// OR array(colspannumber, 'value')
|
55 |
+
)
|
56 |
+
)
|
57 |
+
02 => array(
|
58 |
+
'type' => 'values',
|
59 |
+
'columns' => array(
|
60 |
+
'Value 1',
|
61 |
+
'Value 2',
|
62 |
+
// OR array(colspannumber, 'value')
|
63 |
+
)
|
64 |
+
)
|
65 |
+
)
|
66 |
+
);
|
67 |
+
*/
|
68 |
+
public static function createTable($structure)
|
69 |
+
{
|
70 |
+
|
71 |
+
// Start it off
|
72 |
+
$html = '
|
73 |
+
<div class="infoTable">
|
74 |
+
<h2>'.$structure['root_title'].'</h2>
|
75 |
+
<table>';
|
76 |
+
|
77 |
+
// Go throuch each row
|
78 |
+
foreach ($structure['rows'] as $row) {
|
79 |
+
|
80 |
+
// Let stuff be killed
|
81 |
+
$row['columns'] = array_filter($row['columns']);
|
82 |
+
|
83 |
+
// Ignore this if it's empty
|
84 |
+
if (empty($row['columns'])) {
|
85 |
+
continue;
|
86 |
+
}
|
87 |
+
|
88 |
+
// Start the typical tr
|
89 |
+
$html .= '
|
90 |
+
<tr>';
|
91 |
+
|
92 |
+
// Is this row a header?
|
93 |
+
if ($row['type'] == 'header') {
|
94 |
+
foreach ($row['columns'] as $v) {
|
95 |
+
$html .= is_array($v) ? '
|
96 |
+
<th colspan="'.$v[0].'"'.(array_key_exists('2', $v) ? ' style="width: '.$v[2].';"' : '').'>'.$v[1].'</th>' : '
|
97 |
+
<th>'.$v.'</th>';
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
// Or is it a row saying nothing was found?
|
102 |
+
elseif ($row['type'] == 'none') {
|
103 |
+
foreach ($row['columns'] as $v) {
|
104 |
+
$html .= is_array($v) ? '
|
105 |
+
<td colspan="'.$v[0].'" class="none">'.$v[1].'</td>' : '
|
106 |
+
<td class="none">'.$v.'</td>';
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
// Or is it values?
|
111 |
+
elseif ($row['type'] == 'values') {
|
112 |
+
foreach ($row['columns'] as $v) {
|
113 |
+
$html .= is_array($v) ? '
|
114 |
+
<td colspan="'.$v[0].'">'.$v[1].'</td>' : '
|
115 |
+
<td>'.$v.'</td>';
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
// End the usual tr
|
120 |
+
$html .= '
|
121 |
+
</tr>';
|
122 |
+
}
|
123 |
+
|
124 |
+
// Closing tags
|
125 |
+
$html .= '
|
126 |
+
</table>
|
127 |
+
</div>';
|
128 |
+
|
129 |
+
// Give it
|
130 |
+
return $html;
|
131 |
+
}
|
132 |
+
|
133 |
+
public function output()
|
134 |
+
{
|
135 |
+
$lang = $this->linfo->getLang();
|
136 |
+
$settings = $this->linfo->getSettings();
|
137 |
+
$info = $this->linfo->getInfo();
|
138 |
+
$appName = $this->linfo->getAppName();
|
139 |
+
$version = $this->linfo->getVersion();
|
140 |
+
|
141 |
+
// Fun icons
|
142 |
+
$show_icons = array_key_exists('icons', $settings) ? !empty($settings['icons']) : true;
|
143 |
+
$os_icon = $info['OS'] == 'Windows' ? 'windows' : strtolower(str_replace(' ', '', current(explode('(', $info['OS']))));
|
144 |
+
$distro_icon = $info['OS'] == 'Linux' && is_array($info['Distro']) && $info['Distro']['name'] ? strtolower(str_replace(' ', '', $info['Distro']['name'])) : false;
|
145 |
+
|
146 |
+
// Start compressed output buffering. Try to not do this if we've had errors or otherwise already outputted stuff
|
147 |
+
if ((!function_exists('error_get_last') || !error_get_last()) && (!isset($settings['compress_content']) || $settings['compress_content'])) {
|
148 |
+
ob_start(function_exists('ob_gzhandler') ? 'ob_gzhandler' : null);
|
149 |
+
}
|
150 |
+
|
151 |
+
// See if we have a specific theme file installed
|
152 |
+
if (isset($settings['theme']) && strpos($settings['theme'], '..') === false && file_exists('layout/theme_'.$settings['theme'].'.css')) {
|
153 |
+
$theme_css = 'theme_'.$settings['theme'].'.css';
|
154 |
+
}
|
155 |
+
|
156 |
+
// Does default exist?? Don't bitch at me for assigning an array key in an if-then
|
157 |
+
elseif (($settings['theme'] = 'default') && file_exists('layout/theme_'.$settings['theme'].'.css')) {
|
158 |
+
$theme_css = 'theme_'.$settings['theme'].'.css';
|
159 |
+
}
|
160 |
+
|
161 |
+
// if not, do the old way
|
162 |
+
else {
|
163 |
+
$theme_css = 'styles.css';
|
164 |
+
}
|
165 |
+
|
166 |
+
// Proceed to letting it all out
|
167 |
+
echo '<!DOCTYPE html>
|
168 |
+
<html>
|
169 |
+
<head>
|
170 |
+
<meta charset="UTF-8">
|
171 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
172 |
+
<title>'.$appName.' - '.$info['HostName'].'</title>
|
173 |
+
<link href="./layout/favicon.ico" type="image/x-icon" rel="shortcut icon">
|
174 |
+
<link href="./layout/'.$theme_css.'" rel="stylesheet">'.($show_icons ? '
|
175 |
+
<link href="./layout/icons.css" rel="stylesheet">' : ''
|
176 |
+
).'
|
177 |
+
<script src="./layout/scripts.min.js"></script>
|
178 |
+
<meta name="generator" content="'.$appName.' ('.$version.')">
|
179 |
+
<meta name="author" content="Joseph Gillotti & friends">
|
180 |
+
<!--[if lt IE 8]>
|
181 |
+
<link href="./layout/old_ie.css" type="text/css" rel="stylesheet">
|
182 |
+
<![endif]-->
|
183 |
+
<link rel="stylesheet" type="text/css" href="./layout/mobile.css" media="screen and (max-width: 640px)">
|
184 |
+
</head>
|
185 |
+
<body id="info">
|
186 |
+
<div id="header">
|
187 |
+
<h1>'.$info['HostName'].'</h1>
|
188 |
+
<div class="subtitle">'.$lang['header'].'</div>
|
189 |
+
</div>
|
190 |
+
<div class="col2">
|
191 |
+
<div class="col">
|
192 |
+
<div class="infoTable">
|
193 |
+
<h2>'.$lang['core'].'</h2>
|
194 |
+
<table>';
|
195 |
+
|
196 |
+
// Linfo Core. Decide what to show.
|
197 |
+
$core = array();
|
198 |
+
|
199 |
+
// OS? (with icon, if we have it)
|
200 |
+
if (!empty($settings['show']['os'])) {
|
201 |
+
$core[] = array($lang['os'], ($show_icons && (file_exists($this->linfo->getLocalDir().'layout/icons/os_'.$os_icon.'.gif') || file_exists($this->linfo->getLocalDir().'layout/icons/os_'.$os_icon.'.png')) ? '<span class="icon icon_os_'.$os_icon.'"></span>' : '').$info['OS']);
|
202 |
+
}
|
203 |
+
|
204 |
+
// Distribution? (with icon, if we have it)
|
205 |
+
if (!empty($settings['show']['distro']) && array_key_exists('Distro', $info) && is_array($info['Distro'])) {
|
206 |
+
$core[] = array($lang['distro'], ($show_icons && $distro_icon && (file_exists($this->linfo->getLocalDir().'layout/icons/distro_'.$distro_icon.'.gif') || file_exists($this->linfo->getLocalDir().'layout/icons/distro_'.$distro_icon.'.png')) ? '<span class="icon icon_distro_'.$distro_icon.'"></span>' : '').$info['Distro']['name'].($info['Distro']['version'] ? ' - '.$info['Distro']['version'] : ''));
|
207 |
+
}
|
208 |
+
|
209 |
+
// Virtualization
|
210 |
+
if (!empty($settings['show']['virtualization']) && isset($info['virtualization']) && !empty($info['virtualization'])) {
|
211 |
+
$vmval = false;
|
212 |
+
|
213 |
+
if ($info['virtualization']['type'] == 'guest') {
|
214 |
+
$vmval = '<span class="icon icon_vm_'.str_replace('/', '_', strtolower($info['virtualization']['method'])).'"></span>'.$info['virtualization']['method'].' '.$lang['guest'];
|
215 |
+
} elseif ($info['virtualization']['type'] == 'host') {
|
216 |
+
$vmval = '<span class="icon icon_vm_'.str_replace('/', '_', strtolower($info['virtualization']['method'])).'"></span>'.$info['virtualization']['method'].' '.$lang['host'];
|
217 |
+
}
|
218 |
+
|
219 |
+
if ($vmval) {
|
220 |
+
$core[] = array($lang['virtualization'], $vmval);
|
221 |
+
}
|
222 |
+
}
|
223 |
+
|
224 |
+
// Kernel
|
225 |
+
if (!empty($settings['show']['kernel'])) {
|
226 |
+
$core[] = array($lang['kernel'], $info['Kernel']);
|
227 |
+
}
|
228 |
+
|
229 |
+
// Model?
|
230 |
+
if (!empty($settings['show']['model']) && array_key_exists('Model', $info) && !empty($info['Model'])) {
|
231 |
+
$core[] = array($lang['model'], $info['Model']);
|
232 |
+
}
|
233 |
+
|
234 |
+
// IP
|
235 |
+
if (!isset($settings['show']['ip']) || !empty($settings['show']['ip'])) {
|
236 |
+
$core[] = array($lang['accessed_ip'], $info['AccessedIP']);
|
237 |
+
}
|
238 |
+
|
239 |
+
// Uptime
|
240 |
+
if (!empty($settings['show']['uptime']) && $info['UpTime']) {
|
241 |
+
$core[] = array($lang['uptime'],
|
242 |
+
$info['UpTime']['text'].
|
243 |
+
(isset($info['UpTime']['bootedTimestamp']) && $info['UpTime']['bootedTimestamp'] ? '; booted '.date($settings['dates'], $info['UpTime']['bootedTimestamp']) : ''), );
|
244 |
+
}
|
245 |
+
|
246 |
+
// Hostname
|
247 |
+
if (!empty($settings['show']['hostname'])) {
|
248 |
+
$core[] = array($lang['hostname'], $info['HostName']);
|
249 |
+
}
|
250 |
+
|
251 |
+
//Web server
|
252 |
+
if (!empty($settings['show']['webservice'])) {
|
253 |
+
$core[] = array($lang['webservice'], $info['webService']);
|
254 |
+
}
|
255 |
+
|
256 |
+
//Php version
|
257 |
+
if (!empty($settings['show']['phpversion'])) {
|
258 |
+
$core[] = array($lang['phpversion'], $info['phpVersion']);
|
259 |
+
}
|
260 |
+
|
261 |
+
// The CPUs
|
262 |
+
if (!empty($settings['show']['cpu'])) {
|
263 |
+
$cpus = array();
|
264 |
+
|
265 |
+
foreach ((array) $info['CPU'] as $cpu) {
|
266 |
+
$cpu_html =
|
267 |
+
(array_key_exists('Vendor', $cpu) && !empty($cpu['Vendor']) ? $cpu['Vendor'].' - ' : '').
|
268 |
+
$cpu['Model'].
|
269 |
+
(array_key_exists('MHz', $cpu) ?
|
270 |
+
($cpu['MHz'] < 1000 ? ' ('.$cpu['MHz'].' MHz)' : ' ('.round($cpu['MHz'] / 1000, 3).' GHz)') : '').
|
271 |
+
(array_key_exists('usage_percentage', $cpu) ? ' ('.$cpu['usage_percentage'].'%)' : '');
|
272 |
+
|
273 |
+
if (array_key_exists('usage_percentage', $cpu)) {
|
274 |
+
$cpu_html = '<div class="new_bar_left" style="margin-top: 3px; margin-bottom: 3px;">'.self::generateBarChart($cpu['usage_percentage'], $cpu_html).'</div>';
|
275 |
+
} else {
|
276 |
+
$cpu_html .= '<br>';
|
277 |
+
}
|
278 |
+
|
279 |
+
$cpus[] = $cpu_html;
|
280 |
+
}
|
281 |
+
$core[] = array('CPUs ('.count($info['CPU']).')', implode('', $cpus));
|
282 |
+
}
|
283 |
+
|
284 |
+
// CPU Usage?
|
285 |
+
if (!empty($settings['cpu_usage']) && isset($info['cpuUsage']) && $info['cpuUsage'] !== false) {
|
286 |
+
$core[] = array($lang['cpu_usage'],self::generateBarChart($info['cpuUsage']));
|
287 |
+
}
|
288 |
+
|
289 |
+
// System Load
|
290 |
+
if (!empty($settings['show']['load'])) {
|
291 |
+
$core[] = array($lang['load'],implode(' ', (array) $info['Load']));
|
292 |
+
}
|
293 |
+
|
294 |
+
// CPU architecture. Permissions goes hand in hand with normal CPU
|
295 |
+
if (!empty($settings['show']['cpu']) && array_key_exists('CPUArchitecture', $info)) {
|
296 |
+
$core[] = array($lang['cpu_arch'], $info['CPUArchitecture']);
|
297 |
+
}
|
298 |
+
|
299 |
+
// We very well may not have process stats
|
300 |
+
if (!empty($settings['show']['process_stats']) && $info['processStats']['exists']) {
|
301 |
+
|
302 |
+
// Different os' have different keys of info
|
303 |
+
$proc_stats = array();
|
304 |
+
|
305 |
+
// Load the keys
|
306 |
+
if (array_key_exists('totals', $info['processStats']) && is_array($info['processStats']['totals'])) {
|
307 |
+
foreach ($info['processStats']['totals'] as $k => $v) {
|
308 |
+
$proc_stats[] = $k.': '.number_format($v);
|
309 |
+
}
|
310 |
+
}
|
311 |
+
|
312 |
+
// Total as well
|
313 |
+
$proc_stats[] = 'total: '.number_format($info['processStats']['proc_total']);
|
314 |
+
|
315 |
+
// Show them
|
316 |
+
$core[] = array($lang['processes'], implode('; ', $proc_stats));
|
317 |
+
|
318 |
+
// We might not have threads
|
319 |
+
if ($info['processStats']['threads'] !== false) {
|
320 |
+
$core[] = array($lang['threads'], number_format($info['processStats']['threads']));
|
321 |
+
}
|
322 |
+
}
|
323 |
+
|
324 |
+
// Users with active shells
|
325 |
+
if (!empty($settings['show']['numLoggedIn']) && array_key_exists('numLoggedIn', $info) && $info['numLoggedIn']) {
|
326 |
+
$core[] = array($lang['numLoggedIn'], $info['numLoggedIn']);
|
327 |
+
}
|
328 |
+
|
329 |
+
// Show
|
330 |
+
foreach ($core as $val) {
|
331 |
+
echo '
|
332 |
+
<tr>
|
333 |
+
<th>'.$val[0].'</th>
|
334 |
+
<td>'.$val[1].'</td>
|
335 |
+
</tr>
|
336 |
+
';
|
337 |
+
}
|
338 |
+
|
339 |
+
echo '
|
340 |
+
</table>
|
341 |
+
</div>';
|
342 |
+
|
343 |
+
// Show memory?
|
344 |
+
if (!empty($settings['show']['ram'])) {
|
345 |
+
echo '
|
346 |
+
<div class="infoTable">
|
347 |
+
<h2>'.$lang['memory'].'</h2>
|
348 |
+
<table>
|
349 |
+
<colgroup>
|
350 |
+
<col style="width: 12%;" />
|
351 |
+
<col style="width: 23%;" />
|
352 |
+
<col style="width: 23%;" />
|
353 |
+
<col style="width: 23%;" />
|
354 |
+
<col style="width: 23%;" />
|
355 |
+
</colgroup>
|
356 |
+
<tr>
|
357 |
+
<th>'.$lang['type'].'</th>
|
358 |
+
<th>'.$lang['size'].'</th>
|
359 |
+
<th>'.$lang['used'].'</th>
|
360 |
+
<th>'.$lang['free'].'</th>
|
361 |
+
<th>'.$lang['percent_used'].'</th>
|
362 |
+
</tr>
|
363 |
+
<tr>
|
364 |
+
<td>'.$info['RAM']['type'].'</td>
|
365 |
+
<td>'.Common::byteConvert($info['RAM']['total']).'</td>
|
366 |
+
<td>'.Common::byteConvert($info['RAM']['total'] - $info['RAM']['free']).'</td>
|
367 |
+
<td>'.Common::byteConvert($info['RAM']['free']).'</td>
|
368 |
+
<td>'.self::generateBarChart(round(($info['RAM']['total'] - $info['RAM']['free']) * 100 / $info['RAM']['total'])).'</td>
|
369 |
+
</tr>';
|
370 |
+
$have_swap = (isset($info['RAM']['swapFree']) || isset($info['RAM']['swapTotal']));
|
371 |
+
if ($have_swap && !empty($info['RAM']['swapTotal'])) {
|
372 |
+
// Show detailed swap info?
|
373 |
+
$show_detailed_swap = is_array($info['RAM']['swapInfo']) && count($info['RAM']['swapInfo']) > 0;
|
374 |
+
echo'
|
375 |
+
<tr>
|
376 |
+
<td'.($show_detailed_swap ? ' rowspan="2"' : '').'>Swap</td>
|
377 |
+
<td>'.Common::byteConvert(@$info['RAM']['swapTotal']).'</td>
|
378 |
+
<td>'.Common::byteConvert(@$info['RAM']['swapTotal'] - $info['RAM']['swapFree']).'</td>
|
379 |
+
<td>'.Common::byteConvert(@$info['RAM']['swapFree']).'</td>
|
380 |
+
<td>'.self::generateBarChart(round(($info['RAM']['swapTotal'] - $info['RAM']['swapFree']) * 100 / $info['RAM']['swapTotal'])).'</td>
|
381 |
+
</tr>';
|
382 |
+
|
383 |
+
// As in we have at least one swap device present. Show them.
|
384 |
+
if ($show_detailed_swap) {
|
385 |
+
echo '
|
386 |
+
<tr>
|
387 |
+
<td colspan="4">
|
388 |
+
<table class="mini center">
|
389 |
+
<colgroup>
|
390 |
+
<col style="width: 25%;" />
|
391 |
+
<col style="width: 25%;" />
|
392 |
+
<col style="width: 25%;" />
|
393 |
+
<col style="width: 25%;" />
|
394 |
+
</colgroup>
|
395 |
+
<tr>
|
396 |
+
<th>'.$lang['device'].'</th>
|
397 |
+
<th>'.$lang['type'].'</th>
|
398 |
+
<th>'.$lang['size'].'</th>
|
399 |
+
<th>'.$lang['used'].'</th>
|
400 |
+
</tr>';
|
401 |
+
foreach ($info['RAM']['swapInfo'] as $swap) {
|
402 |
+
echo '
|
403 |
+
<tr>
|
404 |
+
<td>'.$swap['device'].'</td>
|
405 |
+
<td>'.ucfirst($swap['type']).'</td>
|
406 |
+
<td>'.Common::byteConvert($swap['size']).'</td>
|
407 |
+
<td>'.Common::byteConvert($swap['used']).'</td>
|
408 |
+
</tr>
|
409 |
+
';
|
410 |
+
}
|
411 |
+
echo '
|
412 |
+
</table>
|
413 |
+
</td>
|
414 |
+
</tr>';
|
415 |
+
}
|
416 |
+
}
|
417 |
+
|
418 |
+
echo '
|
419 |
+
</table>
|
420 |
+
</div>';
|
421 |
+
}
|
422 |
+
|
423 |
+
// Network Devices?
|
424 |
+
if (!empty($settings['show']['network'])) {
|
425 |
+
$show_type = array_key_exists('nic_type', $info['contains']) ? $info['contains']['nic_type'] : true;
|
426 |
+
$show_speed = array_key_exists('nic_port_speed', $info['contains']) ? $info['contains']['nic_port_speed'] : true;
|
427 |
+
echo '
|
428 |
+
<div class="infoTable network_devices">
|
429 |
+
<h2>'.$lang['network_devices'].'</h2>
|
430 |
+
<table>
|
431 |
+
<tr>
|
432 |
+
<th>'.$lang['device_name'].'</th>'.($show_type ? '
|
433 |
+
<th>'.$lang['type'].'</th>' : '').($show_speed ? '
|
434 |
+
<th>'.$lang['port_speed'].'</th>' : '').'
|
435 |
+
<th>'.$lang['amount_sent'].'</th>
|
436 |
+
<th>'.$lang['amount_received'].'</th>
|
437 |
+
<th>'.$lang['state'].'</th>
|
438 |
+
</tr>';
|
439 |
+
|
440 |
+
if (count($info['Network Devices']) > 0) {
|
441 |
+
foreach ($info['Network Devices'] as $device => $stats) {
|
442 |
+
echo '
|
443 |
+
<tr>
|
444 |
+
<td>'.$device.'</td>'.($show_type ? '
|
445 |
+
<td>'.$stats['type'].'</td>' : '').($show_speed ? '
|
446 |
+
<td>'.(isset($stats['port_speed']) && $stats['port_speed'] !== false ? $stats['port_speed'].'Mb/s' : '').'</td>' : '').'
|
447 |
+
<td>'.Common::byteConvert($stats['sent']['bytes']).'</td>
|
448 |
+
<td>'.Common::byteConvert($stats['recieved']['bytes']).'</td>
|
449 |
+
<td class="net_'.$stats['state'].'">'.ucfirst($stats['state']).'</td>
|
450 |
+
</tr>';
|
451 |
+
}
|
452 |
+
} else {
|
453 |
+
echo '<tr><td colspan="5" class="none">'.$lang['none_found'].'</td></tr>';
|
454 |
+
}
|
455 |
+
echo '
|
456 |
+
</table>
|
457 |
+
</div>';
|
458 |
+
}
|
459 |
+
|
460 |
+
// Show temps?
|
461 |
+
if (!empty($settings['show']['temps']) && count($info['Temps']) > 0) {
|
462 |
+
echo '
|
463 |
+
<div class="infoTable">
|
464 |
+
<h2>'.$lang['temps_voltages'].'</h2>
|
465 |
+
<table>
|
466 |
+
<tr><th>'.$lang['path'].'</th><th>'.$lang['device'].'</th><th>'.$lang['value'].'</th></tr>
|
467 |
+
';
|
468 |
+
if (count($info['Temps']) > 0) {
|
469 |
+
foreach ($info['Temps'] as $stat) {
|
470 |
+
echo '
|
471 |
+
<tr>
|
472 |
+
<td>'.$stat['path'].'</td>
|
473 |
+
<td>'.$stat['name'].'</td>
|
474 |
+
<td>'.(
|
475 |
+
array_key_exists('bar', $stat) && $stat['bar'] && $stat['unit'] == '%' ?
|
476 |
+
'<div class="bar_chart">
|
477 |
+
<div class="bar_inner" style="width: '.$stat['temp'].'%;">
|
478 |
+
<div class="bar_text">
|
479 |
+
'.($stat['temp'] > -1 ? $stat['temp'] : '?').'%
|
480 |
+
</div>
|
481 |
+
</div>
|
482 |
+
</div>
|
483 |
+
':
|
484 |
+
$stat['temp'].' '.$stat['unit']).'</td>
|
485 |
+
</tr>
|
486 |
+
';
|
487 |
+
}
|
488 |
+
} else {
|
489 |
+
echo '<tr><td colspan="3" class="none">'.$lang['none_found'].'</td></tr>';
|
490 |
+
}
|
491 |
+
echo '
|
492 |
+
</table>
|
493 |
+
</div>';
|
494 |
+
}
|
495 |
+
|
496 |
+
// Show battery?
|
497 |
+
if (!empty($settings['show']['battery']) && count($info['Battery']) > 0) {
|
498 |
+
echo '
|
499 |
+
<div class="infoTable">
|
500 |
+
<h2>'.$lang['batteries'].'</h2>
|
501 |
+
<table>
|
502 |
+
<tr>
|
503 |
+
<th>'.$lang['device'].'</th>
|
504 |
+
<th>'.$lang['state'].'</th>
|
505 |
+
<th>'.$lang['charge'].' %</th>
|
506 |
+
</tr>
|
507 |
+
';
|
508 |
+
foreach ($info['Battery'] as $bat) {
|
509 |
+
echo '
|
510 |
+
<tr>
|
511 |
+
<td>'.$bat['device'].'</td>
|
512 |
+
<td>'.$bat['state'].'</td>
|
513 |
+
<td>'.self::generateBarChart((int) $bat['percentage'], $bat['percentage'] > -1 ? $bat['percentage'].'%' : 'N/A').'</td>
|
514 |
+
</tr>
|
515 |
+
';
|
516 |
+
}
|
517 |
+
echo '
|
518 |
+
</table>
|
519 |
+
</div>';
|
520 |
+
}
|
521 |
+
|
522 |
+
// Show services?
|
523 |
+
if (!empty($settings['show']['services']) && count($info['services']) > 0) {
|
524 |
+
echo '
|
525 |
+
<div class="infoTable">
|
526 |
+
<h2>'.$lang['services'].'</h2>
|
527 |
+
<table>
|
528 |
+
<tr>
|
529 |
+
<th>'.$lang['service'].'</th>
|
530 |
+
<th>'.$lang['state'].'</th>
|
531 |
+
<th>'.$lang['pid'].'</th>
|
532 |
+
<th>Threads</th>
|
533 |
+
<th>'.$lang['memory_usage'].'</th>
|
534 |
+
</tr>
|
535 |
+
';
|
536 |
+
|
537 |
+
// Show them
|
538 |
+
foreach ($info['services'] as $service => $state) {
|
539 |
+
$state_parts = explode(' ', $state['state'], 2);
|
540 |
+
echo '
|
541 |
+
<tr>
|
542 |
+
<td>'.$service.'</td>
|
543 |
+
<td>
|
544 |
+
<span class="service_'.strtolower($state_parts[0]).'">'.$state_parts[0].'</span>
|
545 |
+
'.(array_key_exists(1, $state_parts) ? self::fadedText($state_parts[1]).'</span>' : '').'</td>
|
546 |
+
<td>'.$state['pid'].'</td>
|
547 |
+
<td>',$state['threads'] ? $state['threads'] : '?','</td>
|
548 |
+
<td>',$state['memory_usage'] ? Common::byteConvert($state['memory_usage']) : '?','</td>
|
549 |
+
</tr>
|
550 |
+
';
|
551 |
+
}
|
552 |
+
|
553 |
+
echo '
|
554 |
+
</table>
|
555 |
+
</div>';
|
556 |
+
}
|
557 |
+
|
558 |
+
echo '
|
559 |
+
</div>
|
560 |
+
<div class="col">';
|
561 |
+
|
562 |
+
// Show hardware?
|
563 |
+
if (!empty($settings['show']['devices'])) {
|
564 |
+
|
565 |
+
// Don't show vendor?
|
566 |
+
$show_vendor = array_key_exists('hw_vendor', $info['contains']) ? ($info['contains']['hw_vendor'] === false ? false : true) : true;
|
567 |
+
|
568 |
+
echo '
|
569 |
+
<div class="infoTable">
|
570 |
+
<h2>'.$lang['hardware'].'</h2>
|
571 |
+
<table>
|
572 |
+
<tr>
|
573 |
+
<th>'.$lang['type'].'</th>
|
574 |
+
',($show_vendor ? '<th>'.$lang['vendor'].'</th>' : ''),'
|
575 |
+
<th>'.$lang['device'].'</th>
|
576 |
+
</tr>
|
577 |
+
';
|
578 |
+
$num_devs = count($info['Devices']);
|
579 |
+
if ($num_devs > 0) {
|
580 |
+
for ($i = 0; $i < $num_devs; ++$i) {
|
581 |
+
echo '
|
582 |
+
<tr>
|
583 |
+
<td class="center">'.$info['Devices'][$i]['type'].'</td>
|
584 |
+
',$show_vendor ? '<td>'.($info['Devices'][$i]['vendor'] ? $info['Devices'][$i]['vendor'] : 'Unknown').'</td>' : '','
|
585 |
+
<td>'.$info['Devices'][$i]['device'].'</td>
|
586 |
+
</tr>';
|
587 |
+
}
|
588 |
+
} else {
|
589 |
+
echo '<tr><td colspan="3" class="none">'.$lang['none_found'].'</td></tr>';
|
590 |
+
}
|
591 |
+
echo '
|
592 |
+
</table>
|
593 |
+
</div>';
|
594 |
+
}
|
595 |
+
|
596 |
+
// Show drives?
|
597 |
+
if (!empty($settings['show']['hd'])) {
|
598 |
+
|
599 |
+
// Should we not show the Reads and Writes columns?
|
600 |
+
$show_stats = array_key_exists('drives_rw_stats', $info['contains']) ? ($info['contains']['drives_rw_stats'] === false ? false : true) : true;
|
601 |
+
|
602 |
+
// Or vendor columns?
|
603 |
+
$show_vendor = array_key_exists('drives_vendor', $info['contains']) ? ($info['contains']['drives_vendor'] === false ? false : true) : true;
|
604 |
+
|
605 |
+
echo '
|
606 |
+
<div class="infoTable">
|
607 |
+
<h2>'.$lang['drives'].'</h2>
|
608 |
+
<table>
|
609 |
+
<tr>
|
610 |
+
<th>'.$lang['path'].'</th>
|
611 |
+
',$show_vendor ? '<th>'.$lang['vendor'] : '','</th>
|
612 |
+
<th>'.$lang['name'].'</th>
|
613 |
+
',$show_stats ? '<th>'.$lang['reads'].'</th>
|
614 |
+
<th>'.$lang['writes'].'</th>' : '','
|
615 |
+
<th>'.$lang['size'].'</th>
|
616 |
+
</tr>';
|
617 |
+
if (count($info['HD']) > 0) {
|
618 |
+
foreach ($info['HD'] as $drive) {
|
619 |
+
echo '
|
620 |
+
<tr>
|
621 |
+
<td>'.$drive['device'].'</td>
|
622 |
+
',$show_vendor ? '<td>'.($drive['vendor'] ? $drive['vendor'] : $lang['unknown']).'</td>' : '','
|
623 |
+
<td>',$drive['name'] ? $drive['name'] : $lang['unknown'],'</td>
|
624 |
+
', $show_stats ? '<td>'.($drive['reads'] !== false ? number_format($drive['reads']) : $lang['unknown']).'</td>
|
625 |
+
<td>'.($drive['writes'] !== false ? number_format($drive['writes']) : $lang['unknown']).'</td>' : '','
|
626 |
+
<td>',$drive['size'] ? Common::byteConvert($drive['size']) : $lang['unknown'],'</td>
|
627 |
+
</tr>';
|
628 |
+
|
629 |
+
// If we've got partitions for this drive, show them too
|
630 |
+
if (array_key_exists('partitions', $drive) && is_array($drive['partitions']) && count($drive['partitions']) > 0) {
|
631 |
+
echo '
|
632 |
+
<tr>
|
633 |
+
<td colspan="6">';
|
634 |
+
|
635 |
+
// Each
|
636 |
+
foreach ($drive['partitions'] as $partition) {
|
637 |
+
echo '
|
638 |
+
└ '.(isset($partition['number']) ? $drive['device'].$partition['number'] : $partition['name']).' - '.Common::byteConvert($partition['size']).'<br />';
|
639 |
+
}
|
640 |
+
|
641 |
+
echo '
|
642 |
+
</td>
|
643 |
+
</tr>
|
644 |
+
';
|
645 |
+
}
|
646 |
+
}
|
647 |
+
} else {
|
648 |
+
echo '<tr><td colspan="6" class="none">'.$lang['none_found'].'</td></tr>';
|
649 |
+
}
|
650 |
+
|
651 |
+
echo '
|
652 |
+
</table>
|
653 |
+
</div>';
|
654 |
+
}
|
655 |
+
|
656 |
+
// Show sound card stuff?
|
657 |
+
if (!empty($settings['show']['sound']) && count($info['SoundCards']) > 0) {
|
658 |
+
echo '
|
659 |
+
<div class="infoTable">
|
660 |
+
<h2>'.$lang['sound_cards'].'</h2>
|
661 |
+
<table>
|
662 |
+
<tr>
|
663 |
+
<th>'.$lang['number'].'</th>
|
664 |
+
<th>'.$lang['vendor'].'</th>
|
665 |
+
<th>'.$lang['card'].'</th>
|
666 |
+
</tr>';
|
667 |
+
foreach ($info['SoundCards'] as $card) {
|
668 |
+
if (empty($card['vendor'])) {
|
669 |
+
$card['vendor'] = 'Unknown';
|
670 |
+
}
|
671 |
+
echo '
|
672 |
+
<tr>
|
673 |
+
<td>'.$card['number'].'</td>
|
674 |
+
<td>'.$card['vendor'].'</td>
|
675 |
+
<td>'.$card['card'].'</td>
|
676 |
+
</tr>';
|
677 |
+
}
|
678 |
+
echo '
|
679 |
+
</table>
|
680 |
+
</div>
|
681 |
+
';
|
682 |
+
}
|
683 |
+
|
684 |
+
echo '
|
685 |
+
</div>
|
686 |
+
</div>';
|
687 |
+
|
688 |
+
// Show file system mounts?
|
689 |
+
if (!empty($settings['show']['mounts'])) {
|
690 |
+
$has_devices = false;
|
691 |
+
$has_labels = false;
|
692 |
+
$has_types = false;
|
693 |
+
foreach ($info['Mounts'] as $mount) {
|
694 |
+
if (!empty($mount['device'])) {
|
695 |
+
$has_devices = true;
|
696 |
+
}
|
697 |
+
if (!empty($mount['label'])) {
|
698 |
+
$has_labels = true;
|
699 |
+
}
|
700 |
+
if (!empty($mount['devtype'])) {
|
701 |
+
$has_types = true;
|
702 |
+
}
|
703 |
+
}
|
704 |
+
$addcolumns = 0;
|
705 |
+
if ($settings['show']['mounts_options']) {
|
706 |
+
$addcolumns++;
|
707 |
+
}
|
708 |
+
if ($has_devices) {
|
709 |
+
$addcolumns++;
|
710 |
+
}
|
711 |
+
if ($has_labels) {
|
712 |
+
$addcolumns++;
|
713 |
+
}
|
714 |
+
if ($has_types) {
|
715 |
+
$addcolumns++;
|
716 |
+
}
|
717 |
+
echo '
|
718 |
+
<div class="infoTable filesystem_mounts">
|
719 |
+
<h2>'.$lang['filesystem_mounts'].'</h2>
|
720 |
+
<table>
|
721 |
+
<tr>';
|
722 |
+
if ($has_types) {
|
723 |
+
echo '<th>'.$lang['type'].'</th>';
|
724 |
+
}
|
725 |
+
if ($has_devices) {
|
726 |
+
echo '<th>'.$lang['device'].'</th>';
|
727 |
+
}
|
728 |
+
echo '<th>'.$lang['mount_point'].'</th>';
|
729 |
+
if ($has_labels) {
|
730 |
+
echo '<th>'.$lang['label'].'</th>';
|
731 |
+
}
|
732 |
+
echo'
|
733 |
+
<th>'.$lang['filesystem'].'</th>',$settings['show']['mounts_options'] ? '
|
734 |
+
<th>'.$lang['mount_options'].'</th>' : '','
|
735 |
+
<th>'.$lang['size'].'</th>
|
736 |
+
<th>'.$lang['used'].'</th>
|
737 |
+
<th>'.$lang['free'].'</th>
|
738 |
+
<th style="width: 12%;">'.$lang['percent_used'].'</th>
|
739 |
+
</tr>
|
740 |
+
';
|
741 |
+
|
742 |
+
// Calc totals
|
743 |
+
$total_size = 0;
|
744 |
+
$total_used = 0;
|
745 |
+
$total_free = 0;
|
746 |
+
|
747 |
+
// Don't add totals for duplicates. (same filesystem mount twice in different places)
|
748 |
+
$done_devices = array();
|
749 |
+
|
750 |
+
// Are there any?
|
751 |
+
if (count($info['Mounts']) > 0) {
|
752 |
+
|
753 |
+
// Go through each
|
754 |
+
foreach ($info['Mounts'] as $mount) {
|
755 |
+
|
756 |
+
// Only add totals for this device if we haven't already
|
757 |
+
if (!in_array($mount['device'], $done_devices)) {
|
758 |
+
$total_size += $mount['size'];
|
759 |
+
$total_used += $mount['used'];
|
760 |
+
$total_free += $mount['free'];
|
761 |
+
if (!empty($mount['device'])) {
|
762 |
+
$done_devices[] = $mount['device'];
|
763 |
+
}
|
764 |
+
}
|
765 |
+
|
766 |
+
// Possibly don't show this twice
|
767 |
+
elseif (array_key_exists('duplicate_mounts', $settings['show']) && empty($settings['show']['duplicate_mounts'])) {
|
768 |
+
continue;
|
769 |
+
}
|
770 |
+
|
771 |
+
// If it's an NFS mount it's likely in the form of server:path (without a trailing slash),
|
772 |
+
// but if the path is just / it likely just shows up as server:,
|
773 |
+
// which is vague. If there isn't a /, add one
|
774 |
+
if (preg_match('/^.+:$/', $mount['device']) == 1) {
|
775 |
+
$mount['device'] .= DIRECTORY_SEPARATOR;
|
776 |
+
}
|
777 |
+
|
778 |
+
echo '<tr>';
|
779 |
+
if ($has_types) {
|
780 |
+
echo '<td>'.$mount['devtype'].'</td>';
|
781 |
+
}
|
782 |
+
if ($has_devices) {
|
783 |
+
echo '<td>'.$mount['device'].'</td>';
|
784 |
+
}
|
785 |
+
echo '<td>'.$mount['mount'].'</td>';
|
786 |
+
if ($has_labels) {
|
787 |
+
echo '<td>'.$mount['label'].'</td>';
|
788 |
+
}
|
789 |
+
echo'
|
790 |
+
<td>'.$mount['type'].'</td>', $settings['show']['mounts_options'] ? '
|
791 |
+
<td>'.(empty($mount['options']) ? '<em>unknown</em>' : '<ul><li>'.implode('</li><li>', $mount['options']).'</li></ul>').'</td>' : '','
|
792 |
+
<td>'.Common::byteConvert($mount['size']).'</td>
|
793 |
+
<td>'.Common::byteConvert($mount['used']).
|
794 |
+
($mount['used_percent'] !== false ? ' <span class="perc">('.$mount['used_percent'].'%)</span>' : '').'</td>
|
795 |
+
<td>'.Common::byteConvert($mount['free']).
|
796 |
+
($mount['free_percent'] !== false ? ' <span class="perc">('.$mount['free_percent'].'%)</span>' : '').'</td>
|
797 |
+
<td>
|
798 |
+
'.self::generateBarChart((int) $mount['used_percent'], $mount['used_percent'] ? $mount['used_percent'].'%' : 'N/A').'
|
799 |
+
</td>
|
800 |
+
</tr>';
|
801 |
+
}
|
802 |
+
} else {
|
803 |
+
echo '<tr><td colspan="',6 + $addcolumns,'" class="none">None found</td></tr>';
|
804 |
+
}
|
805 |
+
|
806 |
+
// Show totals and finish table
|
807 |
+
$total_used_perc = $total_size > 0 && $total_used > 0 ? round($total_used / $total_size, 2) * 100 : 0;
|
808 |
+
echo '
|
809 |
+
<tr class="alt">
|
810 |
+
<td colspan="',2 + $addcolumns,'">Totals: </td>
|
811 |
+
<td>'.Common::byteConvert($total_size).'</td>
|
812 |
+
<td>'.Common::byteConvert($total_used).'</td>
|
813 |
+
<td>'.Common::byteConvert($total_free).'</td>
|
814 |
+
<td>
|
815 |
+
'.self::generateBarChart($total_used_perc, $total_used_perc.'%').'
|
816 |
+
</td>
|
817 |
+
</tr>
|
818 |
+
</table>
|
819 |
+
</div>';
|
820 |
+
}
|
821 |
+
|
822 |
+
// Show RAID Arrays?
|
823 |
+
if (!empty($settings['show']['raid']) && count($info['Raid']) > 0) {
|
824 |
+
echo '
|
825 |
+
<div class="infoTable drives">
|
826 |
+
<h2>'.$lang['raid_arrays'].'</h2>
|
827 |
+
<table>
|
828 |
+
<colgroup>
|
829 |
+
<col style="width: 10%;" />
|
830 |
+
<col style="width: 30%;" />
|
831 |
+
<col style="width: 10%;" />
|
832 |
+
<col style="width: 10%;" />
|
833 |
+
<col style="width: 30%;" />
|
834 |
+
<col style="width: 10%;" />
|
835 |
+
</colgroup>
|
836 |
+
<tr>
|
837 |
+
<th>'.$lang['name'].'</th>
|
838 |
+
<th>'.$lang['level'].'</th>
|
839 |
+
<th>'.$lang['status'].'</th>
|
840 |
+
<th>'.$lang['size'].'</th>
|
841 |
+
<th>'.$lang['devices'].'</th>
|
842 |
+
<th>'.$lang['active'].'</th>
|
843 |
+
</tr>
|
844 |
+
';
|
845 |
+
if (count($info['Raid']) > 0) {
|
846 |
+
foreach ($info['Raid'] as $raid) {
|
847 |
+
$active = explode('/', $raid['count']);
|
848 |
+
// http://en.wikipedia.org/wiki/Standard_RAID_levels
|
849 |
+
switch ($raid['level']) {
|
850 |
+
case 0:
|
851 |
+
$type = 'Stripe';
|
852 |
+
break;
|
853 |
+
case 1:
|
854 |
+
$type = 'Mirror';
|
855 |
+
break;
|
856 |
+
case 10:
|
857 |
+
$type = 'Mirrored Stripe';
|
858 |
+
break;
|
859 |
+
case 5:
|
860 |
+
case 6:
|
861 |
+
$type = 'Distributed Parity Block-Level Striping';
|
862 |
+
break;
|
863 |
+
default:
|
864 |
+
$type = false;
|
865 |
+
break;
|
866 |
+
}
|
867 |
+
echo '
|
868 |
+
<tr>
|
869 |
+
<td>'.$raid['device'].'</td>
|
870 |
+
<td>'.$raid['level'].($type ? ' <span class="caption">('.$type.')</span>' : '').'</td>
|
871 |
+
<td>'.ucfirst($raid['status']).'</td>
|
872 |
+
<td>'.$raid['size'].'</td>
|
873 |
+
<td><table class="mini center margin_auto"><tr><th>'.$lang['device'].'</th><th>'.$lang['state'].'</th></tr>';
|
874 |
+
|
875 |
+
foreach ($raid['drives'] as $drive) {
|
876 |
+
echo '<tr><td>'.$drive['drive'].'</td><td class="raid_'.$drive['state'].'">'.ucfirst($drive['state']).'</td></tr>';
|
877 |
+
}
|
878 |
+
|
879 |
+
echo '</table></td>
|
880 |
+
<td>'.$active[1].'/'.$active[0].'</td>
|
881 |
+
</tr>
|
882 |
+
';
|
883 |
+
}
|
884 |
+
} else {
|
885 |
+
echo '<tr><td colspan="6" class="none">'.$lang['none_found'].'</td></tr>';
|
886 |
+
}
|
887 |
+
|
888 |
+
echo '
|
889 |
+
</table>
|
890 |
+
</div>';
|
891 |
+
}
|
892 |
+
|
893 |
+
// Feel like showing errors? Are there any even?
|
894 |
+
if (!empty($settings['show_errors']) && Errors::num() > 0) {
|
895 |
+
echo '
|
896 |
+
<div id="errorList" class="infoTable">
|
897 |
+
<h2>'.$lang['error_head'].'</h2>
|
898 |
+
<table>
|
899 |
+
<tr>
|
900 |
+
<th>'.$lang['from_where'].'</th>
|
901 |
+
<th>'.$lang['message'].'</th>
|
902 |
+
</tr>';
|
903 |
+
|
904 |
+
foreach (Errors::show() as $error) {
|
905 |
+
echo '
|
906 |
+
<tr>
|
907 |
+
<td>'.$error[0].'</td>
|
908 |
+
<td>'.$error[1].'</td>
|
909 |
+
</tr>
|
910 |
+
';
|
911 |
+
}
|
912 |
+
|
913 |
+
echo '
|
914 |
+
</table>
|
915 |
+
</div>
|
916 |
+
';
|
917 |
+
}
|
918 |
+
|
919 |
+
// Additional extensions
|
920 |
+
if (count($info['extensions']) > 0) {
|
921 |
+
foreach ($info['extensions'] as $ext) {
|
922 |
+
if (is_array($ext) && count($ext) > 0) {
|
923 |
+
|
924 |
+
// Decide how to show something extra
|
925 |
+
switch (array_key_exists('extra_type', $ext) && !empty($ext['extra_vals']) ? $ext['extra_type'] : false) {
|
926 |
+
|
927 |
+
// Table with a key->value table to the right of it
|
928 |
+
// Useful for stats or other stuff pertaining to
|
929 |
+
// the main info to the left
|
930 |
+
case 'k->v':
|
931 |
+
echo '
|
932 |
+
<div class="col2_side">
|
933 |
+
<div class="col2_side_left">
|
934 |
+
'.self::createTable($ext).'
|
935 |
+
</div>
|
936 |
+
<div class="col2_side_right">
|
937 |
+
<div class="infoTable">
|
938 |
+
<h2>'.$ext['extra_vals']['title'].'</h2>
|
939 |
+
<table>';
|
940 |
+
|
941 |
+
// Give each value
|
942 |
+
foreach (array_filter($ext['extra_vals']['values']) as $v) {
|
943 |
+
echo '
|
944 |
+
<tr>
|
945 |
+
<th>'.$v[0].'</th>
|
946 |
+
<td>'.$v[1].'</td>
|
947 |
+
</tr>';
|
948 |
+
}
|
949 |
+
echo'
|
950 |
+
</table>
|
951 |
+
</div>
|
952 |
+
</div>
|
953 |
+
</div>
|
954 |
+
';
|
955 |
+
break;
|
956 |
+
|
957 |
+
// Nothing extra; just the table
|
958 |
+
default:
|
959 |
+
echo self::createTable($ext);
|
960 |
+
break;
|
961 |
+
}
|
962 |
+
}
|
963 |
+
}
|
964 |
+
}
|
965 |
+
|
966 |
+
// Feel like showing timed results?
|
967 |
+
if (!empty($settings['timer'])) {
|
968 |
+
echo '
|
969 |
+
<div id="timerList" class="infoTable">
|
970 |
+
<h2>'.$lang['timer'].'</h2>
|
971 |
+
<table>
|
972 |
+
<tr>
|
973 |
+
<th>'.$lang['area'].'</th>
|
974 |
+
<th>'.$lang['time_taken'].'</th>
|
975 |
+
</tr>';
|
976 |
+
|
977 |
+
foreach (Timer::getResults() as $result) {
|
978 |
+
echo '
|
979 |
+
<tr>
|
980 |
+
<td>'.$result['id'].'</td>
|
981 |
+
<td>'.round($result['duration'], 3).' '.$lang['seconds'].'</td>
|
982 |
+
</tr>
|
983 |
+
';
|
984 |
+
}
|
985 |
+
|
986 |
+
echo '
|
987 |
+
</table>
|
988 |
+
</div>
|
989 |
+
';
|
990 |
+
}
|
991 |
+
|
992 |
+
echo '
|
993 |
+
<div id="foot">
|
994 |
+
'.sprintf($lang['footer_app'], '<a href="https://github.com/jrgp/linfo"><em>'.$appName.'</em></a> ('.$version.')', round(microtime(true) - $this->linfo->getTimeStart(), 2)).'<br>
|
995 |
+
<em>'.$appName.'</em> © 2010 – '.(date('Y') > 2011 ? date('Y') : 2011).'
|
996 |
+
Joseph Gillotti '.(date('m/d') == '06/03' ? ' (who turns '.(date('Y') - 1993).' today!)' : '').'& friends. Source code licensed under GPL.
|
997 |
+
</div>
|
998 |
+
<div id="foot_time">
|
999 |
+
<br />
|
1000 |
+
Generated on '.date($settings['dates']).'
|
1001 |
+
</div>
|
1002 |
+
<script>Linfo.init()</script>
|
1003 |
+
</body>
|
1004 |
+
</html>';
|
1005 |
+
}
|
1006 |
+
}
|
lib/Linfo/Output/Json.php
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Linfo\Output;
|
4 |
+
|
5 |
+
use Linfo\Linfo;
|
6 |
+
use Linfo\Exceptions\FatalException;
|
7 |
+
|
8 |
+
class Json implements Output
|
9 |
+
{
|
10 |
+
protected $linfo;
|
11 |
+
|
12 |
+
public function __construct(Linfo $linfo)
|
13 |
+
{
|
14 |
+
$this->linfo = $linfo;
|
15 |
+
}
|
16 |
+
|
17 |
+
public function output()
|
18 |
+
{
|
19 |
+
$settings = $this->linfo->getSettings();
|
20 |
+
|
21 |
+
if (!headers_sent()) {
|
22 |
+
header('Content-Type: application/json');
|
23 |
+
}
|
24 |
+
|
25 |
+
// Make sure we have JSON
|
26 |
+
if (!function_exists('json_encode')) {
|
27 |
+
throw new FatalException('{"error":"JSON extension not loaded"}');
|
28 |
+
}
|
29 |
+
|
30 |
+
// Output buffering, along with compression (if supported)
|
31 |
+
if (!isset($settings['compress_content']) || $settings['compress_content']) {
|
32 |
+
ob_start(function_exists('ob_gzhandler') ? 'ob_gzhandler' : null);
|
33 |
+
}
|
34 |
+
|
35 |
+
// Give it. Support JSON-P like functionality if the ?callback param looks like a valid javascript
|
36 |
+
// function name, including object traversal.
|
37 |
+
echo array_key_exists('callback', $_GET) && preg_match('/^[a-z0-9\_\.]+$/i', $_GET['callback']) ?
|
38 |
+
$_GET['callback'].'('.json_encode($this->linfo->getInfo()).')' : json_encode($this->linfo->getInfo());
|
39 |
+
|
40 |
+
// Send it all out
|
41 |
+
if (!isset($settings['compress_content']) || $settings['compress_content']) {
|
42 |
+
ob_end_flush();
|
43 |
+
}
|
44 |
+
}
|
45 |
+
}
|
lib/Linfo/Output/Ncurses.php
ADDED
@@ -0,0 +1,260 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file is part of Linfo (c) 2011, 2015 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*/
|
19 |
+
namespace Linfo\Output;
|
20 |
+
|
21 |
+
use Linfo\Linfo;
|
22 |
+
use Linfo\Common;
|
23 |
+
use Linfo\Exceptions\FatalException;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Output in ncurses format for client side CLI functionality.
|
27 |
+
*
|
28 |
+
* @author Joseph Gillotti
|
29 |
+
*/
|
30 |
+
class Ncurses implements Output
|
31 |
+
{
|
32 |
+
private $linfo,
|
33 |
+
|
34 |
+
// Store our windows here
|
35 |
+
$_windows = array(),
|
36 |
+
$_max_dims = array(),
|
37 |
+
|
38 |
+
// ncurses loaded?
|
39 |
+
$loaded = true;
|
40 |
+
|
41 |
+
public function __construct(Linfo $linfo)
|
42 |
+
{
|
43 |
+
$this->linfo = $linfo;
|
44 |
+
|
45 |
+
// We obviously need this
|
46 |
+
if (!extension_loaded('ncurses')) {
|
47 |
+
$this->loaded = false;
|
48 |
+
throw new FatalException("PHP ncurses extension not loaded.\nRefer to http://php.net/manual/en/ncurses.installation.php for details.");
|
49 |
+
}
|
50 |
+
|
51 |
+
// Start ncurses
|
52 |
+
ncurses_init();
|
53 |
+
|
54 |
+
ncurses_start_color();
|
55 |
+
ncurses_init_pair(1, NCURSES_COLOR_YELLOW, NCURSES_COLOR_BLUE);
|
56 |
+
|
57 |
+
ncurses_timeout(0);
|
58 |
+
}
|
59 |
+
|
60 |
+
// Make sure ncurses_end() always gets called no matter what;
|
61 |
+
// not doing so will leave the terminal messed up until the user
|
62 |
+
// runs 'reset'
|
63 |
+
public function __destruct()
|
64 |
+
{
|
65 |
+
if ($this->loaded) {
|
66 |
+
ncurses_end();
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
public function output()
|
71 |
+
{
|
72 |
+
|
73 |
+
// Gain access to translations
|
74 |
+
$lang = $this->linfo->getLang();
|
75 |
+
|
76 |
+
// And info
|
77 |
+
$this->linfo->scan();
|
78 |
+
$info = $this->linfo->getInfo();
|
79 |
+
|
80 |
+
// Say we're called more than once. Kill previous remnants
|
81 |
+
if (count($this->_windows) > 0) {
|
82 |
+
$this->_kill_windows();
|
83 |
+
}
|
84 |
+
|
85 |
+
// Get dimensions and give lovely header text
|
86 |
+
$fullscreen = ncurses_newwin(0, 0, 0, 0);
|
87 |
+
ncurses_wrefresh($fullscreen);
|
88 |
+
ncurses_getmaxyx($fullscreen, $x, $y);
|
89 |
+
ncurses_mvwaddstr($fullscreen, 0, 0, 'Generated by '.$this->linfo->getAppName().' ('.$this->linfo->getVersion().') (ncurses) on '.date('m/d/Y @ h:i:s A (T)'));
|
90 |
+
ncurses_wrefresh($fullscreen);
|
91 |
+
$this->_max_dims = array($x, $y);
|
92 |
+
|
93 |
+
// Some important windows
|
94 |
+
$core_wins = array(
|
95 |
+
array(
|
96 |
+
'name' => $lang['core'],
|
97 |
+
'content' => array(
|
98 |
+
array($lang['os'], $info['OS']),
|
99 |
+
array_key_exists('Distro', $info) ? array($lang['distro'], $info['Distro']['name'].($info['Distro']['version'] ? ' '.$info['Distro']['version'] : '')) : false,
|
100 |
+
array($lang['kernel'], $info['Kernel']),
|
101 |
+
array_key_exists('Model', $info) && !empty($info['Model']) ? array($lang['model'], $info['Model']) : false,
|
102 |
+
array($lang['uptime'], str_ireplace(array(' ', 'days', 'minutes', 'hours', 'seconds'), array('', 'd', 'm', 'h', 's'), $info['UpTime']['text'])),
|
103 |
+
array($lang['hostname'], $info['HostName']),
|
104 |
+
|
105 |
+
array_key_exists('CPUArchitecture', $info) ? array($lang['cpu_arch'], $info['CPUArchitecture']) : false,
|
106 |
+
|
107 |
+
array($lang['load'], implode(' ', (array) $info['Load'])),
|
108 |
+
),
|
109 |
+
),
|
110 |
+
array(
|
111 |
+
'name' => $lang['memory'],
|
112 |
+
'content' => array(
|
113 |
+
array($lang['size'], Common::byteConvert($info['RAM']['total'])),
|
114 |
+
array($lang['used'], Common::byteConvert($info['RAM']['total'] - $info['RAM']['free'])),
|
115 |
+
array($lang['free'], Common::byteConvert($info['RAM']['free'])),
|
116 |
+
),
|
117 |
+
),
|
118 |
+
);
|
119 |
+
|
120 |
+
// Show them
|
121 |
+
$h = 1;
|
122 |
+
foreach ($core_wins as $win) {
|
123 |
+
list($width, $height) = $this->_window_with_lines($win['name'], $win['content'], $h, 0);
|
124 |
+
$h += $height + 1;
|
125 |
+
}
|
126 |
+
|
127 |
+
// Makeshift event loop
|
128 |
+
while (true) {
|
129 |
+
|
130 |
+
// Die on input
|
131 |
+
$getch = ncurses_getch();
|
132 |
+
if ($getch > 0 && $getch == 113) {
|
133 |
+
$this->__destruct();
|
134 |
+
echo "\nEnding at your request.\n";
|
135 |
+
exit(0);
|
136 |
+
}
|
137 |
+
|
138 |
+
// Stop temporariy
|
139 |
+
ncurses_napms(1000);
|
140 |
+
|
141 |
+
// Call ourselves
|
142 |
+
$this->output();
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
+
// Create a window with various lines as content
|
147 |
+
private function _window_with_lines($name, $lines, $x = 5, $y = 5, $set_width = false)
|
148 |
+
{
|
149 |
+
|
150 |
+
// Need an array of lines.
|
151 |
+
$lines = (array) $lines;
|
152 |
+
|
153 |
+
// Ignore disabled liens
|
154 |
+
$lines = array_filter($lines);
|
155 |
+
|
156 |
+
// Do we not have a specific set width? Calculate the longest line
|
157 |
+
if (!is_numeric($set_width)) {
|
158 |
+
$longest_line = strlen($name) + 10;
|
159 |
+
foreach ($lines as $line) {
|
160 |
+
$length = strlen(implode('', $line));
|
161 |
+
$longest_line = $length > $longest_line ? $length : $longest_line;
|
162 |
+
}
|
163 |
+
$width = $longest_line + 4;
|
164 |
+
}
|
165 |
+
|
166 |
+
// Otherwise we do have a set with
|
167 |
+
else {
|
168 |
+
$width = $set_width;
|
169 |
+
}
|
170 |
+
|
171 |
+
// Calculate window hight
|
172 |
+
$height = 3 + count($lines);
|
173 |
+
|
174 |
+
// Create window
|
175 |
+
$win = ncurses_newwin($height, $width, $x, $y);
|
176 |
+
|
177 |
+
// This character will be the side borders
|
178 |
+
$side = ord('|');
|
179 |
+
|
180 |
+
// Do the borders of the window
|
181 |
+
ncurses_wborder($win, $side, $side, ord('-'), ord('-'), ord('/'), ord('\\'), ord('\\'), ord('/'));
|
182 |
+
|
183 |
+
// Add window title string
|
184 |
+
ncurses_mvwaddstr($win, 1, 1, $this->_charpad($name, $width, 'c', '='));
|
185 |
+
|
186 |
+
// Keep track of vertical position for each line
|
187 |
+
$v = 1;
|
188 |
+
|
189 |
+
// Go through and output each line, while incrementing line position counter
|
190 |
+
foreach ($lines as $line) {
|
191 |
+
ncurses_mvwaddstr($win, $v + 1, 1, $this->_charpad($line[0].$this->_charpad($line[1], $width - strlen($line[0]), 'r', '.'), $width, 'n'));
|
192 |
+
++$v;
|
193 |
+
}
|
194 |
+
|
195 |
+
// Show it
|
196 |
+
ncurses_wrefresh($win);
|
197 |
+
|
198 |
+
// Store it so we can kill it later
|
199 |
+
$this->_windows[] = &$win;
|
200 |
+
|
201 |
+
// Return window dimensions
|
202 |
+
return array($width, $height);
|
203 |
+
}
|
204 |
+
|
205 |
+
// Kill all windows
|
206 |
+
private function _kill_windows()
|
207 |
+
{
|
208 |
+
foreach ($this->_windows as $win) {
|
209 |
+
is_resource($win) &&
|
210 |
+
ncurses_delwin($win);
|
211 |
+
}
|
212 |
+
}
|
213 |
+
|
214 |
+
// Because I got tired of sprintf
|
215 |
+
private function _charpad($string, $length, $direction, $filler = ' ')
|
216 |
+
{
|
217 |
+
|
218 |
+
// Keep length of string handy here
|
219 |
+
$strlen = strlen($string);
|
220 |
+
|
221 |
+
// Difference between max length and string length
|
222 |
+
$difference = $length - $strlen;
|
223 |
+
|
224 |
+
// If the string length is bigger than the max, just return string truncated to the max length
|
225 |
+
if ($difference < 0) {
|
226 |
+
return substr($string, 0, $length);
|
227 |
+
}
|
228 |
+
|
229 |
+
// Deal with direction
|
230 |
+
switch ($direction) {
|
231 |
+
|
232 |
+
// Right aligned (padded to the left)
|
233 |
+
case 'r':
|
234 |
+
return str_repeat($filler, $difference - 2).$string;
|
235 |
+
break;
|
236 |
+
|
237 |
+
// Left aligned (padded to the right)
|
238 |
+
case 'l':
|
239 |
+
return $string.str_repeat($filler, $difference - 2);
|
240 |
+
break;
|
241 |
+
|
242 |
+
// Centered (padded left and right)
|
243 |
+
case 'c':
|
244 |
+
$cdiff = floor($difference / 2) - ($difference % 2 == 0 ? 1 : 0);
|
245 |
+
|
246 |
+
return str_repeat($filler, $cdiff - 1).$string.str_repeat($filler, $cdiff);
|
247 |
+
break;
|
248 |
+
|
249 |
+
// Not padded; returned as is (provided not longer than max, as tested above)
|
250 |
+
case 'n':
|
251 |
+
return $string;
|
252 |
+
break;
|
253 |
+
|
254 |
+
// Uhh not sure?
|
255 |
+
default:
|
256 |
+
return '';
|
257 |
+
break;
|
258 |
+
}
|
259 |
+
}
|
260 |
+
}
|
lib/Linfo/Output/Output.php
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2015 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Output;
|
22 |
+
|
23 |
+
use Linfo\Linfo;
|
24 |
+
|
25 |
+
interface Output
|
26 |
+
{
|
27 |
+
public function __construct(Linfo $linfo);
|
28 |
+
public function output();
|
29 |
+
}
|
lib/Linfo/Output/Serialized.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Linfo\Output;
|
4 |
+
|
5 |
+
use Linfo\Linfo;
|
6 |
+
|
7 |
+
class Serialized implements Output
|
8 |
+
{
|
9 |
+
protected $linfo;
|
10 |
+
|
11 |
+
public function __construct(Linfo $linfo)
|
12 |
+
{
|
13 |
+
$this->linfo = $linfo;
|
14 |
+
}
|
15 |
+
|
16 |
+
public function output()
|
17 |
+
{
|
18 |
+
$settings = $this->linfo->getSettings();
|
19 |
+
|
20 |
+
// Output buffering, along with compression (if supported)
|
21 |
+
if (!isset($settings['compress_content']) || $settings['compress_content']) {
|
22 |
+
ob_start(function_exists('ob_gzhandler') ? 'ob_gzhandler' : null);
|
23 |
+
}
|
24 |
+
|
25 |
+
echo serialize($this->linfo->getInfo());
|
26 |
+
}
|
27 |
+
}
|
lib/Linfo/Output/Xml.php
ADDED
@@ -0,0 +1,326 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Linfo\Output;
|
4 |
+
|
5 |
+
use Exception;
|
6 |
+
use Linfo\Linfo;
|
7 |
+
use Linfo\Common;
|
8 |
+
use Linfo\Exceptions\FatalException;
|
9 |
+
use SimpleXMLElement;
|
10 |
+
|
11 |
+
class Xml implements Output
|
12 |
+
{
|
13 |
+
protected $linfo;
|
14 |
+
|
15 |
+
public function __construct(Linfo $linfo)
|
16 |
+
{
|
17 |
+
if (!extension_loaded('SimpleXML')) {
|
18 |
+
throw new FatalException('Cannot generate XML. Install php\'s SimpleXML extension.');
|
19 |
+
}
|
20 |
+
|
21 |
+
$this->linfo = $linfo;
|
22 |
+
}
|
23 |
+
|
24 |
+
public function output()
|
25 |
+
{
|
26 |
+
$lang = $this->linfo->getLang();
|
27 |
+
$settings = $this->linfo->getSettings();
|
28 |
+
$info = $this->linfo->getInfo();
|
29 |
+
|
30 |
+
try {
|
31 |
+
// Start it up
|
32 |
+
$xml = new SimpleXMLElement('<?xml version="1.0"?><linfo></linfo>');
|
33 |
+
|
34 |
+
// Deal with core stuff
|
35 |
+
$core_elem = $xml->addChild('core');
|
36 |
+
$core = array();
|
37 |
+
if (!empty($settings['show']['os'])) {
|
38 |
+
$core[] = array('os', $info['OS']);
|
39 |
+
}
|
40 |
+
if (!empty($settings['show']['distro']) && isset($info['Distro']) && is_array($info['Distro'])) {
|
41 |
+
$core[] = array('distro', $info['Distro']['name'].($info['Distro']['version'] ? ' - '.$info['Distro']['version'] : ''));
|
42 |
+
}
|
43 |
+
if (!empty($settings['show']['kernel'])) {
|
44 |
+
$core[] = array('kernel', $info['Kernel']);
|
45 |
+
}
|
46 |
+
if (!empty($settings['show']['webservice'])) {
|
47 |
+
$core[] = array('webservice', $info['webService']);
|
48 |
+
}
|
49 |
+
if (!empty($settings['show']['phpversion'])) {
|
50 |
+
$core[] = array('phpversion', $info['phpVersion']);
|
51 |
+
}
|
52 |
+
if (!isset($settings['show']['ip']) || !empty($settings['show']['ip'])) {
|
53 |
+
$core[] = array('accessed_ip', (isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : 'Unknown'));
|
54 |
+
}
|
55 |
+
if (!empty($settings['show']['uptime'])) {
|
56 |
+
$core[] = array('uptime', $info['UpTime']['text']);
|
57 |
+
}
|
58 |
+
if (!empty($settings['show']['hostname'])) {
|
59 |
+
$core[] = array('hostname', $info['HostName']);
|
60 |
+
}
|
61 |
+
if (!empty($settings['show']['cpu'])) {
|
62 |
+
$cpus = '';
|
63 |
+
foreach ((array) $info['CPU'] as $cpu) {
|
64 |
+
$cpus .=
|
65 |
+
(array_key_exists('Vendor', $cpu) && empty($cpu['Vendor']) ? $cpu['Vendor'].' - ' : '').
|
66 |
+
$cpu['Model'].
|
67 |
+
(array_key_exists('MHz', $cpu) ?
|
68 |
+
($cpu['MHz'] < 1000 ? ' ('.$cpu['MHz'].' MHz)' : ' ('.round($cpu['MHz'] / 1000, 3).' GHz)') : '').
|
69 |
+
'<br />';
|
70 |
+
}
|
71 |
+
$core[] = array('cpus', $cpus);
|
72 |
+
}
|
73 |
+
if (!empty($settings['show']['model']) && array_key_exists('Model', $info) && !empty($info['Model'])) {
|
74 |
+
$core[] = array('model', $info['Model']);
|
75 |
+
}
|
76 |
+
if (!empty($settings['show']['process_stats']) && $info['processStats']['exists']) {
|
77 |
+
$proc_stats = array();
|
78 |
+
if (array_key_exists('totals', $info['processStats']) && is_array($info['processStats']['totals'])) {
|
79 |
+
foreach ($info['processStats']['totals'] as $k => $v) {
|
80 |
+
$proc_stats[] = $k.': '.number_format($v);
|
81 |
+
}
|
82 |
+
}
|
83 |
+
$proc_stats[] = 'total: '.number_format($info['processStats']['proc_total']);
|
84 |
+
$core[] = array('processes', implode('; ', $proc_stats));
|
85 |
+
if ($info['processStats']['threads'] !== false) {
|
86 |
+
$core[] = array('threads', number_format($info['processStats']['threads']));
|
87 |
+
}
|
88 |
+
}
|
89 |
+
if (!empty($settings['show']['load'])) {
|
90 |
+
$core[] = array('load', implode(' ', (array) $info['Load']));
|
91 |
+
}
|
92 |
+
|
93 |
+
// Adding each core stuff
|
94 |
+
for ($i = 0, $core_num = count($core); $i < $core_num; ++$i) {
|
95 |
+
$core_elem->addChild($core[$i][0], $core[$i][1]);
|
96 |
+
}
|
97 |
+
|
98 |
+
// RAM
|
99 |
+
if (!empty($settings['show']['ram'])) {
|
100 |
+
$mem = $xml->addChild('memory');
|
101 |
+
$core_mem = $mem->addChild($info['RAM']['type']);
|
102 |
+
$core_mem->addChild('free', $info['RAM']['free']);
|
103 |
+
$core_mem->addChild('total', $info['RAM']['total']);
|
104 |
+
$core_mem->addChild('used', $info['RAM']['total'] - $info['RAM']['free']);
|
105 |
+
if (isset($info['RAM']['swapFree']) || isset($info['RAM']['swapTotal'])) {
|
106 |
+
$swap = $mem->addChild('swap');
|
107 |
+
$swap_core = $swap->addChild('core');
|
108 |
+
$swap_core->addChild('free', $info['RAM']['swapFree']);
|
109 |
+
$swap_core->addChild('total', $info['RAM']['swapTotal']);
|
110 |
+
$swap_core->addChild('used', $info['RAM']['swapTotal'] - $info['RAM']['swapFree']);
|
111 |
+
if (is_array($info['RAM']['swapInfo']) && count($info['RAM']['swapInfo']) > 0) {
|
112 |
+
$swap_devices = $swap->addChild('devices');
|
113 |
+
foreach ($info['RAM']['swapInfo'] as $swap_dev) {
|
114 |
+
$swap_dev_elem = $swap_devices->addChild('device');
|
115 |
+
$swap_dev_elem->addAttribute('device', $swap_dev['device']);
|
116 |
+
$swap_dev_elem->addAttribute('type', $swap_dev['type']);
|
117 |
+
$swap_dev_elem->addAttribute('size', $swap_dev['size']);
|
118 |
+
$swap_dev_elem->addAttribute('used', $swap_dev['used']);
|
119 |
+
}
|
120 |
+
}
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
// NET
|
125 |
+
if (!empty($settings['show']['network']) && isset($info['Network Devices']) && is_array($info['Network Devices'])) {
|
126 |
+
$net = $xml->addChild('net');
|
127 |
+
foreach ($info['Network Devices'] as $device => $stats) {
|
128 |
+
$nic = $net->addChild('interface');
|
129 |
+
$nic->addAttribute('device', $device);
|
130 |
+
$nic->addAttribute('type', $stats['type']);
|
131 |
+
$nic->addAttribute('sent', $stats['sent']['bytes']);
|
132 |
+
$nic->addAttribute('recieved', $stats['recieved']['bytes']);
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
// TEMPS
|
137 |
+
if (!empty($settings['show']['temps']) && isset($info['Temps']) && count($info['Temps']) > 0) {
|
138 |
+
$temps = $xml->addChild('temps');
|
139 |
+
foreach ($info['Temps'] as $stat) {
|
140 |
+
$temp = $temps->addChild('temp');
|
141 |
+
$temp->addAttribute('path', $stat['path']);
|
142 |
+
$temp->addAttribute('name', $stat['name']);
|
143 |
+
$temp->addAttribute('temp', $stat['temp'].' '.$stat['unit']);
|
144 |
+
}
|
145 |
+
}
|
146 |
+
|
147 |
+
// Batteries
|
148 |
+
if (!empty($settings['show']['battery']) && isset($info['Battery']) && count($info['Battery']) > 0) {
|
149 |
+
$bats = $xml->addChild('batteries');
|
150 |
+
foreach ($info['Battery'] as $bat) {
|
151 |
+
$bat = $bats->addChild('battery');
|
152 |
+
$bat->addAttribute('device', $bat['device']);
|
153 |
+
$bat->addAttribute('state', $bat['state']);
|
154 |
+
$bat->addAttribute('percentage', $bat['percentage']);
|
155 |
+
}
|
156 |
+
}
|
157 |
+
|
158 |
+
// SERVICES
|
159 |
+
if (!empty($settings['show']['services']) && isset($info['services']) && count($info['services']) > 0) {
|
160 |
+
$services = $xml->addChild('services');
|
161 |
+
foreach ($info['services'] as $service => $state) {
|
162 |
+
$state_parts = explode(' ', $state['state'], 2);
|
163 |
+
$service_elem = $services->addChild('service');
|
164 |
+
$service_elem->addAttribute('name', $service);
|
165 |
+
$service_elem->addAttribute('state', $state_parts[0].(array_key_exists(1, $state_parts) ? ' '.$state_parts[1] : ''));
|
166 |
+
$service_elem->addAttribute('pid', $state['pid']);
|
167 |
+
$service_elem->addAttribute('threads', $state['threads'] ? $state['threads'] : '?');
|
168 |
+
$service_elem->addAttribute('mem_usage', $state['memory_usage'] ? $state['memory_usage'] : '?');
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
// DEVICES
|
173 |
+
if (!empty($settings['show']['devices']) && isset($info['Devices'])) {
|
174 |
+
$show_vendor = array_key_exists('hw_vendor', $info['contains']) ? ($info['contains']['hw_vendor'] === false ? false : true) : true;
|
175 |
+
$devices = $xml->addChild('devices');
|
176 |
+
for ($i = 0, $num_devs = count($info['Devices']); $i < $num_devs; ++$i) {
|
177 |
+
$device = $devices->addChild('device');
|
178 |
+
$device->addAttribute('type', $info['Devices'][$i]['type']);
|
179 |
+
if ($show_vendor) {
|
180 |
+
$device->addAttribute('vendor', $info['Devices'][$i]['vendor']);
|
181 |
+
}
|
182 |
+
$device->addAttribute('name', $info['Devices'][$i]['device']);
|
183 |
+
}
|
184 |
+
}
|
185 |
+
|
186 |
+
// DRIVES
|
187 |
+
if (!empty($settings['show']['hd']) && isset($info['HD']) && is_array($info['HD'])) {
|
188 |
+
$show_stats = array_key_exists('drives_rw_stats', $info['contains']) ? ($info['contains']['drives_rw_stats'] === false ? false : true) : true;
|
189 |
+
$drives = $xml->addChild('drives');
|
190 |
+
foreach ($info['HD'] as $drive) {
|
191 |
+
$drive_elem = $drives->addChild('drive');
|
192 |
+
$drive_elem->addAttribute('device', $drive['device']);
|
193 |
+
$drive_elem->addAttribute('vendor', $drive['vendor'] ? $drive['vendor'] : $lang['unknown']);
|
194 |
+
$drive_elem->addAttribute('name', $drive['name']);
|
195 |
+
if ($show_stats) {
|
196 |
+
$drive_elem->addAttribute('reads', $drive['reads'] ? $drive['reads'] : 'unknown');
|
197 |
+
$drive_elem->addAttribute('writes', $drive['writes'] ? $drive['writes'] : 'unknown');
|
198 |
+
}
|
199 |
+
$drive_elem->addAttribute('size', $drive['size'] ? $drive['size'] : 'unknown');
|
200 |
+
if (is_array($drive['partitions']) && count($drive['partitions']) > 0) {
|
201 |
+
$partitions = $drive_elem->addChild('partitions');
|
202 |
+
foreach ($drive['partitions'] as $partition) {
|
203 |
+
$partition_elem = $partitions->addChild('partition');
|
204 |
+
$partition_elem->addAttribute('name', isset($partition['number']) ? $drive['device'].$partition['number'] : $partition['name']);
|
205 |
+
$partition_elem->addAttribute('size', $partition['size']);
|
206 |
+
}
|
207 |
+
}
|
208 |
+
}
|
209 |
+
}
|
210 |
+
|
211 |
+
// Sound cards? lol
|
212 |
+
if (!empty($settings['show']['sound']) && isset($info['SoundCards']) && count($info['SoundCards']) > 0) {
|
213 |
+
$cards = $xml->addChild('soundcards');
|
214 |
+
foreach ($info['SoundCards'] as $card) {
|
215 |
+
$card_elem = $cards->addChild('card');
|
216 |
+
$card_elem->addAttribute('number', $card['number']);
|
217 |
+
$card_elem->addAttribute('vendor', empty($card['vendor']) ? 'unknown' : $card['vendor']);
|
218 |
+
$card_elem->addAttribute('card', $card['card']);
|
219 |
+
}
|
220 |
+
}
|
221 |
+
|
222 |
+
// File system mounts
|
223 |
+
if (!empty($settings['show']['mounts'])) {
|
224 |
+
$has_devices = false;
|
225 |
+
$has_labels = false;
|
226 |
+
$has_types = false;
|
227 |
+
foreach ($info['Mounts'] as $mount) {
|
228 |
+
if (!empty($mount['device'])) {
|
229 |
+
$has_devices = true;
|
230 |
+
}
|
231 |
+
if (!empty($mount['label'])) {
|
232 |
+
$has_labels = true;
|
233 |
+
}
|
234 |
+
if (!empty($mount['devtype'])) {
|
235 |
+
$has_types = true;
|
236 |
+
}
|
237 |
+
}
|
238 |
+
$mounts = $xml->addChild('mounts');
|
239 |
+
foreach ($info['Mounts'] as $mount) {
|
240 |
+
$mount_elem = $mounts->addChild('mount');
|
241 |
+
if (preg_match('/^.+:$/', $mount['device']) == 1) {
|
242 |
+
$mount['device'] .= DIRECTORY_SEPARATOR;
|
243 |
+
}
|
244 |
+
if ($has_types) {
|
245 |
+
$mount_elem->addAttribute('type', $mount['devtype']);
|
246 |
+
}
|
247 |
+
if ($has_devices) {
|
248 |
+
$mount_elem->addAttribute('device', $mount['device']);
|
249 |
+
}
|
250 |
+
$mount_elem->addAttribute('mountpoint', $mount['mount']);
|
251 |
+
if ($has_labels) {
|
252 |
+
$mount_elem->addAttribute('label', $mount['label']);
|
253 |
+
}
|
254 |
+
$mount_elem->addAttribute('fstype', $mount['type']);
|
255 |
+
if ($settings['show']['mounts_options'] && !empty($mount['options'])) {
|
256 |
+
$mount_elem->addAttribute('options', implode(',', $mount['options']));
|
257 |
+
}
|
258 |
+
$mount_elem->addAttribute('size', $mount['size']);
|
259 |
+
$mount_elem->addAttribute('used', $mount['used']);
|
260 |
+
$mount_elem->addAttribute('free', $mount['free']);
|
261 |
+
}
|
262 |
+
}
|
263 |
+
|
264 |
+
// RAID arrays
|
265 |
+
if (!empty($settings['show']['raid']) && isset($info['Raid']) && count($info['Raid']) > 0) {
|
266 |
+
$raid_elem = $xml->addChild('raid');
|
267 |
+
foreach ($info['Raid'] as $raid) {
|
268 |
+
$array = $raid_elem->addChild('array');
|
269 |
+
$active = explode('/', $raid['count']);
|
270 |
+
$array->addAttribute('device', $raid['device']);
|
271 |
+
$array->addAttribute('level', $raid['level']);
|
272 |
+
$array->addAttribute('status', $raid['status']);
|
273 |
+
$array->addAttribute('size', $raid['size']);
|
274 |
+
$array->addAttribute('active', $active[1].'/'.$active[0]);
|
275 |
+
$drives = $array->addChild('drives');
|
276 |
+
foreach ($raid['drives'] as $drive) {
|
277 |
+
$drive_elem = $drives->addChild('drive');
|
278 |
+
$drive_elem->addAttribute('drive', $drive['drive']);
|
279 |
+
$drive_elem->addAttribute('state', $drive['state']);
|
280 |
+
}
|
281 |
+
}
|
282 |
+
}
|
283 |
+
|
284 |
+
// Timestamp
|
285 |
+
$xml->addChild('timestamp', $info['timestamp']);
|
286 |
+
|
287 |
+
// Extensions
|
288 |
+
if (count($info['extensions']) > 0) {
|
289 |
+
$extensions = $xml->addChild('extensions');
|
290 |
+
foreach ($info['extensions'] as $ext) {
|
291 |
+
$header = false;
|
292 |
+
if (is_array($ext) && count($ext) > 0) {
|
293 |
+
$this_ext = $extensions->addChild(Common::xmlStringSanitize($ext['root_title']));
|
294 |
+
foreach ((array) $ext['rows'] as $i => $row) {
|
295 |
+
if ($row['type'] == 'header') {
|
296 |
+
$header = $i;
|
297 |
+
} elseif ($row['type'] == 'values') {
|
298 |
+
$this_row = $this_ext->addChild('row');
|
299 |
+
if ($header !== false && array_key_exists($header, $ext['rows'])) {
|
300 |
+
foreach ($ext['rows'][$header]['columns'] as $ri => $rc) {
|
301 |
+
$this_row->addChild(
|
302 |
+
Common::xmlStringSanitize($rc),
|
303 |
+
$ext['rows'][$i]['columns'][$ri]
|
304 |
+
);
|
305 |
+
}
|
306 |
+
}
|
307 |
+
}
|
308 |
+
}
|
309 |
+
}
|
310 |
+
}
|
311 |
+
}
|
312 |
+
|
313 |
+
// Out it
|
314 |
+
if (!headers_sent()) {
|
315 |
+
header('Content-type: text/xml');
|
316 |
+
}
|
317 |
+
echo $xml->asXML();
|
318 |
+
|
319 |
+
// Comment which has stats and generator
|
320 |
+
echo '<!-- Generated in '.round(microtime(true) - $this->linfo->getTimeStart(), 2).
|
321 |
+
' seconds by '.$this->linfo->getAppName().' ('.$this->linfo->getVersion().')-->';
|
322 |
+
} catch (Exception $e) {
|
323 |
+
throw new FatalException('Creation of XML error: '.$e->getMessage());
|
324 |
+
}
|
325 |
+
}
|
326 |
+
}
|
lib/Linfo/Parsers/CallExt.php
ADDED
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*/
|
19 |
+
namespace Linfo\Parsers;
|
20 |
+
|
21 |
+
use Linfo\Common;
|
22 |
+
use Linfo\Linfo;
|
23 |
+
use Exception;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Class used to call external programs.
|
27 |
+
*/
|
28 |
+
class CallExt
|
29 |
+
{
|
30 |
+
protected static $settings = array();
|
31 |
+
|
32 |
+
public static function config(Linfo $linfo)
|
33 |
+
{
|
34 |
+
self::$settings = $linfo->getSettings();
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Maintain a count of how many external programs we call.
|
39 |
+
*
|
40 |
+
* @var int
|
41 |
+
*/
|
42 |
+
public static $callCount = 0;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Store results of commands here to avoid calling them more than once.
|
46 |
+
*
|
47 |
+
* @var array
|
48 |
+
*/
|
49 |
+
protected $cliCache = array();
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Store paths to look for executables here.
|
53 |
+
*
|
54 |
+
* @var array
|
55 |
+
*/
|
56 |
+
protected $searchPaths = array();
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Say where we'll search for execs.
|
60 |
+
*
|
61 |
+
* @param array $paths list of paths
|
62 |
+
*/
|
63 |
+
public function setSearchPaths($paths)
|
64 |
+
{
|
65 |
+
|
66 |
+
// Merge in possible custom paths
|
67 |
+
if (isset(self::$settings['additional_paths'])
|
68 |
+
&& is_array(self::$settings['additional_paths'])
|
69 |
+
&& count(self::$settings['additional_paths']) > 0) {
|
70 |
+
$paths = array_merge(self::$settings['additional_paths'], $paths);
|
71 |
+
}
|
72 |
+
|
73 |
+
// Make sure they all have a trailing slash
|
74 |
+
foreach ($paths as $k => $v) {
|
75 |
+
$paths[$k] .= substr($v, -1) == '/' ? '' : '/';
|
76 |
+
}
|
77 |
+
|
78 |
+
// Save them
|
79 |
+
$this->searchPaths = $paths;
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Run a command and cache its output for later.
|
84 |
+
*
|
85 |
+
* @throws Exception
|
86 |
+
*
|
87 |
+
* @param string $name name of executable to call
|
88 |
+
* @param string $switches command arguments
|
89 |
+
*/
|
90 |
+
public function exec($name, $switches = '')
|
91 |
+
{
|
92 |
+
|
93 |
+
// Sometimes it is necessary to call a program with sudo
|
94 |
+
$attempt_sudo = array_key_exists('sudo_apps', self::$settings) && in_array($name, self::$settings['sudo_apps']);
|
95 |
+
|
96 |
+
// Have we gotten it before?
|
97 |
+
if (array_key_exists($name.$switches, $this->cliCache)) {
|
98 |
+
return $this->cliCache[$name.$switches];
|
99 |
+
}
|
100 |
+
|
101 |
+
// Try finding the exec
|
102 |
+
foreach ($this->searchPaths as $path) {
|
103 |
+
|
104 |
+
// Found it; run it
|
105 |
+
if (is_file($path.$name) && is_executable($path.$name)) {
|
106 |
+
|
107 |
+
// Complete command, path switches and all
|
108 |
+
$command = "$path$name $switches";
|
109 |
+
|
110 |
+
// Sudoing?
|
111 |
+
$command = $attempt_sudo ? Common::locateActualPath(Common::arrayAppendString($this->searchPaths, 'sudo', '%2s%1s')).' '.$command : $command;
|
112 |
+
|
113 |
+
// Result of command
|
114 |
+
$result = `$command`;
|
115 |
+
|
116 |
+
// Increment call count
|
117 |
+
++self::$callCount;
|
118 |
+
|
119 |
+
// Cache that
|
120 |
+
$this->cliCache[$name.$switches] = $result;
|
121 |
+
|
122 |
+
// Give result
|
123 |
+
return $result;
|
124 |
+
}
|
125 |
+
}
|
126 |
+
|
127 |
+
// Never got it
|
128 |
+
throw new Exception('Exec `'.$name.'\' not found');
|
129 |
+
}
|
130 |
+
}
|
lib/Linfo/Parsers/Hddtemp.php
ADDED
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Parsers;
|
22 |
+
|
23 |
+
use Linfo\Common;
|
24 |
+
use Exception;
|
25 |
+
|
26 |
+
/*
|
27 |
+
* Deal with hddtemp
|
28 |
+
*/
|
29 |
+
class Hddtemp
|
30 |
+
{
|
31 |
+
// Store these
|
32 |
+
protected $mode, $host, $port, $settings;
|
33 |
+
|
34 |
+
// Default socket connect timeout
|
35 |
+
const timeout = 3;
|
36 |
+
|
37 |
+
// Start us off
|
38 |
+
public function __construct($settings)
|
39 |
+
{
|
40 |
+
$this->settings = $settings;
|
41 |
+
}
|
42 |
+
|
43 |
+
// Localize mode
|
44 |
+
public function setMode($mode)
|
45 |
+
{
|
46 |
+
$this->mode = $mode;
|
47 |
+
}
|
48 |
+
|
49 |
+
/*
|
50 |
+
* For connecting to HDDTemp daemon
|
51 |
+
*/
|
52 |
+
|
53 |
+
// Localize host and port
|
54 |
+
public function setAddress($host, $port = 7634)
|
55 |
+
{
|
56 |
+
$this->host = $host;
|
57 |
+
$this->port = $port;
|
58 |
+
}
|
59 |
+
|
60 |
+
// Connect to host/port and get info
|
61 |
+
private function getSock()
|
62 |
+
{
|
63 |
+
// Try connecting
|
64 |
+
if (!($sock = @fsockopen($this->host, $this->port, $errno, $errstr, self::timeout))) {
|
65 |
+
throw new Exception('Error connecting');
|
66 |
+
}
|
67 |
+
|
68 |
+
// Try getting stuff
|
69 |
+
$buffer = '';
|
70 |
+
while ($mid = @fgets($sock)) {
|
71 |
+
$buffer .= $mid;
|
72 |
+
}
|
73 |
+
|
74 |
+
// Quit
|
75 |
+
@fclose($sock);
|
76 |
+
|
77 |
+
// Output:
|
78 |
+
return $buffer;
|
79 |
+
}
|
80 |
+
|
81 |
+
// Parse and return info from daemon socket
|
82 |
+
private function parseSockData($data)
|
83 |
+
{
|
84 |
+
|
85 |
+
// Kill surounding ||'s and split it by pipes
|
86 |
+
$drives = explode('||', trim($data, '|'));
|
87 |
+
|
88 |
+
// Return our stuff here
|
89 |
+
$return = array();
|
90 |
+
|
91 |
+
// Go through each
|
92 |
+
foreach ($drives as $drive) {
|
93 |
+
|
94 |
+
// Extract stuff from it
|
95 |
+
list($path, $name, $temp, $unit) = explode('|', trim($drive));
|
96 |
+
|
97 |
+
// Ignore /dev/sg?
|
98 |
+
if (!empty($this->settings['hide']['sg']) && substr($path, 0, 7) == '/dev/sg') {
|
99 |
+
continue;
|
100 |
+
}
|
101 |
+
|
102 |
+
// Ignore no longer existant devices?
|
103 |
+
if (!file_exists($path) && is_readable('/dev')) {
|
104 |
+
continue;
|
105 |
+
}
|
106 |
+
|
107 |
+
// Save it
|
108 |
+
$return[] = array(
|
109 |
+
'path' => $path,
|
110 |
+
'name' => $name,
|
111 |
+
'temp' => $temp,
|
112 |
+
'unit' => strtoupper($unit),
|
113 |
+
);
|
114 |
+
}
|
115 |
+
|
116 |
+
// Give off results
|
117 |
+
return $return;
|
118 |
+
}
|
119 |
+
|
120 |
+
/*
|
121 |
+
* For parsing the syslog looking for hddtemp entries
|
122 |
+
* POTENTIALLY BUGGY -- only tested on debian/ubuntu flavored syslogs
|
123 |
+
* Also slow as balls as it parses the entire syslog instead of
|
124 |
+
* using something like tail
|
125 |
+
*/
|
126 |
+
private function parseSysLogData()
|
127 |
+
{
|
128 |
+
$file = '/var/log/syslog';
|
129 |
+
if (!is_file($file) || !is_readable($file)) {
|
130 |
+
return array();
|
131 |
+
}
|
132 |
+
$devices = array();
|
133 |
+
foreach (Common::getLines($file) as $line) {
|
134 |
+
if (preg_match('/\w+\s*\d+ \d{2}:\d{2}:\d{2} \w+ hddtemp\[\d+\]: (.+): (.+): (\d+) ([CF])/i', trim($line), $match) == 1) {
|
135 |
+
// Replace current record of dev with updated temp
|
136 |
+
$devices[$match[1]] = array($match[2], $match[3], $match[4]);
|
137 |
+
}
|
138 |
+
}
|
139 |
+
$return = array();
|
140 |
+
foreach ($devices as $dev => $stat) {
|
141 |
+
$return[] = array(
|
142 |
+
'path' => $dev,
|
143 |
+
'name' => $stat[0],
|
144 |
+
'temp' => $stat[1],
|
145 |
+
'unit' => strtoupper($stat[2]),
|
146 |
+
);
|
147 |
+
}
|
148 |
+
|
149 |
+
return $return;
|
150 |
+
}
|
151 |
+
|
152 |
+
/*
|
153 |
+
* Wrapper function around the private ones here which do the
|
154 |
+
* actual work, and returns temps
|
155 |
+
*/
|
156 |
+
|
157 |
+
// Use supplied mode, and optionally host/port, to get temps and return them
|
158 |
+
public function work()
|
159 |
+
{
|
160 |
+
|
161 |
+
// Deal with differences in mode
|
162 |
+
switch ($this->mode) {
|
163 |
+
|
164 |
+
// Connect to daemon mode
|
165 |
+
case 'daemon':
|
166 |
+
return $this->parseSockData($this->getSock());
|
167 |
+
break;
|
168 |
+
|
169 |
+
// Syslog every n seconds
|
170 |
+
case 'syslog':
|
171 |
+
return $this->parseSysLogData();
|
172 |
+
break;
|
173 |
+
|
174 |
+
// Some other mode
|
175 |
+
default:
|
176 |
+
throw new Exception('Not supported mode');
|
177 |
+
break;
|
178 |
+
}
|
179 |
+
}
|
180 |
+
}
|
lib/Linfo/Parsers/Hwpci.php
ADDED
@@ -0,0 +1,308 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*/
|
19 |
+
namespace Linfo\Parsers;
|
20 |
+
|
21 |
+
use Exception;
|
22 |
+
use Linfo\Meta\Errors;
|
23 |
+
use Linfo\Common;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Deal with pci.ids and usb.ids workings.
|
27 |
+
*
|
28 |
+
* @author Joe Gillotti
|
29 |
+
*/
|
30 |
+
class Hwpci
|
31 |
+
{
|
32 |
+
private $_use_json = false,
|
33 |
+
$_usb_file = '',
|
34 |
+
$_pci_file = '',
|
35 |
+
$_cache_file = '',
|
36 |
+
$_existing_cache_vals = array(),
|
37 |
+
$_usb_entries = array(),
|
38 |
+
$_pci_entries = array(),
|
39 |
+
$_usb_devices = array(),
|
40 |
+
$_pci_devices = array(),
|
41 |
+
$_result = array(),
|
42 |
+
$exec;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Constructor.
|
46 |
+
* @param $usb_file
|
47 |
+
* @param $pci_file
|
48 |
+
*/
|
49 |
+
public function __construct($usb_file, $pci_file)
|
50 |
+
{
|
51 |
+
|
52 |
+
// Localize paths to the ids files
|
53 |
+
$this->_pci_file = $pci_file;
|
54 |
+
$this->_usb_file = $usb_file;
|
55 |
+
|
56 |
+
// Prefer json, but check for it
|
57 |
+
$this->_use_json = function_exists('json_encode') && function_exists('json_decode');
|
58 |
+
|
59 |
+
// Allow the same web root to be used for multiple insances of linfo, across multiple machines using
|
60 |
+
// nfs or whatever, and to have a different cache file for each
|
61 |
+
$sys_id = is_readable('/proc/sys/kernel/hostname') ?
|
62 |
+
'_'.substr(md5(Common::getContents('/proc/sys/kernel/hostname')), 0, 10) : '_x';
|
63 |
+
|
64 |
+
// Path to the cache file
|
65 |
+
$this->_cache_file = dirname(dirname(dirname(__DIR__))).'/cache/ids_cache'.$sys_id.($this->_use_json ? '.json' : '');
|
66 |
+
|
67 |
+
// Load contents of cache
|
68 |
+
$this->_populate_cache();
|
69 |
+
|
70 |
+
// Might need these
|
71 |
+
$this->exec = new CallExt();
|
72 |
+
$this->exec->setSearchPaths(array('/sbin', '/bin', '/usr/bin', '/usr/local/bin', '/usr/sbin'));
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Run the cache file.
|
77 |
+
*/
|
78 |
+
private function _populate_cache()
|
79 |
+
{
|
80 |
+
if ($this->_use_json) {
|
81 |
+
if (is_readable($this->_cache_file) &&
|
82 |
+
($loaded = @json_decode(Common::getContents($this->_cache_file, ''), true)) && is_array($loaded)) {
|
83 |
+
$this->_existing_cache_vals = $loaded;
|
84 |
+
}
|
85 |
+
} else {
|
86 |
+
if (is_readable($this->_cache_file) &&
|
87 |
+
($loaded = @unserialize(Common::getContents($this->_cache_file, false))) && is_array($loaded)) {
|
88 |
+
$this->_existing_cache_vals = $loaded;
|
89 |
+
}
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Get the USB ids from /sys.
|
95 |
+
*/
|
96 |
+
private function _fetchUsbIdsLinux()
|
97 |
+
{
|
98 |
+
foreach ((array) @glob('/sys/bus/usb/devices/*', GLOB_NOSORT) as $path) {
|
99 |
+
|
100 |
+
// First try uevent
|
101 |
+
if (is_readable($path.'/uevent') &&
|
102 |
+
preg_match('/^product=([^\/]+)\/([^\/]+)\/[^$]+$/m', strtolower(Common::getContents($path.'/uevent')), $match)) {
|
103 |
+
$this->_usb_entries[str_pad($match[1], 4, '0', STR_PAD_LEFT)][str_pad($match[2], 4, '0', STR_PAD_LEFT)] = 1;
|
104 |
+
}
|
105 |
+
|
106 |
+
// And next modalias
|
107 |
+
elseif (is_readable($path.'/modalias') &&
|
108 |
+
preg_match('/^usb:v([0-9A-Z]{4})p([0-9A-Z]{4})/', Common::getContents($path.'/modalias'), $match)) {
|
109 |
+
$this->_usb_entries[strtolower($match[1])][strtolower($match[2])] = 1;
|
110 |
+
}
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Get the PCI ids from /sys.
|
116 |
+
*/
|
117 |
+
private function _fetchPciIdsLinux()
|
118 |
+
{
|
119 |
+
foreach ((array) @glob('/sys/bus/pci/devices/*', GLOB_NOSORT) as $path) {
|
120 |
+
|
121 |
+
// See if we can use simple vendor/device files and avoid taking time with regex
|
122 |
+
if (($f_device = Common::getContents($path.'/device', '')) && ($f_vend = Common::getContents($path.'/vendor', '')) &&
|
123 |
+
$f_device != '' && $f_vend != '') {
|
124 |
+
list(, $v_id) = explode('x', $f_vend, 2);
|
125 |
+
list(, $d_id) = explode('x', $f_device, 2);
|
126 |
+
$this->_pci_entries[$v_id][$d_id] = 1;
|
127 |
+
}
|
128 |
+
|
129 |
+
// Try uevent nextly
|
130 |
+
elseif (is_readable($path.'/uevent') &&
|
131 |
+
preg_match('/pci\_(?:subsys_)?id=(\w+):(\w+)/', strtolower(Common::getContents($path.'/uevent')), $match)) {
|
132 |
+
$this->_pci_entries[$match[1]][$match[2]] = 1;
|
133 |
+
}
|
134 |
+
|
135 |
+
// Now for modalias
|
136 |
+
elseif (is_readable($path.'/modalias') &&
|
137 |
+
preg_match('/^pci:v0{4}([0-9A-Z]{4})d0{4}([0-9A-Z]{4})/', Common::getContents($path.'/modalias'), $match)) {
|
138 |
+
$this->_pci_entries[strtolower($match[1])][strtolower($match[2])] = 1;
|
139 |
+
}
|
140 |
+
}
|
141 |
+
}
|
142 |
+
|
143 |
+
/**
|
144 |
+
* Use the pci.ids file to translate the ids to names.
|
145 |
+
*/
|
146 |
+
private function _fetchPciNames()
|
147 |
+
{
|
148 |
+
for ($v = false, $file = @fopen($this->_pci_file, 'r'); $file != false && $contents = fgets($file);) {
|
149 |
+
if (preg_match('/^(\S{4})\s+([^$]+)$/', $contents, $vend_match) == 1) {
|
150 |
+
$v = $vend_match;
|
151 |
+
} elseif (preg_match('/^\s+(\S{4})\s+([^$]+)$/', $contents, $dev_match) == 1) {
|
152 |
+
if ($v && isset($this->_pci_entries[strtolower($v[1])][strtolower($dev_match[1])])) {
|
153 |
+
$this->_pci_devices[$v[1]][$dev_match[1]] = array('vendor' => rtrim($v[2]), 'device' => rtrim($dev_match[2]));
|
154 |
+
}
|
155 |
+
}
|
156 |
+
}
|
157 |
+
$file && @fclose($file);
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Use the usb.ids file to translate the ids to names.
|
162 |
+
*/
|
163 |
+
private function _fetchUsbNames()
|
164 |
+
{
|
165 |
+
for ($v = false, $file = @fopen($this->_usb_file, 'r'); $file != false && $contents = fgets($file);) {
|
166 |
+
if (preg_match('/^(\S{4})\s+([^$]+)$/', $contents, $vend_match) == 1) {
|
167 |
+
$v = $vend_match;
|
168 |
+
} elseif (preg_match('/^\s+(\S{4})\s+([^$]+)$/', $contents, $dev_match) == 1) {
|
169 |
+
if ($v && isset($this->_usb_entries[strtolower($v[1])][strtolower($dev_match[1])])) {
|
170 |
+
$this->_usb_devices[strtolower($v[1])][$dev_match[1]] = array('vendor' => rtrim($v[2]), 'device' => rtrim($dev_match[2]));
|
171 |
+
}
|
172 |
+
}
|
173 |
+
}
|
174 |
+
$file && @fclose($file);
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Decide if the cache file is sufficient enough to not parse the ids files.
|
179 |
+
*/
|
180 |
+
private function _is_cache_worthy()
|
181 |
+
{
|
182 |
+
$pci_good = true;
|
183 |
+
foreach (array_keys($this->_pci_entries) as $vendor) {
|
184 |
+
foreach (array_keys($this->_pci_entries[$vendor]) as $dever) {
|
185 |
+
if (!isset($this->_existing_cache_vals['hw']['pci'][$vendor][$dever])) {
|
186 |
+
$pci_good = false;
|
187 |
+
break 2;
|
188 |
+
}
|
189 |
+
}
|
190 |
+
}
|
191 |
+
$usb_good = true;
|
192 |
+
foreach (array_keys($this->_usb_entries) as $vendor) {
|
193 |
+
foreach (array_keys($this->_usb_entries[$vendor]) as $dever) {
|
194 |
+
if (!isset($this->_existing_cache_vals['hw']['usb'][$vendor][$dever])) {
|
195 |
+
$usb_good = false;
|
196 |
+
break 2;
|
197 |
+
}
|
198 |
+
}
|
199 |
+
}
|
200 |
+
|
201 |
+
return array('pci' => $pci_good, 'usb' => $usb_good);
|
202 |
+
}
|
203 |
+
|
204 |
+
/*
|
205 |
+
* Write cache file with latest info
|
206 |
+
*
|
207 |
+
* @access private
|
208 |
+
*/
|
209 |
+
private function _write_cache()
|
210 |
+
{
|
211 |
+
if (is_writable(dirname(dirname(dirname(__DIR__))).'/cache')) {
|
212 |
+
@file_put_contents($this->_cache_file, $this->_use_json ?
|
213 |
+
json_encode(array(
|
214 |
+
'hw' => array(
|
215 |
+
'pci' => $this->_pci_devices,
|
216 |
+
'usb' => $this->_usb_devices,
|
217 |
+
),
|
218 |
+
))
|
219 |
+
: serialize(array(
|
220 |
+
'hw' => array(
|
221 |
+
'pci' => $this->_pci_devices,
|
222 |
+
'usb' => $this->_usb_devices,
|
223 |
+
),
|
224 |
+
)));
|
225 |
+
}
|
226 |
+
}
|
227 |
+
|
228 |
+
/*
|
229 |
+
* Parse pciconf to get pci ids
|
230 |
+
*
|
231 |
+
* @access private
|
232 |
+
*/
|
233 |
+
private function _fetchPciIdsPciConf()
|
234 |
+
{
|
235 |
+
try {
|
236 |
+
$pciconf = $this->exec->exec('pciconf', '-l');
|
237 |
+
} catch (Exception $e) {
|
238 |
+
Errors::add('Linfo Core', 'Error using `pciconf -l` to get hardware info');
|
239 |
+
|
240 |
+
return;
|
241 |
+
}
|
242 |
+
|
243 |
+
if (preg_match_all('/^.+chip=0x([a-z0-9]{4})([a-z0-9]{4})/m', $pciconf, $devs, PREG_SET_ORDER) == 0) {
|
244 |
+
return;
|
245 |
+
}
|
246 |
+
|
247 |
+
foreach ($devs as $dev) {
|
248 |
+
$this->_pci_entries[$dev[2]][$dev[1]] = 1;
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* Do its goddam job.
|
254 |
+
* @param $os
|
255 |
+
*/
|
256 |
+
public function work($os)
|
257 |
+
{
|
258 |
+
switch ($os) {
|
259 |
+
case 'linux':
|
260 |
+
$this->_fetchPciIdsLinux();
|
261 |
+
$this->_fetchUsbIdsLinux();
|
262 |
+
break;
|
263 |
+
case 'freebsd':
|
264 |
+
case 'dragonfly':
|
265 |
+
$this->_fetchPciIdsPciConf();
|
266 |
+
break;
|
267 |
+
default:
|
268 |
+
return;
|
269 |
+
break;
|
270 |
+
}
|
271 |
+
$worthiness = $this->_is_cache_worthy();
|
272 |
+
$save_cache = false;
|
273 |
+
if (!$worthiness['pci']) {
|
274 |
+
$save_cache = true;
|
275 |
+
$this->_fetchPciNames();
|
276 |
+
} else {
|
277 |
+
$this->_pci_devices = isset($this->_existing_cache_vals['hw']['pci']) ? $this->_existing_cache_vals['hw']['pci'] : array();
|
278 |
+
}
|
279 |
+
if (!$worthiness['usb']) {
|
280 |
+
$save_cache = true;
|
281 |
+
$this->_fetchUsbNames();
|
282 |
+
} else {
|
283 |
+
$this->_usb_devices = isset($this->_existing_cache_vals['hw']['usb']) ? $this->_existing_cache_vals['hw']['usb'] : array();
|
284 |
+
}
|
285 |
+
if ($save_cache) {
|
286 |
+
$this->_write_cache();
|
287 |
+
}
|
288 |
+
}
|
289 |
+
|
290 |
+
/**
|
291 |
+
* Compile and return results.
|
292 |
+
*/
|
293 |
+
public function result()
|
294 |
+
{
|
295 |
+
foreach (array_keys((array) $this->_pci_devices) as $v) {
|
296 |
+
foreach ($this->_pci_devices[$v] as $d) {
|
297 |
+
$this->_result[] = array('vendor' => $d['vendor'], 'device' => $d['device'], 'type' => 'PCI');
|
298 |
+
}
|
299 |
+
}
|
300 |
+
foreach (array_keys((array) $this->_usb_devices) as $v) {
|
301 |
+
foreach ($this->_usb_devices[$v] as $d) {
|
302 |
+
$this->_result[] = array('vendor' => $d['vendor'], 'device' => $d['device'], 'type' => 'USB');
|
303 |
+
}
|
304 |
+
}
|
305 |
+
|
306 |
+
return $this->_result;
|
307 |
+
}
|
308 |
+
}
|
lib/Linfo/Parsers/Mbmon.php
ADDED
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Parsers;
|
22 |
+
|
23 |
+
use Exception;
|
24 |
+
|
25 |
+
/*
|
26 |
+
* Deal with MbMon
|
27 |
+
*/
|
28 |
+
class Mbmon
|
29 |
+
{
|
30 |
+
// Store these
|
31 |
+
protected $host, $port;
|
32 |
+
|
33 |
+
// Default socket connect timeout
|
34 |
+
const timeout = 3;
|
35 |
+
|
36 |
+
// Localize host and port
|
37 |
+
public function setAddress($host, $port = 411)
|
38 |
+
{
|
39 |
+
$this->host = $host;
|
40 |
+
$this->port = $port;
|
41 |
+
}
|
42 |
+
|
43 |
+
// Connect to host/port and get info
|
44 |
+
private function getSock()
|
45 |
+
{
|
46 |
+
// Try connecting
|
47 |
+
if (!($sock = @fsockopen($this->host, $this->port, $errno, $errstr, self::timeout))) {
|
48 |
+
throw new Exception('Error connecting');
|
49 |
+
}
|
50 |
+
|
51 |
+
// Try getting stuff
|
52 |
+
$buffer = '';
|
53 |
+
while ($mid = @fgets($sock)) {
|
54 |
+
$buffer .= $mid;
|
55 |
+
}
|
56 |
+
|
57 |
+
// Quit
|
58 |
+
@fclose($sock);
|
59 |
+
|
60 |
+
// Output:
|
61 |
+
return $buffer;
|
62 |
+
}
|
63 |
+
|
64 |
+
// Parse and return info from daemon socket
|
65 |
+
private function parseSockData($data)
|
66 |
+
{
|
67 |
+
$return = array();
|
68 |
+
|
69 |
+
$lines = (array) explode("\n", trim($data));
|
70 |
+
|
71 |
+
foreach ($lines as $line) {
|
72 |
+
if (preg_match('/(\w+)\s*:\s*([-+]?[\d\.]+)/i', $line, $match) == 1) {
|
73 |
+
$return[] = array(
|
74 |
+
'path' => 'N/A',
|
75 |
+
'name' => $match[1],
|
76 |
+
'temp' => $match[2],
|
77 |
+
'unit' => '', // TODO
|
78 |
+
);
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
return $return;
|
83 |
+
}
|
84 |
+
|
85 |
+
// Do work and return temps
|
86 |
+
public function work()
|
87 |
+
{
|
88 |
+
$sockResult = $this->getSock();
|
89 |
+
$temps = $this->parseSockData($sockResult);
|
90 |
+
|
91 |
+
return $temps;
|
92 |
+
}
|
93 |
+
}
|
lib/Linfo/Parsers/Sensord.php
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Linfo (c) 2010 Joseph Gillotti.
|
5 |
+
*
|
6 |
+
* Linfo is free software: you can redistribute it and/or modify
|
7 |
+
* it under the terms of the GNU General Public License as published by
|
8 |
+
* the Free Software Foundation, either version 3 of the License, or
|
9 |
+
* (at your option) any later version.
|
10 |
+
*
|
11 |
+
* Linfo is distributed in the hope that it will be useful,
|
12 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 |
+
* GNU General Public License for more details.
|
15 |
+
*
|
16 |
+
* You should have received a copy of the GNU General Public License
|
17 |
+
* along with Linfo. If not, see <http://www.gnu.org/licenses/>.
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
|
21 |
+
namespace Linfo\Parsers;
|
22 |
+
|
23 |
+
use Linfo\Common;
|
24 |
+
|
25 |
+
/*
|
26 |
+
* Main class
|
27 |
+
*/
|
28 |
+
|
29 |
+
class Sensord
|
30 |
+
{
|
31 |
+
public function work()
|
32 |
+
{
|
33 |
+
$temps = $this->parseSysLog();
|
34 |
+
|
35 |
+
return $temps;
|
36 |
+
}
|
37 |
+
|
38 |
+
private function parseSysLog()
|
39 |
+
{
|
40 |
+
|
41 |
+
/*
|
42 |
+
* For parsing the syslog looking for sensord entries
|
43 |
+
* POTENTIALLY BUGGY -- only tested on debian/ubuntu flavored syslogs
|
44 |
+
* Also slow as balls as it parses the entire syslog instead of
|
45 |
+
* using something like tail
|
46 |
+
*/
|
47 |
+
$file = '/var/log/syslog';
|
48 |
+
if (!is_file($file) || !is_readable($file)) {
|
49 |
+
return array();
|
50 |
+
}
|
51 |
+
$devices = array();
|
52 |
+
foreach (Common::getLines($file) as $line) {
|
53 |
+
if (preg_match('/\w+\s*\d+ \d{2}:\d{2}:\d{2} \w+ sensord:\s*(.+):\s*(.+)/i', trim($line), $match) == 1) {
|
54 |
+
// Replace current record of dev with updated temp
|
55 |
+
$devices[$match[1]] = $match[2];
|
56 |
+
}
|
57 |
+
}
|
58 |
+
$return = array();
|
59 |
+
foreach ($devices as $dev => $stat) {
|
60 |
+
$return[] = array(
|
61 |
+
'path' => 'N/A', // These likely won't have paths
|
62 |
+
'name' => $dev,
|
63 |
+
'temp' => $stat,
|
64 |
+
'unit' => '', // Usually included in above
|
65 |
+
);
|
66 |
+
}
|
67 |
+
|
68 |
+
return $return;
|
69 |
+
}
|
70 |
+
}
|
package.xml
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package><name>Neklo_Monitor</name><version>1.1.2</version><stability>stable</stability><license>License</license><channel>community</channel><extends></extends><summary>First Release</summary><description>Connector for Magento Monitor Application</description><notes></notes><authors><author><name>NEKLO</name><user>NEKLO</user><email>info@neklo.com</email></author></authors><date>2016-05-03</date><time>6:49:59</time><compatible></compatible><dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies><contents><target name="mage"><dir name="app"><dir name="etc"><dir name="modules"><file name="Neklo_Core.xml" hash="335032ff690c5272626dca9106642680"/><file name="Neklo_Monitor.xml" hash="e93ded9f7368552a843959e953a2bf10"/></dir></dir><dir name="code"><dir name="community"><dir name="Neklo"><dir name="Monitor"><file name="Autoload.php" hash="612c4e0d0a4db5be84c29650655085f6"/><dir name="etc"><file name="adminhtml.xml" hash="897debfe836ca9d58971b44b2232187e"/><file name="config.xml" hash="87d9106b97e2b1b04945ec934165c6e6"/><file name="system.xml" hash="7df39a98e617da03ebcf0ce1539c15c9"/></dir><dir name="controllers"><file name="AuthController.php" hash="c164010a1b5237587ad4edef5bd14b1d"/><file name="CustomerController.php" hash="b1b11923eff5372e95997e8f0a3716ae"/><file name="DashboardController.php" hash="004e0bd94c30ab5e262e193738eb07e4"/><file name="InfoController.php" hash="6bfe3889fa3454d39e9fa39003cc8d20"/><file name="OrderController.php" hash="6500c3870cd0f4e472de7b474530c60b"/><file name="ProductController.php" hash="811e66a117cd0c27d785eac38bde614e"/><dir name="State"><file name="CacheController.php" hash="efb77eeae42be795d7618c620270d0d7"/><file name="IndexerController.php" hash="fa23622aabd0f1d40d4d03de692ae0a2"/></dir><dir name="Var"><file name="LogController.php" hash="b0c9fb0510dd81d3de890d1050d8ac18"/><file name="ReportController.php" hash="5e871965109e78c57252fd221c8e3a9b"/></dir><dir name="Report"><file name="SalesController.php" hash="25e00ff2fd368450d26bc0d4bc11676c"/></dir></dir><dir name="Controller"><file name="Abstract.php" hash="c451f6e756bac9cbc5460c3b65812bb6"/></dir><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Frontend"><file name="Label.php" hash="bd831c28818a1b998dda55df056b28b4"/><file name="Status.php" hash="c94359824abaf9a4e23f00364071979b"/></dir></dir></dir></dir></dir><dir name="sql"><dir name="neklo_monitor_setup"><file name="mysql4-install-1.0.0.php" hash="3a5ee59cda3ec27eca737f515eec4a71"/><file name="mysql4-upgrade-1.0.0-1.1.0.php" hash="bba6559d5040c937d775a76df6611b77"/><file name="mysql4-upgrade-1.1.0-1.1.1.php" hash="f3bbc768ae43e1b45009de02c519dcd7"/><file name="mysql4-upgrade-1.1.1-1.1.2.php" hash="0a03caae9eb41f5f8bcf1a2a8476a13a"/></dir></dir><dir name="Model"><file name="Linfo.php" hash="585d42953c5585d9851dad82c0881410"/><file name="Log.php" hash="7ae437f9f39e62317faa9a2c4b57a3d2"/><file name="Minfo.php" hash="eaab8efeb41a9d2dd073093b869fe440"/><dir name="System"><dir name="Config"><dir name="Source"><dir name="Server"><file name="Type.php" hash="4c86daaa4320ac41b7bdba25f1285056"/></dir></dir><dir name="Backend"><file name="Empty.php" hash="556343bcf15ea8b294a15e77f6662cf8"/><file name="Token.php" hash="7669597367cd26bd848d0d8251feb4b7"/></dir></dir></dir><dir name="Cron"><file name="Abstract.php" hash="7183a30f5a456ee29a3e58f814999e87"/><file name="Server.php" hash="5f3e4ac9492b6e7d658fabeaa0e35e44"/><file name="Store.php" hash="97a0691ceda29f4b52481666b5ab9406"/></dir><dir name="Resource"><dir name="Minfo"><file name="Log.php" hash="54f05d3ced0a1aee770177265695eac9"/><file name="Report.php" hash="acb9c02688a9403a67904fda72c57533"/><dir name="Log"><file name="Collection.php" hash="fc6cbcd4c15227046cb7e85dfdad614d"/></dir><dir name="Report"><file name="Collection.php" hash="a9c74ab52be17dec7c4fafb883bda732"/></dir></dir></dir><dir name="Minfo"><file name="Log.php" hash="d787eeaab4cae6f3d9fe7e696c427014"/><file name="Parser.php" hash="2d7f4603d25d63b0416d338924add4e9"/><file name="Report.php" hash="d97960716a8c152d1614b8d0c752e064"/></dir><dir name="Linfo"><dir name="Os"><file name="Linux.php" hash="e61e9aceb9723b5c8e72200274b7f6ab"/></dir></dir><dir name="Gateway"><file name="Connector.php" hash="3f9667344ccd34dbe4461e71891335fa"/></dir></dir><dir name="Helper"><file name="Config.php" hash="235ca11d4945dfa3341a12ef6968a0cd"/><file name="Country.php" hash="15176ed5b48639f8c50242b126e9dea4"/><file name="Data.php" hash="ebba3993c28262dc258166187cc41aba"/><file name="Date.php" hash="446cc8698132f4f31886332bdc7ac9d6"/><file name="Request.php" hash="dab02c51e8da47f8cb2b57999576ed5c"/><dir name="Request"><file name="Validator.php" hash="16375fad2da02f6732fefd465a388774"/></dir></dir></dir><dir name="Core"><dir name="etc"><file name="adminhtml.xml" hash="68b00ad4118462d74b0c0a7126063462"/><file name="config.xml" hash="3fc06c04d63578d873a4d4145785e4c0"/><file name="system.xml" hash="f9ee62f79b22584cc6180ec5e8049539"/></dir><dir name="controllers"><dir name="Adminhtml"><dir name="Neklo"><dir name="Core"><file name="ContactController.php" hash="fe735a9c3c0ad9c4ecb88edd009059a9"/><file name="NewsletterController.php" hash="b9342c80bf94c29a463251b1c7b02705"/></dir></dir></dir></dir><dir name="Block"><dir name="System"><file name="Contact.php" hash="a0e89ca48de64bb8526c35598f99802b"/><file name="Extension.php" hash="8cd6609bd4f00bf8a8f5913d20e98e65"/><dir name="Contact"><file name="Header.php" hash="a6c4f8dbf002a0d2f6be0ea37445a562"/><file name="Send.php" hash="333d3059033faa826ef3781946676b16"/><dir name="Send"><file name="Button.php" hash="c94e2ae59246a968d7eb2e89e63485c8"/></dir></dir><dir name="Newsletter"><file name="Subscribe.php" hash="1015b8e49758e40c829667e94bb06220"/><dir name="Subscribe"><file name="Button.php" hash="98162d3c3280bdc3da75c90c45fc9500"/></dir></dir><dir name="Extension"><file name="List.php" hash="0006ff459c6b19de9349fa31c8be6b2b"/></dir></dir></dir><dir name="Model"><file name="Feed.php" hash="b5e0d2343b2c9db1f4d86ca0e8b3a922"/><file name="Observer.php" hash="dfc8c917e3f3882d1d99c734831c6e0b"/><dir name="Source"><file name="Reason.php" hash="02eb3c4cfe3433e5a8194862aef636c4"/><dir name="Subscription"><file name="Type.php" hash="616c3f7e7e4ebe3e42e16d54d159d378"/></dir></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="Empty.php" hash="2af2d53c7c56b9ea4a148a2862da224b"/></dir></dir></dir><dir name="Feed"><file name="Extension.php" hash="1ff201b02db7827df350b11c19902fa2"/></dir></dir><dir name="Helper"><file name="Config.php" hash="42eff18ca97b961e1186a790abcb8690"/><file name="Data.php" hash="5492cb13c72b737d85e9009f0f623336"/><file name="Extension.php" hash="c0c987bd848e5270ec31544460438eab"/></dir></dir></dir></dir></dir><dir name="design"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="neklo"><file name="core.xml" hash="8851b2c111c8e0745fb78af2bb57e6a6"/></dir></dir><dir name="template"><dir name="neklo"><dir name="core"><dir name="system"><dir name="contact"><file name="button.phtml" hash="f7b5f21ddb974aa32c888c29f3057d18"/><file name="header.phtml" hash="3c0a401955a9b2bac799aa65b5bf7a81"/></dir><dir name="extension"><file name="list.phtml" hash="29378800cc0a7488badb2698a02220d7"/></dir><dir name="subscribe"><file name="button.phtml" hash="865b84befba4d00e6a1e4de2b989776e"/></dir></dir></dir></dir></dir></dir></dir></dir></dir><dir name="locale"><dir name="en_US"><file name="Neklo_Core.csv" hash="c6abfbb8be878de9c02339e2ecfc4e16"/></dir></dir></dir><dir name="skin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="neklo"><dir name="core"><dir name="images"><file name="ok.gif" hash="a38bc2ee6e116e39c6e2e3013ee50f5e"/><file name="update.gif" hash="8342e11f7739fcfa25134707f0536ed6"/></dir><dir name="css"><file name="style.css" hash="77e35507d6f2e748afc08f11f322120d"/></dir></dir><dir name="monitor"><dir name="css"><file name="styles.css" hash="ab8dc36c3c18794064b0ea8b8c8334fb"/></dir></dir></dir></dir></dir></dir></dir><dir name="lib"><dir name="Linfo"><file name="Common.php" hash="3d55bb51d9de7438c044a012ae50175b"/><file name="Linfo.php" hash="d26c95e093e3c4d5eb456c6c5dfa1579"/><dir name="Output"><file name="Html.php" hash="5ec70c500dda56a561d188dd6e908e49"/><file name="Json.php" hash="4616bcc1ddd3eaa312ef2235e7da1586"/><file name="Ncurses.php" hash="60dbe6e0b2eb00dedccc972271a712fa"/><file name="Output.php" hash="34ef640283d567d93300a2b9c107d276"/><file name="Serialized.php" hash="aa749737127da4bb25c941557d1cfb81"/><file name="Xml.php" hash="7fb392ee95df014c30dd52130e9db45c"/></dir><dir name="Exceptions"><file name="FatalException.php" hash="ac7ae108aa403bc300ba9086410cf0a9"/></dir><dir name="Extension"><file name="Apcaccess.php" hash="8e274bd0036006e064c0cd85fbd732a9"/><file name="Cups.php" hash="25bb7dfe794d5ff211c9862615e2192b"/><file name="Dhcpd3_leases.php" hash="40ffcf2c2ec8618ff8155d197c15bbf1"/><file name="Dnsmasq_dhcpd.php" hash="bc751a49a09f06d8e4492f7ddf432cea"/><file name="Extension.php" hash="d09316ce5276805b702fdc1115b4adc3"/><file name="Ipmi.php" hash="5536abf11a4f06e0b91852f5e17b77bc"/><file name="Libvirt.php" hash="889dcd93239aecb42d6f80b2618e87b1"/><file name="Smb.php" hash="d6d4e995bf54fbdfeec0a51f70faec37"/><file name="Soldat.php" hash="bce89097e6540818f153b2df5b71b0b5"/><file name="Transmission.php" hash="e438b16dc2040d8676c7ba2c1448b6ef"/><file name="Truecrypt.php" hash="f4838a69d9eda202a5d64e8bb8ced36c"/><file name="Utorrent.php" hash="14119c01579d58a01f6489a0865855f7"/></dir><dir name="Lang"><file name="de.php" hash="e313cc8346be39d62607278bd986af23"/><file name="en.php" hash="8ee1b778ed29c64e02e3e1f118016f82"/><file name="fi.php" hash="10d10cd954719a7cee69d5bfbf67889c"/><file name="fr.php" hash="6edcf8ee5251dee98ee39f84fdd52647"/><file name="it.php" hash="d65c5225fa3ef16fd2966137c18e83f4"/><file name="pl.php" hash="2d9b92e225acf0461540d1224a0141f5"/><file name="pt.php" hash="9dd24ee347278edc24f589f6e3f12c58"/><file name="zh.php" hash="2f9ae1cfcf4e5a80127200bf9c9d0b8b"/></dir><dir name="OS"><file name="BSDcommon.php" hash="3b6c83b58e56e0a0eac250f70451be5a"/><file name="Darwin.php" hash="fc45b3648d75c96596d8c7a8559d2d74"/><file name="DragonFly.php" hash="c5ffffe8e6899a0f8352c1fd0f763135"/><file name="FreeBSD.php" hash="f07d480ebda610153b5f6d42d0143f37"/><file name="Linux.php" hash="5e36caf50252aa24fab289ae4239a591"/><file name="Minix.php" hash="22c19a5e45c4715cfcb0db1f42fd5793"/><file name="NetBSD.php" hash="f576ac8083757848bbd179420c182aeb"/><file name="OS.php" hash="49f2a6e9b1e3e56815896f0364049bef"/><file name="OpenBSD.php" hash="cd6b1bd659a30465903ebc913382b223"/><file name="SunOS.php" hash="2cfa3e63e51ca1d8928f2f521be26b3d"/><file name="Unixcommon.php" hash="9981cca8d8805302983ebe20dc2ef04d"/><file name="Windows.php" hash="f73cd25acaf3774da31b922ab3287038"/></dir><dir name="Meta"><file name="Errors.php" hash="e614a650fd523918b010b4297c4c2acd"/><file name="Timer.php" hash="ea244a5a388fa8cc470799cbdd96b866"/></dir><dir name="Parsers"><file name="CallExt.php" hash="6a671a39e8debf7e4c950491f45d8ee4"/><file name="Hddtemp.php" hash="3d0007ab7349702042a88f1e9ca23649"/><file name="Hwpci.php" hash="e26d72856736d83470e82916ba78a3ca"/><file name="Mbmon.php" hash="aa3782625c7542059838e475ccb13326"/><file name="Sensord.php" hash="2be994a2c77ba0a35398a6fc96a4c77a"/></dir></dir></dir></target></contents></package>
|
skin/adminhtml/default/default/neklo/core/css/style.css
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.ovh{
|
2 |
+
overflow: hidden;
|
3 |
+
display: inline-block;
|
4 |
+
font-size: 16px;
|
5 |
+
color: #494848;
|
6 |
+
text-align: center;
|
7 |
+
}
|
8 |
+
.neklo-img{
|
9 |
+
width: 150px;
|
10 |
+
height: 150px;
|
11 |
+
margin: 0 auto;
|
12 |
+
}
|
13 |
+
.neklo-img img{
|
14 |
+
width: 100%;
|
15 |
+
height: 100%;
|
16 |
+
}
|
17 |
+
.neklo-row{
|
18 |
+
margin-bottom: 20px;
|
19 |
+
}
|
20 |
+
.neklo-link, .neklo-link:hover{
|
21 |
+
color: #494848;
|
22 |
+
text-decoration: none;
|
23 |
+
}
|
24 |
+
.neklo-link:hover .neklo-ext-name{
|
25 |
+
text-decoration: underline;
|
26 |
+
}
|
27 |
+
.neklo-ext-name{
|
28 |
+
font-weight: bold;
|
29 |
+
min-height: 36px;
|
30 |
+
margin-bottom: 10px;
|
31 |
+
}
|
32 |
+
.neklo-item{
|
33 |
+
border: 1px solid #ccc;
|
34 |
+
display: inline-block;
|
35 |
+
padding: 20px;
|
36 |
+
margin: 0 20px 20px 0 !important;
|
37 |
+
vertical-align: top;
|
38 |
+
width: 270px;
|
39 |
+
text-align: center;
|
40 |
+
}
|
41 |
+
.neklo_core_message {
|
42 |
+
text-align: center;
|
43 |
+
padding: 5px 0;
|
44 |
+
font-weight: bold;
|
45 |
+
width: 280px;
|
46 |
+
}
|
47 |
+
.neklo_core_message .error {
|
48 |
+
color: #D40707;
|
49 |
+
}
|
50 |
+
.neklo_core_message .success {
|
51 |
+
color: #3d6611;
|
52 |
+
}
|
skin/adminhtml/default/default/neklo/core/images/ok.gif
ADDED
Binary file
|
skin/adminhtml/default/default/neklo/core/images/update.gif
ADDED
Binary file
|
skin/adminhtml/default/default/neklo/monitor/css/styles.css
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.gateway_status.success {
|
2 |
+
color:#008000;
|
3 |
+
}
|
4 |
+
.gateway_status.error {
|
5 |
+
color:#FF0000;
|
6 |
+
}
|