Jump to content
BethTech

Two Objects Getting Same PHP Response

Recommended Posts

Okay, so I've gotten my product (virtual pets/breedables) all hooked up to a database using PHP and SQL nicely. However, I've run into an issue. When two animals are created in the same second, they both get the same reply from the server. I'll explain how it works below:

  1. The animal is born, POSTs a "create me" message to the server with system password, basic info on the pet (parents, etc), and the owner key.
  2. PHP script sees it and does its thing, making the pet (traits etc) and creates a row in the database with all the pet's info and the owner's key, pet ID is "number of rows" +1.
  3. PHP sees the creation of the pet in the database worked and sends a message back to the pet with its traits and pet ID.

Now, I can tell two pets are getting the same response because they both have the same Pet ID, and the first one poofs informing the owner that another pet is rezzed with that ID in the grid and two of them cannot exist (security measure).

Now, what are some ways I could solve this? End Users may not understand it's a bad idea to just click on all the starter pet generators at once to get them (I did add a random countdown to it but that's not foolproof). I have not gotten to the point of them reproducing yet to see if it also affects new babies, but I'm pretty sure it would due to how it's coded, and who hasn't just clicked on all their kittens/foals/eggs, etc to get it over with?

Is this something I should somehow fix in the LSL, the PHP, both, or another way?

Edited by BethTech
grammar

Share this post


Link to post
Share on other sites

I have close to no experience with breedables.  The one breedable client I worked with a few years ago left SL before he ever got his basic models made, and never had anything ready to script.  However, I have had a lot of experience with systems that can be jammed up by people who spam-click them.  I've decided that some people are just compulsive clickers, and there's not much you can do to make them stop.  You have to take measures to simply disable clicking -- flip a flag, change states, set Click Action, build in a timer-- and then include a foolproof way to re-enable it again once the system has either finished its task or timed out.  It sounds like that's what you need to do in order to keep requests from piling up on each other.

  • Thanks 1

Share this post


Link to post
Share on other sites

Okay, I'm thinking about what you said and wondering if this might work:

  1. During pet creation, the pet generates a random number between 0 and 1000 and includes that in the POST
  2. PHP does its thing and sends the message back including the random number
  3. Pet checks to see if the right number is in the message back and if so, applies the message

Share this post


Link to post
Share on other sites

That sounds reasonable.  When you use llHTTPRequest, you get a unique key that you can match to a response in the http_response event, to be sure that you are keeping requests and responses in sync.  You can keep a list of those keys off to one side and poll it each time a response comes in, instead of looking for only the key of the most recent request.  Then remove keys from the saved list as they are handled, or as the system times out.

Edited by Rolig Loon
  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

Wow, I didn't know about that. I'm certainly going to be looking into that and see how I might be able to work it into my code. Thank you so much for your replies!

Share this post


Link to post
Share on other sites

You can use an autoincrement field in the database. The numbers are unique. If you need it in a variable while performing an insert you can get it with lastInsertId()

Only the database can guarantee you unique numbers, everything else is clumsy.

In LSL - llGetTime delivers a float - I don't know the resolution - random numbers - uuid - date - if you mix it all up you can consrtuct something that is unique (with a 1:1 million chance of failure)

 

  • Like 1

Share this post


Link to post
Share on other sites
Quote

Users may not understand it's a bad idea to just click on all the starter pet generators at once to get them

Mebbe like a vendor system, once you click a generator, it is "in use" and no one else can click it till it is done,

and once a person has clicked one, it sends a msg to all other generators that this person is already

using another generator in the system?

  • Like 2

Share this post


Link to post
Share on other sites

Yeah, they already change states when counting down, so I think I'm going to work in checking the UUID of the object and including that in the POST/GET so the object can check those two numbers to see if they match.

I also ran into an unrelated issue I have to write a debug for.

