| Server IP : 209.209.40.120 / Your IP : 216.73.217.112 Web Server : Microsoft-IIS/10.0 System : Windows NT NEWWWW 10.0 build 17763 (Windows Server 2019) i586 User : NEWWWW$ ( 0) PHP Version : 8.3.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : C:/HostingSpaces/admin/247sms.com/wwwroot/test/dvsa-test-check-master/inc/ |
Upload File : |
<?php
include 'sendmailclient.php';
/**
* DVSA Test Cancellation Check
*
* @category File
* @package DVSATestCheck
* @author Craig Watson <craig@cwatson.org>
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link https://github.com/craigwatson/dvsa-test-check
*/
/**
* Main function to run the check and parse returned data
*
* @param array $data Personal data to use
* @param string $name Name of person being checked
*
* @return boolean
*/
function runTest($data, $name)
{
global $out_dir;
$json_file = "$out_dir/dvsa_" . $data['licence_number'] . "_dates.json";
$cookie_file = "$out_dir/dvsa_" . $data['licence_number'] . "_cookies.txt";
$available = checkDates($data['licence_number'], $data['application_id'], $cookie_file);
// Error if no dates found
//$available =1;
if (count($available) == 0) {
//logger('No dates found', 'WARN');
logger('No dates found this time', 'WARN');
cookieClean($cookie_file);
return false;
}
$seen = readData($json_file, true);
$new = parseDates($available, $seen, $data['earliest_date'], $data['latest_date'], $data['ideal_day']);
//$new =1;
// Take action if new dates have been seen
if (count($new) > 0) {
if (is_array($data['email_to'])) {
foreach ($data['email_to'] as $address) {
echo "am here";
//die();
sendTestCancellationMail($new, $address, $name);
}
} elseif ($data['email_to'] != '') {
sendTestCancellationMail($new, $data['email_to'], $name);
}
saveData($new, $json_file);
}
return true;
}
/**
* Main function to check licence data and parse returned data
*
* @param array $data The data to use for the check
*
* @return boolean
*/
function runLicenceCheck($data)
{
global $out_dir;
$html = new simple_html_dom();
$login_url = "https://www.viewdrivingrecord.service.gov.uk/driving-record/licence-number";
$cookie_file = "$out_dir/dvsa_" . $data['licence_number'] . "_licence_cookies.txt";
$out_file = "$out_dir/dvsa_" . $data['licence_number'] . "_licence_status.json";
$licence_data = array();
$data_changed = false;
$cookies = array('naturalSubmit' => 'true');
$extract_fields = array('licence-status', 'licence-valid-from', 'licence-valid-to', 'issue-number');
// Make inital request for cookie
$init = pageRequest("$login_url/", $cookie_file, array(), 10);
// Error if we don't get a 200 (can happen if we overstep rate-limiting)
if ($init['http_code'] !== 200) {
logger('Initial page load failed.', 'ERROR');
cookieClean($cookie_file);
return false;
}
// Find the hidden "pesel" form field value
foreach ($html->load($init['html'])->find('input[id=pesel]') as $input) {
$pesel = $input->value;
}
// Set the fields for the form, stripping spaces
$login_fields = array (
'applicantPassportNumber' => '',
'pesel' => $pesel,
'dln' => str_replace(' ', '', $data['licence_number']),
'nino' => str_replace(' ', '', $data['ni_number']),
'postcode' => str_replace(' ', '', $data['postcode']),
'dwpPermission' => '1'
);
// Run the login request
$login = pageRequest($login_url, $cookie_file, $login_fields, 0, $cookies);
// Get licence data
logger('Retrieving licence data');
$dom = $html->load($login['html']);
foreach ($extract_fields as $field) {
foreach ( $dom->find("dd[class=$field-field]") as $dd) {
$licence_data[] = $dd->innertext;
logger("... $field: " . $dd->innertext);
}
}
// Read old data and parse for differences
$old_data = readData($out_file);
if (count($old_data) > 0) {
$c = 0;
foreach ($licence_data as $value) {
if ($value != $old_data[$c]) {
$data_changed = true;
}
$c++;
}
} else {
$data_changed = true;
}
// Send email and store new data if it has changed
if ($data_changed === true) {
logger('License status has changed.');
sendLicenceStatusEmail($old_data, $licence_data, $data['email_to']);
saveData($licence_data, $out_file);
} else {
logger('No action to take.');
}
// Clean cookies
cookieClean($cookie_file);
return true;
}
/**
* Reads data from JSON file and returns an array of key/value pairs
*
* @param string $json_file Filename to read
* @param boolean $format_date Whether to format the log output
*
* @return array
*/
function readData($json_file, $format_date = false)
{
if (is_file($json_file)) {
// Read JSON file for previous data
logger("Reading data from $json_file");
$data = json_decode(file_get_contents($json_file), true);
foreach ($data as $item) {
if ($format_date) {
$output = date('l d F H:i', $item);
} else {
$output = $item;
}
logger("... $output");
}
} else {
// Use new array
$data = array();
}
return $data;
}
/**
* Main function to run the check and parse returned data
*
* @param string $licence_number Licnce Number for student
* @param string $application_id ID of the application to find
* @param string $cookie_file Path to file used for cookies
*
* @return array
*/
function checkDates($licence_number, $application_id, $cookie_file)
{
global $out_dir;
$html = new simple_html_dom();
$site_prefix = 'https://driverpracticaltest.dvsa.gov.uk';
$date_url = '';
$slot_url = '';
$login_error = '';
$csrf_query = array();
$found = array();
$fields = array('username' => $licence_number, 'password' => $application_id);
// Make initial request to get cookie, then log in
$init = pageRequest("$site_prefix/login", $cookie_file);
$login = pageRequest("$site_prefix/login", $cookie_file, $fields);
// Parse login error and return an empty array
foreach ($html->load($login['html'])->find('section[role=alert]') as $error) {
foreach ($error->find('li') as $error_text) {
logger('... Error found when logging in: ' . html_entity_decode($error_text->innertext), 'ERROR');
}
return array();
}
foreach ($html->load($login['html'])->find('div[class=onscreen-help]') as $help) {
if (strpos($help, 'The number of allowed changes to your booking has now been exceeded') !== false) {
logger('The number of allowed changes to your booking has now been exceeded - please contact the DVSA to continue.', 'ERROR');
return array();
}
}
// Get date change URL + CSRF token for future use
foreach ($html->load($login['html'])->find('a[id=date-time-change]') as $link) {
$date_url = htmlspecialchars_decode($link->href);
parse_str(html_entity_decode($date_url), $csrf_query);
}
// Get available date fields
$date_change = pageRequest($site_prefix . $date_url, $cookie_file, $fields);
// Get and load slot picker URL
foreach ($html->load($date_change['html'])->find('form') as $form) {
$slot_url = htmlspecialchars_decode($form->action);
}
// Build array of fields to send
$slot_picker_fields = array(
'csrftoken' => $csrf_query['csrftoken'],
'testChoice' => 'ASAP',
'preferredTestDate' => date('d/m/Y'),
'drivingLicenceSubmit' => 'Continue',
);
$slot_picker = pageRequest($site_prefix . $slot_url, $cookie_file, $slot_picker_fields, 2, array(), false);
// Get available slots
foreach ($html->load($slot_picker['html'])->find('input[class=SlotPicker-slot]') as $slot) {
$found[] = ($slot->value/1000);
}
// Remove cookie jar file
cookieClean($cookie_file);
return $found;
}
/**
* Diff two arrays of dates, return new ones
*
* @param array $available Available dates
* @param array $seen Seen dates
* @param datetime $earliest_date Earliest date to treat as 'new'
* @param datetime $latest_date Latest date to treat as 'new'
* @param string $ideal_day Day of the week to treat as 'ideal'
*
* @return array
*/
function parseDates($available, $seen, $earliest_date, $latest_date, $ideal_day)
{
$new = array();
logger('Parsing ' . count($available) . ' available dates and ' . count($seen) . ' new dates');
foreach ($available as $date) {
if ($date > strtotime($latest_date)) {
$class = 'LATE';
} elseif ($date < strtotime($earliest_date)) {
$class = 'EARLY';
} elseif (strcmp(date("l", $date), $ideal_day) == 0) {
$class = 'IDEAL';
$new[] = $date;
} elseif (array_search($date, $seen) !== false) {
$class = 'SEEN';
} else {
$class = 'NEW';
$new[] = $date;
}
logger("... [$class] " . date('l d F H:i', $date));
}
return $new;
}
/**
* Makes a page request with CURL
*
* @param string $url URL to request
* @param string $cookie_jar File to use for cookies
* @param array $post Array of values to use for HTTP POST request
* @param integer $sleep The number of seconds to sleep/pause *after* the request
* @param string $cookies Array of cookies to set in-line
* @param boolean $verbose Latest date to treat as 'new'
*
* @return array
*/
function pageRequest($url, $cookie_jar = '', $post = array(), $sleep = 2, $cookies = array(), $verbose = false)
{
global $proxy;
global $user_agent;
// Setup request
logger("Requesting $url");
$ch = curl_init();
$fields = '';
$capcha = false;
// Set curl options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_MAXREDIRS, 2);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, false);
if ($verbose) {
curl_setopt($ch, CURLOPT_VERBOSE, 1);
}
if ($proxy['host'] != '') {
logger('... Using proxy: http://' . $proxy['host']);
curl_setopt($ch, CURLOPT_PROXY, $proxy['host']);
if ($proxy['auth'] != '') {
logger('... Using proxy auth');
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxy['auth']);
}
}
if (count($cookies) > 0) {
$cookie_string = '';
foreach ($cookies as $key => $val) {
logger("... Setting cookie: $key=$val");
$cookie_string .= " $key=\"$val\";";
}
curl_setopt($ch, CURLOPT_COOKIE, $cookie_string);
}
// Submit POST fields
if (count($post) > 0) {
curl_setopt($ch, CURLOPT_POST, true);
foreach ($post as $key => $value) {
logger("... Sending $key: '".urlEncode($value)."'");
$fields .= $key.'='.urlEncode($value).'&';
}
$fields = rtrim($fields, '&');
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
}
// Execute + extract data to array
$curl_output = curl_exec($ch);
$out['headers'] = explode("\n", substr($curl_output, 0, curl_getinfo($ch, CURLINFO_HEADER_SIZE)));
$out['html'] = substr($curl_output, curl_getinfo($ch, CURLINFO_HEADER_SIZE));
$out['http_code'] = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$out['last_url'] = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
curl_close($ch);
// Log return code
logger('... Got HTTP ' . $out['http_code']);
// Verbose print
if ($verbose) {
print_r($out);
}
// Sleep
if ($sleep > 0) {
logger("... Sleeping for $sleep seconds");
sleep($sleep);
}
// Check for captcha
$dom = new simple_html_dom();
foreach ($dom->load($out['html'])->find('div[id=recaptcha-check]') as $div) {
$capcha = true;
}
if ($capcha) {
cookieClean($cookie_jar);
logger('... Capcha present. Removing cookies.', 'ERROR');
}
// Return
return $out;
}
/**
* Sends email for test cancellations
*
* @param array $dates Available dates
* @param string $email_to Email address
* @param string $name Person's name to include
*
* @return void
*/
function sendTestCancellationMail($dates, $email_to, $name)
{
echo "****************";
global $email_subject;
global $email_from;
$mail_text = 'This email has been sent from DVSA Practical Test software running on ' . gethostname() . ".\n";
$mail_text .= "\nThe software has found the following dates for $name that match your search:\n";
foreach ($dates as $date) {
$mail_text .= date('l d F, H:i', $date) . "\n";
}
$mail_text .= "\nPlease check the DVSA website as soon as possible to see if this slot is still available.\n";
$mfrom ="noreply@247sms.com";
$mfromname=" Support 247sms.com";
$mymail = sendmailtoclient($email_to,$mail_text,$mail_text,$email_subject,$mfrom,$mfromname);
//mail($email_to, $email_subject, $mail_text, "From: $email_from\r\n");
logger("Email sent to $email_to");
}
/**
* Sends email for licence status changes
*
* @param array $old_data Previous licence data
* @param array $new_data New licence data
* @param string $email_to Email address
*
* @return void
*/
function sendLicenceStatusEmail($old_data, $new_data, $email_to)
{
global $email_subject;
global $email_from;
$mail_text = 'This email has been sent from DVLA Licence software running on ' . gethostname() . ".\n";
$mail_text .= "\nThe sofware has found that your licence data has changed:\n\n";
$c = 0;
foreach ($new_data as $value) {
$mail_text .= "$value";
if (array_key_exists($c, $old_data)) {
$mail_text .= " (was: '" . $old_data[$c] . "')";
}
$mail_text .= "\n";
$c++;
}
$mfrom ="noreply@247sms.com";
$mfromname=" Support 247sms.com";
$mymail = sendmailtoclient($email_to,$mail_text,$mail_text,$email_subject,$mfrom,$mfromname);
//mail($email_to, $email_subject, $mail_text, "From: $email_from\r\n");
logger("Email sent to $email_to");
}
/**
* Saves data to file
*
* @param array $data Data to save
* @param string $file File name to write to
*
* @return void
*/
function saveData($data, $file)
{
file_put_contents($file, json_encode($data));
logger("Data saved to $file");
}
/**
* Diff two arrays of dates, return new ones
*
* @param string $message Message to log
* @param string $level Log level
*
* @return void
*/
function logger($message, $level = 'INFO')
{
echo date('Y-m-d H:i:s') . " -- $level : $message\n";
}
/**
* Removed a file, but only if it exists
*
* @param string $file Filename to remove
*
* @return void
*/
function cookieClean($file)
{
if (is_file($file)) {
logger("Clearing cookies from $file");
unlink($file);
}
}
?>