📜 ⬆️ ⬇️

Do-it-yourself XML gateway

If you had to work with payment systems, registration services and other resources that implement remote interaction with the central server, you probably came across the concept of “gateway”. This is a service that is designed to conduct operations on a central server by exchanging electronic messages between the central server (the server of the system having a gateway) and the software of a certain client.

Perhaps the ideal gateway should be able to receive and transmit data in XML format, if only because it is a standardized, self-documenting format, support for which is implemented in all modern programming languages ​​(and even at the hardware level). In addition, XML supports Unicode encodings of UTF-8, UTF-16, and even UTF-32. In brief, but with examples, I will talk about the principles of creating simple XML gateways. Sending requests, simplicity and, at the same time, diversity for the sake of consider the example of POST / GET methods.

To begin, consider the concept of interaction. You are the server that will receive requests, process them and give the requested information to the client in a typed format.
')
image

I suggest, for clarity, to consider the following example: you have a certain database of information materials on your server that you are ready to provide for a monthly fee. The material is divided into categories, there is a database of partners which contains information on which categories each partner has access to.

In order for a partner to receive material only within its access, we need to clearly identify it. Otherwise, he or any other savvy will be able to “pull” out of you more of what he should be, and this is fraught with a tarnished reputation and financial losses, because we have a commercial project.

The identification problem can be solved by giving the partners unique access keys that will be generated with reference to the IP address of the server making the request to the gateway.

For example, there is the company Shishkin Les, which paid for lifelong access to materials from categories 1, 2, 5 and 9. The company's server is located under the director’s bed, but the static IP address and we know it is 12.34.56.78. Now we need to generate a unique access key for this partner, which can be done something like this:
  1. <?php define( 'SECRET_WORD' , 'LsXUS~J' ); function getUniqueKey($ip, $access) { return substr(md5($ip . SECRET_WORD . $access), 5, 20); } ?>
  2. <?php define( 'SECRET_WORD' , 'LsXUS~J' ); function getUniqueKey($ip, $access) { return substr(md5($ip . SECRET_WORD . $access), 5, 20); } ?>
  3. <?php define( 'SECRET_WORD' , 'LsXUS~J' ); function getUniqueKey($ip, $access) { return substr(md5($ip . SECRET_WORD . $access), 5, 20); } ?>
  4. <?php define( 'SECRET_WORD' , 'LsXUS~J' ); function getUniqueKey($ip, $access) { return substr(md5($ip . SECRET_WORD . $access), 5, 20); } ?>
  5. <?php define( 'SECRET_WORD' , 'LsXUS~J' ); function getUniqueKey($ip, $access) { return substr(md5($ip . SECRET_WORD . $access), 5, 20); } ?>
  6. <?php define( 'SECRET_WORD' , 'LsXUS~J' ); function getUniqueKey($ip, $access) { return substr(md5($ip . SECRET_WORD . $access), 5, 20); } ?>

Pay attention to the constant "SECRET_WORD", which is constant regardless of other conditions. The getUniqueKey () function takes as parameters the IP address of the server ($ ip = '12 .34.56.78 ') and the string of the collapsed ID categories to which the partner has access ($ access =' ​​1259 '). Further, md5-hash is generated from all these parameters, which is truncated to a 15-character string (starting, in our example, from the 5th character of the hash). This is our unique key that is generated for each partner. We will check the correctness of the key with each request from the client.

As discussed earlier, the client can make a request to the server using the POST / GET methods, passing the necessary parameters to them. Consider an example of such a query:
mysite.com/gateway.php?id=1&type=list&token=8381ad87b37986ac7bb6

So, we make a request to the gateway and pass it only 3 parameters:

The gateway (gateway.php) can only verify the authenticity of the connection and respond to the client's request. By the way, it is necessary to answer in any case, even if the key is incorrect or a sampling / response error has occurred - the client is still obliged to receive an answer.

Consider the key verification function when requesting the gateway:
  1. <? php
  2. function checkValidation ($ clientID, $ clientToken) {
  3. // client IP address
  4. $ clientRemoteAddr = (getenv ( 'HTTP_X_FORWARDED_FOR' ))? getenv ( 'HTTP_X_FORWARDED_FOR' ): getenv ( 'REMOTE_ADDR' );
  5. // Client access level to categories
  6. // Actually there should be a sample
  7. // client access rights by its $ clientID
  8. $ clientAccessLevel = '1259' ;
  9. // The correct key
  10. $ checkToken = getUniqueKey ($ clientRemoteAddr, $ clientAccessLevel);
  11. // Comparison of verification and keys received from the client
  12. return ($ clientToken == $ checkToken);
  13. }
  14. ?>

Thus, if the checkValidation () function returns true, then connection authentication is passed. Now you can begin to form and prepare a response.

In our example, the answer should contain a certain sample of information from different categories, suppose that such a sample contains the following set of fields:

The structure of the answer in this case would be something like this:
  1. <? xml version = "1.0" encoding = "utf-8" ? >
  2. < response >
  3. < error-code > 0 </ error-code >
  4. < content >
  5. < item >
  6. < element_id > 1 </ element_id >
  7. < category_id > 5 </ category_id >
  8. < title > Title 1 </ title >
  9. < text > Text element number 1, about all garbage </ text >
  10. < time > 1248770309 </ time >
  11. </ item >
  12. < item >
  13. < element_id > 2 </ element_id >
  14. < category_id > 9 </ category_id >
  15. < title > Title 2 </ title >
  16. < text > Text element number 2, about all garbage </ text >
  17. < time > 1248770319 </ time >
  18. </ item >
  19. </ content >
  20. </ response >

The “error-code” attribute in case of successful operation should be equal to zero, which literally says to the client “everything is fine, below what you asked for”. If any error has occurred, then the error code is transmitted in this attribute (the “content” attribute and its entire content will not be in this case).

Suppose our error handler knows the following possible problems:


Well, and so on. The answer with the error will be:
  1. <? xml version = "1.0" encoding = "utf-8" ? >
  2. < response >
  3. < error-code > 102 </ error-code >
  4. </ response >

The last thing left to consider is the formation of such an answer. There may be a lot of implementations, like all of the above, but I will offer such a simple option:
  1. <? php
  2. function sendResponse ($ code, $ content = '' ) {
  3. // Create attribute
  4. function getNode ($ key, $ value ) {
  5. if ($ value ! = '' ) {
  6. return '<' . $ key. '>' . $ value . '</' . $ key. '>' ;
  7. }
  8. }
  9. // Additional fields
  10. $ items = '' ;
  11. // If $ content is not empty and is an array
  12. if (! empty ($ content) && is_array ($ content)) {
  13. foreach ($ content as $ key => $ value ) {
  14. $ items. = '<user>' ;
  15. if (is_array ($ value )) {
  16. foreach ($ value as $ skey => $ svalue) {
  17. $ items. = getNode ($ skey, $ svalue);
  18. }
  19. } else {
  20. $ items. = getNode ($ key, $ value );
  21. }
  22. $ items. = '</ user>' ;
  23. }
  24. }
  25. // Generate and send a response
  26. print '<response> <error-code>' . $ code. '</ error-code>' . $ items. '</ response>' ;
  27. exit ();
  28. }
  29. ?>

Hope this short article was interesting. The proposed implementation, with some modifications, is quite suitable for use on small resources. With a lot of traffic, the results of the issue must be cached, but this, I hope, everyone knows so well.

Criticism, additions, other implementations in the comments are welcome :-)

Source: https://habr.com/ru/post/65570/


All Articles