What a wonderful creative puzzle scripting can be! LOL I'm so glad I stopped putting a date on when these things will be ready, because it's clear it's rarely ever true. I'll be so glad when it's working right.

  • Like 2

Share this post


Link to post
Share on other sites
On 9/5/2019 at 8:13 PM, BethTech said:

Okay, so I've gotten my product (virtual pets/breedables) all hooked up to a database using PHP and SQL nicely. However, I've run into an issue. When two animals are created in the same second, they both get the same reply from the server. I'll explain how it works below:

  1. The animal is born, POSTs a "create me" message to the server with system password, basic info on the pet (parents, etc), and the owner key.
  2. PHP script sees it and does its thing, making the pet (traits etc) and creates a row in the database with all the pet's info and the owner's key, pet ID is "number of rows" +1.
  3. PHP sees the creation of the pet in the database worked and sends a message back to the pet with its traits and pet ID.

Now, I can tell two pets are getting the same response because they both have the same Pet ID, and the first one poofs informing the owner that another pet is rezzed with that ID in the grid and two of them cannot exist (security measure).

Now, what are some ways I could solve this? End Users may not understand it's a bad idea to just click on all the starter pet generators at once to get them (I did add a random countdown to it but that's not foolproof). I have not gotten to the point of them reproducing yet to see if it also affects new babies, but I'm pretty sure it would due to how it's coded, and who hasn't just clicked on all their kittens/foals/eggs, etc to get it over with?

Is this something I should somehow fix in the LSL, the PHP, both, or another way?

I am happy for you that you could sort things out. I still would have some open questions. Yes, it is a good thing to check the http_response by the key that was created by the llHTTPRequest. And to communicate an additional sufficient complext identifier back and forth (it can be UUID as it will work for a first unique registration process - even if the UUID of the object will change whenit is taken into inventory and rezzed again).

However does that really solve the fundamental problem in your LSL-PHP communication, or haven't you just not run into another case yet?

Can you specify a bit more what is happening in the steps 1-3? You are using method POST via an llHTTPRequest in order to send the SL data to a PHP script. The script then does (1) enter the data into the database and (2) SELECT the created data entries and print/echo it in the html_body. The LSL script then receives that http_response and "saves" them to global integers. Is this correct?

Only if my assumptions are correct, then this is my guess to what is happening:

What seems to have created your problem is that two llHTTPRequests arriving at almost the same time receive the same html_body in their http_response event. I can think of two reasons for that: (1) Your PHP script is having a bug, for example: sometimes new data is not entered into the database but the last entry is selected and so it sends the previous information a second time. This is very likely the reason behind your problem (if my assumptions are correct). (2) There is a bug in the LSL-PHP pipeline so that a second call might get the response of the first call. That is rather unlikely.

So if (1) is the reason for your problem then your "solution" will only result in a new problem: A new breedable sends it's information to the database, it does (for whatever scripting reason) not registerd in the database, the php script sends the previous entry. The breedable script sees - because of UUID - that the information does not fit and discards it. Well, then this new breedable will again have a problem: no data.

You need to find out why your PHP script sometimes does not save the new entry to the database. Maybe add a php confirmation to your PHP pipeline that an entry has been saved (which is checked by LSL script) and a notification if it has not been saved (and make your LSL script communicate this error).

 

Edited by Estelle Pienaar
  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

 

On 9/9/2019 at 3:07 PM, Estelle Pienaar said:

Can you specify a bit more what is happening in the steps 1-3? You are using method POST via an llHTTPRequest in order to send the SL data to a PHP script. The script then does (1) enter the data into the database and (2) SELECT the created data entries and print/echo it in the html_body. The LSL script then receives that http_response and "saves" them to global integers. Is this correct?

Yes this is correct.

 

On 9/9/2019 at 3:07 PM, Estelle Pienaar said:

