Dec 112014
 

I’ve had to calculate working time between 2 dates as part of a dashboarding project.
As a result, I’ve built a function to do this for me.

First though I needed the public holidays to make sure that public holidays weren’t counted.
As an example, I’ve only used a couple of days, formatted like ’24-04′.
I’ve stored this in an external php file called hols.php, however this can also be contained within the script.


Then for the main function. This takes 2 dateTime objects to compare. If the start is after the end, then it will return 0.


function work_minutes($dtStart,$dtEnd) {
if($dtStart > $dtEnd) {
return 0;
}
include('hols.php');

$di1Day = new DateInterval('P1D');
$workStartHour = 7; // When the work day starts
$workEndHour = 17; // When the work day ends
$workMinutes = 0; // Initialise the running counter that keeps tracks of the minutes of working time

$diffDays = $dtStart->diff($dtEnd)->format("%a"); // Get the number of days between the 2 timestamps, and add a day to ensure that all the days are checked.

for($x = 0; $x <= $diffDays+1; $x++) { if($dtStart->format('N') < 6) { // checks that it's on a monday-friday if(!in_array($dtStart->format('d-m'),$hols)) { // checks that it's not a public holiday

// Create a couple of new DateTime objects to define the start and end of
// the working day. These will be used to compare against when looping
// through each day to calculate the working minutes.

$dtStartOfDay = new DateTime($dtStart->format('Y-m-d').' '.$workStartHour.':00:00');
$dtEndOfDay = new DateTime($dtStart->format('Y-m-d').' '.$workEndHour.':00:00');
$signStart = '';
$signEnd = '';

// Compare the start of the day, if the starting DateTime Object is before the start of the working day, then the script will calculate the working time from
// the start of the day rather than the starting DateTime Object as any time before the start of the working day is irrelevant.
// The end DateTime objects are compared in a similar way. If the end DateTime object is before the end of the working day, that is used to compare, otherwise
// the end of the day is used to compare.

if($dtStartOfDay >= $dtStart) {
if($dtEndOfDay <= $dtEnd){ $arrDiff = explode(' ',$dtStartOfDay->diff($dtEndOfDay)->format('%H %i));
$signStart = $dtStartOfDay->diff($dtEndOfDay)->format('%R');
} else {
$arrDiff = explode(' ',$dtStartOfDay->diff($dtEnd)->format('%H %i));
$signStart = $dtStartOfDay->diff($dtEnd)->format('%R');
}

// When the starting DateTime object provided is after the start of the working day, then that will be used to calculate working minutes.
} else {
if($dtEndOfDay <= $dtEnd){ $arrDiff = explode(' ',$dtStart->diff($dtEndOfDay)->format('%H %i));
$signEnd = $dtStart->diff($dtEndOfDay)->format('%R');
} else {
$arrDiff = explode(' ',$dtStart->diff($dtEnd)->format('%H %i));
$signEnd = $dtStart->diff($dtEnd)->format('%R');
}
}

// intDiff contains the amount of minutes that was calculated as the amount of time between the start DateTime/Start of the day and end DateTime/End of the day.
$intDiff = $arrDiff[0]*60+$arrDiff[1];
// if theres any negative values, e.g. Starting DateTime stamp was after the end DateTime, the value is ignored, otherwise it adds to the running tally.
if($signStart != '-' && $signEnd != '-') {
$workMinutes += $intDiff;
}
}
}
// Add a day, and loop again.
$dtStart->add($di1Day);
$dtStart->setTime($workStartHour,0);
}

return $workMinutes;
}

Share
Jun 272013
 

I’ve been building a “Stats Grabber” for one of the managers at work. The ServiceNow instance that I’m using only has the XML interface enabled at the moment so I’ll be using that.

This will just be a quick overview of what I’ve used to build this, won’t go into the details too much as each configuration will differ.
The stats that I needed were to be sorted by day, so I’ve defined a function that will return an array that each day will have.
I’ve cut down what I actually had but this gives you a good example.

function CreateArray() {
return array(
"req"=>"0",
"inc"=>"0",
"incMajor"=>"0",
"contacttypePhone"=>"0",
"contacttypeEmail"=>"0",
"contacttypeOther"=>"0",
"contacttypeAuto"=>"0",
"totalTickets"=>"0",
"reqResolved"=>"0",
"incResolved"=>"0",
"totalReqInc"=>"0",
"reqResBySD"=>"0",
"incResBySD"=>"0",
"totalResBySD"=>"0"
);
}

Next up is defining the URLs that are used to retrieve data.
The $instance variable will need to be defined.

// Request Queries
$requrl = "https://".$instance.".service-now.com/u_request_list.do?XML&sysparm_query=u_requestor!%3D9faaf5b90a0a7813005cc0d4347713bc%5Esys_created_onONDateRange%40javascript%3Ags.dateGenerate('".$_POST['startdate']."'%2C'start')%40javascript%3Ags.dateGenerate('".$_POST['enddate']."'%2C'end')";
$resolvedrequrl = "https://".$instance.".service-now.com/u_request_list.do?XML&sysparm_query=u_requestor!%3D9faaf5b90a0a7813005cc0d4347713bc%5Eu_resolvedONDateRange%40javascript%3Ags.dateGenerate('".$_POST['startdate']."'%2C'start')%40javascript%3Ags.dateGenerate('".$_POST['enddate']."'%2C'end')";

// Incident Queries
$incurl = "https://".$instance.".service-now.com/incident_list.do?XML&sysparm_query=sys_created_onONDateRange%40javascript%3Ags.dateGenerate('".$_POST['startdate']."'%2C'start')%40javascript%3Ags.dateGenerate('".$_POST['enddate']."'%2C'end')";
$resolvedincurl = "https://".$instance.".service-now.com/incident_list.do?XML&sysparm_query=u_resolvedONDateRange%40javascript%3Ags.dateGenerate('".$_POST['startdate']."'%2C'start')%40javascript%3Ags.dateGenerate('".$_POST['enddate']."'%2C'end')";

You may also notice the $_POST variables in the url, these will need to be passed to this script in the YYYY-MM-DD format. These will also be used later to construct the array for the days.

I’ve used CURL to retrieve the data, but there are a few different ways to do this
This snippet will create the $ch handle;

$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, $un .":". $pw);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

Next we’ll start getting the data.


// Get Requsts
curl_setopt($ch, CURLOPT_URL, $requrl);
$reqreturn = curl_exec($ch);

// Get Incidents
curl_setopt($ch, CURLOPT_URL, $incurl);
$increturn = curl_exec($ch);

// Get Resolved Requests
curl_setopt($ch, CURLOPT_URL, $resolvedrequrl);
$resreqreturn = curl_exec($ch);

// Get Resolved Incidents
curl_setopt($ch, CURLOPT_URL, $resolvedincurl);
$resincreturn = curl_exec($ch);

curl_close($ch);
// Curl End

I haven’t put in any error capturing but that is something that should be there to catch any errors when trying to retrieve the data.

Now to create the array that will contain all of our data.
As I wanted the data sorted by days, I’ve used a for loop with the start and end dates to create the array.

$DateArray = array();
if(isset($_POST['startdate']) && isset($_POST['enddate'])) {
$start = new DateTime($_POST['startdate']);
$end = new DateTime($_POST['enddate']);
$diff = $start->diff($end)->format("%a");
for($x = 0; $x < $diff+1; $x++) { $datestamp = date("Y-m-d",strtotime("+$x days",strtotime($start->format("Y-m-d"))));
$DateArray[$datestamp] = CreateArray();
}
}

Now we’ll start processing the data.
I’ll only post one of the four blocks for brevity as they’re esssentially the same with minor differences when it comes down to the data.
SimpleXML is used here to parse the xml output of ServiceNow

// Load Incidents XML
$xml = simplexml_load_string($increturn);
// Get Total Incidents
$incTotal = $xml->incident->count();
// Parse incidents for date
foreach($xml->incident as $item) {
$datestamp = date("Y-m-d",strtotime("+8 hours",strtotime($item->opened_at)));
$DateArray[$datestamp]["inc"]++;
$DateArray[$datestamp]["totalTickets"]++;
if($item->priority < 3) { $DateArray[$datestamp]["incMajor"]++; $totalMajorInc++; } switch($item->contact_type) {
case "Email":
$DateArray[$datestamp]["contacttypeEmail"]++;
break;
case "phone":
$DateArray[$datestamp]["contacttypePhone"]++;
break;
case "Auto Monitoring":
$DateArray[$datestamp]["contacttypeAuto"]++;
break;
default:
$DateArray[$datestamp]["contacttypeOther"]++;
break;
}
}

Once all four of those blocks have been executed, you now have the data all in a nice array.
You can then use a foreach loop on the DateArray array to get your data out

Share
Feb 062013
 

After some experimentation with the RaspAP, I decided to write up a simple web interface for it so that when hostapd started broadcasting, I could use a simple web page rather than ssh to control the wifi and hostapd on the Raspberry Pi. The distribution I used was Raspbian Server Edition once again.

I started off by installing lighttpd and php5

apt-get install lighttpd php5-cgi

After that, I enabled php for lighttpd and restarted it for the settings to take effect.

sudo lighty-enable-mod fastcgi-php
/etc/init.d/lighttpd restart

Now, comes the fun part.
For security reasons, the www-data user which lighttpd runs under is not allowed to start or stop daemons, or run commands like ifdown and ifup, all of which I wanted my page to do.
So what I have done, is added the www-data user to the sudoers file, but with restrictions on what commands the user can run.
The line appears in /etc/sudoers like this –

www-data ALL=(ALL) NOPASSWD:/sbin/ifdown wlan0,/sbin/ifup wlan0,/bin/cat /etc/wpa_supplicant/wpa_supplicant.conf,/bin/cp /tmp/wifidata /etc/wpa_supplicant/wpa_supplicant.conf,/sbin/wpa_cli scan_results,/sbin/wpa_cli scan,/bin/cp /tmp/hostapddata /etc/hostapd/hostapd.conf,/etc/init.d/hostapd start,/etc/init.d/hostapd stop,/etc/init.d/dnsmasq start,/etc/init.d/dnsmasq stop,/bin/cp /tmp/dhcpddata /etc/dnsmasq.conf

Notice I’ve restricted the www-data user to only be able to run the exact commands in the sudoers file
This means that the www-data can only take down, bring up, and show the configuration of wlan0 for example.

After the sudoers file has been modified, the script can now do what it needs to do.
I have a very very rough version written up so far, but it’s not available to download yet.

Here are some screenshots of what it’ll be able to do though ! 🙂

WiFi Information screen
infowifi

WiFI Client connection screen
configwifi

WiFi Hotspot setup screen
confighostapd

I’m in the process of prettying up the GUI but in the meantime, this is functional enough 🙂
I’ll get the demo up and running soon enough too ! 🙂

**Update**
I have released the PHP files for this – Please check this post for details.

Share
Jun 112012
 

I have started work on a PHP/mySQL Project which allows for simple uploading of files through a HTML form, and allows for downloads via a file listing.

Currently the features are :
Quotas per user
File upload via PHP form
File download via HTML page

It is not yet complete, but very simple and easy to setup.
Files are stored on the filesystem rather than in the database.

If this would be of use to anyone, please let me know and I can release it out into the wild.

Share