public function Track($trackingNumber) { if (preg_match("/^[A-Z0-9]{13}\$/", $trackingNumber) === 0) { throw new RoyalMailException("Not a valid tracking number - does not match required format"); } $doc = new DOMDocument(); $doc->preserveWhiteSpace = FALSE; $doc->loadHTMLFile("https://www.royalmail.com/track-your-item?trackNumber=" . $trackingNumber); $divs = $doc->getElementsByTagName('table'); @($children = $divs->item(0)->childNodes->item(1)); // Targeting first <Table> on page and then second child of that table, i.e. <Tbody> @($trackingStatus = $children->childNodes); // child nodes of the <Tbody>, i.e. the <tr>'s containing table cells for tracking data. $statusArray = array(); // Try to get the product name, e.g. Special Delivery or Recorded. // There's something really funky going on with the white space here so I'm calling a static function removeEmptyNodes() to strip empty DOMText children. $service1 = $doc->getElementById((string) $trackingNumber); // Targeting element with ID of the tracking number. $service2 = RoyalMail::removeEmptyNodes($service1); // Strip empty DOMText children from service1 and save into service2. if ($service2->childNodes->length > 1) { $service3 = RoyalMail::removeEmptyNodes($service2->childNodes->item(0)); // Currently in ".rml-track-trace-result" and descend into first child (".result-column colour-white") } if ($service3->childNodes->length > 1) { $service4 = RoyalMail::removeEmptyNodes($service3->childNodes->item(1)); // Currently in ".result-column colour-white", descend into second child ("p") $serviceType = $service4->childNodes->item(0)->textContent; // Currently in "p", descend into first child (".product strong") and get node value and save it. } foreach ($trackingStatus as $statusLine) { // Each <Tr> is a status update, loop through the <Tr>'s and extract data from the <Td>'s contained within for our output array. $outStatusLine = array(); $outStatusLine['date'] = $statusLine->childNodes->item(0)->textContent; $outStatusLine['time'] = $statusLine->childNodes->item(1)->textContent; $outStatusLine['report'] = $statusLine->childNodes->item(2)->textContent; $outStatusLine['location'] = $statusLine->childNodes->item(3)->textContent; $statusArray[] = $outStatusLine; } // Do a bit of basic error handling, needs improvement. // If the tracking number is not found then the DOM parsing will be targeting a different table on the page and we will just test for that. if (!is_numeric(substr($statusArray[0]['date'], 0, 1))) { throw new RoyalMailException('Unexpected output - may not be a valid tracking number'); } // Now we have the status updates, before we return them, let's make a decision on whether it's been delivered or not: if (substr($statusArray[0]['report'], 0, 9) == "DELIVERED") { $delivered = "True"; } else { $delivered = "False"; } // Now return the output, item 0 in the return array is our delivery decision and item 1 is an array of status updates: return array('rmService' => $serviceType, 'deliveryDecision' => $delivered, 'statusLines' => $statusArray); }
public function getRoyalMailRates($id_zone, $is_cart, $cart, $product_weight, $dest_zip, $dest_state, $dest_country, $currency, $product, $id_product_attribute, $qty, $dest_city) { $rates = array(); if (file_exists(dirname(__FILE__) . '/../../royalmail/classes/RateAvailableServices.php')) { include_once dirname(__FILE__) . '/../../royalmail/royalmail.php'; include_once dirname(__FILE__) . '/../../royalmail/classes/RateAvailableServices.php'; $rm = new RoyalMail(); if ($rm->active) { $handling = Configuration::get('PS_SHIPPING_HANDLING'); $carriers = $rm->getCarriers($id_zone, $cart, $is_cart, $product); foreach ($carriers as $carrier) { if (get_parent_class($rm) == 'PrestoChangeoCarrierModule') { $rm_rate = new RoyalMailRate(); $amount = $rm_rate->getRate($carrier['id_carrier'], $carrier['id_zone'], $is_cart != '' ? $cart->getTotalWeight() : max($product_weight, 0.001), $dest_zip, $dest_state, $dest_country, "", $is_cart != '' ? 0 : $product->getPrice(true, $id_product_attribute, 6, NULL, false, true, $qty), $is_cart != '' ? 0 : $product->id, $is_cart != '' ? 0 : $id_product_attribute, $qty); } else { $amount = getRoyalMailRate($carrier['id_carrier'], $carrier['id_zone'], $is_cart != '' ? $cart->getTotalWeight() : max($product_weight, 0.001), $dest_zip, $dest_country, $is_cart != '' ? 0 : $product->getPrice(true, $id_product_attribute, 6, NULL, false, true, $qty), $is_cart != '' ? 0 : $product->id); } // Add product spercific cost + handling fee if ($amount > 0) { $amount += $this->getExtraShippingCost($carrier, $handling, $is_cart != '' ? $cart->getProducts() : array(), $product, $qty); } // Apply shipping tax if needed if (!Tax::excludeTaxeOption()) { $carrierTax = Tax::getCarrierTaxRate($carrier['id_carrier']); } if (isset($carrierTax) && $amount !== false) { $amount *= 1 + $carrierTax / 100; } $amount = $amount === false ? -1 : Tools::convertPrice($amount, $currency); if ($amount > 0) { $rates[$carrier['name']] = array(Tools::displayPrice($amount, $currency, false), $carrier['id_carrier']); } elseif ($amount !== false && $amount == 0) { $rates[$carrier['name']] = array($ap->l('Free!'), $carrier['id_carrier']); } } } } return $rates; }
#!/usr/bin/php <?php require_once "RoyalMailTracker.php"; if ($_SERVER['argc'] != 2) { echo "Usage: RoyalMailTrack.php TRACKING_NUMBER"; echo "\n"; exit(1); } try { $rm = new RoyalMail(); $tracker = $rm->Track($_SERVER['argv'][1]); // First print the service type echo "Service: " . $tracker['rmService'] . "\n\n"; // First print the delivery decision: if ($tracker['deliveryDecision'] == "True") { echo "This item has been delivered."; } else { echo "This item has not been delivered."; } echo "\n\n"; // Then print the status updates: echo "** Status updates for this item **\n\n"; foreach ($tracker['statusLines'] as $statusUpdate) { echo $statusUpdate['date'] . " " . $statusUpdate['time'] . " - " . $statusUpdate['report'] . " - " . $statusUpdate['location']; echo "\n"; } } catch (Exception $e) { echo $e->getMessage(); } echo "\n";
<?php require_once "RoyalMailTracker.php"; try { $rm = new RoyalMail(); $tracker = $rm->Track($_GET['t']); echo json_encode($tracker); } catch (Exception $e) { $err = array('error' => $e->getMessage()); echo json_encode($err); } echo "\n";