What seems to have created your problem is that two llHTTPRequests arriving at almost the same time receive the same html_body in their http_response event. I can think of two reasons for that: (1) Your PHP script is having a bug, for example: sometimes new data is not entered into the database but the last entry is selected and so it sends the previous information a second time. This is very likely the reason behind your problem (if my assumptions are correct). (2) There is a bug in the LSL-PHP pipeline so that a second call might get the response of the first call. That is rather unlikely.

So if (1) is the reason for your problem then your "solution" will only result in a new problem: A new breedable sends it's information to the database, it does (for whatever scripting reason) not registerd in the database, the php script sends the previous entry. The breedable script sees - because of UUID - that the information does not fit and discards it. Well, then this new breedable will again have a problem: no data.

You need to find out why your PHP script sometimes does not save the new entry to the database. Maybe add a php confirmation to your PHP pipeline that an entry has been saved (which is checked by LSL script) and a notification if it has not been saved (and make your LSL script communicate this error).

That is something to consider! I can tell this issue will need more time than I originally thought.

Share this post


Link to post
Share on other sites

A question: Do you use llEscapeURL for all data which is sent to php? If you don't use it and the data contains a letter or an expression that is forbidden or reserved in PHP or SQL, then the script will fail and the data will not be added to the database.

  • Like 1

Share this post


Link to post
Share on other sites
On 9/5/2019 at 1:41 PM, Nova Convair said:

You can use an autoincrement field in the database. The numbers are unique. If you need it in a variable while performing an insert you can get it with lastInsertId()

Only the database can guarantee you unique numbers, everything else is clumsy.

Yes. The problem is at "Pet ID is "number of rows" +1." It's quite possible for two PHP scripts running at the same time to get the same value for that. This is a database update race condition.

lastInsertID, though, is unique across multiple simultaneous requests. See the MySQL manual here. Also the PHP manual here.

If you use SQL, you may need to understand how transactions work. If you do several SQL operations in a row, expecting the database to be in the same state it was after the previous operation, you may find that some other event got in there and changed it between your operations. Either write your code to not depend on that, or learn how to use transactions in SQL to lock things.

SL can do many things simultaneously, PHP can do many things simultaneously, and MySQL can do many things simultaneously. Fortunately, how to deal with all that was figured out long ago by the web backend and database people, who deal with this constantly. All the major databases that talk SQL have the features for this.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
21 hours ago, Estelle Pienaar said:

A question: Do you use llEscapeURL for all data which is sent to php? If you don't use it and the data contains a letter or an expression that is forbidden or reserved in PHP or SQL, then the script will fail and the data will not be added to the database.

No. But as far as I can tell nothing gets sent that would require that, and I'm unsure how to rewrite my code to use it as well.

11 hours ago, animats said:

Yes. The problem is at "Pet ID is "number of rows" +1." It's quite possible for two PHP scripts running at the same time to get the same value for that. This is a database update race condition.

lastInsertID, though, is unique across multiple simultaneous requests. See the MySQL manual here. Also the PHP manual here.

If you use SQL, you may need to understand how transactions work. If you do several SQL operations in a row, expecting the database to be in the same state it was after the previous operation, you may find that some other event got in there and changed it between your operations. Either write your code to not depend on that, or learn how to use transactions in SQL to lock things.

SL can do many things simultaneously, PHP can do many things simultaneously, and MySQL can do many things simultaneously. Fortunately, how to deal with all that was figured out long ago by the web backend and database people, who deal with this constantly. All the major databases that talk SQL have the features for this.

Okay, that makes a lot of sense. I'm fairly new to PHP and this is my first real project with it. I feel like I've bitten off a bit more than I can chew, but I'm sure as long as I keep trying, asking questions, and reading more I'll figure it out.

Edited by BethTech

Share this post


Link to post
Share on other sites

This stuff is confusing at first, but well documented. Millions of web developers have been down this road, and it's well-paved. Search for "php sql book" and you'll find more than a dozen books devoted specifically to how to make PHP and SQL play well together.

  • Thanks 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...