Merge pull request #48 from cyberperspectives/v1.3.3

V1.3.3
This commit is contained in:
Cyber Perspectives, LLC 2018-10-02 10:29:50 -04:00 committed by GitHub
commit 2c0bbb793d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
550 changed files with 44513 additions and 5942 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/.buildpath
/.project
/.settings/

View File

@ -1,3 +1,5 @@
## v1.3.3
## v1.3.2 ## v1.3.2
- Initial GitHub load - Initial GitHub load
- Previous versions loaded on [SourceForge](https://sourceforge.net/projects/sagacity/) - Previous versions loaded on [SourceForge](https://sourceforge.net/projects/sagacity/)

6
Dockerfile Normal file
View File

@ -0,0 +1,6 @@
FROM php:7.2.8-apache-stretch
COPY conf/docker-php.ini /usr/local/etc/php/php.ini
RUN apt update && apt -y install zlib1g-dev mysql-client
RUN docker-php-ext-install mysqli zip
RUN mkdir /var/log/sagacity && chown www-data:www-data /var/log/sagacity
EXPOSE 80

View File

@ -52,7 +52,7 @@ include_once 'config.inc';
include_once 'import.inc'; include_once 'import.inc';
include_once 'helper.inc'; include_once 'helper.inc';
chdir(DOC_ROOT); chdir(dirname(__FILE__));
$db = new db(); $db = new db();
$conn = new mysqli(DB_SERVER, "web", db::decrypt_pwd(), 'sagacity'); $conn = new mysqli(DB_SERVER, "web", db::decrypt_pwd(), 'sagacity');
@ -202,8 +202,10 @@ elseif ($action == 'delete-cat') {
} }
} }
elseif ($action == 'delete-file') { elseif ($action == 'delete-file') {
$file = TMP . "/" . filter_input(INPUT_POST, 'filename', FILTER_SANITIZE_STRING); $file = filter_input(INPUT_POST, 'filename', FILTER_SANITIZE_STRING);
if (file_exists($file)) { $file = realpath($file);
if ($file && preg_match("/^" . preg_quote(TMP, '/') . "/", $file)) {
if (unlink($file)) { if (unlink($file)) {
print header(JSON) . json_encode([ print header(JSON) . json_encode([
'success' => 'Deleted file' 'success' => 'Deleted file'
@ -216,6 +218,7 @@ elseif ($action == 'delete-file') {
} }
} }
else { else {
$file = filter_input(INPUT_POST, 'filename', FILTER_SANITIZE_STRING);
print header(JSON) . json_encode([ print header(JSON) . json_encode([
'error' => "$file does not exist" 'error' => "$file does not exist"
]); ]);
@ -1470,7 +1473,7 @@ function update_stig_control()
* *
* @param int $cat_id * @param int $cat_id
* *
* @return type * @return mixed
*/ */
function get_hosts($cat_id = null) function get_hosts($cat_id = null)
{ {
@ -1490,7 +1493,7 @@ function get_hosts($cat_id = null)
return json_encode(['error' => "Invalid info"]); return json_encode(['error' => "Invalid info"]);
} }
foreach ($tgts as $key => $tgt) { foreach ($tgts as $tgt) {
$chks = $db->get_Target_Checklists($tgt->get_ID()); $chks = $db->get_Target_Checklists($tgt->get_ID());
if ($cat_id) { if ($cat_id) {
$exp_scan_srcs = $db->get_Expected_Category_Sources($ste_cat); $exp_scan_srcs = $db->get_Expected_Category_Sources($ste_cat);
@ -1502,6 +1505,7 @@ function get_hosts($cat_id = null)
$icons = []; $icons = [];
$icon_str = ''; $icon_str = '';
$src_str = ''; $src_str = '';
sort($chks);
foreach ($chks as $chk) { foreach ($chks as $chk) {
if (!in_array($chk->get_Icon(), array_keys($icons))) { if (!in_array($chk->get_Icon(), array_keys($icons))) {
@ -1515,7 +1519,7 @@ function get_hosts($cat_id = null)
$icon_str .= "<img src='/img/checklist_icons/$icon' title='{$data['name']}' class='checklist_image' />"; $icon_str .= "<img src='/img/checklist_icons/$icon' title='{$data['name']}' class='checklist_image' />";
} }
foreach ($scan_srcs as $key => $src) { foreach ($scan_srcs as $src) {
$icon = $src['src']->get_Icon(); $icon = $src['src']->get_Icon();
if($src['scan_error']) { if($src['scan_error']) {
$icon = strtolower($src['src']->get_Name()) . "-failed.png"; $icon = strtolower($src['src']->get_Name()) . "-failed.png";

View File

@ -312,8 +312,11 @@ class checklist
case (preg_match("/AIX/i", $this->name) ? true : false): case (preg_match("/AIX/i", $this->name) ? true : false):
$this->icon = 'AIX.png'; $this->icon = 'AIX.png';
break; break;
case (preg_match("/Application Security|Application Server|Application Layer Gateway/i", $this->name) ? true : false): case (preg_match("/Application Security|Application Layer Gateway/i", $this->name) ? true : false):
$this->icon = 'Application Development.gif'; $this->icon = 'Application Development.gif';
break;
case (preg_match("/Application Server/i", $this->name) ? true : false):
$this->icon = 'Application Server.jpg';
break; break;
case (preg_match("/Active Directory/i", $this->name) ? true : false): case (preg_match("/Active Directory/i", $this->name) ? true : false):
$this->icon = 'Active Directory.png'; $this->icon = 'Active Directory.png';
@ -399,7 +402,7 @@ class checklist
case (preg_match("/SharePoint/i", $this->name) ? true : false): case (preg_match("/SharePoint/i", $this->name) ? true : false):
$this->icon = 'Microsoft Sharepoint.png'; $this->icon = 'Microsoft Sharepoint.png';
break; break;
case (preg_match("/Dot Net/i", $this->name) ? true : false): case (preg_match("/Dot Net|DotNet/i", $this->name) ? true : false):
$this->icon = 'Microsoft .NET.png'; $this->icon = 'Microsoft .NET.png';
break; break;
case (preg_match("/Internet Explorer/i", $this->name) ? true : false): case (preg_match("/Internet Explorer/i", $this->name) ? true : false):
@ -574,6 +577,33 @@ class checklist
break; break;
case (preg_match("/Mainframe /i", $this->name) ? true : false): case (preg_match("/Mainframe /i", $this->name) ? true : false):
$this->icon = 'mainframe.png'; $this->icon = 'mainframe.png';
break;
case (preg_match("/HBSS/i", $this->name) ? true : false):
$this->icon = 'HBSS.jpg';
break;
case (preg_match("/Akamai/i", $this->name) ? true : false):
$this->icon = 'Akamai.png';
break;
case (preg_match("/ArcGIS/i", $this->name) ? true : false):
$this->icon = 'ArcGIS.png';
break;
case (preg_match("/Bromium/i", $this->name) ? true : false):
$this->icon = 'Bromium.png';
break;
case (preg_match("/Forescout/i", $this->name) ? true : false):
$this->icon = 'Forescout.jpg';
break;
case (preg_match("/DB Networks|DBN\-6300/i", $this->name) ? true : false):
$this->icon = 'DB Networks.png';
break;
case (preg_match("/Windows PAW/i", $this->name) ? true : false):
$this->icon = 'Windows PAW.jpg';
break;
case (preg_match("/SecNet/i", $this->name) ? true : false):
$this->icon = 'Harris SecNet.jpg';
break;
case (preg_match("/Desktop App/i", $this->name) ? true : false):
$this->icon = 'Desktop Application.jpg';
break; break;
default: default:
$this->icon = 'Orphan.png'; $this->icon = 'Orphan.png';

View File

@ -104,7 +104,7 @@ class scan
/** /**
* Enum defining the type of script * Enum defining the type of script
* *
* @var file_types * @var string
*/ */
protected $type = null; protected $type = null;
@ -419,7 +419,7 @@ class scan
/** /**
* Getter function for the scan type * Getter function for the scan type
* *
* @return file_types * @return string
*/ */
public function get_Type() public function get_Type()
{ {
@ -429,7 +429,7 @@ class scan
/** /**
* Setter function for the scan type * Setter function for the scan type
* *
* @param file_types $type_in * @param string $type_in
*/ */
public function set_Type($type_in) public function set_Type($type_in)
{ {
@ -512,6 +512,30 @@ class scan
$this->status = $status_in; $this->status = $status_in;
} }
/**
* Method to check if the scan has been terminated by the user
*/
public function isTerminated()
{
global $db, $log;
$db->help->select("scans", ['status'], [
[
'field' => 'id',
'op' => '=',
'value' => $this->id
]
]);
$thread_status = $db->help->execute();
$this->status = $thread_status['status'];
if ($this->status == TERMINIATED) {
rename(realpath(TMP . "/{$this->file_name}"), TMP . "/terminated/{$this->file_name}");
$log->notice("File parsing terminated by user");
die();
}
}
/** /**
* Getter function for the percentage the script has completed * Getter function for the percentage the script has completed
* *

14
conf/docker-php.ini Normal file
View File

@ -0,0 +1,14 @@
memory_limit=1024M
error_reporting=E_ALL
display_errors=On
display_startup_errors=On
html_errors=On
variables_order="GPCS"
request_order="GPCS"
post_max_size=1G
include_path="./:/var/www/html:/var/www/html/classes:/var/www/html/inc"
file_uploads=On
upload_max_filesize=1G
allow_url_fopen=On
allow_url_include=Off
date.timezone=America/Indiana/Indianapolis

View File

@ -15,6 +15,7 @@
* - Nov 14, 2017 - File created * - Nov 14, 2017 - File created
* - May 24, 2018 - Updated constants for 1.3.2 release * - May 24, 2018 - Updated constants for 1.3.2 release
* - Jun 2, 2018 - Added new STIG_EXCLUSIONS constant to permanently exclude STIGs * - Jun 2, 2018 - Added new STIG_EXCLUSIONS constant to permanently exclude STIGs
* - Aug 28, 2018 - Updated constants for 1.3.3 release
*/ */
// @new // @new
/** /**
@ -29,8 +30,8 @@ define('E_DEBUG', 65535);
define('DOC_ROOT', '{DOC_ROOT}'); define('DOC_ROOT', '{DOC_ROOT}');
define('PWD_FILE', '{PWD_FILE}'); define('PWD_FILE', '{PWD_FILE}');
define('TMP', '{TMP_PATH}'); define('TMP', '{TMP_PATH}');
define('VER', '1.3.2'); define('VER', '1.3.3');
define('REL_DATE', '2018-05-31'); define('REL_DATE', '2018-08-31');
define('LOG_LEVEL', '{E_ERROR}'); define('LOG_LEVEL', '{E_ERROR}');
define('LOG_PATH', '{LOG_PATH}'); define('LOG_PATH', '{LOG_PATH}');
define('SALT', '{SALT}'); define('SALT', '{SALT}');
@ -59,6 +60,7 @@ define('NOTIFICATIONS', '{NOTIFICATIONS}');
define('PORT_LIMIT', '{PORT_LIMIT}'); define('PORT_LIMIT', '{PORT_LIMIT}');
define('MAX_RESULTS', '{MAX_RESULTS}'); define('MAX_RESULTS', '{MAX_RESULTS}');
define('ECHECKLIST_FORMAT', '{ECHECKLIST_FORMAT}'); define('ECHECKLIST_FORMAT', '{ECHECKLIST_FORMAT}');
define('UPDATE_FREQ', '{UPDATE_FREQ}');
/** /**
* Company variables * Company variables

View File

@ -80,8 +80,6 @@ $dbh = new db();
$files = glob("*.*"); $files = glob("*.*");
$stack = []; $stack = [];
$running = [];
$time = 0;
$threads = []; $threads = [];
foreach ($files as $file) { foreach ($files as $file) {

View File

@ -83,7 +83,6 @@ if (isset($cmd['d']) && $cmd['d']) {
chdir($path); chdir($path);
$db = new db(); $db = new db();
$stack = [];
$zip_files = glob("*.zip"); $zip_files = glob("*.zip");
$zip = new ZipArchive(); $zip = new ZipArchive();
@ -155,7 +154,7 @@ foreach ($xml_files as $key => $file) {
continue; continue;
} }
elseif(!empty(STIG_EXCLUSIONS) && preg_match("/" . STIG_EXCLUSIONS . "/i", $file)) { elseif(!empty(STIG_EXCLUSIONS) && preg_match("/" . STIG_EXCLUSIONS . "/i", $file)) {
unlink($file); unlink(TMP . "/stigs/xml/$file");
$log->debug("Skipping $file due to matching STIG exclusion"); $log->debug("Skipping $file due to matching STIG exclusion");
continue; continue;
} }
@ -235,7 +234,7 @@ if (isset($cmd['delete'])) {
*/ */
function directory_crawl($files) function directory_crawl($files)
{ {
global $zip; global $zip, $log;
foreach ($files as $file) { foreach ($files as $file) {
if (preg_match('/\.zip/', $file)) { if (preg_match('/\.zip/', $file)) {

View File

@ -40,7 +40,8 @@ $db_step = [
'sample-data' => ['filter' => FILTER_VALIDATE_BOOLEAN], 'sample-data' => ['filter' => FILTER_VALIDATE_BOOLEAN],
'cpe' => ['filter' => FILTER_VALIDATE_BOOLEAN], 'cpe' => ['filter' => FILTER_VALIDATE_BOOLEAN],
'cve' => ['filter' => FILTER_VALIDATE_BOOLEAN], 'cve' => ['filter' => FILTER_VALIDATE_BOOLEAN],
'stig' => ['filter' => FILTER_VALIDATE_BOOLEAN] 'stig' => ['filter' => FILTER_VALIDATE_BOOLEAN],
'update-freq' => ['filter' => FILTER_VALIDATE_INT, 'flag' => FILTER_NULL_ON_FAILURE]
]; ];
$company_step = [ $company_step = [
'company' => $params, 'company' => $params,
@ -101,16 +102,26 @@ function save_Database($params)
$php = null; $php = null;
$mysql = null; $mysql = null;
if (strtolower(substr(PHP_OS, 0, 3)) == 'lin') { if (strtolower(substr(PHP_OS, 0, 3)) == 'lin') {
$res = [];
exec("which php", $res);
if (file_exists('/bin/php')) { if (file_exists('/bin/php')) {
$php = realpath("/bin/php"); $php = realpath("/bin/php");
} }
elseif (is_array($res) && isset($res[0]) && file_exists($res[0])) {
$php = realpath($res[0]);
}
else { else {
die(json_encode(['error' => 'Cannot find the PHP executable'])); die(json_encode(['error' => 'Cannot find the PHP executable']));
} }
$res = [];
exec("which mysql", $res);
if (file_exists('/bin/mysql')) { if (file_exists('/bin/mysql')) {
$mysql = realpath('/bin/mysql'); $mysql = realpath('/bin/mysql');
} }
elseif (is_array($res) && isset($res[0]) && file_exists($res[0])) {
$mysql = realpath($res[0]);
}
else { else {
die(json_encode(['error' => 'Cannot find the MySQL executable'])); die(json_encode(['error' => 'Cannot find the MySQL executable']));
} }
@ -138,6 +149,7 @@ function save_Database($params)
my_str_replace("{PHP_CONF}", realpath(php_ini_loaded_file()), $config); my_str_replace("{PHP_CONF}", realpath(php_ini_loaded_file()), $config);
my_str_replace("{DB_SERVER}", $params['db-server'], $config); my_str_replace("{DB_SERVER}", $params['db-server'], $config);
my_str_replace("{DB_BIN}", $mysql, $config); my_str_replace("{DB_BIN}", $mysql, $config);
my_str_replace("'{UPDATE_FREQ}'", $params['update-freq'], $config);
my_str_replace("@new", "@step1", $config); my_str_replace("@new", "@step1", $config);
if (!file_exists($params['tmp-path'])) { if (!file_exists($params['tmp-path'])) {

View File

@ -126,19 +126,7 @@ foreach ($objSS->getWorksheetIterator() as $wksht) {
continue; continue;
} }
$db->help->select("scans", ['status'], [ $scan->isTerminated();
[
'field' => 'id',
'op' => '=',
'value' => $scan->get_ID()
]
]);
$thread_status = $db->help->execute();
if ($thread_status['status'] == 'TERMINATED') {
unset($objSS);
rename(realpath(TMP . "/{$scan->get_File_Name()}"), TMP . "/terminated/{$scan->get_File_Name()}");
$log->notice("File parsing terminated by user");
}
$log->notice("Reading from {$wksht->getTitle()}"); $log->notice("Reading from {$wksht->getTitle()}");
@ -163,96 +151,89 @@ foreach ($objSS->getWorksheetIterator() as $wksht) {
'notes' => 9, 'notes' => 9,
'check_contents' => 10 'check_contents' => 10
]; ];
$finding_count = [];
$tgts = []; $tgts = [];
$short_title_col = Coordinate::stringFromColumnIndex($idx['short_title']); $short_title_col = Coordinate::stringFromColumnIndex($idx['short_title']);
$row_count = $wksht->getHighestDataRow() - 10; $row_count = $highestRow = $wksht->getHighestDataRow() - 10;
$highestCol = $wksht->getHighestDataColumn(10);
foreach ($wksht->getRowIterator(10) as $row) { for ($col = 'F' ; $col != $highestCol ; $col++) {
foreach ($row->getCellIterator() as $cell) { $cell = $wksht->getCell($col . '10');
$ip = null; $log->debug("Checking column: {$cell->getColumn()} {$cell->getCoordinate()}");
$db->help->select("scans", ['status'], [ $ip = null;
[
'field' => 'id',
'op' => '=',
'value' => $scan->get_ID()
]
]);
$thread_status = $db->help->execute();
if ($thread_status['status'] == 'TERMINATED') {
unset($objSS);
rename(realpath(TMP . "/{$scan->get_File_Name()}"), TMP . "/terminated/{$scan->get_File_Name()}");
die($log->notice("File parsing terminated by user"));
}
if ($cell->getColumn() > $short_title_col && !preg_match('/Overall/i', $cell->getValue())) { $scan->isTerminated();
if (preg_match('/status/i', $cell->getValue())) {
$log->error("Invalid host name ('status') in {$wksht->getTitle()}");
break;
}
if ($tgt_id = $db->check_Target($conf['ste'], $cell->getValue())) { if (!preg_match('/Overall/i', $cell->getValue())) {
$tgt = $db->get_Target_Details($conf['ste'], $tgt_id); if (preg_match('/status/i', $cell->getValue())) {
if (is_array($tgt) && count($tgt) && isset($tgt[0]) && is_a($tgt[0], 'target')) { $log->error("Invalid host name ('status') in {$wksht->getTitle()}");
$tgt = $tgt[0];
}
else {
$log->error("Could not find host {$cell->getValue()}");
}
}
else {
$tgt = new target($cell->getValue());
$tgt->set_OS_ID($gen_os->get_ID());
$tgt->set_STE_ID($conf['ste']);
$tgt->set_Location($conf['location']);
$tgt->set_Notes('New Target');
if (preg_match('/((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}/', $cell->getValue())) {
$ip = $cell->getValue();
$int = new interfaces(null, null, null, $ip, null, null, null, null);
$tgt->interfaces["{$ip}"] = $int;
}
$tgt->set_ID($db->save_Target($tgt));
}
$tgts[] = $tgt;
$hl = new host_list();
$hl->setFindingCount($row_count);
$hl->setTargetId($tgt->get_ID());
$hl->setTargetName($tgt->get_Name());
if ($ip) {
$hl->setTargetIp($ip);
}
elseif (is_array($tgt->interfaces) && count($tgt->interfaces)) {
foreach ($tgt->interfaces as $int) {
if (!in_array($int->get_IPv4(), ['0.0.0.0', '127.0.0.1'])) {
$ip = $int->get_IPv4();
break;
}
}
$hl->setTargetIp($ip);
}
$scan->add_Target_to_Host_List($hl);
}
if (preg_match('/Overall/i', $cell->getValue())) {
break; break;
} }
if ($tgt_id = $db->check_Target($conf['ste'], $cell->getValue())) {
$log->debug("Found host for {$cell->getValue()}");
$tgt = $db->get_Target_Details($conf['ste'], $tgt_id);
if (is_array($tgt) && count($tgt) && isset($tgt[0]) && is_a($tgt[0], 'target')) {
$tgt = $tgt[0];
}
else {
$log->error("Could not find host {$cell->getValue()}");
}
}
else {
$log->debug("Creating new target {$cell->getValue()}");
$tgt = new target($cell->getValue());
$tgt->set_OS_ID($gen_os->get_ID());
$tgt->set_STE_ID($conf['ste']);
$tgt->set_Location($conf['location']);
$tgt->set_Notes('New Target');
if (preg_match('/((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}/', $cell->getValue())) {
$ip = $cell->getValue();
$int = new interfaces(null, null, null, $ip, null, null, null, null);
$tgt->interfaces["{$ip}"] = $int;
}
$tgt->set_ID($db->save_Target($tgt));
}
$tgts[] = $tgt;
$log->debug("Adding new target to host list", ['row_count' => $row_count, 'tgt_id' => $tgt->get_ID(), 'tgt_name' => $tgt->get_Name()]);
$hl = new host_list();
$hl->setFindingCount($row_count);
$hl->setTargetId($tgt->get_ID());
$hl->setTargetName($tgt->get_Name());
if ($ip) {
$hl->setTargetIp($ip);
}
elseif (is_array($tgt->interfaces) && count($tgt->interfaces)) {
foreach ($tgt->interfaces as $int) {
if (!in_array($int->get_IPv4(), ['0.0.0.0', '127.0.0.1'])) {
$ip = $int->get_IPv4();
break;
}
}
$hl->setTargetIp($ip);
}
$scan->add_Target_to_Host_List($hl);
}
if (preg_match('/Overall/i', $cell->getValue())) {
$log->debug("Found overall: {$cell->getColumn()}");
break;
} }
break;
} }
$db->update_Running_Scan($base_name, ['name' => 'host_count', 'value' => count($tgts)]); $db->update_Running_Scan($base_name, ['name' => 'host_count', 'value' => count($tgts)]);
// increment the column indexes for notes, check contents, and missing PDI // increment the column indexes for notes, check contents, and missing PDI
if (is_array($tgts) && count($tgts) > 1) { if (is_array($tgts) && count($tgts) > 1) {
$idx['overall'] += count($tgts); $increase = count($tgts) - 1;
$idx['consistent'] += count($tgts); $idx['overall'] += $increase;
$idx['notes'] += count($tgts); $idx['consistent'] += $increase;
$idx['check_contents'] += count($tgts); $idx['notes'] += $increase;
$idx['check_contents'] += $increase;
} }
elseif (empty($tgts)) { elseif (empty($tgts)) {
$log->warning("Failed to identify targets in worksheet {$wksht->getTitle()}"); $log->warning("Failed to identify targets in worksheet {$wksht->getTitle()}");
@ -266,8 +247,21 @@ foreach ($objSS->getWorksheetIterator() as $wksht) {
$title_col = Coordinate::stringFromColumnIndex($idx['short_title']); $title_col = Coordinate::stringFromColumnIndex($idx['short_title']);
$notes_col = Coordinate::stringFromColumnIndex($idx['notes']); $notes_col = Coordinate::stringFromColumnIndex($idx['notes']);
$log->debug("Columns", [
'stig_col' => $stig_col,
'vms_col' => $vms_col,
'cat_col' => $cat_col,
'ia_col' => $ia_col,
'title_col' => $title_col,
'overall_col' => Coordinate::stringFromColumnIndex($idx['overall']),
'consistent_col' => Coordinate::stringFromColumnIndex($idx['consistent']),
'check_contents_col' => Coordinate::stringFromColumnIndex($idx['check_contents']),
'notes_col' => $notes_col
]);
$new_findings = []; $new_findings = [];
$updated_findings = []; $updated_findings = [];
$row_count = 0;
foreach ($wksht->getRowIterator(11) as $row) { foreach ($wksht->getRowIterator(11) as $row) {
$stig_id = $wksht->getCell("{$stig_col}{$row->getRowIndex()}")->getValue(); $stig_id = $wksht->getCell("{$stig_col}{$row->getRowIndex()}")->getValue();
@ -276,6 +270,9 @@ foreach ($objSS->getWorksheetIterator() as $wksht) {
$notes = $wksht->getCell("{$notes_col}{$row->getRowIndex()}")->getValue(); $notes = $wksht->getCell("{$notes_col}{$row->getRowIndex()}")->getValue();
$stig = $db->get_Stig($stig_id); $stig = $db->get_Stig($stig_id);
if($row->getRowIndex() % 10 == 0) {
$scan->isTerminated();
}
if (is_array($stig) && count($stig) && isset($stig[0]) && is_a($stig[0], 'stig')) { if (is_array($stig) && count($stig) && isset($stig[0]) && is_a($stig[0], 'stig')) {
$stig = $stig[0]; $stig = $stig[0];
@ -302,6 +299,7 @@ foreach ($objSS->getWorksheetIterator() as $wksht) {
$finding = $db->get_Finding($tgt, $stig); $finding = $db->get_Finding($tgt, $stig);
if (is_array($finding) && count($finding) && isset($finding[0]) && is_a($finding[0], 'finding')) { if (is_array($finding) && count($finding) && isset($finding[0]) && is_a($finding[0], 'finding')) {
/** @var finding $tmp */
$tmp = $finding[0]; $tmp = $finding[0];
if(preg_match("/Not a Finding|Not Applicable/i", $status)) { if(preg_match("/Not a Finding|Not Applicable/i", $status)) {
@ -327,11 +325,20 @@ foreach ($objSS->getWorksheetIterator() as $wksht) {
$x++; $x++;
} }
if (PHP_SAPI == 'cli') { $row_count++;
print "\r" . sprintf("%.2f%%", (($row->getRowIndex() - 10) / $row_count) * 100);
if($row_count % 100 == 0) {
if(!$db->add_Findings_By_Target($updated_findings, $new_findings)) {
die(print_r(debug_backtrace(), true));
} else {
$updated_findings = [];
$new_findings = [];
}
} }
else {
$db->update_Running_Scan($base_name, ['name' => 'perc_comp', 'value' => (($row->getRowIndex() - 10) / $row_count) * 100]); $db->update_Running_Scan($base_name, ['name' => 'perc_comp', 'value' => (($row->getRowIndex() - 10) / $highestRow) * 100]);
if (PHP_SAPI == 'cli') {
print "\r" . sprintf("%.2f%%", (($row->getRowIndex() - 10) / $highestRow) * 100);
} }
} }

View File

@ -582,7 +582,8 @@ class nessus_parser extends scan_xml_parser
$this->log->script_log("Skipping tcp6 ports because there are " . count($netstat_keys) . " listening", E_DEBUG); $this->log->script_log("Skipping tcp6 ports because there are " . count($netstat_keys) . " listening", E_DEBUG);
} }
$this->tgt->set_ID($this->db->save_Target($this->tgt)); $this->tgt->set_PP_Flag(true);
$this->tgt->set_ID($this->db->save_Target($this->tgt, false));
$dt = DateTime::createFromFormat("D M d H:i:s Y", $this->tag["HOST_START"]); $dt = DateTime::createFromFormat("D M d H:i:s Y", $this->tag["HOST_START"]);
if ($dt < $this->scan->get_File_DateTime()) { if ($dt < $this->scan->get_File_DateTime()) {
@ -1332,7 +1333,8 @@ class nessus_parser extends scan_xml_parser
{ {
$this->log->script_log("ReportHost_end-START: {$this->tgt->get_Name()}"); $this->log->script_log("ReportHost_end-START: {$this->tgt->get_Name()}");
// save findings // save findings
$this->db->save_Target($this->tgt); $this->tgt->set_PP_flag(true);
$this->db->save_Target($this->tgt, false);
$this->log->script_log("Added finding counts: " . count($this->new_findings) . " for target " . $this->tgt->get_Name()); $this->log->script_log("Added finding counts: " . count($this->new_findings) . " for target " . $this->tgt->get_Name());
$this->log->script_log("Updated finding counts: " . count($this->updated_findings) . " for target " . $this->tgt->get_Name()); $this->log->script_log("Updated finding counts: " . count($this->updated_findings) . " for target " . $this->tgt->get_Name());
@ -1363,6 +1365,8 @@ class nessus_parser extends scan_xml_parser
{ {
$this->log->script_log("Saving host list"); $this->log->script_log("Saving host list");
$this->db->update_Scan_Host_List($this->scan); $this->db->update_Scan_Host_List($this->scan);
$this->db->post_Processing();
} }
} }

View File

@ -92,6 +92,7 @@ foreach ($lines as $line_num => $line) {
continue; continue;
} # skip blank lines } # skip blank lines
$line = trim($line, "\t\n\r"); # chomp would be nice... $line = trim($line, "\t\n\r"); # chomp would be nice...
$matches = [];
if (!isset($filetype)) { if (!isset($filetype)) {
if (preg_match('/Starting|\-oN/', $line)) { if (preg_match('/Starting|\-oN/', $line)) {
$filetype = "text"; $filetype = "text";
@ -242,8 +243,6 @@ if ($filetype == "xml") {
$target[$ip]['description'] = $vendor; $target[$ip]['description'] = $vendor;
# Iterate through ports # Iterate through ports
$ports = getValue($xml, "ports/port", $host, true); $ports = getValue($xml, "ports/port", $host, true);
$tcp_ports = [];
$udp_ports = [];
foreach ($ports as $portxml) { foreach ($ports as $portxml) {
$portid = $portxml->getAttribute("portid"); $portid = $portxml->getAttribute("portid");
$proto = $portxml->getAttribute("protocol"); $proto = $portxml->getAttribute("protocol");
@ -284,6 +283,7 @@ if ($filetype == "xml") {
$db->update_Running_Scan($base_name, ['name' => 'host_count', 'value' => count($target)]); $db->update_Running_Scan($base_name, ['name' => 'host_count', 'value' => count($target)]);
$count = 0; $count = 0;
$tgt_ip = null; $tgt_ip = null;
foreach ($target as $ip => $tgt) { foreach ($target as $ip => $tgt) {
# get target ID # get target ID
$tgt_id = 0; $tgt_id = 0;
@ -302,6 +302,7 @@ foreach ($target as $ip => $tgt) {
$tgt_obj->set_STE_ID($conf['ste']); $tgt_obj->set_STE_ID($conf['ste']);
//$tgt_obj->set_Notes("New target found by NMap"); //$tgt_obj->set_Notes("New target found by NMap");
$tgt_obj->set_OS_ID($sw->get_ID()); $tgt_obj->set_OS_ID($sw->get_ID());
$tgt_obj->set_PP_Flag(true);
if ($sw->get_Shortened_SW_String()) { if ($sw->get_Shortened_SW_String()) {
$tgt_obj->set_OS_String($sw->get_Shortened_SW_String()); $tgt_obj->set_OS_String($sw->get_Shortened_SW_String());
} }
@ -344,10 +345,11 @@ foreach ($target as $ip => $tgt) {
} }
} }
$tgt_obj->set_ID($tgt_id = $db->save_Target($tgt_obj)); $tgt_obj->set_ID($tgt_id = $db->save_Target($tgt_obj, false));
} }
else { #Update else { #Update
$db_tgt = $db->get_Target_Details($conf['ste'], $tgt_id)[0]; $db_tgt = $db->get_Target_Details($conf['ste'], $tgt_id)[0];
$db_tgt->set_PP_Flag(true);
if (isset($tgt['tcp'])) { if (isset($tgt['tcp'])) {
foreach ($tgt['tcp'] as $port_num => $port) { foreach ($tgt['tcp'] as $port_num => $port) {
@ -388,7 +390,7 @@ foreach ($target as $ip => $tgt) {
} }
} }
$db->save_Target($db_tgt); $db->save_Target($db_tgt, false);
} }
$count++; $count++;
@ -406,6 +408,7 @@ foreach ($target as $ip => $tgt) {
$db->update_Running_Scan($base_name, ['name' => 'last_host', 'value' => $db_tgt->get_Name()]); $db->update_Running_Scan($base_name, ['name' => 'last_host', 'value' => $db_tgt->get_Name()]);
} }
$db->post_Processing();
$db->update_Scan_Host_List($scan); $db->update_Scan_Host_List($scan);
$db->update_Running_Scan($base_name, ['name' => 'perc_comp', 'value' => 100, 'complete' => 1]); $db->update_Running_Scan($base_name, ['name' => 'perc_comp', 'value' => 100, 'complete' => 1]);
if (!isset($cmd['debug'])) { if (!isset($cmd['debug'])) {

View File

@ -65,7 +65,6 @@ print "Currently " . count($existing_cves) . " in DB" . PHP_EOL . "Parsing: " .
$db_cpes = []; $db_cpes = [];
$new_cves = []; $new_cves = [];
$new_cve_refs = []; $new_cve_refs = [];
$new_cve_web = [];
$sw_rows = []; $sw_rows = [];
$new = 0; $new = 0;
$existing = 0; $existing = 0;
@ -82,9 +81,6 @@ $cve_fields = [
$ref_fields = [ $ref_fields = [
'cve_seq', 'source', 'url', 'val' 'cve_seq', 'source', 'url', 'val'
]; ];
$web_fields = [
'cve_id', 'xml'
];
foreach ($json->CVE_Items as $cve) { foreach ($json->CVE_Items as $cve) {
if (!isset($existing_cves["{$cve->cve->CVE_data_meta->ID}"])) { if (!isset($existing_cves["{$cve->cve->CVE_data_meta->ID}"])) {
@ -168,18 +164,9 @@ foreach ($json->CVE_Items as $cve) {
$new_cves = []; $new_cves = [];
$new_cve_refs = []; $new_cve_refs = [];
$new_cve_web = [];
$sw_rows = []; $sw_rows = [];
print "\t" . ($existing + $new) . " completed" . PHP_EOL; print "\t" . ($existing + $new) . " completed" . PHP_EOL;
$db->help->update("settings", ['meta_value' => number_format((($existing + $new) / count($json->CVE_Items)) * 100, 2)], [
[
'field' => 'meta_key',
'value' => 'nvd-cve-progress'
]
]);
$db->help->execute();
} }
} }

View File

@ -48,7 +48,8 @@
* - Apr 29, 2018 - Added extract parameter to only extract nasl archive file, fixed a couple bugs * - Apr 29, 2018 - Added extract parameter to only extract nasl archive file, fixed a couple bugs
* - May 10, 2018 - Removed ping of cve.mitre.org, and added 'po' and 'do' parameters for NVD CVE * - May 10, 2018 - Removed ping of cve.mitre.org, and added 'po' and 'do' parameters for NVD CVE
* - Jun 5, 2018 - Fixed a couple setting updates * - Jun 5, 2018 - Fixed a couple setting updates
*/ * - Sep 18, 2018 - Jeff - Added --sunset switch for Installing Sunset STIGs from https://iase.disa.mil/stigs/sunset/Pages/index.aspx
*/
include_once 'config.inc'; include_once 'config.inc';
include_once 'helper.inc'; include_once 'helper.inc';
include_once 'error.inc'; include_once 'error.inc';
@ -61,11 +62,10 @@ use Monolog\Handler\StreamHandler;
use Monolog\Formatter\LineFormatter; use Monolog\Formatter\LineFormatter;
$current_date = new DateTime(); $current_date = new DateTime();
$total_time = null; $total_complete = 0;
$total_diff = 0; $threads = [];
$summary_stats = [];
$cmd = getopt("h::u::p::", ['cpe::', 'cce::', 'cve::', 'nvd::', 'nasl::', 'stig::', 'do::', 'po::', 'help::', 'debug::', 'extract::', 'exclude::']); $cmd = getopt("h::u::p::", ['cpe::', 'cce::', 'cve::', 'nvd::', 'nasl::', 'stig::', 'sunset::', 'do::', 'po::', 'help::', 'debug::', 'extract::', 'exclude::']);
$db = new db(); $db = new db();
$diff = new DateTimeDiff(); $diff = new DateTimeDiff();
@ -94,7 +94,7 @@ $log->pushHandler(new StreamHandler(LOG_PATH . "/update_db.log", $log_level));
$log->pushHandler($stream); $log->pushHandler($stream);
if (isset($cmd['h'], $cmd['help']) || if (isset($cmd['h'], $cmd['help']) ||
(!isset($cmd['cpe']) && !isset($cmd['cve']) && !isset($cmd['nasl']) && !isset($cmd['stig']) && !isset($cmd['nvd']))) { (!isset($cmd['cpe']) && !isset($cmd['cve']) && !isset($cmd['nasl']) && !isset($cmd['stig']) && !isset($cmd['sunset']) && !isset($cmd['nvd']))) {
die(usage()); die(usage());
} }
@ -361,9 +361,10 @@ if (isset($cmd['nvd'])) {
$load_date = new DateTime($db->get_Settings("nvd-cve-load-date")); $load_date = new DateTime($db->get_Settings("nvd-cve-load-date"));
if ($load_date < $too_old) { if ($load_date < $too_old) {
// More than 7 days old so have to do a full load // More than 7 days old so have to do a full load
foreach ($nvd_years as $yr) { foreach ($nvd_years as $x => $yr) {
$db->set_Setting('nvd-year', $yr); $db->set_Setting('nvd-year', $yr);
download_file("https://static.nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-{$yr}.json.zip", TMP . "/nvd/nvdcve-{$yr}.json.zip", $db->help, 'nvd-cve-dl-progress'); $db->set_Setting('nvd-cve-dl-progress', (($x + 1) / count($nvd_years)) * 100);
download_file("https://static.nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-{$yr}.json.zip", TMP . "/nvd/nvdcve-{$yr}.json.zip");
$zip = new ZipArchive(); $zip = new ZipArchive();
$zip->open(TMP . "/nvd/nvdcve-{$yr}.json.zip"); $zip->open(TMP . "/nvd/nvdcve-{$yr}.json.zip");
$zip->extractTo(TMP . "/nvd"); $zip->extractTo(TMP . "/nvd");
@ -392,7 +393,7 @@ if (isset($cmd['nvd'])) {
chdir(DOC_ROOT . "/exec"); chdir(DOC_ROOT . "/exec");
if (isset($cmd['po']) || !isset($cmd['do'])) { if (isset($cmd['po']) || !isset($cmd['do'])) {
$json_files = glob(TMP . "/nvd/*.json"); $json_files = glob(TMP . "/nvd/*.json");
foreach ($json_files as $j) { foreach ($json_files as $x => $j) {
$match = []; $match = [];
if (preg_match("/(\d{4}|recent|modified)/", basename($j), $match)) { if (preg_match("/(\d{4}|recent|modified)/", basename($j), $match)) {
$db->set_Setting('nvd-year', $match[1]); $db->set_Setting('nvd-year', $match[1]);
@ -407,6 +408,7 @@ if (isset($cmd['nvd'])) {
$log->debug("Running NVD CVE parsing script on file: $j"); $log->debug("Running NVD CVE parsing script on file: $j");
passthru($script); passthru($script);
$db->set_Setting('nvd-cve-progress', (($x + 1) / count($json_files)) * 100);
} }
} }
@ -458,6 +460,7 @@ if (isset($cmd['nasl'])) {
'nasl-progress' => 0, 'nasl-progress' => 0,
'nasl-count' => 0 'nasl-count' => 0
]); ]);
$count = 0;
// Capture start time for performance monitoring // Capture start time for performance monitoring
$diff->resetClock(); $diff->resetClock();
@ -700,6 +703,75 @@ if (isset($cmd['stig'])) {
sleep(3); sleep(3);
} }
/**
* Update Sunset STIG library from DISA content
*/
if (isset($cmd['sunset'])) {
$db->set_Setting_Array([
'stig-dl-progress' => 0,
'stig-progress' => 0,
'stig-count' => 0
]);
$path = TMP . "/stigs/zip";
check_path($path);
$sunset_array = [];
$diff->resetClock();
print "Started Sunset STIG ingestion ({$diff->getStartClockTime()})" . PHP_EOL;
$sunset_url="https://iase.disa.mil/stigs/Lists/Sunset%20Master%20List/FinalView.aspx";
if (ping("disa.mil") && !isset($cmd['po'])) {
$log->debug("Checking for $sunset_url");
if ($found = url_exists($sunset_url)) {
$contents=file_get_contents($sunset_url);
}
if (!$found) {
$log->debug("Unable to download $sunset_url, aborting Sunset");
die("Unable to open $sunset_url, aborting Sunset");
}
preg_match_all("/a href=\"([^ ]+zip\/U_[^ ]+STIG\.zip)/", $contents, $sunset_array);
foreach($sunset_array[1] as $url) {
$sunset_fname = basename($url);
download_file($url, "{$path}/$sunset_fname");
}
}
if (!isset($cmd['do']) || isset($cmd['po'])) {
$stig_files = array_merge(
glob("{$path}/*.zip"), glob("{$path}/*.xml"),
glob(TMP . "/*.zip"), glob(TMP . "/*.xml"), glob(TMP . "/stigs/xml/*.xml")
);
if (!count($stig_files)) {
die("Could not find any other zip files in " . realpath(TMP));
}
$script = realpath(defined('PHP_BIN') ? PHP_BIN : PHP) .
" -c " . realpath(PHP_CONF) .
" -f " . realpath(DOC_ROOT . "/exec/background_stigs.php") . " --" .
(isset($cmd['exclude']) && $cmd['exclude'] ? " --exclude=\"{$cmd['exclude']}\"" : "") .
" --delete";
$log->debug("Script to run $script");
passthru($script);
}
$db->help->select_count("sagacity.stigs");
$stig_count = $db->help->execute();
$db->set_Setting("stig-count", $stig_count);
$diff->stopClock();
print PHP_EOL . "Finished at {$diff->getEndClockTime()}" . PHP_EOL .
"Total Time: {$diff->getDiffString()}" . PHP_EOL;
sleep(3);
}
if (is_a($diff->getTotalDiff(), 'DateInterval')) { if (is_a($diff->getTotalDiff(), 'DateInterval')) {
print "Total Script Time: {$diff->getTotalDiffString()}" . PHP_EOL; print "Total Script Time: {$diff->getTotalDiffString()}" . PHP_EOL;
} }
@ -721,6 +793,7 @@ Usage: php update_db.php [--cpe] [--cve] [--nvd] [--nasl] [--stig] [-u={URL}] [-
--nasl To download OpenVAS NVT library and update NASL files --nasl To download OpenVAS NVT library and update NASL files
You can also extract *.nasl files from the Nessus library to $tmp/nessus_plugins and it will include these in the update You can also extract *.nasl files from the Nessus library to $tmp/nessus_plugins and it will include these in the update
--stig To download and update the STIG library --stig To download and update the STIG library
--sunset To download and update the STIG library with the STIGs DISA has archived
--do To download the files only...do not call the parsers will overwrite any existing files --do To download the files only...do not call the parsers will overwrite any existing files
--po To parse the downloaded files only, do not download --po To parse the downloaded files only, do not download

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -91,7 +91,7 @@
}, },
success: function (data) { success: function (data) {
if ($('#toggle_refresh').html() == 'Stop Refresh' && !to) { if ($('#toggle_refresh').html() == 'Stop Refresh' && !to) {
to = setTimeout(update_script_status, 3000); to = setTimeout(update_script_status, <?php print UPDATE_FREQ * 1000; ?>);
} }
}, },
error: function (xhr, status, error) { error: function (xhr, status, error) {

1
inc/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/passwd

View File

@ -1,12 +1,31 @@
{ {
"require" : { "require" : {
"phpoffice/phpspreadsheet" : "^1.0", "phpoffice/phpspreadsheet" : "~1.4",
"cocur/background-process" : "^0.7.0", "cocur/background-process" : "~0.7",
"tecnickcom/tcpdf" : "^6.2", "tecnickcom/tcpdf" : "~6.2",
"pacificsec/cpe" : "^1.0", "pacificsec/cpe" : "1.0.1",
"monolog/monolog": "^1.23" "monolog/monolog" : "~1.23"
}, },
"require-dev" : { "require-dev" : {
"phpunit/phpunit" : "^6.2" "phpunit/phpunit" : "~7.3"
} },
"type" : "project",
"homepage" : "https://cyberperspectives.com",
"license" : "Apache-2.0",
"authors" : [{
"name" : "Ryan Prather",
"email" : "ryan.prather@cyberperspectives.com",
"role" : "Braun"
}, {
"name" : "Jeff Odegard",
"email" : "jeff.odegard@cyberperspectives.com",
"role" : "Brains"
}
],
"keywords" : [
"security",
"disa",
"rmf"
],
"name" : "cyberperspectives\\sagacity"
} }

418
inc/composer.lock generated
View File

@ -1,10 +1,10 @@
{ {
"_readme": [ "_readme": [
"This file locks the dependencies of your project to a known state", "This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "92ac4709f5221f74a1c7f00e59df8ad7", "content-hash": "8bf5f4a76098ff9277648c58793a04b5",
"packages": [ "packages": [
{ {
"name": "cocur/background-process", "name": "cocur/background-process",
@ -44,6 +44,101 @@
], ],
"time": "2017-02-11T12:41:41+00:00" "time": "2017-02-11T12:41:41+00:00"
}, },
{
"name": "markbaker/complex",
"version": "1.4.6",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPComplex.git",
"reference": "a78d82ae4e682c3809fc3023d1b0ce654f6ab12b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/a78d82ae4e682c3809fc3023d1b0ce654f6ab12b",
"reference": "a78d82ae4e682c3809fc3023d1b0ce654f6ab12b",
"shasum": ""
},
"require": {
"php": "^5.6.0|^7.0.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3",
"phpcompatibility/php-compatibility": "^8.0",
"phpdocumentor/phpdocumentor": "2.*",
"phploc/phploc": "2.*",
"phpmd/phpmd": "2.*",
"phpunit/phpunit": "^4.8.35|^5.4.0",
"sebastian/phpcpd": "2.*",
"squizlabs/php_codesniffer": "^3.3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Complex\\": "classes/src/"
},
"files": [
"classes/src/functions/abs.php",
"classes/src/functions/acos.php",
"classes/src/functions/acosh.php",
"classes/src/functions/acot.php",
"classes/src/functions/acoth.php",
"classes/src/functions/acsc.php",
"classes/src/functions/acsch.php",
"classes/src/functions/argument.php",
"classes/src/functions/asec.php",
"classes/src/functions/asech.php",
"classes/src/functions/asin.php",
"classes/src/functions/asinh.php",
"classes/src/functions/atan.php",
"classes/src/functions/atanh.php",
"classes/src/functions/conjugate.php",
"classes/src/functions/cos.php",
"classes/src/functions/cosh.php",
"classes/src/functions/cot.php",
"classes/src/functions/coth.php",
"classes/src/functions/csc.php",
"classes/src/functions/csch.php",
"classes/src/functions/exp.php",
"classes/src/functions/inverse.php",
"classes/src/functions/ln.php",
"classes/src/functions/log2.php",
"classes/src/functions/log10.php",
"classes/src/functions/negative.php",
"classes/src/functions/pow.php",
"classes/src/functions/rho.php",
"classes/src/functions/sec.php",
"classes/src/functions/sech.php",
"classes/src/functions/sin.php",
"classes/src/functions/sinh.php",
"classes/src/functions/sqrt.php",
"classes/src/functions/tan.php",
"classes/src/functions/tanh.php",
"classes/src/functions/theta.php",
"classes/src/operations/add.php",
"classes/src/operations/subtract.php",
"classes/src/operations/multiply.php",
"classes/src/operations/divideby.php",
"classes/src/operations/divideinto.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@lange.demon.co.uk"
}
],
"description": "PHP Class for working with complex numbers",
"homepage": "https://github.com/MarkBaker/PHPComplex",
"keywords": [
"complex",
"mathematics"
],
"time": "2018-07-31T08:38:40+00:00"
},
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
"version": "1.23.0", "version": "1.23.0",
@ -124,33 +219,59 @@
}, },
{ {
"name": "pacificsec/cpe", "name": "pacificsec/cpe",
"version": "1.0.0", "version": "1.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pacificsec/cpe.git", "url": "https://github.com/pacificsec/cpe.git",
"reference": "3d78d66fc4ea249b6f353a7c48f426835a792d11" "reference": "52cc49e04388ba00493be634287f6ce3efb30afc"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pacificsec/cpe/zipball/3d78d66fc4ea249b6f353a7c48f426835a792d11", "url": "https://api.github.com/repos/pacificsec/cpe/zipball/52cc49e04388ba00493be634287f6ce3efb30afc",
"reference": "3d78d66fc4ea249b6f353a7c48f426835a792d11", "reference": "52cc49e04388ba00493be634287f6ce3efb30afc",
"shasum": "" "shasum": ""
}, },
"require": {
"php": ">=5.3.0"
},
"type": "library", "type": "library",
"notification-url": "https://packagist.org/downloads/" "autoload": {
"psr-4": {
"PacificSec\\CPE\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Antonio Franco",
"email": "antonio.franco@pacificsec.com"
}
],
"description": "CPE: Common Platform Enumeration for PHP",
"homepage": "https://github.com/pacificsec/cpe",
"keywords": [
"cpe",
"cve",
"pacificsec",
"security"
],
"time": "2018-08-22T17:55:09+00:00"
}, },
{ {
"name": "phpoffice/phpspreadsheet", "name": "phpoffice/phpspreadsheet",
"version": "1.2.1", "version": "1.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git", "url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "36acc372875c4d894dc093825ce4f62209db5a76" "reference": "125f462a718956f37d81305ca0df4f17cef0f3b9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/36acc372875c4d894dc093825ce4f62209db5a76", "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/125f462a718956f37d81305ca0df4f17cef0f3b9",
"reference": "36acc372875c4d894dc093825ce4f62209db5a76", "reference": "125f462a718956f37d81305ca0df4f17cef0f3b9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -166,6 +287,7 @@
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"ext-zip": "*", "ext-zip": "*",
"ext-zlib": "*", "ext-zlib": "*",
"markbaker/complex": "^1.4.1",
"php": "^5.6|^7.0", "php": "^5.6|^7.0",
"psr/simple-cache": "^1.0" "psr/simple-cache": "^1.0"
}, },
@ -175,7 +297,7 @@
"jpgraph/jpgraph": "^4.0", "jpgraph/jpgraph": "^4.0",
"mpdf/mpdf": "^7.0.0", "mpdf/mpdf": "^7.0.0",
"phpunit/phpunit": "^5.7", "phpunit/phpunit": "^5.7",
"squizlabs/php_codesniffer": "^2.7", "squizlabs/php_codesniffer": "^3.3",
"tecnickcom/tcpdf": "^6.2" "tecnickcom/tcpdf": "^6.2"
}, },
"suggest": { "suggest": {
@ -223,7 +345,7 @@
"xls", "xls",
"xlsx" "xlsx"
], ],
"time": "2018-04-10T03:53:16+00:00" "time": "2018-08-06T02:58:06+00:00"
}, },
{ {
"name": "psr/log", "name": "psr/log",
@ -322,16 +444,16 @@
}, },
{ {
"name": "tecnickcom/tcpdf", "name": "tecnickcom/tcpdf",
"version": "6.2.17", "version": "6.2.22",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/tecnickcom/TCPDF.git", "url": "https://github.com/tecnickcom/TCPDF.git",
"reference": "64fc19439863e1b1314487a72a74d9bfd0b55a53" "reference": "ac6e92fccc7d9383dfd787056831349621b1aca2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/64fc19439863e1b1314487a72a74d9bfd0b55a53", "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/ac6e92fccc7d9383dfd787056831349621b1aca2",
"reference": "64fc19439863e1b1314487a72a74d9bfd0b55a53", "reference": "ac6e92fccc7d9383dfd787056831349621b1aca2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -380,7 +502,7 @@
"pdf417", "pdf417",
"qrcode" "qrcode"
], ],
"time": "2018-02-24T11:48:20+00:00" "time": "2018-09-14T15:26:29+00:00"
} }
], ],
"packages-dev": [ "packages-dev": [
@ -440,16 +562,16 @@
}, },
{ {
"name": "myclabs/deep-copy", "name": "myclabs/deep-copy",
"version": "1.8.0", "version": "1.8.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/myclabs/DeepCopy.git", "url": "https://github.com/myclabs/DeepCopy.git",
"reference": "478465659fd987669df0bd8a9bf22a8710e5f1b6" "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/478465659fd987669df0bd8a9bf22a8710e5f1b6", "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8",
"reference": "478465659fd987669df0bd8a9bf22a8710e5f1b6", "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -484,26 +606,26 @@
"object", "object",
"object graph" "object graph"
], ],
"time": "2018-05-29T17:25:09+00:00" "time": "2018-06-11T23:09:50+00:00"
}, },
{ {
"name": "phar-io/manifest", "name": "phar-io/manifest",
"version": "1.0.1", "version": "1.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phar-io/manifest.git", "url": "https://github.com/phar-io/manifest.git",
"reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
"reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-dom": "*", "ext-dom": "*",
"ext-phar": "*", "ext-phar": "*",
"phar-io/version": "^1.0.1", "phar-io/version": "^2.0",
"php": "^5.6 || ^7.0" "php": "^5.6 || ^7.0"
}, },
"type": "library", "type": "library",
@ -539,20 +661,20 @@
} }
], ],
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
"time": "2017-03-05T18:14:27+00:00" "time": "2018-07-08T19:23:20+00:00"
}, },
{ {
"name": "phar-io/version", "name": "phar-io/version",
"version": "1.0.1", "version": "2.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phar-io/version.git", "url": "https://github.com/phar-io/version.git",
"reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
"reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -586,7 +708,7 @@
} }
], ],
"description": "Library for handling version information and constraints", "description": "Library for handling version information and constraints",
"time": "2017-03-05T17:38:23+00:00" "time": "2018-07-08T19:19:57+00:00"
}, },
{ {
"name": "phpdocumentor/reflection-common", "name": "phpdocumentor/reflection-common",
@ -742,16 +864,16 @@
}, },
{ {
"name": "phpspec/prophecy", "name": "phpspec/prophecy",
"version": "1.7.6", "version": "1.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpspec/prophecy.git", "url": "https://github.com/phpspec/prophecy.git",
"reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
"reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -763,12 +885,12 @@
}, },
"require-dev": { "require-dev": {
"phpspec/phpspec": "^2.5|^3.2", "phpspec/phpspec": "^2.5|^3.2",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.7.x-dev" "dev-master": "1.8.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -801,44 +923,44 @@
"spy", "spy",
"stub" "stub"
], ],
"time": "2018-04-18T13:57:24+00:00" "time": "2018-08-05T17:53:17+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "5.3.2", "version": "6.0.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "c89677919c5dd6d3b3852f230a663118762218ac" "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/865662550c384bc1db7e51d29aeda1c2c161d69a",
"reference": "c89677919c5dd6d3b3852f230a663118762218ac", "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-dom": "*", "ext-dom": "*",
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"php": "^7.0", "php": "^7.1",
"phpunit/php-file-iterator": "^1.4.2", "phpunit/php-file-iterator": "^2.0",
"phpunit/php-text-template": "^1.2.1", "phpunit/php-text-template": "^1.2.1",
"phpunit/php-token-stream": "^2.0.1", "phpunit/php-token-stream": "^3.0",
"sebastian/code-unit-reverse-lookup": "^1.0.1", "sebastian/code-unit-reverse-lookup": "^1.0.1",
"sebastian/environment": "^3.0", "sebastian/environment": "^3.1",
"sebastian/version": "^2.0.1", "sebastian/version": "^2.0.1",
"theseer/tokenizer": "^1.1" "theseer/tokenizer": "^1.1"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^6.0" "phpunit/phpunit": "^7.0"
}, },
"suggest": { "suggest": {
"ext-xdebug": "^2.5.5" "ext-xdebug": "^2.6.0"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "5.3.x-dev" "dev-master": "6.0-dev"
} }
}, },
"autoload": { "autoload": {
@ -864,29 +986,32 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2018-04-06T15:36:58+00:00" "time": "2018-06-01T07:51:50+00:00"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
"version": "1.4.5", "version": "2.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" "reference": "050bedf145a257b1ff02746c31894800e5122946"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946",
"reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", "reference": "050bedf145a257b1ff02746c31894800e5122946",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.3" "php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^7.1"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.4.x-dev" "dev-master": "2.0.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -901,7 +1026,7 @@
"authors": [ "authors": [
{ {
"name": "Sebastian Bergmann", "name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de", "email": "sebastian@phpunit.de",
"role": "lead" "role": "lead"
} }
], ],
@ -911,7 +1036,7 @@
"filesystem", "filesystem",
"iterator" "iterator"
], ],
"time": "2017-11-27T13:52:08+00:00" "time": "2018-09-13T20:33:42+00:00"
}, },
{ {
"name": "phpunit/php-text-template", "name": "phpunit/php-text-template",
@ -956,28 +1081,28 @@
}, },
{ {
"name": "phpunit/php-timer", "name": "phpunit/php-timer",
"version": "1.0.9", "version": "2.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git", "url": "https://github.com/sebastianbergmann/php-timer.git",
"reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f",
"reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^5.3.3 || ^7.0" "php": "^7.1"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" "phpunit/phpunit": "^7.0"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0-dev" "dev-master": "2.0-dev"
} }
}, },
"autoload": { "autoload": {
@ -992,7 +1117,7 @@
"authors": [ "authors": [
{ {
"name": "Sebastian Bergmann", "name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de", "email": "sebastian@phpunit.de",
"role": "lead" "role": "lead"
} }
], ],
@ -1001,33 +1126,33 @@
"keywords": [ "keywords": [
"timer" "timer"
], ],
"time": "2017-02-26T11:10:40+00:00" "time": "2018-02-01T13:07:23+00:00"
}, },
{ {
"name": "phpunit/php-token-stream", "name": "phpunit/php-token-stream",
"version": "2.0.2", "version": "3.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git", "url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "791198a2c6254db10131eecfe8c06670700904db" "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace",
"reference": "791198a2c6254db10131eecfe8c06670700904db", "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-tokenizer": "*", "ext-tokenizer": "*",
"php": "^7.0" "php": "^7.1"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^6.2.4" "phpunit/phpunit": "^7.0"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.0-dev" "dev-master": "3.0-dev"
} }
}, },
"autoload": { "autoload": {
@ -1050,40 +1175,40 @@
"keywords": [ "keywords": [
"tokenizer" "tokenizer"
], ],
"time": "2017-11-27T05:48:46+00:00" "time": "2018-02-01T13:16:43+00:00"
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "6.5.8", "version": "7.3.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b" "reference": "7b331efabbb628c518c408fdfcaf571156775de2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4f21a3c6b97c42952fd5c2837bb354ec0199b97b", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7b331efabbb628c518c408fdfcaf571156775de2",
"reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b", "reference": "7b331efabbb628c518c408fdfcaf571156775de2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/instantiator": "^1.1",
"ext-dom": "*", "ext-dom": "*",
"ext-json": "*", "ext-json": "*",
"ext-libxml": "*", "ext-libxml": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"ext-xml": "*", "ext-xml": "*",
"myclabs/deep-copy": "^1.6.1", "myclabs/deep-copy": "^1.7",
"phar-io/manifest": "^1.0.1", "phar-io/manifest": "^1.0.2",
"phar-io/version": "^1.0", "phar-io/version": "^2.0",
"php": "^7.0", "php": "^7.1",
"phpspec/prophecy": "^1.7", "phpspec/prophecy": "^1.7",
"phpunit/php-code-coverage": "^5.3", "phpunit/php-code-coverage": "^6.0.7",
"phpunit/php-file-iterator": "^1.4.3", "phpunit/php-file-iterator": "^2.0.1",
"phpunit/php-text-template": "^1.2.1", "phpunit/php-text-template": "^1.2.1",
"phpunit/php-timer": "^1.0.9", "phpunit/php-timer": "^2.0",
"phpunit/phpunit-mock-objects": "^5.0.5", "sebastian/comparator": "^3.0",
"sebastian/comparator": "^2.1", "sebastian/diff": "^3.0",
"sebastian/diff": "^2.0",
"sebastian/environment": "^3.1", "sebastian/environment": "^3.1",
"sebastian/exporter": "^3.1", "sebastian/exporter": "^3.1",
"sebastian/global-state": "^2.0", "sebastian/global-state": "^2.0",
@ -1092,15 +1217,15 @@
"sebastian/version": "^2.0.1" "sebastian/version": "^2.0.1"
}, },
"conflict": { "conflict": {
"phpdocumentor/reflection-docblock": "3.0.2", "phpunit/phpunit-mock-objects": "*"
"phpunit/dbunit": "<3.0"
}, },
"require-dev": { "require-dev": {
"ext-pdo": "*" "ext-pdo": "*"
}, },
"suggest": { "suggest": {
"ext-soap": "*",
"ext-xdebug": "*", "ext-xdebug": "*",
"phpunit/php-invoker": "^1.1" "phpunit/php-invoker": "^2.0"
}, },
"bin": [ "bin": [
"phpunit" "phpunit"
@ -1108,7 +1233,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "6.5.x-dev" "dev-master": "7.3-dev"
} }
}, },
"autoload": { "autoload": {
@ -1134,66 +1259,7 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2018-04-10T11:38:34+00:00" "time": "2018-09-08T15:14:29+00:00"
},
{
"name": "phpunit/phpunit-mock-objects",
"version": "5.0.7",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "3eaf040f20154d27d6da59ca2c6e28ac8fd56dce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3eaf040f20154d27d6da59ca2c6e28ac8fd56dce",
"reference": "3eaf040f20154d27d6da59ca2c6e28ac8fd56dce",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.5",
"php": "^7.0",
"phpunit/php-text-template": "^1.2.1",
"sebastian/exporter": "^3.1"
},
"conflict": {
"phpunit/phpunit": "<6.0"
},
"require-dev": {
"phpunit/phpunit": "^6.5"
},
"suggest": {
"ext-soap": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Mock Object library for PHPUnit",
"homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
"keywords": [
"mock",
"xunit"
],
"time": "2018-05-29T13:50:43+00:00"
}, },
{ {
"name": "sebastian/code-unit-reverse-lookup", "name": "sebastian/code-unit-reverse-lookup",
@ -1242,30 +1308,30 @@
}, },
{ {
"name": "sebastian/comparator", "name": "sebastian/comparator",
"version": "2.1.3", "version": "3.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git", "url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
"reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.0", "php": "^7.1",
"sebastian/diff": "^2.0 || ^3.0", "sebastian/diff": "^3.0",
"sebastian/exporter": "^3.1" "sebastian/exporter": "^3.1"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^6.4" "phpunit/phpunit": "^7.1"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.1.x-dev" "dev-master": "3.0-dev"
} }
}, },
"autoload": { "autoload": {
@ -1302,32 +1368,33 @@
"compare", "compare",
"equality" "equality"
], ],
"time": "2018-02-01T13:46:46+00:00" "time": "2018-07-12T15:12:46+00:00"
}, },
{ {
"name": "sebastian/diff", "name": "sebastian/diff",
"version": "2.0.1", "version": "3.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/diff.git", "url": "https://github.com/sebastianbergmann/diff.git",
"reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" "reference": "366541b989927187c4ca70490a35615d3fef2dce"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/366541b989927187c4ca70490a35615d3fef2dce",
"reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", "reference": "366541b989927187c4ca70490a35615d3fef2dce",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.0" "php": "^7.1"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^6.2" "phpunit/phpunit": "^7.0",
"symfony/process": "^2 || ^3.3 || ^4"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.0-dev" "dev-master": "3.0-dev"
} }
}, },
"autoload": { "autoload": {
@ -1352,9 +1419,12 @@
"description": "Diff implementation", "description": "Diff implementation",
"homepage": "https://github.com/sebastianbergmann/diff", "homepage": "https://github.com/sebastianbergmann/diff",
"keywords": [ "keywords": [
"diff" "diff",
"udiff",
"unidiff",
"unified diff"
], ],
"time": "2017-08-03T08:09:46+00:00" "time": "2018-06-10T07:54:39+00:00"
}, },
{ {
"name": "sebastian/environment", "name": "sebastian/environment",

View File

@ -73,6 +73,7 @@
* - May 31, 2018 - Changes to support renaming sagacity.pdi_catalog.check_content field and scan error detection * - May 31, 2018 - Changes to support renaming sagacity.pdi_catalog.check_content field and scan error detection
* - Jun 2, 2018 - Formatting and added set_Setting_Array method * - Jun 2, 2018 - Formatting and added set_Setting_Array method
* - Jun 5, 2018 - Changed set_Setting_Array method to use SQL update instead of replace * - Jun 5, 2018 - Changed set_Setting_Array method to use SQL update instead of replace
* - Sep 5, 2018 - Fix for #8
*/ */
include_once 'base.inc'; include_once 'base.inc';
include_once 'software.inc'; include_once 'software.inc';
@ -1270,7 +1271,7 @@ class db_helper
"Executing: $this->query_type\t" . "Executing: $this->query_type\t" .
"SQL: {$errmsg}" . PHP_EOL, FILE_APPEND); "SQL: {$errmsg}" . PHP_EOL, FILE_APPEND);
if ($errno == E_DEBUG && $this->result && LOG_LEVEL == E_DEBUG) { if ($errno == E_DEBUG && $this->result && LOG_LEVEL == E_DEBUG && is_a($this->result, 'mysqli_result')) {
file_put_contents(realpath(LOG_PATH . '/db.debug'), print_r($this->result, true), FILE_APPEND); file_put_contents(realpath(LOG_PATH . '/db.debug'), print_r($this->result, true), FILE_APPEND);
} }
elseif ($errno == E_ERROR && $this->c->error) { elseif ($errno == E_ERROR && $this->c->error) {
@ -1695,7 +1696,7 @@ class db_helper
/** /**
* *
* @return type * @return string
*/ */
public static function mysql_escape_string() public static function mysql_escape_string()
{ {
@ -2352,6 +2353,7 @@ class db
{ {
$ret = true; $ret = true;
$fields = array('pdi_id', 'cce_id'); $fields = array('pdi_id', 'cce_id');
$params = [];
if (is_array($cces)) { if (is_array($cces)) {
foreach ($cces as $cce) { foreach ($cces as $cce) {
@ -2784,7 +2786,7 @@ class db
* @param integer $cat_id * @param integer $cat_id
* Integer category ID to get the summary on * Integer category ID to get the summary on
* *
* @return NULL|array:targets,checklist,summary * @return NULL|array:targets,checklist,string
* Returns an associative array of target (id & name), checklists, and a summary that joins the two * Returns an associative array of target (id & name), checklists, and a summary that joins the two
*/ */
public function get_Checklist_Summary($cat_id) public function get_Checklist_Summary($cat_id)
@ -4102,7 +4104,7 @@ class db
* Function to get the findings that are assigned to specific controls * Function to get the findings that are assigned to specific controls
* *
* @param ste $ste * @param ste $ste
* @param proc_ia_control $ia_ctrl * @param proc_ia_controls $ia_ctrl
* @param string $status * @param string $status
* @return array:finding |NULL * @return array:finding |NULL
*/ */
@ -4258,7 +4260,7 @@ class db
* The status to look for * The status to look for
* @param integer $cat [optional] * @param integer $cat [optional]
* The CAT/severity level * The CAT/severity level
* @param proc_ia_control $ctrl [optional] * @param proc_ia_controls $ctrl [optional]
* A IA control to filter for * A IA control to filter for
* *
* @return integer * @return integer
@ -4312,7 +4314,7 @@ class db
]; ];
} }
if (!is_null($ctrl) && is_a($ctrl, 'proc_ia_control')) { if (!is_null($ctrl) && is_a($ctrl, 'proc_ia_controls')) {
$where[] = [ $where[] = [
'field' => 'fc.ia_control', 'field' => 'fc.ia_control',
'value' => $ctrl->get_Control_ID(), 'value' => $ctrl->get_Control_ID(),
@ -4333,7 +4335,7 @@ class db
"JOIN sagacity.target t ON t.id=f.tgt_id" "JOIN sagacity.target t ON t.id=f.tgt_id"
]; ];
if (!is_null($ctrl) && is_a($ctrl, 'proc_ia_control')) { if (!is_null($ctrl) && is_a($ctrl, 'proc_ia_controls')) {
$joins[] = "JOIN sagacity.finding_controls fc ON fc.finding_id=f.id"; $joins[] = "JOIN sagacity.finding_controls fc ON fc.finding_id=f.id";
} }
@ -4378,7 +4380,7 @@ class db
]; ];
} }
if (!is_null($ctrl) && is_a($ctrl, 'proc_ia_control')) { if (!is_null($ctrl) && is_a($ctrl, 'proc_ia_controls')) {
$where[] = [ $where[] = [
'field' => 'fc.ia_control', 'field' => 'fc.ia_control',
'value' => $ctrl->get_Control_ID(), 'value' => $ctrl->get_Control_ID(),
@ -4403,7 +4405,7 @@ class db
* The status to look for * The status to look for
* @param integer $cat * @param integer $cat
* The CAT/severity level * The CAT/severity level
* @param proc_ia_control $ctrl * @param proc_ia_controls $ctrl
* A IA control to filter for * A IA control to filter for
* *
* @return integer * @return integer
@ -4460,7 +4462,7 @@ class db
* The status to look for * The status to look for
* @param integer $cat [optional] * @param integer $cat [optional]
* The CAT/severity level * The CAT/severity level
* @param proc_ia_control $ctrl [optional] * @param proc_ia_controls $ctrl [optional]
* A IA control to filter for * A IA control to filter for
* @param array $chk_ids [optional] * @param array $chk_ids [optional]
* @param boolean $is_orphan [optional] * @param boolean $is_orphan [optional]
@ -4470,7 +4472,6 @@ class db
*/ */
public function get_Host_Finding_Count_By_Status($tgt, $status, $cat = null, $ctrl = null, $chk_ids = null, $is_orphan = false) public function get_Host_Finding_Count_By_Status($tgt, $status, $cat = null, $ctrl = null, $chk_ids = null, $is_orphan = false)
{ {
$count = 0;
if (!$is_orphan) { if (!$is_orphan) {
$sql = "SELECT (SELECT COUNT(DISTINCT(pcl.`pdi_id`)) " . $sql = "SELECT (SELECT COUNT(DISTINCT(pcl.`pdi_id`)) " .
"FROM `sagacity`.`target` t " . "FROM `sagacity`.`target` t " .
@ -4644,12 +4645,11 @@ class db
* @TODO - FINISH * @TODO - FINISH
* *
* @param ste $ste * @param ste $ste
* @param proc_ia_control $ia_ctrl * @param proc_ia_controls $ia_ctrl
* @param string $status * @param string $status
*/ */
public function get_Finding_Pervasivity_by_Control($ste, $ia_ctrl, $status = null) public function get_Finding_Pervasivity_by_Control($ste, $ia_ctrl, $status = null)
{ {
$sql = "SELECT COUNT";
} }
/** /**
@ -4851,7 +4851,7 @@ class db
$updated_finding = []; $updated_finding = [];
$new_finding = []; $new_finding = [];
$x = 0; $x = 0;
foreach ($tgts as $key => $tgt) { foreach ($tgts as $tgt) {
switch (strtolower(str_replace('_', ' ', $finding_data[self::FIRST_ECHECKLIST_HOST_COL + $x]))) { switch (strtolower(str_replace('_', ' ', $finding_data[self::FIRST_ECHECKLIST_HOST_COL + $x]))) {
case 'not reviewed': case 'not reviewed':
case 'not a finding': case 'not a finding':
@ -4991,7 +4991,7 @@ class db
$notes = (isset($current_finding) && is_array($current_finding) && count($current_finding) ? $current_finding->get_Notes() . " " . $notes : $notes); $notes = (isset($current_finding) && is_array($current_finding) && count($current_finding) ? $current_finding->get_Notes() . " " . $notes : $notes);
if (isset($updated_finding) && is_array($updated_finding) && count($updated_finding) > 0) { if (isset($updated_finding) && is_array($updated_finding) && count($updated_finding) > 0) {
foreach ($updated_finding as $key => $finding) { foreach ($updated_finding as $finding) {
$update_sql = "UPDATE `findings` SET " . $update_sql = "UPDATE `findings` SET " .
"`scan_id` = " . $this->conn->real_escape_string($finding->get_Scan_ID()) . ", " . "`scan_id` = " . $this->conn->real_escape_string($finding->get_Scan_ID()) . ", " .
"`findings_status_id` = " . $this->conn->real_escape_string($finding->get_Finding_Status()) . ", " . "`findings_status_id` = " . $this->conn->real_escape_string($finding->get_Finding_Status()) . ", " .
@ -5007,13 +5007,13 @@ class db
if (!$this->conn->real_query($update_sql)) { if (!$this->conn->real_query($update_sql)) {
Sagacity_Error::sql_handler($update_sql); Sagacity_Error::sql_handler($update_sql);
error_log($this->conn->error); error_log($this->conn->error);
$ret = false; return false;
} }
$this->conn->real_query("DELETE FROM `finding_controls` WHERE `finding_id` = " . $finding->get_ID()); $this->conn->real_query("DELETE FROM `finding_controls` WHERE `finding_id` = " . $finding->get_ID());
$sql2 = "INSERT INTO `finding_controls` (`finding_id`, `ia_control`) VALUES "; $sql2 = "INSERT INTO `finding_controls` (`finding_id`, `ia_control`) VALUES ";
foreach ($finding->get_IA_Controls() as $key => $ia) { foreach ($finding->get_IA_Controls() as $ia) {
$sql2 .= "({$this->conn->real_escape_string($finding->get_ID())}, " . $sql2 .= "({$this->conn->real_escape_string($finding->get_ID())}, " .
"'{$this->conn->real_escape_string($ia)}'),"; "'{$this->conn->real_escape_string($ia)}'),";
} }
@ -5025,7 +5025,7 @@ class db
} }
if (isset($new_finding) && count($new_finding) > 0) { if (isset($new_finding) && count($new_finding) > 0) {
foreach ($new_finding as $key => $finding) { foreach ($new_finding as $finding) {
$insert_sql = "INSERT INTO `findings` (`tgt_id`, `pdi_id`, `scan_id`, `findings_status_id`, `cat`, `notes`) VALUES " . $insert_sql = "INSERT INTO `findings` (`tgt_id`, `pdi_id`, `scan_id`, `findings_status_id`, `cat`, `notes`) VALUES " .
"(" . $this->conn->real_escape_string($finding->get_Tgt_ID()) . ", " . "(" . $this->conn->real_escape_string($finding->get_Tgt_ID()) . ", " .
$this->conn->real_escape_string($finding->get_PDI_ID()) . ", " . $this->conn->real_escape_string($finding->get_PDI_ID()) . ", " .
@ -5040,14 +5040,14 @@ class db
if (!$this->conn->real_query($insert_sql)) { if (!$this->conn->real_query($insert_sql)) {
Sagacity_Error::sql_handler($insert_sql); Sagacity_Error::sql_handler($insert_sql);
error_log($this->conn->error); error_log($this->conn->error);
$ret = false; return false;
} }
} }
$find_id = $this->conn->insert_id; $find_id = $this->conn->insert_id;
$sql2 = "INSERT INTO `finding_controls` (`finding_id`, `ia_control`) VALUES "; $sql2 = "INSERT INTO `finding_controls` (`finding_id`, `ia_control`) VALUES ";
foreach ($finding->get_IA_Controls() as $key => $ia) { foreach ($finding->get_IA_Controls() as $ia) {
$sql2 .= "({$this->conn->real_escape_string($find_id)}, " . $sql2 .= "({$this->conn->real_escape_string($find_id)}, " .
"'{$this->conn->real_escape_string($ia)}'),"; "'{$this->conn->real_escape_string($ia)}'),";
} }
@ -5170,14 +5170,14 @@ class db
if (!$this->conn->real_query($update_sql)) { if (!$this->conn->real_query($update_sql)) {
Sagacity_Error::sql_handler($update_sql); Sagacity_Error::sql_handler($update_sql);
error_log($this->conn->error); error_log($this->conn->error);
$ret = false; return false;
} }
$this->conn->real_query("DELETE FROM `sagacity`.`finding_controls` WHERE `finding_id` = " . $updated_finding->get_ID()); $this->conn->real_query("DELETE FROM `sagacity`.`finding_controls` WHERE `finding_id` = " . $updated_finding->get_ID());
$sql2 = "INSERT INTO `sagacity`.`finding_controls` (`finding_id`, `ia_control`) VALUES "; $sql2 = "INSERT INTO `sagacity`.`finding_controls` (`finding_id`, `ia_control`) VALUES ";
foreach ($updated_finding->get_IA_Controls() as $key => $ia) { foreach ($updated_finding->get_IA_Controls() as $ia) {
$sql2 .= "(" . $sql2 .= "(" .
$this->conn->real_escape_string($updated_finding->get_ID()) . ", " . $this->conn->real_escape_string($updated_finding->get_ID()) . ", " .
"'" . $this->conn->real_escape_string($ia) . "'), "; "'" . $this->conn->real_escape_string($ia) . "'), ";
@ -5203,14 +5203,14 @@ class db
if (!$this->conn->real_query($insert_sql)) { if (!$this->conn->real_query($insert_sql)) {
Sagacity_Error::sql_handler($insert_sql); Sagacity_Error::sql_handler($insert_sql);
error_log($this->conn->error); error_log($this->conn->error);
$ret = false; return false;
} }
} }
$find_id = $this->conn->insert_id; $find_id = $this->conn->insert_id;
$sql2 = "INSERT INTO `sagacity`.`finding_controls` (`finding_id`, `ia_control`) VALUES "; $sql2 = "INSERT INTO `sagacity`.`finding_controls` (`finding_id`, `ia_control`) VALUES ";
foreach ($new_finding->get_IA_Controls() as $key => $ia) { foreach ($new_finding->get_IA_Controls() as $ia) {
$sql2 .= "(" . $sql2 .= "(" .
$this->conn->real_escape_string($find_id) . ", " . $this->conn->real_escape_string($find_id) . ", " .
"'" . $this->conn->real_escape_string($ia) . "'), "; "'" . $this->conn->real_escape_string($ia) . "'), ";
@ -5728,7 +5728,7 @@ class db
* Function to get the icon that represents the IA control status * Function to get the icon that represents the IA control status
* *
* @param ste $ste * @param ste $ste
* @param proc_ia_control $ctrl * @param proc_ia_controls $ctrl
* *
* @return string * @return string
*/ */
@ -5747,7 +5747,7 @@ class db
} }
if (false) { if (false) {
$ctrl = new proc_ia_control(); $ctrl = new proc_ia_controls();
} }
if (empty($ctrl->finding->vul_desc)) { if (empty($ctrl->finding->vul_desc)) {
return "exclamation.png"; return "exclamation.png";
@ -6250,7 +6250,7 @@ class db
* @param integer $tgt_id * @param integer $tgt_id
* @param string $ip * @param string $ip
* *
* @return NULL|interface * @return NULL|interfaces
*/ */
public function get_Interface_By_IP($tgt_id, $ip) public function get_Interface_By_IP($tgt_id, $ip)
{ {
@ -6554,7 +6554,7 @@ class db
array( array(
'field' => 'int_id', 'field' => 'int_id',
'op' => '=', 'op' => '=',
'value' => $id 'value' => $int_id
) )
)); ));
$this->help->execute(); $this->help->execute();
@ -6562,7 +6562,7 @@ class db
array( array(
'field' => 'id', 'field' => 'id',
'op' => '=', 'op' => '=',
'value' => $id 'value' => $int_id
) )
)); ));
$this->help->execute(); $this->help->execute();
@ -6632,7 +6632,7 @@ class db
$ret = true; $ret = true;
$ins_sql = 'REPLACE INTO `sagacity`.`pps_list` (`int_id`,`pps_id`,`name`,`banner`,`notes`) VALUES '; $ins_sql = 'REPLACE INTO `sagacity`.`pps_list` (`int_id`,`pps_id`,`name`,`banner`,`notes`) VALUES ';
if ($action == 'insert') { if ($action == 'insert') {
foreach ($ports as $key => $port) { foreach ($ports as $port) {
$ins_sql .= "(" . $int->get_ID() . ", " . $ins_sql .= "(" . $int->get_ID() . ", " .
"(SELECT `id` FROM `sagacity`.`ports_proto_services` WHERE `port` = '" . $port->get_Port() . "'" . "(SELECT `id` FROM `sagacity`.`ports_proto_services` WHERE `port` = '" . $port->get_Port() . "'" .
" AND `proto` = '" . (is_a($port, 'tcp_ports') ? 'tcp' : 'udp') . "' " . " AND `proto` = '" . (is_a($port, 'tcp_ports') ? 'tcp' : 'udp') . "' " .
@ -6673,10 +6673,12 @@ class db
public function get_TCP_Ports($port_number = null) public function get_TCP_Ports($port_number = null)
{ {
$ret = []; $ret = [];
$where[] = [ $where = [
'field' => 'proto', [
'op' => '=', 'field' => 'proto',
'value' => 'tcp' 'op' => '=',
'value' => 'tcp'
]
]; ];
if (!is_null($port_number)) { if (!is_null($port_number)) {
@ -6719,10 +6721,12 @@ class db
public function get_UDP_Ports($port_number = null) public function get_UDP_Ports($port_number = null)
{ {
$ret = []; $ret = [];
$where[] = [ $where = [
'field' => 'proto', [
'op' => '=', 'field' => 'proto',
'value' => 'udp' 'op' => '=',
'value' => 'udp'
]
]; ];
if (!is_null($port_number)) { if (!is_null($port_number)) {
@ -7088,13 +7092,14 @@ class db
while ($sth->fetch()) { while ($sth->fetch()) {
$x++; $x++;
$ret = preg_match('/Registry Hive: +(\S*)/', $check_contents, $match); $match = [];
preg_match('/Registry Hive: +(\S*)/', $check_contents, $match);
$hive = $match[1]; $hive = $match[1];
$ret = preg_match('/(Subkey|Path|Registry Path): +(\\\)?(.*)/', $check_contents, $match); preg_match('/(Subkey|Path|Registry Path): +(\\\)?(.*)/', $check_contents, $match);
$path = is_array($match) && count($match) > 3 ? $match[3] : "STIG ID: $stig_id" . PHP_EOL; $path = is_array($match) && count($match) > 3 ? $match[3] : "STIG ID: $stig_id" . PHP_EOL;
$ret = preg_match('/Value Name: +(\S*)/', $check_contents, $match); preg_match('/Value Name: +(\S*)/', $check_contents, $match);
$name = is_array($match) && count($match) > 1 ? $match[1] : ''; $name = is_array($match) && count($match) > 1 ? $match[1] : '';
if (is_array($match) && count($match) == 2) { if (is_array($match) && count($match) == 2) {
@ -7102,10 +7107,10 @@ class db
$c_count = 1; $c_count = 1;
} }
$ret = preg_match('/Type: +(\S*)/', $check_contents, $match); preg_match('/Type: +(\S*)/', $check_contents, $match);
$type = is_array($match) && count($match) > 0 ? $match[1] : "PDI ID: $pdi_id" . PHP_EOL; $type = is_array($match) && count($match) > 0 ? $match[1] : "PDI ID: $pdi_id" . PHP_EOL;
$ret = preg_match('/Value: +(\S*)/', $check_contents, $match); preg_match('/Value: +(\S*)/', $check_contents, $match);
$value = is_array($match) && count($match) > 0 ? $match[1] : "PDI ID: $pdi_id" . PHP_EOL; $value = is_array($match) && count($match) > 0 ? $match[1] : "PDI ID: $pdi_id" . PHP_EOL;
if (strpos($type, "PDI ID: " . $pdi_id) !== false) { if (strpos($type, "PDI ID: " . $pdi_id) !== false) {
@ -7521,7 +7526,7 @@ class db
} }
else { else {
$cves = $nessus->get_Reference_By_Type('cve'); $cves = $nessus->get_Reference_By_Type('cve');
foreach ($cves as $key => $cve_num) { foreach ($cves as $cve_num) {
$cve = $this->get_CVE($cve_num); $cve = $this->get_CVE($cve_num);
if ($cve->get_PDI_ID()) { if ($cve->get_PDI_ID()) {
return $cve->get_PDI_ID(); return $cve->get_PDI_ID();
@ -7544,7 +7549,7 @@ class db
} }
$bids = $nessus->get_Reference_By_Type('bid'); $bids = $nessus->get_Reference_By_Type('bid');
foreach ($bids as $key => $bid_num) { foreach ($bids as $bid_num) {
$sql = "SELECT iavm.`pdi_id` " . $sql = "SELECT iavm.`pdi_id` " .
"FROM `sagacity`.`nessus_refs` nr " . "FROM `sagacity`.`nessus_refs` nr " .
"JOIN `sagacity`.`iavm_bids` ib ON ib.`bid`=nr.`val` " . "JOIN `sagacity`.`iavm_bids` ib ON ib.`bid`=nr.`val` " .
@ -9259,7 +9264,7 @@ class db
/** /**
* Function to retrieve a software item by using the CPE or CPE v2.3 * Function to retrieve a software item by using the CPE or CPE v2.3
* *
* @param strinig $cpe_in * @param string $cpe_in
* CPE to search for * CPE to search for
* *
* @return software|NULL * @return software|NULL
@ -10734,11 +10739,11 @@ class db
public function get_Target_Details($int_STE_ID, $TGT = null) public function get_Target_Details($int_STE_ID, $TGT = null)
{ {
$ret = []; $ret = [];
$where[] = [ $where = [[
'field' => 't.ste_id', 'field' => 't.ste_id',
'op' => '=', 'op' => '=',
'value' => $int_STE_ID 'value' => $int_STE_ID
]; ]];
if (!is_null($TGT)) { if (!is_null($TGT)) {
if (is_numeric($TGT)) { if (is_numeric($TGT)) {
@ -10915,8 +10920,7 @@ class db
if (is_array($rows) && count($rows) && isset($rows[0])) { if (is_array($rows) && count($rows) && isset($rows[0])) {
foreach ($rows as $row) { foreach ($rows as $row) {
$tgt = $this->get_Target_Details($cat->get_STE_ID(), $row['id'])[0]; $ret[] = $this->get_Target_Details($cat->get_STE_ID(), $row['id'])[0];
$ret[] = $tgt;
} }
} }
@ -11065,7 +11069,7 @@ class db
"SELECT {$tgt['id']},c.`id` FROM (" . "SELECT {$tgt['id']},c.`id` FROM (" .
"SELECT chk.*,s.`id` AS 'real_sw' " . "SELECT chk.*,s.`id` AS 'real_sw' " .
"FROM `checklist` chk " . "FROM `checklist` chk " .
"JOIN `checklist_software_lookup` csl ON csl.`chk_id`=chk`.id` " . "JOIN `checklist_software_lookup` csl ON csl.`chk_id`=chk.`id` " .
"JOIN `software` s ON csl.`sw_id`=s.`id` " . "JOIN `software` s ON csl.`sw_id`=s.`id` " .
"WHERE " . "WHERE " .
"chk.`type` = 'manual' AND " . "chk.`type` = 'manual' AND " .
@ -11092,6 +11096,7 @@ class db
elseif (strtolower($os->man) == 'microsoft' && strtolower($os->name) == 'windows 7') { elseif (strtolower($os->man) == 'microsoft' && strtolower($os->name) == 'windows 7') {
$sw = "Win7"; $sw = "Win7";
} }
$this->help->query_type = db_helper::INSERT;
$this->help->sql = "INSERT IGNORE INTO `target_checklist` (`tgt_id`,`chk_id`) " . $this->help->sql = "INSERT IGNORE INTO `target_checklist` (`tgt_id`,`chk_id`) " .
"SELECT '{$tgt['id']}',c.`id` FROM (" . "SELECT '{$tgt['id']}',c.`id` FROM (" .
"SELECT chk.*,s.`id` as 'real_sw' " . "SELECT chk.*,s.`id` as 'real_sw' " .
@ -11113,6 +11118,7 @@ class db
if (strtolower($os->man) == 'microsoft') { if (strtolower($os->man) == 'microsoft') {
$sw = "Windows"; $sw = "Windows";
} }
$this->help->query_type = db_helper::INSERT;
$this->help->sql = "INSERT IGNORE INTO `target_checklist` (`tgt_id`,`chk_id`) " . $this->help->sql = "INSERT IGNORE INTO `target_checklist` (`tgt_id`,`chk_id`) " .
"SELECT '{$tgt['id']}',c.`id` FROM (" . "SELECT '{$tgt['id']}',c.`id` FROM (" .
"SELECT chk.*,s.`id` AS 'real_sw' " . "SELECT chk.*,s.`id` AS 'real_sw' " .
@ -11129,6 +11135,7 @@ class db
; ;
$this->help->execute(); $this->help->execute();
$this->help->query_type = db_helper::INSERT;
$this->help->sql = "INSERT IGNORE INTO `target_checklist` (`tgt_id`,`chk_id`) " . $this->help->sql = "INSERT IGNORE INTO `target_checklist` (`tgt_id`,`chk_id`) " .
"SELECT '{$tgt['id']}',c.`id` FROM (" . "SELECT '{$tgt['id']}',c.`id` FROM (" .
"SELECT chk.*,csl.`sw_id` AS 'real_sw' FROM `checklist` chk " . "SELECT chk.*,csl.`sw_id` AS 'real_sw' FROM `checklist` chk " .
@ -11151,12 +11158,15 @@ class db
]); ]);
$this->help->execute(); $this->help->execute();
$this->help->query_type = db_helper::INSERT;
$this->help->sql = "INSERT IGNORE INTO `findings` (`tgt_id`,`pdi_id`,`findings_status_id`) " . $this->help->sql = "INSERT IGNORE INTO `findings` (`tgt_id`,`pdi_id`,`findings_status_id`) " .
"SELECT {$tgt['id']},pcl.pdi_id,'1' " . "SELECT {$tgt['id']},pcl.pdi_id,'1' " .
"FROM target_checklist tc " . "FROM target_checklist tc " .
"JOIN pdi_checklist_lookup pcl ON pcl.checklist_id = tc.chk_id " . "JOIN pdi_checklist_lookup pcl ON pcl.checklist_id = tc.chk_id " .
"WHERE tc.tgt_id = {$tgt['id']}"; "WHERE tc.tgt_id = {$tgt['id']}";
$this->help->execute(); $this->help->execute();
$this->update_Target_Counts($tgt['id']);
} }
} }
} }
@ -11302,6 +11312,8 @@ class db
"JOIN pdi_checklist_lookup pcl ON pcl.checklist_id = tc.chk_id " . "JOIN pdi_checklist_lookup pcl ON pcl.checklist_id = tc.chk_id " .
"WHERE tc.tgt_id = {$id}"; "WHERE tc.tgt_id = {$id}";
$this->help->execute(); $this->help->execute();
$this->update_Target_Counts($id);
} }
return true; return true;
@ -11310,9 +11322,9 @@ class db
/** /**
* Function to update the target finding counts * Function to update the target finding counts
* *
* @param target $tgt * @param int $tgt_id
*/ */
public function update_Target_Counts(target $tgt) public function update_Target_Counts($tgt_id)
{ {
$nf = 0; $nf = 0;
$nr = 0; $nr = 0;
@ -11321,24 +11333,43 @@ class db
$cat_2 = 0; $cat_2 = 0;
$cat_3 = 0; $cat_3 = 0;
$this->help->select("get_pdi_count", ['pdi_count'], [ $this->help->select('target t', ["COUNT(DISTINCT(pcl.pdi_id)) AS 'pdi_count'"], [
[ [
'field' => 'id', 'field' => 't.id',
'op' => '=', 'op' => '=',
'value' => $tgt->get_ID() 'value' => $tgt_id
] ]
], [
'table_joins' => [
"LEFT JOIN target_checklist tc ON tc.tgt_id = t.id",
"LEFT JOIN pdi_checklist_lookup pcl ON pcl.checklist_id = tc.chk_id",
"LEFT JOIN findings f ON f.pdi_id = pcl.pdi_id AND f.tgt_id = t.id"
],
'group' => 't.id'
]); ]);
$row = $this->help->execute(); $row = $this->help->execute();
if (is_array($row) && count($row) && isset($row['pdi_count'])) { if (is_array($row) && count($row) && isset($row['pdi_count'])) {
$nr = $row['pdi_count']; $nr = $row['pdi_count'];
} }
$this->help->select("get_finding_count", ['status', 'severity', 'finding_count'], [ $this->help->select("target t", [
"IF(ISNULL(fs.status), 'Not Reviewed', fs.status) AS 'status'",
"f.cat AS 'severity'",
"COUNT(DISTINCT f.pdi_id) AS 'finding_count'"
], [
[ [
'field' => 'id', 'field' => 't.id',
'op' => '=', 'op' => '=',
'value' => $tgt->get_ID() 'value' => $tgt_id
] ]
], [
'table_joins' => [
"LEFT JOIN target_checklist tc ON tc.tgt_id = t.id",
"LEFT JOIN pdi_checklist_lookup pcl ON tc.chk_id = pcl.checklist_id",
"LEFT JOIN findings f ON f.tgt_id = t.id AND f.pdi_id = pcl.pdi_id",
"LEFT JOIN findings_status fs ON f.findings_status_id = fs.id"
],
'group' => "t.id,`severity`,f.findings_status_id"
]); ]);
$rows = $this->help->execute(); $rows = $this->help->execute();
@ -11392,7 +11423,7 @@ class db
[ [
'field' => 'id', 'field' => 'id',
'op' => '=', 'op' => '=',
'value' => $tgt->get_ID() 'value' => $tgt_id
] ]
]); ]);
$this->help->execute(); $this->help->execute();
@ -11609,8 +11640,6 @@ class db
$this->help->debug(E_WARNING); $this->help->debug(E_WARNING);
} }
$this->update_Target_Counts($tgt);
return $tgt->get_ID(); return $tgt->get_ID();
} }
@ -12218,7 +12247,7 @@ class db
} }
$int_ids = $tmp; $int_ids = $tmp;
} }
if (count($int_ids)) { if (is_array($int_ids) && count($int_ids)) {
$this->help->delete("pps_list", null, [ $this->help->delete("pps_list", null, [
[ [
'field' => 'int_id', 'field' => 'int_id',

View File

@ -353,10 +353,16 @@ $conditions['not_reviewed_count']->getStyle()
->setEndColor($yellow); ->setEndColor($yellow);
$validation['host_status']->setType(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_LIST); $validation['host_status']->setType(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_LIST);
$validation['host_status']->setFormula1("=ValidStatus"); $validation['host_status']->setAllowBlank(false);
$validation['host_status']->setFormula1('"Not Reviewed,Not a Finding,Open,Not Applicable,No Data,Exception,False Positive"');
$validation['host_status']->setShowDropDown(true); $validation['host_status']->setShowDropDown(true);
$validation['host_status']->setShowErrorMessage(true);
$validation['host_status']->setError("Selected value not valid");
$validation['host_status']->setErrorTitle("Invalid selection");
$validation['host_status']->setErrorStyle(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_STOP);
$validation['true_false']->setType(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_LIST); $validation['true_false']->setType(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_LIST);
$validation['true_false']->setAllowBlank(false);
$validation['true_false']->setFormula1("=TRUE,FALSE"); $validation['true_false']->setFormula1("=TRUE,FALSE");
$validation['true_false']->setShowDropDown(true); $validation['true_false']->setShowDropDown(true);

View File

@ -190,7 +190,7 @@ if (!$nasl['nasl-count']) {
} }
if (reload) { if (reload) {
setTimeout(getLoadStatus, 1000); setTimeout(getLoadStatus, <?php print UPDATE_FREQ * 1000; ?>);
} }
else { else {
$('#db-err').remove(); $('#db-err').remove();

View File

@ -42,6 +42,9 @@
*/ */
include_once 'error.inc'; include_once 'error.inc';
include_once 'validation.inc'; include_once 'validation.inc';
include_once 'vendor/autoload.php';
use Monolog\Logger;
/** /**
* Function to get element or value from XML document using XPath * Function to get element or value from XML document using XPath
@ -122,6 +125,7 @@ function getValue($xml, $path, $starting = null, $keep = false)
*/ */
function FileDetection($filename) function FileDetection($filename)
{ {
$name = [];
$name['base_name'] = basename($filename); $name['base_name'] = basename($filename);
// print "\tCheck if exists".PHP_EOL; // print "\tCheck if exists".PHP_EOL;
if (!file_exists($filename)) { if (!file_exists($filename)) {
@ -720,9 +724,9 @@ function url_exists($url)
/** /**
* *
* @param type $start * @param float $start
* @param type $end * @param float $end
* @return type * @return float
*/ */
function microtime_diff($start, $end = null) function microtime_diff($start, $end = null)
{ {

View File

@ -186,7 +186,7 @@ class BackgroundProcess {
/** /**
* @param int $pid PID of process to resume * @param int $pid PID of process to resume
* *
* @return Cocur\BackgroundProcess\BackgroundProcess * @return BackgroundProcess
*/ */
static public function createFromPID($pid) { static public function createFromPID($pid) {
$process = new self(); $process = new self();

View File

@ -6,5 +6,46 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
'6124b4c8570aa390c21fafd04a26c69f' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php', 'abede361264e2ae69ec1eee813a101af' => $vendorDir . '/markbaker/complex/classes/src/functions/abs.php',
'21a5860fbef5be28db5ddfbc3cca67c4' => $vendorDir . '/markbaker/complex/classes/src/functions/acos.php',
'1546e3f9d127f2a9bb2d1b6c31c26ef1' => $vendorDir . '/markbaker/complex/classes/src/functions/acosh.php',
'd2516f7f4fba5ea5905f494b4a8262e0' => $vendorDir . '/markbaker/complex/classes/src/functions/acot.php',
'4511163d560956219b96882c0980b65e' => $vendorDir . '/markbaker/complex/classes/src/functions/acoth.php',
'c361f5616dc2a8da4fa3e137077cd4ea' => $vendorDir . '/markbaker/complex/classes/src/functions/acsc.php',
'02d68920fc98da71991ce569c91df0f6' => $vendorDir . '/markbaker/complex/classes/src/functions/acsch.php',
'88e19525eae308b4a6aa3419364875d3' => $vendorDir . '/markbaker/complex/classes/src/functions/argument.php',
'60e8e2d0827b58bfc904f13957e51849' => $vendorDir . '/markbaker/complex/classes/src/functions/asec.php',
'13d2f040713999eab66c359b4d79871d' => $vendorDir . '/markbaker/complex/classes/src/functions/asech.php',
'838ab38beb32c68a79d3cd2c007d5a04' => $vendorDir . '/markbaker/complex/classes/src/functions/asin.php',
'bb28eccd0f8f008333a1b3c163d604ac' => $vendorDir . '/markbaker/complex/classes/src/functions/asinh.php',
'9e483de83558c98f7d3feaa402c78cb3' => $vendorDir . '/markbaker/complex/classes/src/functions/atan.php',
'36b74b5b765ded91ee58c8ee3c0e85e3' => $vendorDir . '/markbaker/complex/classes/src/functions/atanh.php',
'05c15ee9510da7fd6bf6136f436500c0' => $vendorDir . '/markbaker/complex/classes/src/functions/conjugate.php',
'd3208dfbce2505e370788f9f22f6785f' => $vendorDir . '/markbaker/complex/classes/src/functions/cos.php',
'141cf1fb3a3046f8b64534b0ebab33ca' => $vendorDir . '/markbaker/complex/classes/src/functions/cosh.php',
'be660df75fd0dbe7fa7c03b7434b3294' => $vendorDir . '/markbaker/complex/classes/src/functions/cot.php',
'01e31ea298a51bc9e91517e3ce6b9e76' => $vendorDir . '/markbaker/complex/classes/src/functions/coth.php',
'803ddd97f7b1da68982a7b087c3476f6' => $vendorDir . '/markbaker/complex/classes/src/functions/csc.php',
'3001cdfd101ec3c32da34ee43c2e149b' => $vendorDir . '/markbaker/complex/classes/src/functions/csch.php',
'77b2d7629ef2a93fabb8c56754a91051' => $vendorDir . '/markbaker/complex/classes/src/functions/exp.php',
'4a4471296dec796c21d4f4b6552396a9' => $vendorDir . '/markbaker/complex/classes/src/functions/inverse.php',
'c3e9897e1744b88deb56fcdc39d34d85' => $vendorDir . '/markbaker/complex/classes/src/functions/ln.php',
'a83cacf2de942cff288de15a83afd26d' => $vendorDir . '/markbaker/complex/classes/src/functions/log2.php',
'6a861dacc9ee2f3061241d4c7772fa21' => $vendorDir . '/markbaker/complex/classes/src/functions/log10.php',
'4d2522d968c8ba78d6c13548a1b4200e' => $vendorDir . '/markbaker/complex/classes/src/functions/negative.php',
'fd587ca933fc0447fa5ab4843bdd97f7' => $vendorDir . '/markbaker/complex/classes/src/functions/pow.php',
'383ef01c62028fc78cd4388082fce3c2' => $vendorDir . '/markbaker/complex/classes/src/functions/rho.php',
'150fbd1b95029dc47292da97ecab9375' => $vendorDir . '/markbaker/complex/classes/src/functions/sec.php',
'549abd9bae174286d660bdaa07407c68' => $vendorDir . '/markbaker/complex/classes/src/functions/sech.php',
'6bfbf5eaea6b17a0ed85cb21ba80370c' => $vendorDir . '/markbaker/complex/classes/src/functions/sin.php',
'22efe13f1a497b8e199540ae2d9dc59c' => $vendorDir . '/markbaker/complex/classes/src/functions/sinh.php',
'e90135ab8e787795a509ed7147de207d' => $vendorDir . '/markbaker/complex/classes/src/functions/sqrt.php',
'bb0a7923ffc6a90919cd64ec54ff06bc' => $vendorDir . '/markbaker/complex/classes/src/functions/tan.php',
'2d302f32ce0fd4e433dd91c5bb404a28' => $vendorDir . '/markbaker/complex/classes/src/functions/tanh.php',
'24dd4658a952171a4ee79218c4f9fd06' => $vendorDir . '/markbaker/complex/classes/src/functions/theta.php',
'e49b7876281d6f5bc39536dde96d1f4a' => $vendorDir . '/markbaker/complex/classes/src/operations/add.php',
'47596e02b43cd6da7700134fd08f88cf' => $vendorDir . '/markbaker/complex/classes/src/operations/subtract.php',
'883af48563631547925fa4c3b48ead07' => $vendorDir . '/markbaker/complex/classes/src/operations/multiply.php',
'f190e3308e6ca23234a2875edc985c03' => $vendorDir . '/markbaker/complex/classes/src/operations/divideby.php',
'ac9e33ce6841aa5bf5d16d465a2f03a7' => $vendorDir . '/markbaker/complex/classes/src/operations/divideinto.php',
); );

View File

@ -9,6 +9,8 @@ return array(
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'PhpOffice\\PhpSpreadsheet\\' => array($vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet'), 'PhpOffice\\PhpSpreadsheet\\' => array($vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet'),
'PacificSec\\CPE\\' => array($vendorDir . '/pacificsec/cpe/src'),
'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'), 'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'),
'Cocur\\BackgroundProcess\\' => array($vendorDir . '/cocur/background-process/src'), 'Cocur\\BackgroundProcess\\' => array($vendorDir . '/cocur/background-process/src'),
); );

View File

@ -47,6 +47,24 @@ class ComposerAutoloaderInit69a0c53551ee5f4e61c53efb549e5e72
$loader->register(true); $loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit69a0c53551ee5f4e61c53efb549e5e72::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire69a0c53551ee5f4e61c53efb549e5e72($fileIdentifier, $file);
}
return $loader; return $loader;
} }
} }
function composerRequire69a0c53551ee5f4e61c53efb549e5e72($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}

View File

@ -6,12 +6,58 @@ namespace Composer\Autoload;
class ComposerStaticInit69a0c53551ee5f4e61c53efb549e5e72 class ComposerStaticInit69a0c53551ee5f4e61c53efb549e5e72
{ {
public static $files = array (
'abede361264e2ae69ec1eee813a101af' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/abs.php',
'21a5860fbef5be28db5ddfbc3cca67c4' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acos.php',
'1546e3f9d127f2a9bb2d1b6c31c26ef1' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acosh.php',
'd2516f7f4fba5ea5905f494b4a8262e0' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acot.php',
'4511163d560956219b96882c0980b65e' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acoth.php',
'c361f5616dc2a8da4fa3e137077cd4ea' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acsc.php',
'02d68920fc98da71991ce569c91df0f6' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acsch.php',
'88e19525eae308b4a6aa3419364875d3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/argument.php',
'60e8e2d0827b58bfc904f13957e51849' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asec.php',
'13d2f040713999eab66c359b4d79871d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asech.php',
'838ab38beb32c68a79d3cd2c007d5a04' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asin.php',
'bb28eccd0f8f008333a1b3c163d604ac' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asinh.php',
'9e483de83558c98f7d3feaa402c78cb3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/atan.php',
'36b74b5b765ded91ee58c8ee3c0e85e3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/atanh.php',
'05c15ee9510da7fd6bf6136f436500c0' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/conjugate.php',
'd3208dfbce2505e370788f9f22f6785f' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cos.php',
'141cf1fb3a3046f8b64534b0ebab33ca' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cosh.php',
'be660df75fd0dbe7fa7c03b7434b3294' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cot.php',
'01e31ea298a51bc9e91517e3ce6b9e76' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/coth.php',
'803ddd97f7b1da68982a7b087c3476f6' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/csc.php',
'3001cdfd101ec3c32da34ee43c2e149b' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/csch.php',
'77b2d7629ef2a93fabb8c56754a91051' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/exp.php',
'4a4471296dec796c21d4f4b6552396a9' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/inverse.php',
'c3e9897e1744b88deb56fcdc39d34d85' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/ln.php',
'a83cacf2de942cff288de15a83afd26d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/log2.php',
'6a861dacc9ee2f3061241d4c7772fa21' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/log10.php',
'4d2522d968c8ba78d6c13548a1b4200e' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/negative.php',
'fd587ca933fc0447fa5ab4843bdd97f7' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/pow.php',
'383ef01c62028fc78cd4388082fce3c2' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/rho.php',
'150fbd1b95029dc47292da97ecab9375' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sec.php',
'549abd9bae174286d660bdaa07407c68' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sech.php',
'6bfbf5eaea6b17a0ed85cb21ba80370c' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sin.php',
'22efe13f1a497b8e199540ae2d9dc59c' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sinh.php',
'e90135ab8e787795a509ed7147de207d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sqrt.php',
'bb0a7923ffc6a90919cd64ec54ff06bc' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/tan.php',
'2d302f32ce0fd4e433dd91c5bb404a28' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/tanh.php',
'24dd4658a952171a4ee79218c4f9fd06' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/theta.php',
'e49b7876281d6f5bc39536dde96d1f4a' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/add.php',
'47596e02b43cd6da7700134fd08f88cf' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/subtract.php',
'883af48563631547925fa4c3b48ead07' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/multiply.php',
'f190e3308e6ca23234a2875edc985c03' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/divideby.php',
'ac9e33ce6841aa5bf5d16d465a2f03a7' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/divideinto.php',
);
public static $prefixLengthsPsr4 = array ( public static $prefixLengthsPsr4 = array (
'P' => 'P' =>
array ( array (
'Psr\\SimpleCache\\' => 16, 'Psr\\SimpleCache\\' => 16,
'Psr\\Log\\' => 8, 'Psr\\Log\\' => 8,
'PhpOffice\\PhpSpreadsheet\\' => 25, 'PhpOffice\\PhpSpreadsheet\\' => 25,
'PacificSec\\CPE\\' => 15,
), ),
'M' => 'M' =>
array ( array (
@ -19,6 +65,7 @@ class ComposerStaticInit69a0c53551ee5f4e61c53efb549e5e72
), ),
'C' => 'C' =>
array ( array (
'Complex\\' => 8,
'Cocur\\BackgroundProcess\\' => 24, 'Cocur\\BackgroundProcess\\' => 24,
), ),
); );
@ -36,10 +83,18 @@ class ComposerStaticInit69a0c53551ee5f4e61c53efb549e5e72
array ( array (
0 => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet', 0 => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet',
), ),
'PacificSec\\CPE\\' =>
array (
0 => __DIR__ . '/..' . '/pacificsec/cpe/src',
),
'Monolog\\' => 'Monolog\\' =>
array ( array (
0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog', 0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog',
), ),
'Complex\\' =>
array (
0 => __DIR__ . '/..' . '/markbaker/complex/classes/src',
),
'Cocur\\BackgroundProcess\\' => 'Cocur\\BackgroundProcess\\' =>
array ( array (
0 => __DIR__ . '/..' . '/cocur/background-process/src', 0 => __DIR__ . '/..' . '/cocur/background-process/src',

View File

@ -39,6 +39,103 @@
"unix" "unix"
] ]
}, },
{
"name": "markbaker/complex",
"version": "1.4.6",
"version_normalized": "1.4.6.0",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPComplex.git",
"reference": "a78d82ae4e682c3809fc3023d1b0ce654f6ab12b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/a78d82ae4e682c3809fc3023d1b0ce654f6ab12b",
"reference": "a78d82ae4e682c3809fc3023d1b0ce654f6ab12b",
"shasum": ""
},
"require": {
"php": "^5.6.0|^7.0.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3",
"phpcompatibility/php-compatibility": "^8.0",
"phpdocumentor/phpdocumentor": "2.*",
"phploc/phploc": "2.*",
"phpmd/phpmd": "2.*",
"phpunit/phpunit": "^4.8.35|^5.4.0",
"sebastian/phpcpd": "2.*",
"squizlabs/php_codesniffer": "^3.3.0"
},
"time": "2018-07-31T08:38:40+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Complex\\": "classes/src/"
},
"files": [
"classes/src/functions/abs.php",
"classes/src/functions/acos.php",
"classes/src/functions/acosh.php",
"classes/src/functions/acot.php",
"classes/src/functions/acoth.php",
"classes/src/functions/acsc.php",
"classes/src/functions/acsch.php",
"classes/src/functions/argument.php",
"classes/src/functions/asec.php",
"classes/src/functions/asech.php",
"classes/src/functions/asin.php",
"classes/src/functions/asinh.php",
"classes/src/functions/atan.php",
"classes/src/functions/atanh.php",
"classes/src/functions/conjugate.php",
"classes/src/functions/cos.php",
"classes/src/functions/cosh.php",
"classes/src/functions/cot.php",
"classes/src/functions/coth.php",
"classes/src/functions/csc.php",
"classes/src/functions/csch.php",
"classes/src/functions/exp.php",
"classes/src/functions/inverse.php",
"classes/src/functions/ln.php",
"classes/src/functions/log2.php",
"classes/src/functions/log10.php",
"classes/src/functions/negative.php",
"classes/src/functions/pow.php",
"classes/src/functions/rho.php",
"classes/src/functions/sec.php",
"classes/src/functions/sech.php",
"classes/src/functions/sin.php",
"classes/src/functions/sinh.php",
"classes/src/functions/sqrt.php",
"classes/src/functions/tan.php",
"classes/src/functions/tanh.php",
"classes/src/functions/theta.php",
"classes/src/operations/add.php",
"classes/src/operations/subtract.php",
"classes/src/operations/multiply.php",
"classes/src/operations/divideby.php",
"classes/src/operations/divideinto.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@lange.demon.co.uk"
}
],
"description": "PHP Class for working with complex numbers",
"homepage": "https://github.com/MarkBaker/PHPComplex",
"keywords": [
"complex",
"mathematics"
]
},
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
"version": "1.23.0", "version": "1.23.0",
@ -121,36 +218,62 @@
}, },
{ {
"name": "pacificsec/cpe", "name": "pacificsec/cpe",
"version": "1.0.0", "version": "1.0.1",
"version_normalized": "1.0.0.0", "version_normalized": "1.0.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pacificsec/cpe.git", "url": "https://github.com/pacificsec/cpe.git",
"reference": "3d78d66fc4ea249b6f353a7c48f426835a792d11" "reference": "52cc49e04388ba00493be634287f6ce3efb30afc"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pacificsec/cpe/zipball/3d78d66fc4ea249b6f353a7c48f426835a792d11", "url": "https://api.github.com/repos/pacificsec/cpe/zipball/52cc49e04388ba00493be634287f6ce3efb30afc",
"reference": "3d78d66fc4ea249b6f353a7c48f426835a792d11", "reference": "52cc49e04388ba00493be634287f6ce3efb30afc",
"shasum": "" "shasum": ""
}, },
"require": {
"php": ">=5.3.0"
},
"time": "2018-08-22T17:55:09+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "source",
"notification-url": "https://packagist.org/downloads/" "autoload": {
"psr-4": {
"PacificSec\\CPE\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Antonio Franco",
"email": "antonio.franco@pacificsec.com"
}
],
"description": "CPE: Common Platform Enumeration for PHP",
"homepage": "https://github.com/pacificsec/cpe",
"keywords": [
"cpe",
"cve",
"pacificsec",
"security"
]
}, },
{ {
"name": "phpoffice/phpspreadsheet", "name": "phpoffice/phpspreadsheet",
"version": "1.2.1", "version": "1.4.0",
"version_normalized": "1.2.1.0", "version_normalized": "1.4.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git", "url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "36acc372875c4d894dc093825ce4f62209db5a76" "reference": "125f462a718956f37d81305ca0df4f17cef0f3b9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/36acc372875c4d894dc093825ce4f62209db5a76", "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/125f462a718956f37d81305ca0df4f17cef0f3b9",
"reference": "36acc372875c4d894dc093825ce4f62209db5a76", "reference": "125f462a718956f37d81305ca0df4f17cef0f3b9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -166,6 +289,7 @@
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"ext-zip": "*", "ext-zip": "*",
"ext-zlib": "*", "ext-zlib": "*",
"markbaker/complex": "^1.4.1",
"php": "^5.6|^7.0", "php": "^5.6|^7.0",
"psr/simple-cache": "^1.0" "psr/simple-cache": "^1.0"
}, },
@ -175,7 +299,7 @@
"jpgraph/jpgraph": "^4.0", "jpgraph/jpgraph": "^4.0",
"mpdf/mpdf": "^7.0.0", "mpdf/mpdf": "^7.0.0",
"phpunit/phpunit": "^5.7", "phpunit/phpunit": "^5.7",
"squizlabs/php_codesniffer": "^2.7", "squizlabs/php_codesniffer": "^3.3",
"tecnickcom/tcpdf": "^6.2" "tecnickcom/tcpdf": "^6.2"
}, },
"suggest": { "suggest": {
@ -184,7 +308,7 @@
"mpdf/mpdf": "Option for rendering PDF with PDF Writer", "mpdf/mpdf": "Option for rendering PDF with PDF Writer",
"tecnick.com/tcpdf": "Option for rendering PDF with PDF Writer" "tecnick.com/tcpdf": "Option for rendering PDF with PDF Writer"
}, },
"time": "2018-04-10T03:53:16+00:00", "time": "2018-08-06T02:58:06+00:00",
"type": "library", "type": "library",
"installation-source": "source", "installation-source": "source",
"autoload": { "autoload": {
@ -327,23 +451,23 @@
}, },
{ {
"name": "tecnickcom/tcpdf", "name": "tecnickcom/tcpdf",
"version": "6.2.17", "version": "6.2.22",
"version_normalized": "6.2.17.0", "version_normalized": "6.2.22.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/tecnickcom/TCPDF.git", "url": "https://github.com/tecnickcom/TCPDF.git",
"reference": "64fc19439863e1b1314487a72a74d9bfd0b55a53" "reference": "ac6e92fccc7d9383dfd787056831349621b1aca2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/64fc19439863e1b1314487a72a74d9bfd0b55a53", "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/ac6e92fccc7d9383dfd787056831349621b1aca2",
"reference": "64fc19439863e1b1314487a72a74d9bfd0b55a53", "reference": "ac6e92fccc7d9383dfd787056831349621b1aca2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.0" "php": ">=5.3.0"
}, },
"time": "2018-02-24T11:48:20+00:00", "time": "2018-09-14T15:26:29+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {

155
inc/vendor/markbaker/complex/README.md vendored Normal file
View File

@ -0,0 +1,155 @@
PHPComplex
==========
---
PHP Class for handling Complex numbers
Master: [![Build Status](https://travis-ci.org/MarkBaker/PHPComplex.png?branch=master)](http://travis-ci.org/MarkBaker/PHPComplex)
Develop: [![Build Status](https://travis-ci.org/MarkBaker/PHPComplex.png?branch=develop)](http://travis-ci.org/MarkBaker/PHPComplex)
---
The library currently provides the following operations:
- addition
- subtraction
- multiplication
- division
- division by
- division into
together with functions for
- theta (polar theta angle)
- rho (polar distance/radius)
- conjugate
* negative
- inverse (1 / complex)
- cos (cosine)
- acos (inverse cosine)
- cosh (hyperbolic cosine)
- acosh (inverse hyperbolic cosine)
- sin (sine)
- asin (inverse sine)
- sinh (hyperbolic sine)
- asinh (inverse hyperbolic sine)
- sec (secant)
- asec (inverse secant)
- sech (hyperbolic secant)
- asech (inverse hyperbolic secant)
- csc (cosecant)
- acsc (inverse cosecant)
- csch (hyperbolic secant)
- acsch (inverse hyperbolic secant)
- tan (tangent)
- atan (inverse tangent)
- tanh (hyperbolic tangent)
- atanh (inverse hyperbolic tangent)
- cot (cotangent)
- acot (inverse cotangent)
- coth (hyperbolic cotangent)
- acoth (inverse hyperbolic cotangent)
- sqrt (square root)
- exp (exponential)
- ln (natural log)
- log10 (base-10 log)
- log2 (base-2 log)
- pow (raised to the power of a real number)
---
# Usage
To create a new complex object, you can provide either the real, imaginary and suffix parts as individual values, or as an array of values passed passed to the constructor; or a string representing the value. e.g
```
$real = 1.23;
$imaginary = -4.56;
$suffix = 'i';
$complexObject = new Complex\Complex($real, $imaginary, $suffix);
```
or
```
$real = 1.23;
$imaginary = -4.56;
$suffix = 'i';
$arguments = [$real, $imaginary, $suffix];
$complexObject = new Complex\Complex($arguments);
```
or
```
$complexString = '1.23-4.56i';
$complexObject = new Complex\Complex($complexString);
```
Complex objects are immutable: whenever you call a method or pass a complex value to a function that returns a complex value, a new Complex object will be returned, and the original will remain unchanged.
This also allows you to chain multiple methods as you would for a fluent interface (as long as they are methods that will return a Complex result).
## Performing Mathematical Operations
To perform mathematical operations with Complex values, you can call the appropriate method against a complex value, passing other values as arguments
```
$complexString1 = '1.23-4.56i';
$complexString2 = '2.34+5.67i';
$complexObject = new Complex\Complex($complexString1);
echo $complexObject->add($complexString2);
```
or pass all values to the appropriate function
```
$complexString1 = '1.23-4.56i';
$complexString2 = '2.34+5.67i';
echo Complex\add($complexString1, $complexString2);
```
If you want to perform the same operation against multiple values (e.g. to add three or more complex numbers), then you can pass multiple arguments to any of the operations.
You can pass these arguments as Complex objects, or as an array or string that will parse to a complex object.
## Using functions
When calling any of the available functions for a complex value, you can either call the relevant method for the Complex object
```
$complexString = '1.23-4.56i';
$complexObject = new Complex\Complex($complexString);
echo $complexObject->sinh();
```
or you can call the function as you would in procedural code, passing the Complex object as an argument
```
$complexString = '1.23-4.56i';
$complexObject = new Complex\Complex($complexString);
echo Complex\sinh($complexObject);
```
When called procedurally using the function, you can pass in the argument as a Complex object, or as an array or string that will parse to a complex object.
```
$complexString = '1.23-4.56i';
echo Complex\sinh($complexString);
```
In the case of the `pow()` function (the only implemented function that requires an additional argument) you need to pass both arguments when calling the function procedurally
```
$complexString = '1.23-4.56i';
$complexObject = new Complex\Complex($complexString);
echo Complex\pow($complexObject, 2);
```
or pass the additional argument when calling the method
```
$complexString = '1.23-4.56i';
$complexObject = new Complex\Complex($complexString);
echo $complexObject->pow(2);
```

View File

@ -0,0 +1,53 @@
<?php
namespace Complex;
/**
*
* Autoloader for Complex classes
*
* @package Complex
* @copyright Copyright (c) 2014 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
*/
class Autoloader
{
/**
* Register the Autoloader with SPL
*
*/
public static function Register()
{
if (function_exists('__autoload')) {
// Register any existing autoloader function with SPL, so we don't get any clashes
spl_autoload_register('__autoload');
}
// Register ourselves with SPL
return spl_autoload_register(['Complex\Autoloader', 'Load']);
}
/**
* Autoload a class identified by name
*
* @param string $pClassName Name of the object to load
*/
public static function Load($pClassName)
{
if ((class_exists($pClassName, false)) || (strpos($pClassName, 'Complex\\') !== 0)) {
// Either already loaded, or not a Complex class request
return false;
}
$pClassFilePath = __DIR__ . DIRECTORY_SEPARATOR .
'src' . DIRECTORY_SEPARATOR .
str_replace('Complex\\', '', $pClassName) .
'.php';
if ((file_exists($pClassFilePath) === false) || (is_readable($pClassFilePath) === false)) {
// Can't load
return false;
}
require($pClassFilePath);
}
}

View File

@ -0,0 +1,38 @@
<?php
include_once __DIR__ . '/Autoloader.php';
\Complex\Autoloader::Register();
abstract class FilesystemRegexFilter extends RecursiveRegexIterator
{
protected $regex;
public function __construct(RecursiveIterator $it, $regex)
{
$this->regex = $regex;
parent::__construct($it, $regex);
}
}
class FilenameFilter extends FilesystemRegexFilter
{
// Filter files against the regex
public function accept()
{
return (!$this->isFile() || preg_match($this->regex, $this->getFilename()));
}
}
$srcFolder = __DIR__ . DIRECTORY_SEPARATOR . 'src';
$srcDirectory = new RecursiveDirectoryIterator($srcFolder);
$filteredFileList = new FilenameFilter($srcDirectory, '/(?:php)$/i');
$filteredFileList = new FilenameFilter($filteredFileList, '/^(?!.*(Complex|Exception)\.php).*$/i');
foreach (new RecursiveIteratorIterator($filteredFileList) as $file) {
if ($file->isFile()) {
include_once $file;
}
}

View File

@ -0,0 +1,387 @@
<?php
/**
*
* Class for the management of Complex numbers
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Complex Number object.
*
* @package Complex
*
* @method float abs()
* @method Complex acos()
* @method Complex acosh()
* @method Complex acot()
* @method Complex acoth()
* @method Complex acsc()
* @method Complex acsch()
* @method float argument()
* @method Complex asec()
* @method Complex asech()
* @method Complex asin()
* @method Complex asinh()
* @method Complex atan()
* @method Complex atanh()
* @method Complex conjugate()
* @method Complex cos()
* @method Complex cosh()
* @method Complex cot()
* @method Complex coth()
* @method Complex csc()
* @method Complex csch()
* @method Complex exp()
* @method Complex inverse()
* @method Complex ln()
* @method Complex log2()
* @method Complex log10()
* @method Complex negative()
* @method Complex pow(int|float $power)
* @method float rho()
* @method Complex sec()
* @method Complex sech()
* @method Complex sin()
* @method Complex sinh()
* @method Complex sqrt()
* @method Complex tan()
* @method Complex tanh()
* @method float theta()
* @method Complex add(...$complexValues)
* @method Complex subtract(...$complexValues)
* @method Complex multiply(...$complexValues)
* @method Complex divideby(...$complexValues)
* @method Complex divideinto(...$complexValues)
*/
class Complex
{
/**
* @constant Euler's Number.
*/
const EULER = 2.7182818284590452353602874713526624977572;
/**
* @constant Regexp to split an input string into real and imaginary components and suffix
*/
const NUMBER_SPLIT_REGEXP =
'` ^
( # Real part
[-+]?(\d+\.?\d*|\d*\.?\d+) # Real value (integer or float)
([Ee][-+]?[0-2]?\d{1,3})? # Optional real exponent for scientific format
)
( # Imaginary part
[-+]?(\d+\.?\d*|\d*\.?\d+) # Imaginary value (integer or float)
([Ee][-+]?[0-2]?\d{1,3})? # Optional imaginary exponent for scientific format
)?
( # Imaginary part is optional
([-+]?) # Imaginary (implicit 1 or -1) only
([ij]?) # Imaginary i or j - depending on whether mathematical or engineering
)
$`uix';
/**
* @var float $realPart The value of of this complex number on the real plane.
*/
protected $realPart = 0.0;
/**
* @var float $imaginaryPart The value of of this complex number on the imaginary plane.
*/
protected $imaginaryPart = 0.0;
/**
* @var string $suffix The suffix for this complex number (i or j).
*/
protected $suffix;
/**
* Validates whether the argument is a valid complex number, converting scalar or array values if possible
*
* @param mixed $complexNumber The value to parse
* @return array
* @throws Exception If the argument isn't a Complex number or cannot be converted to one
*/
private static function parseComplex($complexNumber)
{
// Test for real number, with no imaginary part
if (is_numeric($complexNumber)) {
return [$complexNumber, 0, null];
}
// Fix silly human errors
$complexNumber = str_replace(
['+-', '-+', '++', '--'],
['-', '-', '+', '+'],
$complexNumber
);
// Basic validation of string, to parse out real and imaginary parts, and any suffix
$validComplex = preg_match(
self::NUMBER_SPLIT_REGEXP,
$complexNumber,
$complexParts
);
if (!$validComplex) {
// Neither real nor imaginary part, so test to see if we actually have a suffix
$validComplex = preg_match('/^([\-\+]?)([ij])$/ui', $complexNumber, $complexParts);
if (!$validComplex) {
throw new Exception('Invalid complex number');
}
// We have a suffix, so set the real to 0, the imaginary to either 1 or -1 (as defined by the sign)
$imaginary = 1;
if ($complexParts[1] === '-') {
$imaginary = 0 - $imaginary;
}
return [0, $imaginary, $complexParts[2]];
}
// If we don't have an imaginary part, identify whether it should be +1 or -1...
if (($complexParts[4] === '') && ($complexParts[9] !== '')) {
if ($complexParts[7] !== $complexParts[9]) {
$complexParts[4] = 1;
if ($complexParts[8] === '-') {
$complexParts[4] = -1;
}
} else {
// ... or if we have only the real and no imaginary part
// (in which case our real should be the imaginary)
$complexParts[4] = $complexParts[1];
$complexParts[1] = 0;
}
}
// Return real and imaginary parts and suffix as an array, and set a default suffix if user input lazily
return [
$complexParts[1],
$complexParts[4],
!empty($complexParts[9]) ? $complexParts[9] : 'i'
];
}
public function __construct($realPart = 0.0, $imaginaryPart = null, $suffix = 'i')
{
if ($imaginaryPart === null) {
if (is_array($realPart)) {
// We have an array of (potentially) real and imaginary parts, and any suffix
list ($realPart, $imaginaryPart, $suffix) = array_values($realPart) + [0.0, 0.0, 'i'];
} elseif ((is_string($realPart)) || (is_numeric($realPart))) {
// We've been given a string to parse to extract the real and imaginary parts, and any suffix
list($realPart, $imaginaryPart, $suffix) = self::parseComplex($realPart);
}
}
if ($imaginaryPart <> 0.0 && empty($suffix)) {
$suffix = 'i';
}
// Set parsed values in our properties
$this->realPart = (float) $realPart;
$this->imaginaryPart = (float) $imaginaryPart;
$this->suffix = strtolower($suffix);
}
/**
* Gets the real part of this complex number
*
* @return Float
*/
public function getReal()
{
return $this->realPart;
}
/**
* Gets the imaginary part of this complex number
*
* @return Float
*/
public function getImaginary()
{
return $this->imaginaryPart;
}
/**
* Gets the suffix of this complex number
*
* @return String
*/
public function getSuffix()
{
return $this->suffix;
}
/**
* Returns true if this is a real value, false if a complex value
*
* @return Bool
*/
public function isReal()
{
return $this->imaginaryPart == 0.0;
}
/**
* Returns true if this is a complex value, false if a real value
*
* @return Bool
*/
public function isComplex()
{
return !$this->isReal();
}
public function format()
{
$str = "";
if ($this->imaginaryPart != 0.0) {
if (\abs($this->imaginaryPart) != 1.0) {
$str .= $this->imaginaryPart . $this->suffix;
} else {
$str .= (($this->imaginaryPart < 0.0) ? '-' : '') . $this->suffix;
}
}
if ($this->realPart != 0.0) {
if (($str) && ($this->imaginaryPart > 0.0)) {
$str = "+" . $str;
}
$str = $this->realPart . $str;
}
if (!$str) {
$str = "0.0";
}
return $str;
}
public function __toString()
{
return $this->format();
}
/**
* Validates whether the argument is a valid complex number, converting scalar or array values if possible
*
* @param mixed $complex The value to validate
* @return Complex
* @throws Exception If the argument isn't a Complex number or cannot be converted to one
*/
public static function validateComplexArgument($complex)
{
if (is_scalar($complex) || is_array($complex)) {
$complex = new Complex($complex);
} elseif (!is_object($complex) || !($complex instanceof Complex)) {
throw new Exception('Value is not a valid complex number');
}
return $complex;
}
/**
* Returns the reverse of this complex number
*
* @return Complex
*/
public function reverse()
{
return new Complex(
$this->imaginaryPart,
$this->realPart,
($this->realPart == 0.0) ? null : $this->suffix
);
}
public function invertImaginary()
{
return new Complex(
$this->realPart,
$this->imaginaryPart * -1,
($this->imaginaryPart == 0.0) ? null : $this->suffix
);
}
public function invertReal()
{
return new Complex(
$this->realPart * -1,
$this->imaginaryPart,
($this->imaginaryPart == 0.0) ? null : $this->suffix
);
}
protected static $functions = [
'abs',
'acos',
'acosh',
'acot',
'acoth',
'acsc',
'acsch',
'argument',
'asec',
'asech',
'asin',
'asinh',
'atan',
'atanh',
'conjugate',
'cos',
'cosh',
'cot',
'coth',
'csc',
'csch',
'exp',
'inverse',
'ln',
'log2',
'log10',
'negative',
'pow',
'rho',
'sec',
'sech',
'sin',
'sinh',
'sqrt',
'tan',
'tanh',
'theta',
];
protected static $operations = [
'add',
'subtract',
'multiply',
'divideby',
'divideinto',
];
/**
* Returns the result of the function call or operation
*
* @return Complex|float
* @throws Exception|\InvalidArgumentException
*/
public function __call($functionName, $arguments)
{
$functionName = strtolower(str_replace('_', '', $functionName));
// Test for function calls
if (in_array($functionName, self::$functions)) {
$functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
return $functionName($this, ...$arguments);
}
// Test for operation calls
if (in_array($functionName, self::$operations)) {
$functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
return $functionName($this, ...$arguments);
}
throw new Exception('Function or Operation does not exist');
}
}

View File

@ -0,0 +1,13 @@
<?php
/**
* Exception.
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
class Exception extends \Exception
{
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex abs() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the absolute value (modulus) of a complex number.
* Also known as the rho of the complex number, i.e. the distance/radius
* from the centrepoint to the representation of the number in polar coordinates.
*
* This function is a synonym for rho()
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return float The absolute (or rho) value of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*
* @see rho
*
*/
function abs($complex)
{
return rho($complex);
}

View File

@ -0,0 +1,38 @@
<?php
/**
*
* Function code for the complex acos() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse cosine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse cosine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function acos($complex)
{
$complex = Complex::validateComplexArgument($complex);
$square = clone $complex;
$square = multiply($square, $complex);
$invsqrt = new Complex(1.0);
$invsqrt = subtract($invsqrt, $square);
$invsqrt = sqrt($invsqrt);
$adjust = new Complex(
$complex->getReal() - $invsqrt->getImaginary(),
$complex->getImaginary() + $invsqrt->getReal()
);
$log = ln($adjust);
return new Complex(
$log->getImaginary(),
-1 * $log->getReal()
);
}

View File

@ -0,0 +1,34 @@
<?php
/**
*
* Function code for the complex acosh() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse hyperbolic cosine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse hyperbolic cosine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function acosh($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal() && ($complex->getReal() > 1)) {
return new Complex(\acosh($complex->getReal()));
}
$acosh = acos($complex)
->reverse();
if ($acosh->getReal() < 0.0) {
$acosh = $acosh->invertReal();
}
return $acosh;
}

View File

@ -0,0 +1,25 @@
<?php
/**
*
* Function code for the complex acot() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse cotangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse cotangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function acot($complex)
{
$complex = Complex::validateComplexArgument($complex);
return atan(inverse($complex));
}

View File

@ -0,0 +1,25 @@
<?php
/**
*
* Function code for the complex acoth() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse hyperbolic cotangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse hyperbolic cotangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function acoth($complex)
{
$complex = Complex::validateComplexArgument($complex);
return atanh(inverse($complex));
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex acsc() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse cosecant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse cosecant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function acsc($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return INF;
}
return asin(inverse($complex));
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex acsch() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse hyperbolic cosecant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse hyperbolic cosecant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function acsch($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return INF;
}
return asinh(inverse($complex));
}

View File

@ -0,0 +1,28 @@
<?php
/**
*
* Function code for the complex argument() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the argument of a complex number.
* Also known as the theta of the complex number, i.e. the angle in radians
* from the real axis to the representation of the number in polar coordinates.
*
* This function is a synonym for theta()
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return float The argument (or theta) value of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*
* @see theta
*/
function argument($complex)
{
return theta($complex);
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex asec() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse secant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse secant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function asec($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return INF;
}
return acos(inverse($complex));
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex asech() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse hyperbolic secant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse hyperbolic secant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function asech($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return INF;
}
return acosh(inverse($complex));
}

View File

@ -0,0 +1,37 @@
<?php
/**
*
* Function code for the complex asin() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse sine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse sine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function asin($complex)
{
$complex = Complex::validateComplexArgument($complex);
$square = multiply($complex, $complex);
$invsqrt = new Complex(1.0);
$invsqrt = subtract($invsqrt, $square);
$invsqrt = sqrt($invsqrt);
$adjust = new Complex(
$invsqrt->getReal() - $complex->getImaginary(),
$invsqrt->getImaginary() + $complex->getReal()
);
$log = ln($adjust);
return new Complex(
$log->getImaginary(),
-1 * $log->getReal()
);
}

View File

@ -0,0 +1,33 @@
<?php
/**
*
* Function code for the complex asinh() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse hyperbolic sine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse hyperbolic sine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function asinh($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal() && ($complex->getReal() > 1)) {
return new Complex(\asinh($complex->getReal()));
}
$asinh = clone $complex;
$asinh = $asinh->reverse()
->invertReal();
$asinh = asin($asinh);
return $asinh->reverse()
->invertImaginary();
}

View File

@ -0,0 +1,45 @@
<?php
/**
*
* Function code for the complex atan() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
//include_once 'Math/Complex.php';
//include_once 'Math/ComplexOp.php';
/**
* Returns the inverse tangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse tangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function atan($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
return new Complex(\atan($complex->getReal()));
}
$t1Value = new Complex(-1 * $complex->getImaginary(), $complex->getReal());
$uValue = new Complex(1, 0);
$d1Value = clone $uValue;
$d1Value = subtract($d1Value, $t1Value);
$d2Value = add($t1Value, $uValue);
$uResult = $d1Value->divideBy($d2Value);
$uResult = ln($uResult);
return new Complex(
(($uResult->getImaginary() == M_PI) ? -M_PI : $uResult->getImaginary()) * -0.5,
$uResult->getReal() * 0.5,
$complex->getSuffix()
);
}

View File

@ -0,0 +1,38 @@
<?php
/**
*
* Function code for the complex atanh() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse hyperbolic tangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse hyperbolic tangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function atanh($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
$real = $complex->getReal();
if ($real >= -1.0 && $real <= 1.0) {
return new Complex(\atanh($real));
} else {
return new Complex(\atanh(1 / $real), (($real < 0.0) ? M_PI_2 : -1 * M_PI_2));
}
}
$iComplex = clone $complex;
$iComplex = $iComplex->invertImaginary()
->reverse();
return atan($iComplex)
->invertReal()
->reverse();
}

View File

@ -0,0 +1,28 @@
<?php
/**
*
* Function code for the complex conjugate() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the complex conjugate of a complex number
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The conjugate of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function conjugate($complex)
{
$complex = Complex::validateComplexArgument($complex);
return new Complex(
$complex->getReal(),
-1 * $complex->getImaginary(),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,34 @@
<?php
/**
*
* Function code for the complex cos() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the cosine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The cosine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function cos($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
return new Complex(\cos($complex->getReal()));
}
return conjugate(
new Complex(
\cos($complex->getReal()) * \cosh($complex->getImaginary()),
\sin($complex->getReal()) * \sinh($complex->getImaginary()),
$complex->getSuffix()
)
);
}

View File

@ -0,0 +1,32 @@
<?php
/**
*
* Function code for the complex cosh() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the hyperbolic cosine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The hyperbolic cosine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function cosh($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
return new Complex(\cosh($complex->getReal()));
}
return new Complex(
\cosh($complex->getReal()) * \cos($complex->getImaginary()),
\sinh($complex->getReal()) * \sin($complex->getImaginary()),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex cot() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the cotangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The cotangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function cot($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return new Complex(INF);
}
return inverse(tan($complex));
}

View File

@ -0,0 +1,24 @@
<?php
/**
*
* Function code for the complex coth() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the hyperbolic cotangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The hyperbolic cotangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function coth($complex)
{
$complex = Complex::validateComplexArgument($complex);
return inverse(tanh($complex));
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex csc() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the cosecant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The cosecant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function csc($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return INF;
}
return inverse(sin($complex));
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex csch() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the hyperbolic cosecant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The hyperbolic cosecant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function csch($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return INF;
}
return inverse(sinh($complex));
}

View File

@ -0,0 +1,34 @@
<?php
/**
*
* Function code for the complex exp() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the exponential of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The exponential of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function exp($complex)
{
$complex = Complex::validateComplexArgument($complex);
if (($complex->getReal() == 0.0) && (\abs($complex->getImaginary()) == M_PI)) {
return new Complex(-1.0, 0.0);
}
$rho = \exp($complex->getReal());
return new Complex(
$rho * \cos($complex->getImaginary()),
$rho * \sin($complex->getImaginary()),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex inverse() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function inverse($complex)
{
$complex = clone Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
throw new \InvalidArgumentException('Division by zero');
}
return $complex->divideInto(1.0);
}

View File

@ -0,0 +1,33 @@
<?php
/**
*
* Function code for the complex ln() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the natural logarithm of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The natural logarithm of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If the real and the imaginary parts are both zero
*/
function ln($complex)
{
$complex = Complex::validateComplexArgument($complex);
if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
throw new \InvalidArgumentException();
}
return new Complex(
\log(rho($complex)),
theta($complex),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,32 @@
<?php
/**
*
* Function code for the complex log10() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the common logarithm (base 10) of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The common logarithm (base 10) of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If the real and the imaginary parts are both zero
*/
function log10($complex)
{
$complex = Complex::validateComplexArgument($complex);
if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
throw new \InvalidArgumentException();
} elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) {
return new Complex(\log10($complex->getReal()), 0.0, $complex->getSuffix());
}
return ln($complex)
->multiply(\log10(Complex::EULER));
}

View File

@ -0,0 +1,32 @@
<?php
/**
*
* Function code for the complex log2() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the base-2 logarithm of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The base-2 logarithm of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If the real and the imaginary parts are both zero
*/
function log2($complex)
{
$complex = Complex::validateComplexArgument($complex);
if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
throw new \InvalidArgumentException();
} elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) {
return new Complex(\log($complex->getReal(), 2), 0.0, $complex->getSuffix());
}
return ln($complex)
->multiply(\log(Complex::EULER, 2));
}

View File

@ -0,0 +1,31 @@
<?php
/**
*
* Function code for the complex negative() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the negative of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return float The negative value of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*
* @see rho
*
*/
function negative($complex)
{
$complex = Complex::validateComplexArgument($complex);
return new Complex(
-1 * $complex->getReal(),
-1 * $complex->getImaginary(),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,40 @@
<?php
/**
*
* Function code for the complex pow() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns a complex number raised to a power.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @param float|integer $power The power to raise this value to
* @return Complex The complex argument raised to the real power.
* @throws Exception If the power argument isn't a valid real
*/
function pow($complex, $power)
{
$complex = Complex::validateComplexArgument($complex);
if (!is_numeric($power)) {
throw new Exception('Power argument must be a real number');
}
if ($complex->getImaginary() == 0.0 && $complex->getReal() >= 0.0) {
return new Complex(\pow($complex->getReal(), $power));
}
$rValue = \sqrt(($complex->getReal() * $complex->getReal()) + ($complex->getImaginary() * $complex->getImaginary()));
$rPower = \pow($rValue, $power);
$theta = $complex->argument() * $power;
if ($theta == 0) {
return new Complex(1);
}
return new Complex($rPower * \cos($theta), $rPower * \sin($theta), $complex->getSuffix());
}

View File

@ -0,0 +1,28 @@
<?php
/**
*
* Function code for the complex rho() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the rho of a complex number.
* This is the distance/radius from the centrepoint to the representation of the number in polar coordinates.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return float The rho value of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function rho($complex)
{
$complex = Complex::validateComplexArgument($complex);
return \sqrt(
($complex->getReal() * $complex->getReal()) +
($complex->getImaginary() * $complex->getImaginary())
);
}

View File

@ -0,0 +1,25 @@
<?php
/**
*
* Function code for the complex sec() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the secant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The secant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function sec($complex)
{
$complex = Complex::validateComplexArgument($complex);
return inverse(cos($complex));
}

View File

@ -0,0 +1,25 @@
<?php
/**
*
* Function code for the complex sech() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the hyperbolic secant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The hyperbolic secant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function sech($complex)
{
$complex = Complex::validateComplexArgument($complex);
return inverse(cosh($complex));
}

View File

@ -0,0 +1,32 @@
<?php
/**
*
* Function code for the complex sin() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the sine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The sine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function sin($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
return new Complex(\sin($complex->getReal()));
}
return new Complex(
\sin($complex->getReal()) * \cosh($complex->getImaginary()),
\cos($complex->getReal()) * \sinh($complex->getImaginary()),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,32 @@
<?php
/**
*
* Function code for the complex sinh() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the hyperbolic sine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The hyperbolic sine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function sinh($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
return new Complex(\sinh($complex->getReal()));
}
return new Complex(
\sinh($complex->getReal()) * \cos($complex->getImaginary()),
\cosh($complex->getReal()) * \sin($complex->getImaginary()),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex sqrt() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the square root of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The Square root of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function sqrt($complex)
{
$complex = Complex::validateComplexArgument($complex);
$theta = theta($complex);
$delta1 = \cos($theta / 2);
$delta2 = \sin($theta / 2);
$rho = \sqrt(rho($complex));
return new Complex($delta1 * $rho, $delta2 * $rho, $complex->getSuffix());
}

View File

@ -0,0 +1,40 @@
<?php
/**
*
* Function code for the complex tan() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the tangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The tangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function tan($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
return new Complex(\tan($complex->getReal()));
}
$real = $complex->getReal();
$imaginary = $complex->getImaginary();
$divisor = 1 + \pow(\tan($real), 2) * \pow(\tanh($imaginary), 2);
if ($divisor == 0.0) {
throw new \InvalidArgumentException('Division by zero');
}
return new Complex(
\pow(sech($imaginary)->getReal(), 2) * \tan($real) / $divisor,
\pow(sec($real)->getReal(), 2) * \tanh($imaginary) / $divisor,
$complex->getSuffix()
);
}

View File

@ -0,0 +1,35 @@
<?php
/**
*
* Function code for the complex tanh() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the hyperbolic tangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The hyperbolic tangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function tanh($complex)
{
$complex = Complex::validateComplexArgument($complex);
$real = $complex->getReal();
$imaginary = $complex->getImaginary();
$divisor = \cos($imaginary) * \cos($imaginary) + \sinh($real) * \sinh($real);
if ($divisor == 0.0) {
throw new \InvalidArgumentException('Division by zero');
}
return new Complex(
\sinh($real) * \cosh($real) / $divisor,
0.5 * \sin(2 * $imaginary) / $divisor,
$complex->getSuffix()
);
}

View File

@ -0,0 +1,38 @@
<?php
/**
*
* Function code for the complex theta() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the theta of a complex number.
* This is the angle in radians from the real axis to the representation of the number in polar coordinates.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return float The theta value of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function theta($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0) {
if ($complex->isReal()) {
return 0.0;
} elseif ($complex->getImaginary() < 0.0) {
return M_PI / -2;
}
return M_PI / 2;
} elseif ($complex->getReal() > 0.0) {
return \atan($complex->getImaginary() / $complex->getReal());
} elseif ($complex->getImaginary() < 0.0) {
return -(M_PI - \atan(\abs($complex->getImaginary()) / \abs($complex->getReal())));
}
return M_PI - \atan($complex->getImaginary() / \abs($complex->getReal()));
}

View File

@ -0,0 +1,46 @@
<?php
/**
*
* Function code for the complex addition operation
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Adds two or more complex numbers
*
* @param array of string|integer|float|Complex $complexValues The numbers to add
* @return Complex
*/
function add(...$complexValues)
{
if (count($complexValues) < 2) {
throw new \Exception('This function requires at least 2 arguments');
}
$base = array_shift($complexValues);
$result = clone Complex::validateComplexArgument($base);
foreach ($complexValues as $complex) {
$complex = Complex::validateComplexArgument($complex);
if ($result->isComplex() && $complex->isComplex() &&
$result->getSuffix() !== $complex->getSuffix()) {
throw new Exception('Suffix Mismatch');
}
$real = $result->getReal() + $complex->getReal();
$imaginary = $result->getImaginary() + $complex->getImaginary();
$result = new Complex(
$real,
$imaginary,
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
);
}
return $result;
}

View File

@ -0,0 +1,56 @@
<?php
/**
*
* Function code for the complex division operation
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Divides two or more complex numbers
*
* @param array of string|integer|float|Complex $complexValues The numbers to divide
* @return Complex
*/
function divideby(...$complexValues)
{
if (count($complexValues) < 2) {
throw new \Exception('This function requires at least 2 arguments');
}
$base = array_shift($complexValues);
$result = clone Complex::validateComplexArgument($base);
foreach ($complexValues as $complex) {
$complex = Complex::validateComplexArgument($complex);
if ($result->isComplex() && $complex->isComplex() &&
$result->getSuffix() !== $complex->getSuffix()) {
throw new Exception('Suffix Mismatch');
}
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
throw new \InvalidArgumentException('Division by zero');
}
$delta1 = ($result->getReal() * $complex->getReal()) +
($result->getImaginary() * $complex->getImaginary());
$delta2 = ($result->getImaginary() * $complex->getReal()) -
($result->getReal() * $complex->getImaginary());
$delta3 = ($complex->getReal() * $complex->getReal()) +
($complex->getImaginary() * $complex->getImaginary());
$real = $delta1 / $delta3;
$imaginary = $delta2 / $delta3;
$result = new Complex(
$real,
$imaginary,
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
);
}
return $result;
}

View File

@ -0,0 +1,56 @@
<?php
/**
*
* Function code for the complex division operation
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Divides two or more complex numbers
*
* @param array of string|integer|float|Complex $complexValues The numbers to divide
* @return Complex
*/
function divideinto(...$complexValues)
{
if (count($complexValues) < 2) {
throw new \Exception('This function requires at least 2 arguments');
}
$base = array_shift($complexValues);
$result = clone Complex::validateComplexArgument($base);
foreach ($complexValues as $complex) {
$complex = Complex::validateComplexArgument($complex);
if ($result->isComplex() && $complex->isComplex() &&
$result->getSuffix() !== $complex->getSuffix()) {
throw new Exception('Suffix Mismatch');
}
if ($result->getReal() == 0.0 && $result->getImaginary() == 0.0) {
throw new \InvalidArgumentException('Division by zero');
}
$delta1 = ($complex->getReal() * $result->getReal()) +
($complex->getImaginary() * $result->getImaginary());
$delta2 = ($complex->getImaginary() * $result->getReal()) -
($complex->getReal() * $result->getImaginary());
$delta3 = ($result->getReal() * $result->getReal()) +
($result->getImaginary() * $result->getImaginary());
$real = $delta1 / $delta3;
$imaginary = $delta2 / $delta3;
$result = new Complex(
$real,
$imaginary,
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
);
}
return $result;
}

View File

@ -0,0 +1,48 @@
<?php
/**
*
* Function code for the complex multiplication operation
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Multiplies two or more complex numbers
*
* @param array of string|integer|float|Complex $complexValues The numbers to multiply
* @return Complex
*/
function multiply(...$complexValues)
{
if (count($complexValues) < 2) {
throw new \Exception('This function requires at least 2 arguments');
}
$base = array_shift($complexValues);
$result = clone Complex::validateComplexArgument($base);
foreach ($complexValues as $complex) {
$complex = Complex::validateComplexArgument($complex);
if ($result->isComplex() && $complex->isComplex() &&
$result->getSuffix() !== $complex->getSuffix()) {
throw new Exception('Suffix Mismatch');
}
$real = ($result->getReal() * $complex->getReal()) -
($result->getImaginary() * $complex->getImaginary());
$imaginary = ($result->getReal() * $complex->getImaginary()) +
($result->getImaginary() * $complex->getReal());
$result = new Complex(
$real,
$imaginary,
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
);
}
return $result;
}

View File

@ -0,0 +1,46 @@
<?php
/**
*
* Function code for the complex subtraction operation
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Subtracts two or more complex numbers
*
* @param array of string|integer|float|Complex $complexValues The numbers to subtract
* @return Complex
*/
function subtract(...$complexValues)
{
if (count($complexValues) < 2) {
throw new \Exception('This function requires at least 2 arguments');
}
$base = array_shift($complexValues);
$result = clone Complex::validateComplexArgument($base);
foreach ($complexValues as $complex) {
$complex = Complex::validateComplexArgument($complex);
if ($result->isComplex() && $complex->isComplex() &&
$result->getSuffix() !== $complex->getSuffix()) {
throw new Exception('Suffix Mismatch');
}
$real = $result->getReal() - $complex->getReal();
$imaginary = $result->getImaginary() - $complex->getImaginary();
$result = new Complex(
$real,
$imaginary,
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
);
}
return $result;
}

View File

@ -0,0 +1,77 @@
{
"name": "markbaker/complex",
"type": "library",
"description": "PHP Class for working with complex numbers",
"keywords": ["complex", "mathematics"],
"homepage": "https://github.com/MarkBaker/PHPComplex",
"license": "MIT",
"authors": [
{
"name": "Mark Baker",
"email": "mark@lange.demon.co.uk"
}
],
"require": {
"php": "^5.6.0|^7.0.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35|^5.4.0",
"phpdocumentor/phpdocumentor":"2.*",
"phpmd/phpmd": "2.*",
"sebastian/phpcpd": "2.*",
"phploc/phploc": "2.*",
"squizlabs/php_codesniffer": "^3.3.0",
"phpcompatibility/php-compatibility": "^8.0",
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3"
},
"autoload": {
"psr-4": {
"Complex\\": "classes/src/"
},
"files": [
"classes/src/functions/abs.php",
"classes/src/functions/acos.php",
"classes/src/functions/acosh.php",
"classes/src/functions/acot.php",
"classes/src/functions/acoth.php",
"classes/src/functions/acsc.php",
"classes/src/functions/acsch.php",
"classes/src/functions/argument.php",
"classes/src/functions/asec.php",
"classes/src/functions/asech.php",
"classes/src/functions/asin.php",
"classes/src/functions/asinh.php",
"classes/src/functions/atan.php",
"classes/src/functions/atanh.php",
"classes/src/functions/conjugate.php",
"classes/src/functions/cos.php",
"classes/src/functions/cosh.php",
"classes/src/functions/cot.php",
"classes/src/functions/coth.php",
"classes/src/functions/csc.php",
"classes/src/functions/csch.php",
"classes/src/functions/exp.php",
"classes/src/functions/inverse.php",
"classes/src/functions/ln.php",
"classes/src/functions/log2.php",
"classes/src/functions/log10.php",
"classes/src/functions/negative.php",
"classes/src/functions/pow.php",
"classes/src/functions/rho.php",
"classes/src/functions/sec.php",
"classes/src/functions/sech.php",
"classes/src/functions/sin.php",
"classes/src/functions/sinh.php",
"classes/src/functions/sqrt.php",
"classes/src/functions/tan.php",
"classes/src/functions/tanh.php",
"classes/src/functions/theta.php",
"classes/src/operations/add.php",
"classes/src/operations/subtract.php",
"classes/src/operations/multiply.php",
"classes/src/operations/divideby.php",
"classes/src/operations/divideinto.php"
]
},
"minimum-stability": "dev"
}

View File

@ -0,0 +1,154 @@
<?php
use Complex\Complex as Complex;
include('../classes/Bootstrap.php');
echo 'Create', PHP_EOL;
$x = new Complex(123);
echo $x, PHP_EOL;
$x = new Complex(123, 456);
echo $x, PHP_EOL;
$x = new Complex(array(123,456,'j'));
echo $x, PHP_EOL;
$x = new Complex('1.23e-4--2.34e-5i');
echo $x, PHP_EOL;
echo PHP_EOL, 'Add', PHP_EOL;
$x = new Complex(123);
$x->add(456);
echo $x, PHP_EOL;
$x = new Complex(123.456);
$x->add(789.012);
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->add(new Complex(-987.654, -32.1));
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->add(-987.654);
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->add(new Complex(0, 1));
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->add(new Complex(0, -1));
echo $x, PHP_EOL;
echo PHP_EOL, 'Subtract', PHP_EOL;
$x = new Complex(123);
$x->subtract(456);
echo $x, PHP_EOL;
$x = new Complex(123.456);
$x->subtract(789.012);
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->subtract(new Complex(-987.654, -32.1));
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->subtract(-987.654);
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->subtract(new Complex(0, 1));
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->subtract(new Complex(0, -1));
echo $x, PHP_EOL;
echo PHP_EOL, 'Multiply', PHP_EOL;
$x = new Complex(123);
$x->multiply(456);
echo $x, PHP_EOL;
$x = new Complex(123.456);
$x->multiply(789.012);
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->multiply(new Complex(-987.654, -32.1));
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->multiply(-987.654);
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->multiply(new Complex(0, 1));
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->multiply(new Complex(0, -1));
echo $x, PHP_EOL;
echo PHP_EOL, 'Divide By', PHP_EOL;
$x = new Complex(123);
$x->divideBy(456);
echo $x, PHP_EOL;
$x = new Complex(123.456);
$x->divideBy(789.012);
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->divideBy(new Complex(-987.654, -32.1));
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->divideBy(-987.654);
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->divideBy(new Complex(0, 1));
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->divideBy(new Complex(0, -1));
echo $x, PHP_EOL;
echo PHP_EOL, 'Divide Into', PHP_EOL;
$x = new Complex(123);
$x->divideInto(456);
echo $x, PHP_EOL;
$x = new Complex(123.456);
$x->divideInto(789.012);
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->divideInto(new Complex(-987.654, -32.1));
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->divideInto(-987.654);
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->divideInto(new Complex(0, 1));
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->divideInto(new Complex(0, -1));
echo $x, PHP_EOL;

View File

@ -0,0 +1,52 @@
<?php
namespace Complex;
include('../classes/Bootstrap.php');
echo 'Function Examples', PHP_EOL;
$functions = array(
'abs',
'acos',
'acosh',
'acsc',
'acsch',
'argument',
'asec',
'asech',
'asin',
'asinh',
'conjugate',
'cos',
'cosh',
'csc',
'csch',
'exp',
'inverse',
'ln',
'log2',
'log10',
'rho',
'sec',
'sech',
'sin',
'sinh',
'sqrt',
'theta'
);
for ($real = -3.5; $real <= 3.5; $real += 0.5) {
for ($imaginary = -3.5; $imaginary <= 3.5; $imaginary += 0.5) {
foreach ($functions as $function) {
$complexFunction = __NAMESPACE__ . '\\' . $function;
$complex = new Complex($real, $imaginary);
try {
echo $function, '(', $complex, ') = ', $complexFunction($complex), PHP_EOL;
} catch (\Exception $e) {
echo $function, '(', $complex, ') ERROR: ', $e->getMessage(), PHP_EOL;
}
}
echo PHP_EOL;
}
}

View File

@ -0,0 +1,34 @@
<?php
use Complex\Complex as Complex;
include('../classes/Bootstrap.php');
$values = [
new Complex(123),
new Complex(456, 123),
new Complex(0.0, 456),
];
foreach ($values as $value) {
echo $value, PHP_EOL;
}
echo 'Addition', PHP_EOL;
$result = \Complex\add(...$values);
echo '=> ', $result, PHP_EOL;
echo PHP_EOL;
echo 'Subtraction', PHP_EOL;
$result = \Complex\subtract(...$values);
echo '=> ', $result, PHP_EOL;
echo PHP_EOL;
echo 'Multiplication', PHP_EOL;
$result = \Complex\multiply(...$values);
echo '=> ', $result, PHP_EOL;

25
inc/vendor/markbaker/complex/license.md vendored Normal file
View File

@ -0,0 +1,25 @@
The MIT License (MIT)
=====================
Copyright © `2017` `Mark Baker`
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the “Software”), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

5
inc/vendor/pacificsec/cpe/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/.settings/
/.buildpath
/.project
/vendor/
/composer.lock

View File

@ -22,3 +22,45 @@ Features
- CPE rich comparison. - CPE rich comparison.
- CPE Language parsing and evaluation. - CPE Language parsing and evaluation.
- MIT Licensed. - MIT Licensed.
Getting Started
--------
- Clone repository
```bash
$ git clone https://github.com/pacificsec/cpe.git
$ cd cpe
```
- Create a new PHP file to run tests
```php
<?php
require('autoload.php');
use PacificSec\CPE\Matching\CPENameMatcher;
use PacificSec\CPE\Naming\CPENameUnbinder;
use PacificSec\CPE\Naming\CPENameBinder;
CPENameMatcher::test();
CPENameUnbinder::test();
CPENameBinder::test();
```
```php
<?php
require('autoload.php');
use PacificSec\CPE\Naming\CPENameUnbinder;
$cpenu = new CPENameUnbinder();
$wfn = $cpenu->unbindURI("cpe:/a:microsoft:internet_explorer%01%01%01%01:?:beta");
var_dump($wfn);
$wfn = $cpenu->unbindURI("cpe:/a:microsoft:internet_explorer:8.%2a:sp%3f");
var_dump($wfn);
$wfn = $cpenu->unbindURI("cpe:/a:microsoft:internet_explorer:8.%02:sp%01");
var_dump($wfn);
$wfn = $cpenu->unbindURI("cpe:/a:hp:insight_diagnostics:7.4.0.1570::~~online~win2003~x64~");
var_dump($wfn);
$wfn = $cpenu->unbindFS("cpe:2.3:a:micr\\?osoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*");
var_dump($wfn);
```

26
inc/vendor/pacificsec/cpe/composer.json vendored Normal file
View File

@ -0,0 +1,26 @@
{
"name" : "pacificsec/cpe",
"type" : "library",
"description" : "CPE: Common Platform Enumeration for PHP",
"keywords" : [
"cpe",
"cve",
"security",
"pacificsec"
],
"homepage" : "https://github.com/pacificsec/cpe",
"license" : "MIT",
"authors" : [{
"name" : "Antonio Franco",
"email" : "antonio.franco@pacificsec.com"
}
],
"require" : {
"php" : ">=5.3.0"
},
"autoload" : {
"psr-4" : {
"PacificSec\\CPE\\" : "src"
}
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace PacificSec\CPE\Common;
use \Exception;
/**
* This class represents a Logical Value. It is based on Java version
* implemented by JKRAUNELIS <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class LogicalValue {
private $any = false;
private $na = false;
// Object must be constructed with the string "ANY" or "NA".
public function __construct($type) {
if ($type == "ANY") {
$this->any = true;
} else if ($type == "NA") {
$this->na = true;
} else {
throw new Exception("LogicalValue must be ANY or NA");
}
}
public function isANY(){
return $this->any;
}
public function isNA(){
return $this->na;
}
public function __toString(){
if ($this->any){
return "ANY";
}
return "NA";
}
}

View File

@ -0,0 +1,166 @@
<?php
namespace PacificSec\CPE\Common;
use \Exception;
/**
* A collection of utility functions for use with the matching and
* naming namespaces. It is based on Java version implemented by
* Joshua Kraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class Utilities {
/**
* Searches string for special characters * and ?
* @param string $string to be searched
* @return bool true if string contains wildcard, false otherwise
*/
public static function containsWildcards($string) {
if (strpos($string, "*") !== false || strpos($string, "?") !== false) {
if (!(strpos($string, "\\") !== false)) {
return true;
}
}
return false;
}
/**
* Checks if given number is even or not
* @param int $num number to check
* @return bool true if number is even, false if not
*/
public static function isEvenNumber($num) {
return (is_int($num) && $num % 2 == 0);
}
/**
* Counts the number of escape characters in the string beginning and ending
* at the given indices
* @param string $str string to search
* @param int $start beginning index
* @param int $end ending index
* @return number of escape characters in string
* @todo fix the use of $str. The Java version is also not using this variable.
*/
public static function countEscapeCharacters($str, $start, $end) {
$result = 0;
$active = false;
$i = 0;
while ($i < $end) {
if ($active && ($i >= $start)) {
$result = $result + 1;
}
$i = $i + 1;
}
return $result;
}
/**
* Searches a string for the first unescaped colon and returns the index of
* that colon
* @param string $str string to search
* @return int index of first unescaped colon, or 0 if not found
*/
public static function getUnescapedColonIndex($str) {
$found = false;
$colon_idx = 0;
$start_idx = 0;
// Find the first non-escaped colon.
while (!$found) {
$colon_idx = strpos($str, ":", $start_idx + 1);
// If no colon is found, return 0.
if ($colon_idx === false) {
return 0;
}
// Peek at character before colon.
if (substr($str, $colon_idx-1, 1) == "\\") {
// If colon is escaped, keep looking.
$start_idx = $colon_idx;
} else {
$found = true;
}
}
return $colon_idx;
}
/**
* Returns true if the string contains only
* alphanumeric characters or the underscore character,
* false otherwise.
* @param string $c the string in question
* @return bool true if $c is alphanumeric or underscore, false if not
*/
public static function isAlphanum($c) {
return (preg_match("/^[a-zA-Z0-9\_]+$/", $c) ? true : false);
}
/**
* This function is not part of the reference implementation pseudo code
* found in the CPE 2.3 specification. It enforces two rules in the
* specification:
* URI must start with the characters "cpe:/"
* A URI may not contain more than 7 components
* If either rule is violated, a Exception is thrown.
* @param $in string with URI to be validated
*/
public static function validateURI($in) {
// make sure uri starts with cpe:/
if (strpos(strtolower($in), "cpe:/") !== 0) {
throw new Exception("Error: URI must start with 'cpe:/'. Given: " . $in, 0);
}
// make sure uri doesn't contain more than 7 colons
$count = sizeof(explode(":", $in));
if ($count > 8) {
throw new Exception("Error parsing URI. Found " . ($count - 8) . " extra components in: " . $in, 0);
}
}
/**
* This function is not part of the reference implementation pseudo code
* found in the CPE 2.3 specification. It enforces three rules found in the
* specification:
* Formatted string must start with the characters "cpe:2.3:"
* A formatted string must contain 11 components
* A formatted string must not contain empty components
* If any rule is violated, a ParseException is thrown.
* @param $in string with FS to be validated
*/
public static function validateFS($in) {
if (strpos(strtolower($in), "cpe:2.3:") !== 0) {
throw new Exception("Error: Formatted String must start with \"cpe:2.3\". Given: " . $in, 0);
}
$count = 0;
for ($i = 0; $i != strlen($in); $i++){
if (substr($in, $i, 1) == ":"){
if (substr($in, $i - 1, 1) != "\\"){
$count++;
}
if (($i+1) < strlen($in) && substr($in, $i+1, 1) == ":"){
throw new Exception("Error parsing formatted string. Found empty component", 0);
}
}
}
if ($count > 12){
$extra = $count - 12;
$s = "Error parsing formatted string. Found " . $extra . " extra component";
if ($extra > 1){
$s = $s . "s";
}
$s = $s . " in: " . $in;
throw new Exception($s, 0);
}
if ($count < 12){
$missing = 12 - $count;
$s = "Error parsing formatted string. Missing " . $missing . " component";
if ($missing > 1){
$s = $s . "s";
}
throw new Exception($s, 0);
}
}
}

View File

@ -0,0 +1,210 @@
<?php
namespace PacificSec\CPE\Common;
use \Exception;
/**
* The WellFormedName class represents a Well Formed Name, as defined
* in the CPE Specification version 2.3. It is based on Java version
* implemented by jkraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for details.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class WellFormedName {
// Underlying wfn representation.
private $wfn = null;
// All permissible WFN attributes as defined by specification.
private $attributes = array("part", "vendor", "product", "version",
"update", "edition", "language", "sw_edition", "target_sw",
"target_hw", "other");
/**
* Constructs a new WellFormedName object, setting each component to the
* given parameter value. If a parameter is null, the component is set to
* the default value "ANY".
* @param $part string representing the part component
* @param $vendor string representing the vendor component
* @param $product string representing the product component
* @param $version string representing the version component
* @param $update string representing the update component
* @param $edition string representing the edition component
* @param $language string representing the language component
* @param $sw_edition string representing the sw_edition component
* @param $target_sw string representing the target_sw component
* @param $target_hw string representing the target_hw component
* @param $other string representing the other component
*/
public function __construct($part = null, $vendor = null, $product = null, $version = null,
$update = null, $edition = null, $language = null, $sw_edition = null, $target_sw = null,
$target_hw = null, $other = null) {
$this->wfn = array();
// Constructs a new WellFormedName object, with all components set to the default value "ANY".
if ($part === null && $vendor === null && $product === null && $version === null &&
$update === null && $edition === null && $language === null && $sw_edition === null && $target_sw === null &&
$target_hw === null && $other === null){
foreach ($this->attributes as $a){
if ($a != "part"){
$this->set($a, new LogicalValue("ANY"));
}
}
return;
}
$this->set("part", $part);
$this->set("vendor", $vendor);
$this->set("product", $product);
$this->set("version", $version);
$this->set("update", $update);
$this->set("edition", $edition);
$this->set("language", $language);
$this->set("sw_edition", $sw_edition);
$this->set("target_sw", $target_sw);
$this->set("target_hw", $target_hw);
$this->set("other", $other);
}
/**
* @param $attribute string representing the component value to get
* @return string the string value of the given component, or default value "ANY"
* if the component does not exist
*/
public function get($attribute){
if (array_key_exists($attribute, $this->wfn))
return $this->wfn[$attribute];
else
return new LogicalValue("ANY");
}
/**
* Sets the given attribute to value, if the attribute is in the list of
* permissible components
* @param $attribute string representing the component to set
* @param $value object or string representing the value of the given component
*/
public final function set($attribute, $value){
// Iterate over permissible attributes.
foreach ($this->attributes as $a){
// If the argument is a valid attribute, set that attribute's value.
if ($attribute == $a) {
// check to see if we're setting a LogicalValue ANY or NA
if ($value instanceof LogicalValue){
// don't allow logical values in part component
if ($attribute == "part"){
var_dump($value); echo "<br>\n";
var_dump($a); echo "<br>\n";
var_dump($attribute); echo "<br>\n";
throw new Exception("Error! part component cannot be a logical value");
}
// put the Object in the ht and break
$this->wfn[$attribute] = $value;
break;
}
if ($value == null || $value == ""){
// if value is null or blank, set attribute to default logical ANY
$this->wfn[$attribute] = new LogicalValue("ANY");
break;
}
$svalue = $value;
// Reg exs
// check for printable characters - no control characters
if (!preg_match("/^[[:print:]]*$/", $svalue)){
throw new Exception("Error! encountered non printable character in: " . $svalue, 0);
}
// svalue has whitespace
if (preg_match("/^.*\\s+.*$/", $svalue)){
throw new Exception("Error! component cannot contain whitespace: " . $svalue, 0);
}
// svalue has more than one unquoted star
if (preg_match("/^\\*{2,}.*$/", $svalue) || preg_match("/^.*\\*{2,}$/", $svalue)){
throw new Exception("Error! component cannot contain more than one * in sequence: " . $svalue, 0);
}
// svalue has unquoted punctuation embedded
if (preg_match("/^.*(?<!\\\\)[\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\+\\,\\.\\/\\:\\;\\<\\=\\>\\@\\[\\]\\^\\`\\{\\|\\}\\~\\-].*$/", $svalue)) {
throw new Exception("Error! component cannot contain unquoted punctuation: " . $svalue, 0);
}
// svalue has an unquoted *
if (preg_match("/^.+(?<!\\\\)[\\*].+$/", $svalue)) {
throw new Exception("Error! component cannot contain embedded *: " . $svalue, 0);
}
// svalue has embedded unquoted ?
// this will catch a single unquoted ?, so make sure we deal with that
if (strpos($svalue, "?") !== false) {
if ($svalue == "?") {
// single ? is valid
$this->wfn[$attribute] = $svalue;
break;
}
// remove leading and trailing ?s
$v = $svalue;
while (strpos($v, "?") === 0) {
// remove all leading ?'s
$v = substr($v, 1);
}
$v = strrev($v);
while (strpos($v, "?") === 0) {
// remove all trailing ?'s (string has been reversed)
$v = substr($v, 1);
}
// back to normal
$v = strrev($v);
// after leading and trailing ?s are removed, check if value
// contains unquoted ?s
if (preg_match("/^.+(?<!\\\\)[\\?].+$/", $v)) {
throw new Exception("Error! component cannot contain embedded ?: " . $svalue, 0);
}
}
// single asterisk is not allowed
if ($svalue == "*") {
throw new Exception("Error! component cannot be a single *: " . $svalue, 0);
}
// quoted hyphen not allowed by itself
if ($svalue == "-") {
throw new Exception("Error! component cannot be quoted hyphen: " . $svalue, 0);
}
// part must be a, o, or h
if ($attribute == "part") {
if ($svalue != "a" && $svalue != "o" && $svalue != "h") {
throw new Exception("Error! part component must be one of the following: 'a', 'o', 'h': " . $svalue, 0);
}
}
// should be good to go
$this->wfn[$attribute] = $svalue;
break;
}
}
}
/**
*
* @return string representation of the WellFormedName
*/
public function __toString() {
$str = "wfn:[";
foreach ($this->attributes as $attr) {
$str = $str . $attr;
$str = $str . "=";
$o = $this->wfn[$attr];
if ($o instanceof LogicalValue) {
$str = $str . $o;
$str = $str . ", ";
} else {
$str = $str . "\"";
$str = $str . $o;
$str = $str . "\", ";
}
}
$str = substr($str, 0, strlen($str)-1);
$str = substr($str, 0, strlen($str)-1);
$str = $str . "]";
return $str;
}
}

View File

@ -0,0 +1,287 @@
<?php
namespace PacificSec\CPE\Matching;
use PacificSec\CPE\Common\WellFormedName;
use PacificSec\CPE\Common\Utilities;
use PacificSec\CPE\Common\LogicalValue;
use PacificSec\CPE\Naming\CPENameBinder;
use PacificSec\CPE\Naming\CPENameUnbinder;
/**
* The CPENameMatcher is an implementation of the CPE Matching algorithm,
* as specified in the CPE Matching Standard version 2.3. It is based on
* Java version implemented by Joshua Kraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class CPENameMatcher {
/**
* Tests two Well Formed Names for disjointness.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return true if the names are disjoint, false otherwise
*/
public function isDisjoint(WellFormedName $source, WellFormedName $target) {
// if any pairwise comparison is disjoint, the names are disjoint.
$resultList = $this->compareWFNs($source, $target);
foreach ($resultList as $result){
if ($result == Relation::DISJOINT)
return true;
}
return false;
}
/**
* Tests two Well Formed Names for equality.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return true if the names are equal, false otherwise
*/
public function isEqual(WellFormedName $source, WellFormedName $target) {
// if every pairwise comparison is equal, the names are equal.
$resultList = $this->compareWFNs($source, $target);
foreach ($resultList as $result){
if ($result != Relation::EQUAL){
return false;
}
}
return true;
}
/**
* Tests if the target Well Formed Name is a subset of the source Well Formed
* Name.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return true if the target is a subset of the source, false otherwise
*/
public function isSubset(WellFormedName $source, WellFormedName $target) {
// if any comparison is anything other than subset or equal, then target is
// not a subset of source.
$resultList = $this->compareWFNs($source, $target);
foreach ($resultList as $result){
if ($result != Relation::SUBSET && $result != Relation::EQUAL) {
return false;
}
}
return true;
}
/**
* Tests if the target Well Formed name is a superset of the source Well Formed
* Name.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return true if the target is a superset of the source, false otherwise
*/
public function isSuperset(WellFormedName $source, WellFormedName $target) {
// if any comparison is anything other than superset or equal, then target is not
// a superset of source.
$resultList = $this->compareWFNs($source, $target);
foreach ($resultList as $result){
if ($result != Relation::SUPERSET && $result != Relation::EQUAL) {
return false;
}
}
return true;
}
/**
* Compares each attribute value pair in two Well Formed Names.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return array A array mapping attribute string to attribute value Relation
*/
public function compareWFNs(WellFormedName $source, WellFormedName $target) {
$result = array();
$result["part"] = $this->compare($source->get("part"), $target->get("part"));
$result["vendor"] = $this->compare($source->get("vendor"), $target->get("vendor"));
$result["product"] = $this->compare($source->get("product"), $target->get("product"));
$result["version"] = $this->compare($source->get("version"), $target->get("version"));
$result["update"] = $this->compare($source->get("update"), $target->get("update"));
$result["edition"] = $this->compare($source->get("edition"), $target->get("edition"));
$result["language"] = $this->compare($source->get("language"), $target->get("language"));
$result["sw_edition"] = $this->compare($source->get("sw_edition"), $target->get("sw_edition"));
$result["target_sw"] = $this->compare($source->get("target_sw"), $target->get("target_sw"));
$result["target_hw"] = $this->compare($source->get("target_hw"), $target->get("target_hw"));
$result["other"] = $this->compare($source->get("other"), $target->get("other"));
return $result;
}
/**
* Compares an attribute value pair.
* @param string $source Source attribute value.
* @param string $target Target attribute value.
* @return int The relation between the two attribute values.
*/
private function compare($source, $target) {
// matching is case insensitive, convert strings to lowercase.
if ($this->isString($source)) {
$source = strtolower($source);
}
if ($this->isString($target)) {
$target = strtolower($target);
}
// Unquoted wildcard characters yield an undefined result.
if ($this->isString($target) && Utilities::containsWildcards($target)) {
return Relation::UNDEFINED;
}
// If source and target values are equal, then result is equal.
if ($source == $target) {
return Relation::EQUAL;
}
// Check to see if source or target are Logical Values.
$lvSource = null;
$lvTarget = null;
if ($source instanceof LogicalValue) {
$lvSource = $source;
}
if ($target instanceof LogicalValue) {
$lvTarget = $target;
}
if ($lvSource != null && $lvTarget != null) {
// If Logical Values are equal, result is equal.
if ($lvSource->isANY() == $lvTarget->isANY() || $lvSource->isNA() == $lvTarget->isNA()) {
return Relation::EQUAL;
}
}
// If source value is ANY, result is a superset.
if ($lvSource != null) {
if ($lvSource->isANY()) {
return Relation::SUPERSET;
}
}
// If target value is ANY, result is a subset.
if ($lvTarget != null) {
if ($lvTarget->isANY()) {
return Relation::SUBSET;
}
}
// If source or target is NA, result is disjoint.
if ($lvSource != null) {
if ($lvSource->isNA()) {
return Relation::DISJOINT;
}
}
if ($lvTarget != null) {
if ($lvTarget->isNA()) {
return Relation::DISJOINT;
}
}
// only Strings will get to this point, not LogicalValues
return $this->compareStrings($source, $target);
}
/**
* Compares a source string to a target string, and addresses the condition
* in which the source string includes unquoted special characters. It
* performs a simple regular expression match, with the assumption that
* (as required) unquoted special characters appear only at the beginning
* and/or the end of the source string. It also properly differentiates
* between unquoted and quoted special characters.
*
* @param $source string Source attribute value.
* @param $target string Target attribute value.
* @return Relation between source and target Strings.
*/
private function compareStrings($source, $target) {
$start = 0;
$end = strlen($source);
$begins = 0;
$ends = 0;
$index = 0; $leftover = 0; $escapes = 0;
if (substr($source, 0, 1) == "*") {
$start = 1;
$begins = -1;
} else {
while (($start < strlen($source)) && (substr($source, $start, 1) == "?")) {
$start = $start + 1;
$begins = $begins + 1;
}
}
if ((substr($source, $end - 1, 1) == "*") && ($this->isEvenWildcards($source, $end - 1))) { //TODO
$end = $end - 1;
$ends = -1;
} else {
while (($end > 0) && substr($source, $end - 1, 1) == "?" && ($this->isEvenWildcards($source, $end - 1))) { //TODO
$end = $end - 1;
$ends = $ends + 1;
}
}
$source = substr($source, $start, $end-$start);
$index = -1;
$leftover = strlen($target);
while ($leftover > 0) {
$index = strpos($target, $source, $index + 1);
if ($index === false) {
break;
}
$escapes = Utilities::countEscapeCharacters($target, 0, $index);
if (($index > 0) && ($begins != -1) && ($begins < ($index - $escapes))) {
break;
}
$escapes = Utilities::countEscapeCharacters($target, $index + 1, strlen($target));
$leftover = strlen($target) - $index - $escapes - strlen($source);
if (($leftover > 0) && (($ends != -1) && ($leftover > $ends))) {
continue;
}
return Relation::SUPERSET;
}
return Relation::DISJOINT;
}
/**
* Searches a string for the backslash character
* @param $str string to search in
* @param int $idx end index
* @return true if the number of backslash characters is even, false if odd
*/
private function isEvenWildcards($str, $idx) {
$result = 0;
while (($idx > 0) && (strpos($str, "\\", $idx - 1)) !== false) {
$idx = $idx - 1;
$result = $result + 1;
}
return Utilities::isEvenNumber($result);
}
/**
* Tests if an Object is an instance of the String class
* @param mixed $arg the var to test
* @return bool true if arg is a string, false if not
*/
private function isString($arg) {
return is_string($arg);
}
/*
* Static method to demonstrate this class.
*/
public static function test() {
// Examples.
$wfn = new WellFormedName("a", "microsoft", "internet_explorer", "8\\.0\\.6001", "beta", new LogicalValue("ANY"), "sp2", null, null, null, null);
$wfn2 = new WellFormedName("a", "microsoft", "internet_explorer", new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"));
$cpenm = new CPENameMatcher();
$cpenu = new CPENameUnbinder();
$cpenb = new CPENameBinder();
$wfn = $cpenu->unbindURI($cpenb->bindToURI($wfn));
$wfn2 = $cpenu->unbindFS($cpenb->bindToFS($wfn2));
var_dump($cpenm->isDisjoint($wfn, $wfn2)); // false
var_dump($cpenm->isEqual($wfn, $wfn2)); // false
var_dump($cpenm->isSubset($wfn, $wfn2)); // true, $wfn2 is a subset of wfn
var_dump($cpenm->isSuperset($wfn, $wfn2)); // false
$wfn = $cpenu->unbindFS("cpe:2.3:a:adobe:*:9.*:*:PalmOS:*:*:*:*:*");
$wfn2 = $cpenu->unbindURI("cpe:/a::Reader:9.3.2:-:-");
var_dump($cpenm->isDisjoint($wfn, $wfn2)); // true, $wfn2 and wfn are disjoint
var_dump($cpenm->isEqual($wfn, $wfn2)); // false
var_dump($cpenm->isSubset($wfn, $wfn2)); // false
var_dump($cpenm->isSuperset($wfn, $wfn2)); // false
}
}

View File

@ -8,27 +8,40 @@ use PacificSec\CPE\Common\LogicalValue;
/** /**
* The CPENameBinder class is a simple implementation * The CPENameBinder class is a simple implementation
* of the CPE Name binding algorithm, as specified in the * of the CPE Name binding algorithm, as specified in the
* CPE Naming Standard version 2.3. It is based on Java version * CPE Naming Standard version 2.3.
* It is based on Java version
* implemented by Joshua Kraunelis <jkraunelis@mitre.org>. * implemented by Joshua Kraunelis <jkraunelis@mitre.org>.
* *
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information. * @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco * @author Antonio Franco
* @email antonio.franco@pacificsec.com * @email antonio.franco@pacificsec.com
*/ */
class CPENameBinder { class CPENameBinder
{
/** /**
* Binds a {@link WellFormedName} object to a URI. * Binds a {@link WellFormedName} object to a URI.
* @param $w WellFormedName to be bound to URI *
* @return URI binding of WFN * @param $w WellFormedName
* to be bound to URI
* @return string URI binding of WFN
*/ */
public function bindToURI(WellFormedName $w) { public function bindToURI(WellFormedName $w)
{
// Initialize the output with the CPE v2.2 URI prefix. // Initialize the output with the CPE v2.2 URI prefix.
$uri = "cpe:/"; $uri = "cpe:/";
// Define the attributes that correspond to the seven components in a v2.2. CPE. // Define the attributes that correspond to the seven components in a v2.2. CPE.
$attributes = array("part", "vendor", "product", "version", "update", "edition", "language"); $attributes = array(
"part",
"vendor",
"product",
"version",
"update",
"edition",
"language"
);
// Iterate over the well formed name // Iterate over the well formed name
foreach ($attributes as $a) { foreach ($attributes as $a) {
@ -56,15 +69,28 @@ class CPENameBinder {
/** /**
* Top-level function used to bind WFN w to formatted string. * Top-level function used to bind WFN w to formatted string.
* @param $w WellFormedName to bind *
* @return Formatted String * @param $w WellFormedName
* to bind
* @return string Formatted String
*/ */
public function bindToFS(WellFormedName $w) { public function bindToFS(WellFormedName $w)
{
// Initialize the output with the CPE v2.3 string prefix. // Initialize the output with the CPE v2.3 string prefix.
$fs = "cpe:2.3:"; $fs = "cpe:2.3:";
foreach (array("part", "vendor", "product", "version", foreach (array(
"update", "edition", "language", "sw_edition", "target_sw", "part",
"target_hw", "other") as $a) { "vendor",
"product",
"version",
"update",
"edition",
"language",
"sw_edition",
"target_sw",
"target_hw",
"other"
) as $a) {
$v = $this->bindValueForFS($w->get($a)); $v = $this->bindValueForFS($w->get($a));
$fs = $fs . $v; $fs = $fs . $v;
// add a colon except at the very end // add a colon except at the very end
@ -78,10 +104,13 @@ class CPENameBinder {
/** /**
* Convert the value v to its proper string representation for insertion to * Convert the value v to its proper string representation for insertion to
* formatted string. * formatted string.
* @param $v value to convert *
* @return Formatted value * @param mixed $v
* value to convert
* @return mixed Formatted value
*/ */
private function bindValueForFS($v) { private function bindValueForFS($v)
{
if ($v instanceof LogicalValue) { if ($v instanceof LogicalValue) {
$l = $v; $l = $v;
// The value NA binds to a blank. // The value NA binds to a blank.
@ -97,30 +126,34 @@ class CPENameBinder {
} }
/** /**
* Inspect each character in string s. Certain nonalpha characters pass * Inspect each character in string s.
* Certain nonalpha characters pass
* thru without escaping into the result, but most retain escaping. * thru without escaping into the result, but most retain escaping.
* @param $s *
* @param
* $s
* @return * @return
*/ */
private function processQuotedChars($s) { private function processQuotedChars($s)
{
$result = ""; $result = "";
$idx = 0; $idx = 0;
while ($idx < strlen($s)) { while ($idx < strlen($s)) {
$c = substr($s, $idx, 1); $c = substr($s, $idx, 1);
if ($c != "\\") { if ($c != "\\") {
// unquoted characters pass thru unharmed. // unquoted characters pass thru unharmed.
$result = $result . $c; $result .= $c;
} else { } else {
// escaped characters are examined. // escaped characters are examined.
$nextchr = substr($s, $idx + 1, 1); $nextchr = substr($s, $idx + 1, 1);
// the period, hyphen and underscore pass unharmed. // the period, hyphen and underscore pass unharmed.
if ($nextchr == "." || $nextchr == "-" || $nextchr == "_") { if ($nextchr == "." || $nextchr == "-" || $nextchr == "_") {
$result = $result . $nextchr; $result .= $nextchr;
$idx = $idx + 2; $idx = $idx + 2;
continue; continue;
} else { } else {
// all others retain escaping. // all others retain escaping.
$result = $result . "\\" . $nextchr; $result .= "\\" . $nextchr;
$idx = $idx + 2; $idx = $idx + 2;
continue; continue;
} }
@ -132,12 +165,16 @@ class CPENameBinder {
/** /**
* Converts a string to the proper string for including in * Converts a string to the proper string for including in
* a CPE v2.2-conformant URI. The logical value ANY binds * a CPE v2.2-conformant URI.
* The logical value ANY binds
* to the blank in the 2.2-conformant URI. * to the blank in the 2.2-conformant URI.
* @param $s string to be converted *
* @return converted string * @param $s string
* to be converted
* @return string converted string
*/ */
private function bindValueForURI($s) { private function bindValueForURI($s)
{
if ($s instanceof LogicalValue) { if ($s instanceof LogicalValue) {
$l = $s; $l = $s;
// The value NA binds to a blank. // The value NA binds to a blank.
@ -159,10 +196,13 @@ class CPENameBinder {
* - Pass alphanumeric characters thru untouched * - Pass alphanumeric characters thru untouched
* - Percent-encode quoted non-alphanumerics as needed * - Percent-encode quoted non-alphanumerics as needed
* - Unquoted special characters are mapped to their special forms * - Unquoted special characters are mapped to their special forms
* @param $s string to be transformed *
* @return transformed string * @param $s string
* to be transformed
* @return string transformed string
*/ */
private function transformForURI($s) { private function transformForURI($s)
{
$result = ""; $result = "";
$idx = 0; $idx = 0;
@ -171,7 +211,7 @@ class CPENameBinder {
$thischar = substr($s, $idx, 1); $thischar = substr($s, $idx, 1);
// Alphanumerics (incl. underscore) pass untouched. // Alphanumerics (incl. underscore) pass untouched.
if (Utilities::isAlphanum($thischar)) { if (Utilities::isAlphanum($thischar)) {
$result = $result . $thischar; $result .= $thischar;
$idx = $idx + 1; $idx = $idx + 1;
continue; continue;
} }
@ -179,17 +219,17 @@ class CPENameBinder {
if ($thischar == "\\") { if ($thischar == "\\") {
$idx = $idx + 1; $idx = $idx + 1;
$nxtchar = substr($s, $idx, 1); $nxtchar = substr($s, $idx, 1);
$result = $result . $this->pctEncode($nxtchar); $result .= $this->pctEncode($nxtchar);
$idx = $idx + 1; $idx = $idx + 1;
continue; continue;
} }
// Bind the unquoted '?' special character to "%01". // Bind the unquoted '?' special character to "%01".
if ($thischar == "?") { if ($thischar == "?") {
$result = $result . "%01"; $result .= "%01";
} }
// Bind the unquoted '*' special character to "%02". // Bind the unquoted '*' special character to "%02".
if ($thischar == "*") { if ($thischar == "*") {
$result = $result . "%02"; $result .= "%02";
} }
$idx = $idx + 1; $idx = $idx + 1;
} }
@ -199,122 +239,98 @@ class CPENameBinder {
/** /**
* Returns the appropriate percent-encoding of character c. * Returns the appropriate percent-encoding of character c.
* Certain characters are returned without encoding. * Certain characters are returned without encoding.
* @param $c the single character string to be encoded *
* @return the percent encoded string * @param string $c the
* single character string to be encoded
* @return string the percent encoded string
*/ */
private function pctEncode($c) { private function pctEncode($c)
if ($c == "!") { {
return "%21"; switch ($c) {
case '!':
return "%21";
case "\"":
return "%22";
case "#":
return "%23";
case "$":
return "%24";
case "%":
return "%25";
case "&":
return "%26";
case "'":
return "%27";
case "(":
return "%28";
case ")":
return "%29";
case "*":
return "%2a";
case "+":
return "%2b";
case ",":
return "%2c";
case "/":
return "%2f";
case ":":
return "%3a";
case ";":
return "%3b";
case "<":
return "%3c";
case "=":
return "%3d";
case ">":
return "%3e";
case "?":
return "%3f";
case "@":
return "%40";
case "[":
return "%5b";
case "\\":
return "%5c";
case "]":
return "%5d";
case "^":
return "%5e";
case "`":
return "%60";
case "{":
return "%7b";
case "|":
return "%7c";
case "}":
return "%7d";
case "~":
return "%7e";
default:
return $c;
} }
if ($c == "\"") {
return "%22";
}
if ($c == "#") {
return "%23";
}
if ($c == "$") {
return "%24";
}
if ($c == "%") {
return "%25";
}
if ($c == "&") {
return "%26";
}
if ($c == "'") {
return "%27";
}
if ($c == "(") {
return "%28";
}
if ($c == ")") {
return "%29";
}
if ($c == "*") {
return "%2a";
}
if ($c == "+") {
return "%2b";
}
if ($c == ",") {
return "%2c";
}
// bound without encoding.
if ($c == "-") {
return $c;
}
// bound without encoding.
if ($c == ".") {
return $c;
}
if ($c == "/") {
return "%2f";
}
if ($c == ":") {
return "%3a";
}
if ($c == ";") {
return "%3b";
}
if ($c == "<") {
return "%3c";
}
if ($c == "=") {
return "%3d";
}
if ($c == ">") {
return "%3e";
}
if ($c == "?") {
return "%3f";
}
if ($c == "@") {
return "%40";
}
if ($c == "[") {
return "%5b";
}
if ($c == "\\") {
return "%5c";
}
if ($c == "]") {
return "%5d";
}
if ($c == "^") {
return "%5e";
}
if ($c == "`") {
return "%60";
}
if ($c == "{") {
return "%7b";
}
if ($c == "|") {
return "%7c";
}
if ($c == "}") {
return "%7d";
}
if ($c == "~") {
return "%7d";
}
// Shouldn't reach here, return original character
return $c;
} }
/** /**
* Packs the values of the five arguments into the single * Packs the values of the five arguments into the single
* edition component. If all the values are blank, the * edition component.
* If all the values are blank, the
* function returns a blank. * function returns a blank.
* @param $ed edition string *
* @param $sw_ed software edition string * @param string $ed edition
* @param $t_sw target software string * string
* @param $t_hw target hardware string * @param string $sw_ed software
* @param $oth other edition information string * edition string
* @return the packed string, or blank * @param string $t_sw target
* software string
* @param string $t_hw target
* hardware string
* @param string $oth other
* edition information string
* @return string the packed string, or blank
*/ */
private function pack($ed, $sw_ed, $t_sw, $t_hw, $oth) { private function pack($ed, $sw_ed, $t_sw, $t_hw, $oth)
if ($sw_ed == "" && $t_sw == "" && $t_hw == "" && $oth == "") { {
if ($sw_ed == "" && $t_sw == "" && $t_hw == "" && $oth == "") {
// All the extended attributes are blank, so don't do // All the extended attributes are blank, so don't do
// any packing, just return ed. // any packing, just return ed.
return $ed; return $ed;
@ -326,13 +342,16 @@ class CPENameBinder {
/** /**
* Removes trailing colons from the URI. * Removes trailing colons from the URI.
* @param $s the string to be trimmed *
* @return the trimmed string * @param string $s the
* string to be trimmed
* @return string the trimmed string
*/ */
private function trim($s) { private function trim($s)
{
$s1 = strrev($s); $s1 = strrev($s);
$idx = 0; $idx = 0;
for ($i = 0; $i != strlen($s1); $i++) { for ($i = 0; $i != strlen($s1); $i ++) {
if (substr($s1, $i, 1) == ":") { if (substr($s1, $i, 1) == ":") {
$idx = $idx + 1; $idx = $idx + 1;
} else { } else {
@ -341,30 +360,30 @@ class CPENameBinder {
} }
// Return the substring after all trailing colons, // Return the substring after all trailing colons,
// reversed back to its original character order. // reversed back to its original character order.
return strrev(substr($s1, $idx, strlen($s1)-$idx)); return strrev(substr($s1, $idx, strlen($s1) - $idx));
} }
/* /*
* Static method to demonstrate this class. * Static method to demonstrate this class.
*/ */
public static function test() { public static function test()
{
// A few examples. // A few examples.
echo "Testing CPENamingBind...<br>\n"; echo "Testing CPENamingBind...<br>\n";
$wfn = new WellFormedName("a", "microsoft", "internet_explorer", "8\\.0\\.6001", $wfn = new WellFormedName("a", "microsoft", "internet_explorer", "8\\.0\\.6001", "beta", new LogicalValue("ANY"), "sp2", null, null, null, null);
"beta", new LogicalValue("ANY"), "sp2", null, null, null, null); $wfn2 = new WellFormedName();
$wfn2 = new WellFormedName();
$wfn2->set("part", "a"); $wfn2->set("part", "a");
$wfn2->set("vendor", "foo\\\$bar"); $wfn2->set("vendor", "foo\\\$bar");
$wfn2->set("product", "insight"); $wfn2->set("product", "insight");
$wfn2->set("version", "7\\.4\\.0\\.1570"); $wfn2->set("version", "7\\.4\\.0\\.1570");
$wfn2->set("target_sw", "win2003"); $wfn2->set("target_sw", "win2003");
$wfn2->set("update", new LogicalValue("NA")); $wfn2->set("update", new LogicalValue("NA"));
$wfn2->set("sw_edition", "online"); $wfn2->set("sw_edition", "online");
$wfn2->set("target_hw", "x64"); $wfn2->set("target_hw", "x64");
$cpenb = new CPENameBinder(); $cpenb = new CPENameBinder();
echo $cpenb->bindToURI($wfn) . "<br>\n"; echo $cpenb->bindToURI($wfn) . "<br>\n";
echo $cpenb->bindToFS($wfn2) . "<br>\n"; echo $cpenb->bindToFS($wfn2) . "<br>\n";
} }
} }

Some files were not shown because too many files have changed in this diff Show More