system.inc - fixed typo parse_excel_echecklist.php - added functionality to assign OS and checklists based on worksheet contents database.inc - Added a couple methods to support changes for #25 export.php - Minor change to OS listing and added add_cell_comment method to migrate scanner notes to a comment instead of the main note (separating the scanner and anaylst comments)
		
			
				
	
	
		
			534 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			534 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /**
 | |
|  * File: export.php
 | |
|  * Author: Ryan Prather
 | |
|  * Purpose: Export findings to an Excel spreadsheet eChecklist
 | |
|  * Created: Oct 15, 2013
 | |
|  *
 | |
|  * Portions Copyright 2016-2018: Cyber Perspectives, LLC, 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:
 | |
|  *  - Oct 15, 2013 - File created
 | |
|  *  - Dec 12, 2016 - Added Cyber Perspectives license, changed writing to spreadsheet to use constants for company data, and
 | |
|  *                   Added ST&E ending date to cover page
 | |
|  *  - Mar 9, 2017 - Fixed issue with export overwriting columns
 | |
|  *  - Apr 15, 2017 - Set text wrapping if enabled on Short Title column
 | |
|  *  - May 13, 2017 - Migrated to PHPSpreadsheet library, and add support for other export formats
 | |
|  *  - Jun 3, 2017 - Fixed bug #232
 | |
|  *  - Jul 23, 2017 - MAS Added comments and rudimentary RMF control support to eChecklist export
 | |
|  *  - Dec 27, 2017 - Updating classification info on cover sheet page,
 | |
|  *      removed classification from G2,
 | |
|  *      fixed invalid function call to stringFromColumnIndex as it was moved to a different class and changed to 1-based instead of 0-based,
 | |
|  *      syntax updates, updated PDF writer to Tcpdf class, added die if constant ECHECKLIST_FORMAT is not set as expected
 | |
|  *  - Jan 15, 2018 - Formatting, updated use statements, not seeing behavior explained in #373
 | |
|  *  - Nov 8, 2018 - Minor change to OS listing and added add_cell_comment method to migrate scanner notes to a comment instead of the main note (separating the scanner and anaylst comments)
 | |
|  */
 | |
| include_once 'config.inc';
 | |
| include_once 'database.inc';
 | |
| include_once 'helper.inc';
 | |
| 
 | |
| require_once 'vendor/autoload.php';
 | |
| require_once 'excelConditionalStyles.inc';
 | |
| 
 | |
| use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
 | |
| use PhpOffice\PhpSpreadsheet\Writer\Xls;
 | |
| use PhpOffice\PhpSpreadsheet\Writer\Ods;
 | |
| use PhpOffice\PhpSpreadsheet\Writer\Csv;
 | |
| use PhpOffice\PhpSpreadsheet\Writer\Html;
 | |
| use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
 | |
| use PhpOffice\PhpSpreadsheet\Worksheet;
 | |
| use Monolog\Logger;
 | |
| use Monolog\Handler\StreamHandler;
 | |
| 
 | |
| global $conditions, $validation, $borders;
 | |
| 
 | |
| set_time_limit(0);
 | |
| $db = new db();
 | |
| $emass_ccis = null;
 | |
| $log_level = convert_log_level();
 | |
| $chk_hosts = filter_input_array(INPUT_POST, 'chk_host');
 | |
