I'm currently working on a project, where i have to get the status of a packet (sent with DHL). I read about the DHL API, which return an XML, but somehow there are no good examples out there. I have found some code snippets, but i have no clue where to register for API Key's.
Have anyone some links or examples for me?
Best regards,
Lukas
There is also this PHP client that can be used to consume the DHL XML API. It can handle all the different services exposed by DHL.
https://github.com/alfallouji/DHL-API
This client does not rely or depend on any framework and it should be fairly easy to integrate with your own code. You can check the samples folder for example on how to use it.
https://github.com/jklz/DHL-API-Tracking-PHP
It is used to connect into DHL using the XML-PI to track shipments using the Air Way Bill. it can handle a single tracking number or as many as you feed into it (has been tested with 250 and other then taking a little time to run had no problems). automatically takes and breaks the array of tracking numbers into chunks and then sends the request to DHL making sure not to pass the max number that can be tracked per request then returns the results as a array.
Quick and dirty without any third party lib and using official API:
<?php
$mode = 'sandbox'; // sandbox or production
$username = ''; // dhl developer account name, not email
$password = ''; // dhl developer account pass
$appname = 'zt12345'; // sandbox app
$apppass = 'geheim'; // sandbox app
$endpoint = 'https://cig.dhl.de/services/' . $mode . '/rest/sendungsverfolgung';
$payload = simplexml_load_string( '<?xml version="1.0" encoding="UTF-8" standalone="no"?><data appname="' . $appname . '" language-code="de" password="' . $apppass . '" piece-code="" request="d-get-piece-detail"/>' );
$shipmentids = array(
'00340434161094015902' // in sandbox only special numbers are allowed
);
$opts = array(
'http' => array(
'method' => "GET",
'header' => "Authorization: Basic " . base64_encode( "$username:$password" )
)
);
$context = stream_context_create( $opts );
foreach ( $shipmentids as $shipmentid ) {
$payload->attributes()->{'piece-code'} = $shipmentid;
$response = file_get_contents( $endpoint . '?' . http_build_query( array( 'xml' => $payload->saveXML() ) ), false, $context );
$responseXml = simplexml_load_string( $response );
$status = null;
// get last state
foreach ( $responseXml->data->data->data as $event ) {
$status = $event->attributes()->{'event-short-status'};
}
echo "Shipment " . $shipmentid . " is in state: " . $status . "\n";
}
There is a nice blog about this. It is unfortunately in German, but the code that is displayed there should still make sense to you.
Source: https://blog.simlau.net/dhl-tracking-api-php.html
Excerpt:
function dhl_tracking($trackingnumber)
{
$data = '<?xml version="1.0" encoding="ISO-8859-1" ?>';
$data .= '<data appname="nol-public" password="anfang" request="get-status-for-public-user" language-code="de">';
$data .= ' <data piece-code="'.$trackingnumber.'"></data>';
$data .= '</data>';
// URL bauen und File hohlen
$xml = simplexml_load_file(sprintf(
'http://nolp.dhl.de/nextt-online-public/direct/nexttjlibpublicservlet?xml=%s', $data
));
// FALSE, wenn Syntax oder HTTP Error
if ($xml === false) return false;
// Wandelt das SimpleXML Objekt in ein Array um
foreach ($xml->data->data->attributes() as $key => $value) {
$return[$key] = (string) $value;
}
return $return;
}
// Aufruf der Funktion
print_r(dhl_tracking($tracking_number));
This function will give back an array that will contain some tracking information:
Array
(
[status] => Die Sendung wurde erfolgreich zugestellt.
[recipient-id-text] => Nachbar
[product-name] => DHL PAKET
[pan-recipient-name] => SIMON LAUGER
)
(In fact, there is WAY more data in there.)
I hope this will help you in some way.
Related
I am trying to validate EU VAT numbers using the script by Eugene Mihailescu that can be found here:
https://stackoverflow.com/a/29955950
Although this script was working flawlessly up until a recently, now Apache comes up with the following error:
PHP Warning: file_get_contents(http://ec.europa.eu/taxation_customs/vies/services/checkVatService): failed to open stream: HTTP request failed! HTTP/1.1 500 Internal Server Error
I searched and found a cUrl version of the same script by Professor Abronsius which can be found here:
https://stackoverflow.com/a/56035880
Unfortunately a similar error comes up in the console:
Object { response: false, info: {…}, errors: "The requested URL returned error: 500 Internal Server Error" } errors: "The requested URL returned error: 500 Internal Server Error" info: Object { url: "https://ec.europa.eu/taxation_customs/vies/services/checkVatService", http_code: 500, header_size: 0, … } …….
To my understanding the problem may rely in the "VIES" server itself, but there are no announcements in their website:
https://ec.europa.eu/taxation_customs/vies/#/vat-validation
Any ideas/suggestions?
Thanks to MexicanGuy for your solution, it was really useful in fixing the problem. In regard to the original question and the code used from :
https://github.com/lepoco/vies-api/blob/master/veis-api.php
by Eugene Mihailescu
It can be fixed by removing : "SOAPAction: checkVatService" from the end of the header line.
After this it returns XML content, however it is slightly different than before as it includes the XML namespace "NS2" on the relevant nodes. Adjusting the regex to the following can fix it.
$pattern = '/ns2:(%s).*?([\s\S]*)</ns2:\1/';
Then it started working again for us.
However we came to the conclusion that the solution isn't optimal in that it uses a regex to read XML data. There are bespoke XML readers and indeed SOAP extensions in PHP that can be used. There is also a potential library that seems perhaps more robust to future changes :
https://github.com/DragonBe/vies
Which we are thinking is a superior long term solution.
Ran into the same problem, searched a little bit, and it seems that soap envelope as changed.
Made some changes and included some functions to maintain previous workflow.
Hope it helps
DEFINE ( 'VIES_URL', 'http://ec.europa.eu/taxation_customs/vies/services/checkVatService' );
/**
* VIES VAT number validation
*
* #author Eugen Mihailescu
*
* #param string $countryCode
* #param string $vatNumber
* #param int $timeout
*/
function array_key_replace($item, $replace_with, array $array){
$updated_array = [];
foreach ($array as $key => $value) {
if (!is_array($value) && $key == $item) {
$updated_array = array_merge($updated_array, [$replace_with => $value]);
continue;
}
$updated_array = array_merge($updated_array, [$key => $value]);
}
return $updated_array;
}
function string_between_two_string($str, $starting_word, $ending_word)
{
$subtring_start = strpos($str, $starting_word);
//Adding the starting index of the starting word to
//its length would give its ending index
$subtring_start += strlen($starting_word);
//Length of our required sub string
$size = strpos($str, $ending_word) - $subtring_start;
// Return the substring from the index substring_start of length size
return substr($str, $subtring_start, $size);
}
function viesCheckVAT($countryCode, $vatNumber, $timeout = 30) {
$response = array ();
$pattern = '/<(%s).*?>([\s\S]*)<\/\1/';
$keys = array (
'countryCode',
'vatNumber',
'requestDate',
'valid',
'name',
'address'
);
//Changed envelope
$content = "<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'
xmlns:tns1='urn:ec.europa.eu:taxud:vies:services:checkVat:types'
xmlns:impl='urn:ec.europa.eu:taxud:vies:services:checkVat'>
<soap:Header>
</soap:Header>
<soap:Body>
<tns1:checkVat xmlns:tns1='urn:ec.europa.eu:taxud:vies:services:checkVat:types'
xmlns='urn:ec.europa.eu:taxud:vies:services:checkVat:types'>
<tns1:countryCode>".$countryCode."</tns1:countryCode>
<tns1:vatNumber>".$vatNumber."</tns1:vatNumber>
</tns1:checkVat>
</soap:Body>
</soap:Envelope>";
$opts = array (
'http' => array (
'method' => 'POST',
'header' => "Content-Type: text/xml; charset=utf-8;",
'content' => sprintf ( $content ),
'timeout' => $timeout
)
);
$ctx = stream_context_create ( $opts );
$result = file_get_contents ( 'https://ec.europa.eu/taxation_customs/vies/services/checkVatService', false, $ctx );
//extract necessary values from answer string
$valid = string_between_two_string($result, '<ns2:valid>', '</ns2:valid>');
$country = string_between_two_string($result, '<ns2:countryCode>', '</ns2:countryCode>');
$vatnumber = string_between_two_string($result, '<ns2:vatNumber>', '</ns2:vatNumber>');
$address = string_between_two_string($result, '<ns2:address>', '</ns2:address>');
$name = string_between_two_string($result, '<ns2:name>', '</ns2:name>');
$dater = string_between_two_string($result, '<ns2:requestDate>', '</ns2:requestDate>');
//insert strings in array and replace index keys by name
$vat = "$country$vatnumber";
$vars = array($vat, $name, $address, $dater, $valid);
$new_array = array_key_replace('0', 'vat', $vars);
$new_array = array_key_replace('0', 'name', $new_array);
$new_array = array_key_replace('0', 'address', $new_array);
$new_array = array_key_replace('0', 'requestDate', $new_array);
$new_array = array_key_replace('0', 'status', $new_array);
return $new_array;
}
print_r (viesCheckVAT ( 'RO', '19386256' ));
Run into the same problem today. Try changing the Content-Type in the Header to text/xml. That's what solved the problem for us in Postman.
Run into the same problem today.
Thanks to EmeseMora for the solution...
I change the Content-Type in the Header to text/xml.
In this way the problem is solved in Postman.
But in my old C++ code I cannot solve.
I try in this way:
LPCWSTR header=L"Content-type: text/xml";
SIZE_T len = lstrlenW(header);
WinHttpAddRequestHeaders (hRequest,header,DWORD(len), WINHTTP_ADDREQ_FLAG_REPLACE);
I wrote this piece of script to get the conversion rates from Yahoo API . What it does is I have a config file which has currency details I have to make an array of rates of all the currency present in the config here is my script .
Please review it and let me know if there is a better way to do this .
$cur = $this->parent->parent->config->conversionCurrencies;
//$cur=array(11=>'USD/CRC');
foreach($cur as $key=>$val){
$get_cur = str_replace("/","",$val);echo "<br>";
$code=file_get_contents('http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22'.$get_cur.'%22)&format=json&env=store://datatables.org/alltableswithkeys&callback=');
var_dump($array1 = json_decode($code, true));
$rates_array = array();
$myaskRate = $array1['query']['results']['rate']['Ask'];
$mybidRate = $array1['query']['results']['rate']['Bid'];
$rates_array[$key] = round(($myaskRate+$mybidRate)/2,2);
}
var_dump( $rates_array);
I look for an example of PHP code to retrieve the text of a note on the Evernote server.
So far, I only found trivial examples listing the notebooks, and helping to get authenticated. But all the references are for Java and not for PHP, and nothing lists the notes self.
I understand I have to use the function findNotesMetaData but I don't understand what to specify as fourth argument.
I need some help to get further. I don't know enough Java to understand the equivalent statement in PHP. Thanks in advance.
Pierre
You can't get note contents with findNotesMetaData. Here's simple code snippet for getting notes (also refer to the sample on github to know how to get token with OAuth).
use EDAM\NoteStore\NoteFilter;
use Evernote\Client;
$client = new Client(array(
'token' => $accessToken,
'sandbox' => true
));
$filter = new NoteFilter();
$filter->words = "Evernote";
$notes = $client->getNoteStore()->findNotes($filter, 0, 10);
You can see more details about searching notes here.
On github there is PHP Evernote API SDK
https://github.com/evernote/evernote-sdk-php
Not PHP, but the perl answer for this is as follows:
use strict;
use Net::Evernote::Simple;
my $evernote = Net::Evernote::Simple->new(
# Obtain a developer token from Evernote and put it here
dev_token => 'YOUR DEV TOKEN HERE',
);
warn "Evernote API version out of date!\n" if( ! $evernote->version_check() ); # check if our client API version still works
my $note_store = $evernote->note_store() or die "getting notestore failed: $#";
my $notebooks = $note_store->listNotebooks( $evernote->dev_token() ) or die "oops:$!"; # retrieve all of our notebooks. See https://dev.evernote.com/doc/reference/ for other things you can do.
for my $notebook ( #$notebooks ) {
print "evernote->note_store->listNotebooks: " . $notebook->guid() . "\t" . $notebook->name(), "\n";
$arg{'guid'}=$notebook->guid() if($notebook->name() eq 'Some Notebook Name');
}
my $tags = $note_store->listTags( $evernote->dev_token() ) or die "oops:$!";
for my $s ( #$tags ) {
print "evernote->note_store->listTags: " . $s->guid() . "\t" . $s->name(), "\n";
}
use Data::Dumper; print Data::Dumper->Dump([ $notebooks ],['$notebooks']);
my $srch = Net::Evernote::Simple::EDAMNoteStore::NoteFilter->new() or die "oops:$!";
$srch->notebookGuid( $arg{'guid'} ) or warn "hmm: $!";
# $srch->inactive( 1 ); # set this to go through the trash
print Data::Dumper->Dump([ $srch ],['$srch']);
my $res=Net::Evernote::Simple::EDAMNoteStore::NotesMetadataResultSpec->new();
# $authenticationToken, $filter, $offset, $maxNotes, $resultSpec);
my $sr = $note_store->findNotesMetadata( $evernote->dev_token(), $srch, 0, 99999, $res) or die "oops:$!";
print Data::Dumper->Dump([ $res ],['$res']);
print Data::Dumper->Dump([ $sr ],['$sr']);
#($authenticationToken, $guid, $withContent, $withResourcesData, $withResourcesRecognition, $withResourcesAlternateData);
my $note = $note_store->getNote( $evernote->dev_token(), 'some_note_GUID_here', 1, 1, 1, 1) or die "oops:$!";
print Data::Dumper->Dump([ $note ],['$note']);
my $tags = $note_store->listTags( $evernote->dev_token() ) or die "oops:$!";
print Data::Dumper->Dump([ $tags ],['$tags']);
I am trying to work with the PHP API for Amazon's Flexible Payments.
Here is my PHP snippet to send a payment request:
<?php
$string_to_sign = 'GET
authorize.payments-sandbox.amazon.com
/cobranded-ui/actions/start
SignatureMethod=HmacSHA256&SignatureVersion=2&callerKey=my_access_key&callerReference=YourCallerReference&paymentReason=donation&pipelineName=SingleUse&returnUrl=http%3A%2F%2Fproblemio.com&transactionAmount=4.0';
$encoded_string_to_sign = URLEncode(Base64_Encode(hash_hmac('sha256', $string_to_sign, 'my_secret_key')));
$amazon_request_sandbox = 'https://authorize.payments-sandbox.amazon.com/cobranded-ui/actions/start?SignatureVersion=2&returnUrl='.$return_url.'&paymentReason='.$payment_reason.'&callerReference=YourCallerReference&callerKey='.$my_access_key_id.'&transactionAmount=4.0&pipelineName=SingleUse&SignatureMethod=HmacSHA256&Signature='.$encoded_string_to_sign;
// When it goes to the url, it gets the invalid signature error
header('Location: '.$amazon_request_sandbox);
?>
This seems to be following their instructions, but I can't get past that error.
Thanks!!
<?php
$method = 'GET';
$host = 'authorize.payments-sandbox.amazon.com';
$path = '/cobranded-ui/actions/start';
$params = array(
'signatureMethod' => 'HmacSHA256',
'signatureVersion' => '2',
'currencyCode' => 'USD',
'callerKey' => 'Your_Key_ID',
'callerReference' => 'YourCallerReference',
'paymentReason' => 'donation',
'pipelineName' => 'SingleUse',
'returnUrl' => 'http://yourcallback.com',
'transactionAmount'=> '5',
'version' => '2009-01-09',
);
$params = array_map('rawurlencode', $params);
$paramStringArray = array();
foreach($params as $key => $value){
$paramStringArray[] = $key . '=' . $value;
}
$paramString = implode('&', $paramStringArray);
$string_to_sign = $method . "\n"
. $host . "\n"
. $path . "\n"
. $paramString;
$signature = base64_encode(hash_hmac(
'sha256',
$string_to_sign,
'Your_Super_Secret_Key',
true
));
$amazon_request_sandbox = "https://{$host}{$path}?" . $paramString .
'&signature=' . rawurlencode($signature);
header('Location: '.$amazon_request_sandbox);
?>
Okay... using the structure from the code below, I've finally figured this whole thing out via the code above. There are three things of note to keep track of while forming your signature/URL...
It seems that the parameter "transactionAmount" is necessary for a valid Co-branded UI Pipeline, even though there's no specific instruction alluding to the issue.
If any of your parameters have/had spaces in them, and you tried to use html_build_query() in all but the latest (5.4) version of PHP, you would be given an encoding scheme that featured "+" marks for spaces instead of "%20" which is what Amazon appears to like. My code above takes care of that by implementing rawurlencode() on the entire parameter array.
The ordering of the parameters is paramount in the construction of the signature. The keys (not the values) need to be in case-insensitive alphabetical order. It's also worth noting that despite what the documentation says for the API, both the ampersands (&) and the equals (=) must be present in the creation of the query string for the signature.
Ex:
Query String for Signature: callerKey=1111111111111¤cyCode=USD&signatureVersion=2
Some Other Things I Noticed...
In the sample code included with the PHP SDK (2010-8-28), the "paymentReason" attribute in the file "CBUISingleUsePipelineSample.php" is listed as "HarryPotter 1-5 DVD set". Since this attribute has spaces in it, it throws that ever-annoying "invalid signature" error when you try to visit the generated link because html_build_query() is used to generate the query string for the URL. To fix this issue, open up "CBUIPipeline.php", and look for the following line in the constructUrl() method...
$queryString = http_build_query($parameters, '', '&');
replace it with:
$queryString = str_replace('+', '%20', http_build_query($parameters, '', '&'));
That'll solve the space-encoding problem for older versions of PHP (< 5.4). With the latest version, there's an "enc_type" flag you can set.
Last things Last...
This is my first post on StackOverflow so don't kill me if I broke protocol. Hope it helps!
Try this piece of code:
<?php
$method = 'GET';
$host = 'authorize.payments-sandbox.amazon.com';
$path = '/cobranded-ui/actions/start';
$params = array(
'SignatureMethod' => 'HmacSHA256'
'SignatureVersion' => 2,
'callerKey' => 'my_access_key',
'callerReference' => 'YourCallerReference',
'paymentReason' => 'donation',
'pipelineName' => 'SingleUse',
'returnUrl' => 'http://problemio.com&transactionAmount=4.0',
);
$string_to_sign = $method . "\n"
. $host . "\n"
. $path . "\n"
. http_build_query($params);
$signature = base64_encode(hash_hmac(
'sha256',
$string_to_sign,
'my_secret_key'
));
$params['Signature'] = $signature;
$amazon_request_sandbox = "https://{$host}{$path}?" . http_build_query($params);
header('Location: ' . $amazon_request_sandbox);
So I made a few changes:
PHP's http_build_query() to build the query string (ensure correct encoding)
trying to re-use your vars vs. duplicating the efforts (makes it easier to spot mistakes, etc.)
explicit \n - maybe your editor entered \r or \r\n
HTH
I'm building a little backoffice for my site and I want to display the webmaster tools data within it, I cannot for the life of me figure this out!
Does anyone have any PHP examples of pulling data from webmaster tools using the API with PHP, I'm not getting the documentation and have found a php class that looks like it no longer works, but is there a working one already out there?
If I had an example to start with I think I could figure out the rest, I have been googling this for a couple of days now and have not had any success.
If I could just pull a list of sites belonging to my account that would be a start!!
For the record I have been digging through the docs at google, but I can't be the first person to have wanted to do this, so there must be people who have got this working!
Any Takers on throwing me a bone?
Iain
Here is a working example to fetch the sites list. I used my xhttp class, which is a PHP cURL wrapper, to hide the finer details in using cURL.
<?php
// Set account login info
$data['post'] = array(
'accountType' => 'HOSTED_OR_GOOGLE', // indicates a Google account
'Email' => '', // full email address
'Passwd' => '',
'service' => 'sitemaps', // Name of the Google service
'source' => 'codecri.me-example-1.0' // Application's name'
);
// POST request
$response = xhttp::fetch('https://www.google.com/accounts/ClientLogin', $data);
// Extract Auth
preg_match('/Auth=(.+)/', $response['body'], $matches);
$auth = $matches[1];
$data = array();
$data['headers'] = array(
'Authorization' => 'GoogleLogin auth="'.$auth.'"',
);
// GET request
$response = xhttp::fetch('https://www.google.com/webmasters/tools/feeds/sites/', $data);
echo $response['body'];
?>
First thing the script does is to get an Authorization key via Google's ClientLogin. The service name used is sitemaps. You could also use OAuth or Oauth2 or AuthSub.
Next is to fetch the API URL endpoint for getting the sites list and just adding an Authorization header field.
UPDATE: APRIL 20, 2012
CLIENT LOGIN method as illustrated in the above script example won't work anymore because its deprecated by Google. See details here: https://developers.google.com/accounts/docs/AuthForInstalledApps
The best solution would be to use Oauth 2.0 to connect to Google webmaster tools API.
You can use this class to get data: This has been tested, help you to get
TOP_PAGES, TOP_QUERIES,CRAWL_ERRORS, CONTENT_ERRORS,CONTENT_KEYWORDS, INTERNAL_LINKS, EXTERNAL_LINKS, SOCIAL_ACTIVITY
https://github.com/eyecatchup/php-webmaster-tools-downloads
Hope this may help you.
Assuming you have your Application setup correctly, here's an example of the approach I took:
// Authenticate through OAuth 2.0
$credentials = new Google_Auth_AssertionCredentials(
'1111111111-somebigemail#developer.gserviceaccount.com',
[Google_Service_Webmasters::WEBMASTERS_READONLY],
file_get_contents( 'path-to-your-key.p12' )
);
$client = new Google_Client();
$client->setAssertionCredentials( $credentials );
if ( $client->getAuth()->isAccessTokenExpired() ) {
$client->getAuth()->refreshTokenWithAssertion();
}
$service = new Google_Service_Webmasters($client);
// Setup our Search Analytics Query object
$search = new Google_Service_Webmasters_SearchAnalyticsQueryRequest;
$search->setStartDate( date( 'Y-m-d', strtotime( '1 month ago' ) ) );
$search->setEndDate( date( 'Y-m-d', strtotime( 'now' ) ) );
$search->setDimensions( array( 'query' ) );
$search->setRowLimit( 50 );
// Pass our Search Analytics Query object as the second param to our searchanalytics query() method
$results = $service->searchanalytics->query( $url, $search, $options )->getRows();
// Build a CSV
if ( ! empty( $results ) ) {
// Setup our header row
$csv = "Rank,Query,Clicks,Impressions,CTR,Position\r\n";
foreach ( $results as $key => $result ) {
// Columns
$columns = array(
$key + 1,
$result->keys[0],
$result->clicks,
$result->impressions,
round( $result->ctr * 100, 2 ) . '%',
round( $result->position, 1 ),
);
$csv .= '"' . implode( '","', $columns ) . '"' . "\r\n";
}
file_put_contents( dirname( __FILE__ ) . '/data.csv' );
}
I have a full article I just posted on my blog that has an example class I started to write as a wrapper for both Webmaster Tools API and Analytics API. Feel free to use this as a reference:
http://robido.com/php/a-google-webmaster-tools-api-php-example-using-search-analytics-api-to-download-search-analytics-data-as-csv-with-the-new-oauth-2-0-method/