7

I am trying to implement Google+ login on my website and am running into an issue. Here is my code (after creating a Google_Client object):

try {
    $client->authenticate($_GET['code']);

    $plus = new \Google_Service_Plus($client);
    $person = $plus->people->get('me');

    $firstName = $person->modelData->name->givenName;

} catch (Google_Auth_Exception $e) {
    $response = array(
        'error' => 'Error: Authentication exception.'
    );
} catch (Exception $e) {
    $response = array(
        'error' => 'Error: Uncaught exception.'
    );
}
  1. $client->authenticate() throws a Google_Auth_Exception if the code passed to it is invalid
  2. If authentication failed, then reading properties from the $person object causes fatal errors
  3. $responseis echo'd out as a JSON-encoded object

The problem is that the try/catch code does not seem to be working properly. When authentication fails due to the code in $_GET['code'] being invalid, the following response is returned from the script:

{"error":"Error: Authentication exception."}

So far so good -- the code in the first catch block was executed.

However, the code in the try block continues to execute in a weird fashion. I say "weird" because in the above form, a bunch of errors (culminating in a fatal error) occur, meaning this line:

$firstName = $person->modelData->name->givenName;

Is still executed! It should not be executed since an exception was thrown on a previous line. If I comment out the above line, the errors are not thrown (again indicating this line is executed, which it shouldn't be).

Here are the errors outputted due to the above line executing after the exception has been thrown:

Notice: Undefined index: modelData in [...]\google-api-php-client-master\src\Google\Model.php on line 78

Notice: Trying to get property of non-object in [...]\ajax_handler.php on line 720 [note: this is the line shown above, where the property is being accessed]

Notice: Trying to get property of non-object in [...]\ajax_handler.php on line 720

Another reason I said "weird" is that if I add this line:

die('dying before reading property');

Right before the above line (where I read a property), no errors occur, BUT the "dying before reading property" text is not output onto the page! This is weird because the script is clearly still executing code in the try block after the error is thrown (since without this die() line, the line reading the property is executed and results in lots of errors being output). As with before, the code in the catch block is still executed and the JSON is output onto the page.

What on earth is going on?

Community
  • 1
  • 1
Nate
  • 26,164
  • 34
  • 130
  • 214
  • What exactly happens? Does it catch the exception, and then continue on executing code, or maybe it sends the requests to G+ and continues to execute code asynchronously, and then the exception comes in? – Jurijs Kastanovs May 28 '14 at 13:21
  • @JurijsKastanovs I'm not sure how to explain it any better than I did in my question. It seems the exception is caught, but the code in the try block continues to execute. I'm not sure how the code could execute asynchronously, as I didn't think such a thing was possible in PHP. If you have the Google+ framework, this code would be very easy to test. – Nate May 28 '14 at 13:28
  • well, I would just add more debug lines in code and the catch block, and see how things are actually working. Believe me, I've had quite a bit of surprises that way ) – Jurijs Kastanovs May 28 '14 at 13:44
  • 1
    Is it possible you've defined another exception handler elsewhere in your code using `set_exception_handler()`? – klugerama May 28 '14 at 17:20
  • 1
    Can you write the actual errors? PHP will still parse those lines, while not executing them, so looking at the errors we might be able to see something else. `I say "weird" because in the above form, a bunch of errors (culminating in a fatal error) occur, meaning this line:` – Francisco Presencia May 29 '14 at 00:29
  • @klugerama No, I'm not using that anywhere. – Nate May 29 '14 at 20:55
  • @FranciscoPresencia `PHP will still parse those lines, while not executing them` Really? I updated my question with the errors outputted to the page. – Nate May 29 '14 at 21:00
  • 2
    Not sure if related, but `$person->modelData` is `protected`; I would expect you should instead be using `$firstName = $person->name->givenName;` – klugerama May 29 '14 at 21:38
  • 1
    Well I'm not native so excuse if I didn't say it properly. However, what I wanted to say is that `if (false) 1 = 5;` will still throw an error, and other errors can arise in code that is not "run". – Francisco Presencia May 29 '14 at 22:27
  • How do you know your `Authentication exception` is coming from `$client->authenticate($_GET['code']);`, and not from `$firstName = $person->modelData->name->givenName;` ? Are you using breakpoints ? – nl-x Jun 03 '14 at 19:46

2 Answers2

6

PHP is a compiled language. See this question and this answer for an explanation.

Basically, the code is parsed, assembled, and compiled into bytecode before it's executed; what's happening with your script is that the code is invalid. The syntax is correct, so PHP doesn't just outright fail. The issue arises after the object $person is constructed, when you try to access a dynamic property (modelData) that doesn't exist or is inaccessible due to its scope. So the errors you are seeing are because PHP can't find it.

The reason the code doesn't output 'dying before reading property' is because the code isn't actually being executed, so it can't "stop" execution; it's already stopped.

Change

$firstName = $person->modelData->name->givenName;

to

$firstName = $person->name->givenName;

and you should be good to go.

Community
  • 1
  • 1
klugerama
  • 3,312
  • 19
  • 25
  • @nl-x You are right about the buffer hypothesis. I deleted my answer. I didn't notice the first time that some JSON is output somehow after the die(). There is some code that is left out of this. I think the way the question was asked is really confusing. – jtmanteo Jun 04 '14 at 15:51
  • I would agree that it should only be accepted as an answer if the proposed solution actually works, and if the reasoning is sound. I assume that it did work, since only @Nate can mark it as answered, and there were no further questions or comments after it was so marked. – klugerama Jun 04 '14 at 22:25
  • Yes, your suggestion worked. I clearly don't understand how PHP works at a low level :) Thank you very much for your help! – Nate Jun 06 '14 at 11:37
1

This question and its selected answer keep bothering me. It seems so unlikely that PHP would have executed/parsed/whatever, while an exception was already thrown.

I would rather suggest the code is being run twice. The first time giving the Exception message, and the second time producing the notices.

I suggest you try this:

  • put $testVar = uniqid(); just before try {
  • put echo $testVar; just after try {

When you run the code now you should see a unique ID just before the Exception message, and (my theory) another/different unique ID just before your notices. This would prove the code is being run twice.

About the die("..."); not appearing, I would ask if you really checked this looking in your HTML source, because it could be hidden for some reasong. (eg invisible div)

nl-x
  • 11,762
  • 7
  • 33
  • 61