| $cat_id = filter_input(INPUT_GET, 'cat', FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
 | |
| if (!$cat_id) {
 | |
|   $cat_id = filter_input(INPUT_POST, 'cat', FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
 | |
| }
 | |
| $ste_id = filter_input(INPUT_COOKIE, 'ste', FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
 | |
| if (!$ste_id) {
 | |
|   $ste_id = filter_input(INPUT_POST, 'ste', FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
 | |
| }
 | |
| 
 | |
| if (!$ste_id || !$cat_id) {
 | |
| 	die("Could not find the STE or Category ID");
 | |
| }
 | |
| 
 | |
| $cat = $db->get_Category($cat_id)[0];
 | |
| if (!is_a($cat, 'ste_cat')) {
 | |
| 	die("Error finding category $cat_id");
 | |
| }
 | |
| 
 | |
| $ste = $db->get_STE($ste_id)[0];
 | |
| if (!is_a($ste, 'ste')) {
 | |
| 	die("Error finding ST&E");
 | |
| }
 | |
| 
 | |
| $log = new Logger("eChecklist-export");
 | |
| $log->pushHandler(new StreamHandler(LOG_PATH . "/{$cat->get_Name()}-echecklist-export.log", $log_level));
 | |
| 
 | |
| if ($chk_hosts) {
 | |
|   $findings = $db->get_Category_Findings($cat_id, $chk_hosts);
 | |
| }
 | |
| else {
 | |
|   $findings = $db->get_Category_Findings($cat_id);
 | |
| }
 | |
| $log->debug("Got findings");
 | |
| 
 | |
| // Get mapping of eMASS controls to CCIs from DB
 | |
| if ($ste->get_System()->get_Accreditation_Type() == accrediation_types::RMF) {
 | |
|   $emass_ccis = $db->get_EMASS_CCIs();
 | |
| }
 | |
| 
 | |
| $Reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile("eChecklist-Template.xlsx");
 | |
| $ss = $Reader->load("eChecklist-Template.xlsx");
 | |
| 
 | |
| $log->debug("Loaded template");
 | |
| 
 | |
| $ss->setActiveSheetIndexByName('Cover Sheet')
 | |
|    ->setCellValue("B5", "{$ste->get_System()->get_Name()} eChecklist")
 | |
|    ->setCellValue("B9", "{$ste->get_Eval_Start_Date()->format("m/d/Y")}-{$ste->get_Eval_End_Date()->format("m/d/Y")}")
 | |
|    ->setCellValue("B2", ($ste->get_System()->get_Classification() == 'Classified' ? "SECRET" : "UNCLASSIFIED"))
 | |
|    ->setCellValue("B12", "by:\r" . COMPANY . "\r" . COMP_ADD)
 | |
|    ->setCellValue("B15", "Derived from: " . SCG . "\rReasons: <reasons>\rDeclassify on: " . DECLASSIFY_ON);
 | |
| 
 | |
| // set properties
 | |
| $ss->getProperties()
 | |
|    ->setCreator(CREATOR);
 | |
| $ss->getProperties()
 | |
|    ->setLastModifiedBy(LAST_MODIFIED_BY);
 | |
| $ss->getProperties()
 | |
|    ->setCompany(COMPANY);
 | |
| $ss->getProperties()
 | |
|    ->setTitle("{$cat->get_Name()} eChecklist");
 | |
| $ss->getProperties()
 | |
|    ->setSubject("{$cat->get_Name()} eChecklist");
 | |
| $ss->getProperties()
 | |
|    ->setDescription("{$cat->get_Name()} eChecklist");
 | |
| 
 | |
| $log->debug("File properties set");
 | |
| 
 | |
| // set active sheet
 | |
| $ss->setActiveSheetIndex(2);
 | |
| 
 | |
| $host_status = array(
 | |
|   $conditions['open'],
 | |
|   $conditions['exception'],
 | |
|   $conditions['false_positive'],
 | |
|   $conditions['not_a_finding'],
 | |
|   $conditions['not_applicable'],
 | |
|   $conditions['no_data'],
 | |
|   $conditions['not_reviewed'],
 | |
|   $conditions['true'],
 | |
|   $conditions['false']
 | |
| );
 | |
| 
 | |
| // Iterate over worksheets in the category; populating each with the checklists and finding data
 | |
| foreach ($findings as $worksheet_name => $data) {
 | |
|   $log->debug("Looping through worksheet $worksheet_name");
 | |
|   $chk_arr = [];
 | |
| 
 | |
|   // Build the "Checklist" cell string with titles of all checklists on this worksheet
 | |
|   foreach ($data['checklists'] as $key => $chk_id) {
 | |
|     $checklist = $db->get_Checklist($chk_id)[0];
 | |
|     $chk_arr[] = "{$checklist->get_Name()} V{$checklist->get_Version()}R{$checklist->get_Release()} ({$checklist->get_type()})";
 | |
|   }
 | |
| 
 | |
|   $checklist_str = implode(", ", $chk_arr);
 | |
| 
 | |
|   if (is_null($sheet = $ss->getSheetByName($worksheet_name))) {
 | |
|     $new_sheet = clone $ss->getSheet(2);
 | |
|     $new_sheet->setTitle($worksheet_name);
 | |
|     $ss->addSheet($new_sheet);
 | |
| 
 | |
|     $sheet = $ss->getSheetByName($worksheet_name);
 | |
| 
 | |
|     if (is_array($data['target_list']) && count($data['target_list']) > 1) {
 | |
|       $sheet->insertNewColumnBefore("G", count($data['target_list']) - 1);
 | |
|     }
 | |
| 
 | |
|     $sheet->setCellValue("B9", $checklist_str);
 | |
|   }
 | |
|   else {
 | |
|     $sheet->setCellValue("B9", "{$sheet->getCellValue("B9")}, {$checklist_str}");
 | |
|   }
 | |
| 
 | |
|   $class = 'UNCLASSIFIED';
 | |
|   if (isset($data['highest_class'])) {
 | |
|     switch ($data['highest_class']) {
 | |
|       case 'FOUO':
 | |
|         $class = 'UNCLASSIFIED//FOUO';
 | |
|         break;
 | |
|       case 'S':
 | |
|         $class = 'SECRET';
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
|   else {
 | |
|     if ($ste->get_System()->get_Classification() == 'Sensitive') {
 | |
|       $class = 'UNCLASSIFIED//FOUO';
 | |
|     }
 | |
|     elseif ($ste->get_System()->get_Classification() == 'Classified') {
 | |
|       $class = 'SECRET';
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   $log->debug("Setting classification: $class");
 | |
|   $sheet->setCellValue("A1", $class)
 | |
|       ->setCellValue('E2', $ste->get_System()->get_Name());
 | |
| 
 | |
|   $sheet->getStyle("A1")
 | |
|       ->setConditionalStyles([$conditions['unclass_classification'], $conditions['secret_classification']]);
 | |
| 
 | |
|   $row = 11;
 | |
|   $last_tgt_col = Coordinate::stringFromColumnIndex(count($data['target_list']) + 5);
 | |
|   $overall_col = Coordinate::stringFromColumnIndex(count($data['target_list']) + 6);
 | |
|   $same_col = Coordinate::stringFromColumnIndex(count($data['target_list']) + 7);
 | |
|   $notes_col = Coordinate::stringFromColumnIndex(count($data['target_list']) + 8);
 | |
|   $check_contents_col = Coordinate::stringFromColumnIndex(count($data['target_list']) + 9);
 | |
| 
 | |
|   // Iterate over checklist items ($stig_id) and populate spreadsheet with status of each
 | |
|   foreach ($data['stigs'] as $stig_id => $tgt_status) {
 | |
| 	$log->debug("Running through STIG $stig_id", $tgt_status);
 | |
|     $ia_controls_string = null;
 | |
| 
 | |
|     // If $do_rmf is set, replace CCIs w/ eMASS RMF Control and build string to
 | |
|     // insert into IA Controls cell, otherwise just use CCIs.
 | |
|     if ($ste->get_System()->get_Accreditation_Type() == accrediation_types::RMF) {
 | |
|       $ia_controls = $tgt_status['echecklist']->get_IA_Controls();
 | |
|       $rmf_controls = [];
 | |
| 
 | |
|       foreach ($ia_controls as $control) {
 | |
|         // Remove 'CCI-' and leading zeros
 | |
|         $id = ltrim(substr($control, strpos($control, "-") + 1), '0');
 | |
|         // lookup cci in $emass_ccis
 | |
|         $key = array_search($id, array_column($emass_ccis, 'id'));
 | |
|         // Push the control onto $rmf_controls
 | |
|         array_push($rmf_controls, $emass_ccis[$key]['control']);
 | |
|       }
 | |
| 
 | |
|       $ia_controls_string = implode(" ", $rmf_controls);
 | |
|     }
 | |
|     else {
 | |
|       $ia_controls_string = $tgt_status['echecklist']->get_IA_Controls_String();
 | |
|     }
 | |
| 
 | |
|     $sheet->setCellValue("A{$row}", $stig_id)
 | |
|         ->setCellValue("B{$row}", $tgt_status['echecklist']->get_VMS_ID())
 | |
|         ->setCellValue("C{$row}", $tgt_status['echecklist']->get_Cat_Level_String())
 | |
|         ->setCellValue("D{$row}", $ia_controls_string)
 | |
|         ->setCellValue("E{$row}", deduplicateString($tgt_status['echecklist']->get_Short_Title()));
 | |
| 	$log->debug("Added STIG info ($stig_id), not to targets");
 | |
| 
 | |
|     foreach ($data['target_list'] as $host_name => $col_id) {
 | |
|       $status = 'Not Applicable';
 | |
|       if (isset($tgt_status["{$host_name}"])) {
 | |
|         $status = $tgt_status["{$host_name}"];
 | |
|       }
 | |
| 
 | |
|       $col = Coordinate::stringFromColumnIndex($col_id);
 | |
|       $sheet->setCellValue("{$col}{$row}", $status);
 | |
|     }
 | |
| 
 | |
|     $overall_str = "=IF(" .
 | |
|         "COUNTIF(F{$row}:{$last_tgt_col}{$row},\"Open\")+" .
 | |
|         "COUNTIF(F{$row}:{$last_tgt_col}{$row},\"Exception\")" .
 | |
|         ">0,\"Open\",\"Not a Finding\")";
 | |
|     $same_str = "=IF(" .
 | |
|         "COUNTIF(F{$row}:{$last_tgt_col}{$row},F{$row})=" .
 | |
|         "COLUMNS(F{$row}:{$last_tgt_col}{$row}), TRUE, FALSE)";
 | |
| 
 | |
|     $sheet->setCellValue($overall_col . $row, $overall_str);
 | |
| 
 | |
|     $sheet->setCellValue($same_col . $row, $same_str, true)
 | |
|         ->getStyle("{$same_col}11:{$same_col}{$sheet->getHighestDataRow()}")
 | |
|         ->setConditionalStyles([$conditions['true'], $conditions['false']]);
 | |
|     //->setDataValidation($validation['true_false']);
 | |
| 
 | |
|     $sheet->setCellValue($notes_col . $row, deduplicateString($tgt_status['echecklist']->get_Notes()))
 | |
|         ->setCellValue($check_contents_col . $row, deduplicateString($tgt_status['echecklist']->get_Check_Contents()));
 | |
| 	$log->debug("Added remaining cells");
 | |
| 
 | |
|     $row++;
 | |
|   }
 | |
| 
 | |
|   $sheet->setDataValidation("F11:{$last_tgt_col}{$row}", clone $validation['host_status']);
 | |
|   $log->debug("Set data validation for target $host_name");
 | |
| 
 | |
|   $log->debug("Completed STIG parsing");
 | |
|   $sheet->getStyle("F11:" . Coordinate::stringFromColumnIndex(count($data['target_list']) + 6) . $row)
 | |
|       ->setConditionalStyles($host_status);
 | |
|   $sheet->getStyle("C11:C{$sheet->getHighestDataRow()}")
 | |
|       ->setConditionalStyles(array($conditions['cat_1'], $conditions['cat_2'], $conditions['cat_3']));
 | |
| 
 | |
|   $sheet->getStyle("{$notes_col}11:{$notes_col}{$row}")
 | |
|       ->setConditionalStyles(array(
 | |
|         $conditions['open_conflict'],
 | |
|         $conditions['nf_na_conflict']
 | |
|   ));
 | |
|   if (is_array($data['target_list']) && count($data['target_list']) > 1) {
 | |
|     $sheet->getStyle("G3:{$notes_col}7")
 | |
|         ->getFill()
 | |
|         ->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_NONE);
 | |
|     $sheet->getStyle("G2")
 | |
|         ->getFill()
 | |
|         ->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_NONE);
 | |
|     $sheet->getStyle("G2")
 | |
|         ->getFont()
 | |
|         ->setBold(false);
 | |
|     $sheet->getStyle("G2")
 | |
|         ->getAlignment()
 | |
|         ->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_LEFT);
 | |
|   }
 | |
| 
 | |
|   $sheet->getStyle("A1:{$sheet->getHighestDataColumn()}{$sheet->getHighestDataRow()}")
 | |
|       ->applyFromArray($borders);
 | |
|   $sheet->freezePane("A11");
 | |
|   $sheet->setAutoFilter("A10:{$sheet->getHighestDataColumn()}10");
 | |
| 
 | |
|   updateHostHeader($sheet, $data['target_list'], $db);
 | |
| 
 | |
|   $log->debug("Completed worksheet $worksheet_name");
 | |
| }
 | |
| 
 | |
| $ss->removeSheetByIndex(2);
 | |
| 
 | |
| $log->debug("Writing to file");
 | |
| 
 | |
| $ct = '';
 | |
| $writer = null;
 | |
| 
 | |
| switch (ECHECKLIST_FORMAT) {
 | |
|   case 'xlsx':
 | |
|     $writer = new Xlsx($ss);
 | |
|     $writer->setPreCalculateFormulas(false);
 | |
|     $ct = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
 | |
|     break;
 | |
|   case 'ods':
 | |
|     $writer = new Ods($ss);
 | |
|     $writer->setPreCalculateFormulas(false);
 | |
|     $ct = "application/vnd.oasis.opendocument.spreadsheet";
 | |
|     break;
 | |
|   case 'pdf':
 | |
|     \PhpOffice\PhpSpreadsheet\Settings::setPdfRendererName(PhpOffice\PhpSpreadsheet\Settings::PDF_RENDERER_TCPDF);
 | |
|     $writer = new Tcpdf($ss);
 | |
|     $writer->writeAllSheets();
 | |
|     $ct = "application/pdf";
 | |
|     break;
 | |
|   case 'html':
 | |
|     $writer = new Html($ss);
 | |
|     $writer->writeAllSheets();
 | |
|     $writer->setPreCalculateFormulas(false);
 | |
|     $ct = "text/html";
 | |
|     break;
 | |
|   case 'xls':
 | |
|     $writer = new Xls($ss);
 | |
|     $writer->setPreCalculateFormulas(false);
 | |
|     $ct = "application/vnd.ms-excel";
 | |
|     break;
 | |
|   case 'csv':
 | |
|     $writer = new Csv($ss);
 | |
|     $ct = "text/csv";
 | |
|     break;
 | |
|   default:
 | |
|     die("Did not recognize eChecklist format " . ECHECKLIST_FORMAT);
 | |
| }
 | |
| 
 | |
| $cat_name = str_replace(" ", "_", $cat->get_Name());
 | |
| header("Content-type: $ct");
 | |
| header("Content-disposition: attachment; filename='{$cat_name}-eChecklist-{$ste_id}." . ECHECKLIST_FORMAT . "'");
 | |
| $writer->save("php://output");
 | |
| $log->debug("Writing complete");
 | |
| 
 | |
| /**
 | |
|  * Update the header on the worksheet
 | |
|  *
 | |
|  * @param Worksheet $sheet
 | |
|  * @param array:integer $tgts
 | |
|  * @param db $db
 | |
|  */
 | |
| function updateHostHeader($sheet, $tgts, &$db) {
 | |
|   global $ste_id, $log;
 | |
| 
 | |
|   $host_names = [];
 | |
|   $ips = [];
 | |
|   $oses = [];
 | |
| 
 | |
|   $open_cat_1 = null;
 | |
|   $open_cat_2 = null;
 | |
|   $open_cat_3 = null;
 | |
|   $not_a_finding = null;
 | |
|   $not_applicable = null;
 | |
|   $not_reviewed = null;
 | |
| 
 | |
|   foreach ($tgts as $tgt_name => $col_id) {
 | |
|     $log->notice("tgt_name: $tgt_name\tcol_id: $col_id");
 | |
|     $tgt = $db->get_Target_Details($ste_id, $tgt_name)[0];
 | |
|     /** @var software $os */
 | |
|     $os = $db->get_Software($tgt->get_OS_ID())[0];
 | |
| 
 | |
|     $oses[] = $os->get_SW_String();
 | |
|     $host_names[] = $tgt->get_Name();
 | |
| 
 | |
|     if (is_array($tgt->interfaces) && count($tgt->interfaces)) {
 | |
|       foreach ($tgt->interfaces as $int) {
 | |
|         if (!in_array($int->get_IPv4(), ["127.0.0.1", "", "0.0.0.0", null])) {
 | |
|           $ips[] = $int->get_IPv4();
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     $col = Coordinate::stringFromColumnIndex($col_id);
 | |
|     $highest_row = $sheet->getHighestDataRow();
 | |
| 
 | |
|     $sheet->getColumnDimension($col)
 | |
|         ->setWidth(14.14);
 | |
|     $sheet->setCellValue("{$col}8", "=COUNTIFS({$col}11:{$col}{$highest_row}, \"Open\", \$C\$11:\$C\${$highest_row}, \"I\")")
 | |
|         ->setCellValue("{$col}9", "=COUNTIF({$col}11:{$col}{$highest_row}, \"Not Reviewed\")")
 | |
|         ->setCellValue("{$col}10", $tgt->get_Name());
 | |
|     $sheet->getStyle("{$col}10")
 | |
|         ->getFont()
 | |
|         ->setBold(true);
 | |
|     $sheet->getStyle("{$col}10")
 | |
|         ->getFill()
 | |
|         ->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
 | |
|         ->setStartColor($GLOBALS['yellow']);
 | |
| 
 | |
|     if (!is_null($open_cat_1)) {
 | |
|       $open_cat_1 .= "+";
 | |
|       $open_cat_2 .= "+";
 | |
|       $open_cat_3 .= "+";
 | |
|       $not_a_finding .= "+";
 | |
|       $not_applicable .= "+";
 | |
|       $not_reviewed .= "+";
 | |
|     }
 | |
|     else {
 | |
|       $open_cat_1 = "=";
 | |
|       $open_cat_2 = "=";
 | |
|       $open_cat_3 = "=";
 | |
|       $not_a_finding = "=";
 | |
|       $not_applicable = "=";
 | |
|       $not_reviewed = "=";
 | |
|     }
 | |
| 
 | |
|     $open_cat_1 .= "COUNTIFS({$col}11:{$col}{$highest_row}, \"Open\", \$C\$11:\$C\${$highest_row}, \"I\")";
 | |
|     $open_cat_2 .= "COUNTIFS({$col}11:{$col}{$highest_row}, \"Open\", \$C\$11:\$C\${$highest_row}, \"II\")";
 | |
|     $open_cat_3 .= "COUNTIFS({$col}11:{$col}{$highest_row}, \"Open\", \$C\$11:\$C\${$highest_row}, \"III\")";
 | |
|     $not_a_finding .= "COUNTIF({$col}11:{$col}{$highest_row}, \"Not a Finding\")";
 | |
|     $not_applicable .= "COUNTIF({$col}11:{$col}{$highest_row}, \"Not Applicable\")";
 | |
|     $not_reviewed .= "COUNTIF({$col}11:{$col}{$highest_row}, \"Not Reviewed\")";
 | |
|   }
 | |
| 
 | |
|   $overall_col = Coordinate::stringFromColumnIndex(count($tgts) + 6);
 | |
|   $same_col = Coordinate::stringFromColumnIndex(count($tgts) + 7);
 | |
|   $notes_col = Coordinate::stringFromColumnIndex(count($tgts) + 8);
 | |
|   $check_contents_col = Coordinate::stringFromColumnIndex(count($tgts) + 9);
 | |
| 
 | |
|   $sheet->getStyle("{$overall_col}8:{$same_col}8")
 | |
|       ->getFill()
 | |
|       ->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
 | |
|       ->setStartColor($GLOBALS['orange']);
 | |
|   $sheet->getStyle("{$overall_col}9:{$same_col}9")
 | |
|       ->getFill()
 | |
|       ->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
 | |
|       ->setStartColor($GLOBALS['green']);
 | |
|   $sheet->getStyle("{$overall_col}10:{$same_col}10")
 | |
|       ->getFill()
 | |
|       ->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
 | |
|       ->setStartColor($GLOBALS['yellow']);
 | |
|   $sheet->getStyle("{$notes_col}10:{$check_contents_col}10")
 | |
|       ->getFill()
 | |
|       ->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
 | |
|       ->setStartColor($GLOBALS['light_gray']);
 | |
| 
 | |
|   $sheet->setCellValue("{$overall_col}8", "=COUNTIF({$overall_col}11:{$overall_col}{$highest_row}, \"Open\")")
 | |
|       ->setCellValue("{$overall_col}9", "=COUNTIF({$overall_col}11:{$overall_col}{$highest_row}, \"Not a Finding\")")
 | |
|       ->setCellValue("{$same_col}8", "=COUNTIF({$same_col}11:{$same_col}{$highest_row}, FALSE)")
 | |
|       ->setCellValue("{$same_col}9", "=COUNTIF({$same_col}11:{$same_col}{$highest_row}, TRUE)")
 | |
|       ->setCellValue("E3", implode(", ", $host_names))
 | |
|       ->setCellValue("E4", implode(", ", $ips))
 | |
|       ->setCellValue("G4", implode(", ", array_unique($oses)))
 | |
|       ->setCellValue("{$overall_col}10", "Overall Status")
 | |
|       ->setCellValue("{$same_col}10", "Consistent")
 | |
|       ->setCellValue("{$notes_col}10", "Notes")
 | |
|       ->setCellValue("{$check_contents_col}10", "Check Contents");
 | |
|   $sheet->getStyle("{$overall_col}10:{$check_contents_col}10")
 | |
|       ->getFont()
 | |
|       ->setBold(true);
 | |
| 
 | |
|   if (!FLATTEN) {
 | |
|     $sheet->getColumnDimension($overall_col)->setVisible(false);
 | |
|     $sheet->getColumnDimension($same_col)->setVisible(false);
 | |
|   }
 | |
| 
 | |
|   if (WRAP_TEXT) {
 | |
|     $sheet->getStyle("{$check_contents_col}11:{$check_contents_col}{$sheet->getHighestDataRow()}")
 | |
|         ->getAlignment()->setWrapText(true);
 | |
|     $sheet->getStyle("E11:E{$sheet->getHighestDataRow()}")
 | |
|         ->getAlignment()->setWrapText(true);
 | |
|   }
 | |
| 
 | |
|   $sheet->setCellValue('C2', $open_cat_1)
 | |
|       ->setCellValue('C3', $open_cat_2)
 | |
|       ->setCellValue('C4', $open_cat_3)
 | |
|       ->setCellValue('C5', $not_a_finding)
 | |
|       ->setCellValue('C6', $not_applicable)
 | |
|       ->setCellValue('C7', $not_reviewed);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Method to split a string into an array (by new line \n) and use array_unique to remove duplicate strings
 | |
|  *
 | |
|  * @param string $str
 | |
|  *
 | |
|  * @return string
 | |
|  */
 | |
| function deduplicateString($str)
 | |
| {
 | |
|     $ret = null;
 | |
|     $ret = str_replace(["\\n", PHP_EOL], "\r", $str);
 | |
|     $ret = array_unique(explode("\r", $ret));
 | |
|     $ret = html_entity_decode(implode("\r", $ret));
 | |
| 
 | |
|     return $ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Method to add a comment to a particular cell
 | |
|  *
 | |
|  * @param PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet
 | |
|  * @param string $cell
 | |
|  * @param string $note
 | |
|  */
 | |
| function add_cell_comment(&$sheet, $cell, $note)
 | |
| {
 | |
|     $sheet->getActiveSheet()
 | |
|         ->getComment($cell)
 | |
|         ->setAuthor(CREATOR);
 | |
|     $commentRichText = $sheet->getActiveSheet()
 | |
|         ->getComment($cell)
 | |
|         ->getText()->createTextRun('Scanner Notes:');
 | |
|     $commentRichText->getFont()->setBold(true);
 | |
|     $sheet->getActiveSheet()
 | |
|         ->getComment($cell)
 | |
|         ->getText()->createTextRun("\r\n");
 | |
|     $sheet->getActiveSheet()
 | |
|         ->getComment($cell)
 | |
|         ->getText()->createTextRun($note);
 | |
| }
 |