2018-05-07 10:51:08 -04:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* File: helper.inc
|
|
|
|
* Author: Ryan Prather
|
|
|
|
* Purpose: The purpose of this file is to hold any helper functions that are used in various locations in the application
|
|
|
|
* Created: 6 Jan 2014
|
|
|
|
*
|
|
|
|
* Portions Copyright 2016-2017: Cyber Perspectives, All rights reserved
|
|
|
|
* Released under the Apache v2.0 License
|
|
|
|
*
|
|
|
|
* Portions Copyright (c) 2012-2015, Salient Federal Solutions
|
|
|
|
* Portions Copyright (c) 2008-2011, Science Applications International Corporation (SAIC)
|
|
|
|
* Released under Modified BSD License
|
|
|
|
*
|
|
|
|
* See license.txt for details
|
|
|
|
*
|
|
|
|
* Change Log:
|
|
|
|
* - 6 Jan 14 - File created
|
|
|
|
* - Sep 1, 2016 - Copyright Update and
|
|
|
|
* changed file types to string instead of index
|
|
|
|
* - Oct 24, 2016 - Added check in download_file function to ensure can open the local file
|
|
|
|
* - Nov 7, 2016 - Added check for existence of file_types class before creating
|
|
|
|
* - Dec 7, 2016 - Changed PHP constant to PHP_BIN
|
|
|
|
* - Dec 12, 2016 - Added parsing for company variables in config.xml
|
|
|
|
* - Dec 13, 2016 - Changed error in load_Config() to die if it can't find the config.xml file
|
|
|
|
* - Jan 30, 2017 - Formatting
|
|
|
|
* - Feb 15, 2017 - Added BZip, ping, between, and url_exists functions
|
|
|
|
* Migrated file_types constants to defined constants
|
|
|
|
* - Feb 21, 2017 - Added documentation, fixed issue with remote_filesize not correctly retrieving the file size of a remote file on Windows,
|
|
|
|
* Started adding download speed checker, but need to troubleshoot
|
|
|
|
* - Mar 3, 2017 - Deleted what_software method (all code is using software::identify_Software method instead)
|
|
|
|
* - Mar 13, 2017 - Cleaned up download_file and url_exists functions
|
|
|
|
* - Mar 22, 2017 - Documentation for constants, added JSON constant for header output,
|
|
|
|
* Added check for 5-digit extensions (.debug) in check_path,
|
|
|
|
* - Apr 5, 2017 - Added $chdir parameter to check_path function to change directory if set true
|
|
|
|
* - May 13, 2017 - Added ECHECKLIST_OUTPUT_FORMAT constant
|
|
|
|
* - May 19, 2017 - Added NOTIFICATIONS constant
|
|
|
|
* - Oct 2, 2017 - Fixed error with file downloads showing as moved and return largest content-size from http header
|
|
|
|
* - Oct 27, 2017 - Added UNSUPPORTED_INI constant and file detection for desktop.ini files
|
|
|
|
* - Dec 27, 2017 - Expanded download_file method to allow for download progress meta key
|
2018-07-26 08:33:50 -04:00
|
|
|
* - Jun 2, 2018 - Added $salt parameter to my_encrypt method to support changing passwords
|
2018-05-07 10:51:08 -04:00
|
|
|
*/
|
|
|
|
include_once 'error.inc';
|
|
|
|
include_once 'validation.inc';
|
2018-09-06 13:43:23 -04:00
|
|
|
include_once 'vendor/autoload.php';
|
|
|
|
|
|
|
|
use Monolog\Logger;
|
2018-05-07 10:51:08 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to get element or value from XML document using XPath
|
|
|
|
*
|
|
|
|
* @param DOMDocument $xml
|
|
|
|
* Document
|
|
|
|
* @param string $path
|
|
|
|
* XPath string
|
|
|
|
* @param string $starting [optional]
|
|
|
|
* Starting node
|
|
|
|
* @param boolean $keep [optional]
|
|
|
|
* Return the DOMElement
|
|
|
|
*
|
|
|
|
* @return mixed
|
|
|
|
* Will a DOMElement if $keep is true, a string if a single element, or an array:string if there are multiple elements
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function getValue($xml, $path, $starting = null, $keep = false)
|
|
|
|
{
|
|
|
|
$xpath = new DOMXPath($xml);
|
|
|
|
$ns = $xml->lookupNamespaceUri($xml->namespaceURI);
|
|
|
|
|
|
|
|
$xpath->registerNamespace('x', $ns);
|
|
|
|
if (is_null($starting)) {
|
|
|
|
$buf = $xpath->query($path);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$buf = $xpath->query($path, $starting);
|
|
|
|
}
|
|
|
|
$ret = null;
|
|
|
|
|
|
|
|
if ($keep) {
|
|
|
|
return $buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($buf->length == 1) {
|
|
|
|
if (get_class($buf->item(0)) == 'DOMAttr') {
|
|
|
|
$ret = $buf->item(0)->value;
|
|
|
|
}
|
|
|
|
elseif (get_class($buf->item(0)) == 'DOMElement' && $buf->item(0)->childNodes->length == 1) {
|
|
|
|
$ret = $buf->item(0)->nodeValue;
|
|
|
|
}
|
|
|
|
elseif (get_class($buf->item(0)) == 'DOMElement' && $buf->item(0)->childNodes->length > 1) {
|
|
|
|
foreach ($buf->item(0)->childNodes as $node) {
|
|
|
|
if ($node->nodeName != '#text') {
|
|
|
|
$ret[$node->nodeName][] = $node->nodeValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif ($buf->length > 1) {
|
|
|
|
foreach ($buf as $node) {
|
|
|
|
if ($node->childNodes->length == 1) {
|
|
|
|
$ret[] = $node->nodeValue;
|
|
|
|
}
|
|
|
|
elseif ($node->childNodes->length > 1) {
|
|
|
|
foreach ($node->childNodes as $childNode) {
|
|
|
|
if ($childNode->nodeName != '#text') {
|
|
|
|
$ret[$childNode->nodeName][] = $childNode->nodeValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $ret;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to determine a file type
|
|
|
|
*
|
|
|
|
* @param string $filename
|
|
|
|
* Path to file being evaulated
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
* <p><i>type</i> - file_types class enum</p>
|
|
|
|
* <p><i>msg</i> - string notice</p>
|
|
|
|
* <p><i>base_name</i> - string file name alone</p>
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function FileDetection($filename)
|
|
|
|
{
|
2018-09-26 10:39:38 -04:00
|
|
|
$name = [];
|
2018-07-26 08:33:50 -04:00
|
|
|
$name['base_name'] = basename($filename);
|
|
|
|
// print "\tCheck if exists".PHP_EOL;
|
|
|
|
if (!file_exists($filename)) {
|
|
|
|
$name['type'] = "ERROR";
|
|
|
|
$name['msg'] = "File not found";
|
|
|
|
return $name;
|
|
|
|
}
|
|
|
|
// print "\tCheck if dir".PHP_EOL;
|
|
|
|
if (is_dir($filename)) {
|
|
|
|
$name['type'] = DIRECTORY;
|
|
|
|
return $name;
|
|
|
|
}
|
|
|
|
// print "\tStarting".PHP_EOL;
|
|
|
|
$name['type'] = UNSUPPORTED; // if we can't find it - it stays unsupported
|
|
|
|
if (preg_match("/desktop\.ini/", $filename)) {
|
|
|
|
$name['type'] = UNSUPPORTED_INI;
|
|
|
|
$name['msg'] = 'Unsupported INI';
|
|
|
|
return $name;
|
|
|
|
}
|
|
|
|
// check file extension
|
|
|
|
if (preg_match('/\.xml$/i', $name['base_name'])) {
|
|
|
|
// STIG XCCDF or SCC Results or XML Nmap
|
|
|
|
if (preg_match('/SCC.*XCCDF\-Results.*\.xml/i', $name['base_name'])) {
|
|
|
|
$name['type'] = SCC_XCCDF;
|
|
|
|
}
|
|
|
|
elseif (preg_match('/SCC.*OVAL\-Results.*\.xml/i', $name['base_name'])) {
|
|
|
|
$name['type'] = SCC_OVAL;
|
|
|
|
}
|
|
|
|
elseif (preg_match('/STIG\-(oval|cpe\-dictionary|cpe\-oval)/i', $name['base_name'])) { // DISA STIG Checklist
|
|
|
|
$name['type'] = DISA_STIG_OVAL;
|
|
|
|
}
|
|
|
|
elseif (preg_match('/\$/', $name['base_name'])) { // Invalid DISA STIG checklist
|
|
|
|
$name['type'] = UNSUPPORTED_XML;
|
|
|
|
}
|
|
|
|
elseif (preg_match('/xccdf.*xml/i', $name['base_name'])) { // DISA STIG Checklist
|
|
|
|
$name['type'] = DISA_STIG_XML;
|
|
|
|
}
|
|
|
|
elseif (preg_match('/VMS6X\.xml|Session\.xml/i', $name['base_name'])) { // Gold Disk
|
|
|
|
$name['type'] = GOLDDISK;
|
|
|
|
}
|
|
|
|
elseif (preg_match('/MBSA/i', $name['base_name'])) {
|
|
|
|
$name['type'] = MBSA_XML;
|
|
|
|
}
|
|
|
|
elseif (preg_match("/nmap/i", $name['base_name'])) {
|
|
|
|
$name['type'] = NMAP_XML;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// could be XML Nmap, or unknown
|
|
|
|
$name['type'] = UNSUPPORTED_XML;
|
|
|
|
$f = fopen($filename, 'r');
|
|
|
|
for ($x = 0; $x < 5; $x++) {
|
|
|
|
$line = fgets($f);
|
|
|
|
if (preg_match('/nmap\.xsl|nmaprun/i', $line)) {
|
|
|
|
$name['type'] = NMAP_XML;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
elseif (preg_match("/IMPORT_FILE/i", $line)) {
|
|
|
|
$name['type'] = MSSQL_XML;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose($f);
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/\.nessus$/i', $name['base_name'])) { // usually starts with nessus_report
|
|
|
|
$name['type'] = NESSUS;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/\.messages$/i', $name['base_name'])) {
|
|
|
|
$name['type'] = NESSUS_MESSAGES;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/\.txt$/i', $name['base_name'])) {
|
|
|
|
if (preg_match('/All\-Settings|Non\-Compliance/i', $name['base_name'])) {
|
|
|
|
$name['type'] = UNSUPPORTED_SCC_TEXT;
|
|
|
|
}
|
|
|
|
elseif (preg_match('/SCC.*Error_Log/i', $name['base_name'])) {
|
|
|
|
$name['type'] = UNSUPPORTED_SCC_ERROR;
|
|
|
|
}
|
|
|
|
elseif (preg_match('/MBSA/i', $name['base_name'])) {
|
|
|
|
$name['type'] = MBSA_TEXT;
|
|
|
|
}
|
|
|
|
elseif (preg_match("/nmap/i", $name['base_name'])) {
|
|
|
|
$name['type'] = NMAP_TEXT;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// see if it's an nmap file named .txt
|
|
|
|
$f = fopen($filename, 'r');
|
|
|
|
$line = fgets($f);
|
|
|
|
fclose($f);
|
|
|
|
if (preg_match('/Nmap/i', $line)) {
|
|
|
|
if (preg_match('/\-oN|Starting/i', $line)) {
|
|
|
|
$name['type'] = NMAP_TEXT;
|
|
|
|
}
|
|
|
|
elseif (preg_match('/\-oG/i', $line)) {
|
|
|
|
$name['type'] = NMAP_GREPABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif (preg_match('/Script started|telnet|User access|sh conf|Using/i', $line)) {
|
|
|
|
$name['type'] = NMAP_NETWORK_DEVICE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$name['type'] = UNSUPPORTED_TEXT;
|
|
|
|
error_log($name['base_name'] . " is unsupported");
|
|
|
|
}
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/All\-PDI\-Catalog\.csv$/i', $name['base_name'])) {
|
|
|
|
$name['type'] = PDI_CATALOG;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/\.csv$/i', $name['base_name'])) {
|
|
|
|
// E-Checklist or Retina
|
|
|
|
$f = fopen($filename, 'r');
|
2018-05-07 10:51:08 -04:00
|
|
|
$line = fgets($f);
|
2018-07-26 08:33:50 -04:00
|
|
|
fclose($f);
|
|
|
|
if (preg_match('/Checklist:|Unclassified|Secret|STIG[_| ]ID/i', $line)) {
|
|
|
|
$name['type'] = ECHECKLIST_CSV;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-10-25 11:32:48 -04:00
|
|
|
elseif (preg_match("/host\-list/", $name['base_name'])) {
|
|
|
|
$name['type'] = HOST_LIST;
|
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/^\"NetBIOSName|^\"JobName/', $line)) {
|
|
|
|
$name['type'] = UNSUPPORTED_RETINA_CSV;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$name['type'] = UNSUPPORTED_CSV;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/\.xlsx$|\.xls$/i', $name['base_name'])) {
|
|
|
|
// Could be procedural or technical E-Checklist
|
|
|
|
if (preg_match('/e\-?checklist/i', $name['base_name'])) {
|
|
|
|
$name['type'] = TECH_ECHECKLIST_EXCEL;
|
|
|
|
}
|
|
|
|
elseif (preg_match('/validation|ia[\-]*controls/i', $name['base_name'])) {
|
|
|
|
$name['type'] = PROC_ECHECKLIST_EXCEL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$name['type'] = UNSUPPORTED_EXCEL;
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/benchmark.*\.zip$/i', $name['base_name'])) {
|
|
|
|
$name['type'] = DISA_STIG_BENCHMARK_ZIP;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/(STIG_Library|IAVM|stig|srg).*\.zip$/i', $name['base_name'])) {
|
|
|
|
$name['type'] = DISA_STIG_LIBRARY_ZIP;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/all\-2\.0\.tar\.gz$/i', $name['base_name'])) {
|
|
|
|
$name['type'] = NESSUS_PLUGIN_GZIP;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/\.nasl$/i', $name['base_name'])) {
|
|
|
|
$name['type'] = NESSUS_PLUGIN_NASL;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/\.ckl$/i', $name['base_name'])) {
|
|
|
|
$name['type'] = STIG_VIEWER_CKL;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/\.nmap$/i', $name['base_name'])) {
|
|
|
|
$name['type'] = NMAP_TEXT;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/\.nbe$/i', $name['base_name'])) {
|
|
|
|
$name['type'] = UNSUPPORTED_NESSUS_NBE;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
elseif (preg_match('/\.Result$|\.log$|\.Examples$/i', $name['base_name'])) {
|
|
|
|
$name['type'] = UNSUPPORTED_UNIX_SRR;
|
|
|
|
}
|
|
|
|
if ($name['type'] == UNSUPPORTED) {
|
|
|
|
$name['msg'] = 'Unsupported File Type';
|
|
|
|
}
|
|
|
|
return $name;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert a string memory notation (1024K, 10M, 1G) to an integer byte
|
|
|
|
*
|
|
|
|
* @param string $val
|
|
|
|
* Pass in value of memory. Either an integer or integer with a measurement (g, m, k)
|
|
|
|
*
|
|
|
|
* @return integer
|
|
|
|
* Returns the amount of member in bytes being
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function return_bytes($val)
|
|
|
|
{
|
|
|
|
$val = trim($val);
|
|
|
|
$measurement = strtolower(substr($val, -1));
|
|
|
|
$val = (int) substr($val, 0, -1);
|
|
|
|
switch ($measurement) {
|
|
|
|
case 't':
|
|
|
|
$val *= 1024;
|
|
|
|
case 'g':
|
|
|
|
$val *= 1024;
|
|
|
|
case 'm':
|
|
|
|
$val *= 1024;
|
|
|
|
case 'k':
|
|
|
|
$val *= 1024;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $val;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to query and find a target based on a hostname or IP. If not found will create the target
|
|
|
|
*
|
|
|
|
* @param mysqli $db
|
|
|
|
* The mysqli connection
|
|
|
|
* @param integer $steid
|
|
|
|
* The ST&E that we are operating in
|
|
|
|
* @param string $hostname
|
|
|
|
* The hostname of the target being searched for
|
|
|
|
* @param string $ip
|
|
|
|
* The IP address of the target being searched for
|
|
|
|
*
|
|
|
|
* @return integer
|
|
|
|
* The target ID for any targets found or created
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function get_a_tgt_id($db, $steid, $hostname, $ip)
|
|
|
|
{
|
|
|
|
# gets a target ID for the hostname/ip combo
|
|
|
|
$tgt_id = $db->check_Target($steid, $hostname);
|
|
|
|
if (!$tgt_id) {
|
|
|
|
$tgt_id = $db->check_Target($steid, $ip);
|
|
|
|
}
|
|
|
|
# If it doesn't exist, we'll have to create a target.
|
|
|
|
# OS for MBSA is Windows, but probably use generic if we have to add a host.
|
|
|
|
#$tgt_id = 0;
|
|
|
|
if (!$tgt_id) {
|
|
|
|
$sw = $db->get_Software("cpe:/o:generic:generic:-")[0];
|
|
|
|
$tgt_id = $db->save_Target('insert', array(
|
|
|
|
'ste' => $steid,
|
|
|
|
'osSoftware' => $sw->get_ID(),
|
|
|
|
'DeviceName' => $hostname,
|
|
|
|
'location' => '',
|
|
|
|
'targetNotes' => 'Created by MBSA Parser'
|
|
|
|
));
|
|
|
|
$new_int = array(
|
|
|
|
'action' => 'insert',
|
|
|
|
'tgt_id' => $tgt_id,
|
|
|
|
'ipv4' => $ip,
|
|
|
|
'hostname' => $hostname,
|
|
|
|
'fqdn' => $hostname,
|
|
|
|
);
|
|
|
|
$db->save_Interface($new_int);
|
|
|
|
}
|
|
|
|
Sagacity_Error::err_handler("Target ID: $tgt_id");
|
|
|
|
return $tgt_id;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clean up passed in string
|
|
|
|
*
|
|
|
|
* @param string $string
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function textCleanup($string)
|
|
|
|
{
|
|
|
|
return htmlentities(preg_replace('/\n+/', '\n', preg_replace('/\r|\t|^\n$/', "", $string)));
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to assist in the creation and appending of XML elements to an XML DOM Document
|
|
|
|
*
|
|
|
|
* @param DOMDocument $xml
|
|
|
|
* The DOMDocument to add the element to
|
|
|
|
* @param string $element_name
|
|
|
|
* The name of the element/tag to create
|
|
|
|
* @param string $element_value
|
|
|
|
* The element value
|
|
|
|
* @param boolean $is_cdata
|
|
|
|
* Is the value supposed to be inside a CData section
|
|
|
|
* @param array $attrs
|
|
|
|
* Array of name/value pair attributes
|
|
|
|
*
|
|
|
|
* @return DOMElement
|
|
|
|
* The returned element (can be passed into appendChild)
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function xml_helper(&$xml, $element_name, $element_value = null, $is_cdata = false, $attrs = array())
|
|
|
|
{
|
|
|
|
if (false) {
|
|
|
|
$xml = new DOMDocument();
|
|
|
|
}
|
|
|
|
if (!is_null($element_value)) {
|
|
|
|
if ($is_cdata) {
|
|
|
|
$cdata = $xml->createCDATASection($element_value);
|
|
|
|
$el = $xml->createElement($element_name);
|
|
|
|
$el->appendChild($cdata);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$el = $xml->createElement($element_name, $element_value);
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
else {
|
2018-07-26 08:33:50 -04:00
|
|
|
$el = $xml->createElement($element_name);
|
|
|
|
}
|
|
|
|
if (is_array($attrs) && count($attrs)) {
|
|
|
|
foreach ($attrs as $name => $value) {
|
|
|
|
$el->setAttribute($name, $value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $el;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to log to the time log file
|
|
|
|
*
|
|
|
|
* @param resource $fh
|
|
|
|
* File handle of the file to output too
|
|
|
|
* @param string $msg
|
|
|
|
* Message to send to the file
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function time_log_diff($fh, $msg)
|
|
|
|
{
|
|
|
|
global $last_time;
|
|
|
|
//$now = new DateTime();
|
|
|
|
$now = microtime(true);
|
|
|
|
$diff = $now - $last_time;
|
|
|
|
//if($diff > 1) {
|
|
|
|
$lt_format = DateTime::createFromFormat("U.u", $last_time);
|
|
|
|
$now_format = DateTime::createFromFormat("U.u", $now);
|
|
|
|
if (is_a($lt_format, 'DateTime') && is_a($now_format, 'DateTime')) {
|
|
|
|
fwrite($fh, $lt_format->format("H:i:s.u") . "," . $now_format->format("H:i:s.u") . ",\"$msg\"," . round($diff, 6) . PHP_EOL);
|
|
|
|
}
|
|
|
|
//}
|
|
|
|
$last_time = $now;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to download a file from a remote server
|
|
|
|
*
|
|
|
|
* @param string $url
|
|
|
|
* @param string $newname [optional]
|
|
|
|
* @param db_helper $db [optional]
|
|
|
|
* @param string $db_meta [optional]
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function download_file($url, $newname = null, &$db = null, $db_meta = null)
|
|
|
|
{
|
|
|
|
if (!url_exists($url)) {
|
|
|
|
Sagacity_Error::err_handler("Could not find the URL $url", E_WARNING);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$total_size = remote_filesize($url);
|
|
|
|
|
|
|
|
if (!is_null($newname)) {
|
|
|
|
$fname = $newname;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$fname = basename($url);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!($local_fh = fopen($fname, "w"))) {
|
|
|
|
Sagacity_Error::err_handler("Failed to open the local file handle" . PHP_EOL, E_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!($remote_fh = fopen($url, "r"))) {
|
|
|
|
Sagacity_Error::err_handler("Was not able to open the file $url", E_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
$written_size = 0;
|
|
|
|
print "Downloading $url (" . human_filesize($total_size) . ")" . PHP_EOL;
|
|
|
|
//$start = microtime();
|
|
|
|
while ($data = fread($remote_fh, 1048576)) {
|
|
|
|
//$end = microtime();
|
|
|
|
fwrite($local_fh, $data);
|
|
|
|
$written_size += strlen($data);
|
|
|
|
$complete = ($written_size / $total_size) * 100;
|
|
|
|
|
|
|
|
print "\rComplete " . sprintf("%.2f%%", $complete);
|
|
|
|
|
|
|
|
if (is_a($db, 'db_helper') && !is_null($db_meta) && strlen($db_meta)) {
|
|
|
|
$db->update("sagacity.settings", ['meta_value' => number_format($complete, 2)], [
|
|
|
|
[
|
|
|
|
'field' => 'meta_key',
|
|
|
|
'op' => '=',
|
|
|
|
'value' => $db_meta
|
|
|
|
]
|
|
|
|
]);
|
|
|
|
$db->execute();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
print PHP_EOL;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* To convert the byte size of a file to a human readable format
|
|
|
|
*
|
|
|
|
* @param int $bytes
|
|
|
|
* @param int $decimals
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function human_filesize($bytes, $decimals = 2)
|
|
|
|
{
|
|
|
|
$sz = 'BKMGTP';
|
|
|
|
$factor = floor((strlen($bytes) - 1) / 3);
|
|
|
|
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor];
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* To get the remote file size (returns bytes)
|
|
|
|
*
|
|
|
|
* @param string $url
|
|
|
|
*
|
|
|
|
* @return boolean|int
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function remote_filesize($url)
|
|
|
|
{
|
|
|
|
error_reporting(E_ERROR);
|
|
|
|
try {
|
|
|
|
if ($size = filesize($url)) {
|
|
|
|
return $size;
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-07-26 08:33:50 -04:00
|
|
|
catch (Exception $e) {
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
$regex = "/Content\-Length: *([\d]+)/i";
|
|
|
|
$matches = array();
|
|
|
|
if (!$fp = @fopen($url, 'rb')) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
isset($http_response_header) &&
|
|
|
|
preg_match_all($regex, implode(PHP_EOL, $http_response_header), $matches)
|
|
|
|
) {
|
|
|
|
if (count($matches[0])) {
|
|
|
|
return (int) max($matches[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
print "Could not find the content-length in the header, so downloading the file to get the length" . PHP_EOL;
|
|
|
|
return strlen(stream_get_contents($fp));
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to replace only the first instance of a string
|
|
|
|
*
|
|
|
|
* @param string $search
|
|
|
|
* @param string $replace
|
|
|
|
* @param string $subject
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function str_replace_first($search, $replace, $subject)
|
|
|
|
{
|
|
|
|
return implode($replace, explode($search, $subject, 2));
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to check for the existence of a path and create a directory if not found
|
|
|
|
*
|
|
|
|
* @param string $path
|
|
|
|
* @param boolean $chdir
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function check_path($path, $chdir = false)
|
|
|
|
{
|
|
|
|
if (!file_exists($path)) {
|
|
|
|
try {
|
|
|
|
// come in 4 characters from the end and check to see if it is a . (period), which signifies a file was passed in
|
|
|
|
if (strpos($path, ".") !== false && substr($path, -4, 1) == '.' || substr($path, -6, 1) == '.') {
|
|
|
|
touch($path);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mkdir($path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception $e) {
|
|
|
|
die($e->getMessage());
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
if ($chdir && is_dir($path)) {
|
|
|
|
chdir($path);
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* To create a bzip file
|
|
|
|
*
|
|
|
|
* @param string $in
|
|
|
|
* @param string $out
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function bzip2($in, $out)
|
|
|
|
{
|
|
|
|
if (!file_exists($in) || !is_readable($in))
|
|
|
|
return false;
|
|
|
|
if ((!file_exists($out) && !is_writeable(dirname($out)) || (file_exists($out) && !is_writable($out))))
|
|
|
|
return false;
|
|
|
|
if (!function_exists("bzopen"))
|
|
|
|
return false;
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
$in_file = fopen($in, "r");
|
|
|
|
$out_file = bzopen($out, "w");
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
while (!feof($in_file)) {
|
|
|
|
$buffer = fgets($in_file, 4096);
|
|
|
|
bzwrite($out_file, $buffer, 4096);
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
fclose($in_file);
|
|
|
|
bzclose($out_file);
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
return true;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* To unzip a bzip file
|
|
|
|
*
|
|
|
|
* @param string $in
|
|
|
|
* @param string $out
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function bunzip2($in, $out)
|
|
|
|
{
|
|
|
|
if (!file_exists($in) || !is_readable($in))
|
|
|
|
return false;
|
|
|
|
if ((!file_exists($out) && !is_writeable(dirname($out)) || (file_exists($out) && !is_writable($out))))
|
|
|
|
return false;
|
|
|
|
if (!function_exists("bzopen"))
|
|
|
|
return false;
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
$in_file = bzopen($in, "r");
|
|
|
|
$out_file = fopen($out, "w");
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
while ($buffer = bzread($in_file, 4096)) {
|
|
|
|
fwrite($out_file, $buffer, 4096);
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
bzclose($in_file);
|
|
|
|
fclose($out_file);
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
return true;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to ping a host and respond boolean
|
|
|
|
*
|
|
|
|
* @param string $host
|
|
|
|
* @param int $port
|
|
|
|
* @param int $timeout
|
|
|
|
*
|
|
|
|
* @return boolean
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function ping($host, $port = 80, $timeout = 6)
|
|
|
|
{
|
|
|
|
//$e = new Exception("Test");
|
|
|
|
//die($e->getTraceAsString());
|
|
|
|
$errno = null;
|
|
|
|
$errstr = null;
|
|
|
|
$fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
|
|
|
|
if (is_resource($fsock)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* To evaluate $val and see if it is between low and high values inclusively.
|
|
|
|
*
|
|
|
|
* @param number $val
|
|
|
|
* The value to check
|
|
|
|
* @param number $low
|
|
|
|
* The minimum allowed value
|
|
|
|
* @param number $high
|
|
|
|
* The maximum allowed value
|
|
|
|
*
|
|
|
|
* @return boolean
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function between($val, $low, $high)
|
|
|
|
{
|
|
|
|
if (is_numeric($val) && is_numeric($low) && is_numeric($high)) {
|
|
|
|
if ($val >= $low && $val <= $high) {
|
|
|
|
return true;
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
return false;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to check if a URL exists (run prior to downloading a file)
|
|
|
|
*
|
|
|
|
* @param string $url
|
|
|
|
*
|
|
|
|
* @return boolean
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function url_exists($url)
|
|
|
|
{
|
|
|
|
$file_headers = get_headers($url);
|
|
|
|
foreach ($file_headers as $header) {
|
|
|
|
if (preg_match("/HTTP\/[\d\.]+ 200 OK/", $header)) {
|
|
|
|
return true;
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
return false;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
2018-09-06 13:43:23 -04:00
|
|
|
* @param float $start
|
|
|
|
* @param float $end
|
|
|
|
* @return float
|
2018-05-07 10:51:08 -04:00
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function microtime_diff($start, $end = null)
|
|
|
|
{
|
|
|
|
list($start_usec, $start_sec) = explode(" ", $start);
|
|
|
|
list($end_usec, $end_sec) = explode(" ", $end);
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
$diff_sec = intval($end_sec) - intval($start_sec);
|
|
|
|
$diff_usec = floatval($end_usec) - floatval($start_usec);
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
return floatval($diff_sec) + $diff_usec;
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sagacity encryption algorithm
|
|
|
|
*
|
|
|
|
* @param string $data
|
2018-07-26 08:33:50 -04:00
|
|
|
* @param string $salt
|
2018-05-07 10:51:08 -04:00
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function my_encrypt($data, $salt = null)
|
|
|
|
{
|
|
|
|
// Remove the base64 encoding from our key
|
|
|
|
if (is_null($salt)) {
|
|
|
|
$encryption_key = base64_decode(SALT);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$encryption_key = base64_decode($salt);
|
|
|
|
}
|
|
|
|
// Generate an initialization vector
|
|
|
|
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(ALGORITHM));
|
|
|
|
// Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
|
|
|
|
$encrypted = openssl_encrypt($data, ALGORITHM, $encryption_key, 0, $iv);
|
|
|
|
// The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
|
|
|
|
return base64_encode($encrypted . '::' . $iv);
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sagacity decryption algorithm
|
|
|
|
*
|
|
|
|
* @param string $data
|
|
|
|
* @param string $key
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function my_decrypt($data)
|
|
|
|
{
|
|
|
|
// Remove the base64 encoding from our key
|
|
|
|
$encryption_key = base64_decode(SALT);
|
|
|
|
// To decrypt, split the encrypted data from our IV - our unique separator used was "::"
|
|
|
|
list($encrypted_data, $iv) = explode('::', base64_decode($data), 2);
|
|
|
|
return openssl_decrypt($encrypted_data, ALGORITHM, $encryption_key, 0, $iv);
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sagacity method to replace string by reference
|
|
|
|
*
|
|
|
|
* @param string $search
|
|
|
|
* @param string $replace
|
|
|
|
* @param string &$subject
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function my_str_replace($search, $replace, &$subject)
|
|
|
|
{
|
|
|
|
$subject = str_replace($search, $replace, $subject);
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper method to add DateIntervals
|
|
|
|
*
|
|
|
|
* @param DateInterval $i1
|
|
|
|
* @param DateInterval $i2
|
|
|
|
*
|
|
|
|
* @return DateInterval
|
|
|
|
*/
|
2018-07-26 08:33:50 -04:00
|
|
|
function add_intervals($i1, $i2)
|
|
|
|
{
|
|
|
|
$a = new DateTime("00:00");
|
|
|
|
$b = clone $a;
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
if (is_a($i1, 'DateInterval')) {
|
|
|
|
$a->add($i1);
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
if (is_a($i2, 'DateInterval')) {
|
|
|
|
$a->add($i2);
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
|
2018-07-26 08:33:50 -04:00
|
|
|
return $b->diff($a);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper method to convert a file name to a .log file
|
2018-09-06 13:43:23 -04:00
|
|
|
*
|
2018-07-26 08:33:50 -04:00
|
|
|
* @param string $fname
|
|
|
|
*
|
|
|
|
* @return string New filename with the prepended LOG_PATH
|
|
|
|
*/
|
|
|
|
function logify($fname)
|
|
|
|
{
|
|
|
|
$fname = preg_replace("/[\.][^\.]+$/", '', basename($fname));
|
|
|
|
if (!file_exists(LOG_PATH . "/{$fname}.log")) {
|
|
|
|
touch(LOG_PATH . "/{$fname}.log");
|
|
|
|
}
|
|
|
|
|
2018-10-17 22:19:41 -04:00
|
|
|
return realpath(LOG_PATH . "/{$fname}.log");
|
2018-07-26 08:33:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper method to convert LOG_LEVEL to Logger PSR log level
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function convert_log_level()
|
|
|
|
{
|
|
|
|
switch (LOG_LEVEL) {
|
|
|
|
case E_DEBUG:
|
|
|
|
return Logger::DEBUG;
|
|
|
|
case E_NOTICE:
|
|
|
|
return Logger::NOTICE;
|
|
|
|
case E_WARNING:
|
|
|
|
return Logger::WARNING;
|
|
|
|
default:
|
|
|
|
return Logger::ERROR;
|
|
|
|
}
|
2018-05-07 10:51:08 -04:00
|
|
|
}
|
2018-10-29 13:19:31 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper method to scrape a web page
|
|
|
|
*
|
|
|
|
* @param string $url
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function scrape_webpage($url)
|
|
|
|
{
|
|
|
|
$config = [
|
|
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
|
|
CURLOPT_FOLLOWLOCATION => true,
|
|
|
|
CURLOPT_HEADER => true,
|
|
|
|
CURLOPT_SSL_VERIFYPEER => false,
|
|
|
|
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13',
|
|
|
|
CURLOPT_URL => $url
|
|
|
|
];
|
|
|
|
$c = curl_init();
|
|
|
|
|
|
|
|
curl_setopt_array($c, $config);
|
|
|
|
|
|
|
|
$output = curl_exec($c);
|
|
|
|
|
|
|
|
return $output;
|
|
|
|
}
|