Link to home
Create AccountLog in
Avatar of APD Toronto
APD TorontoFlag for Canada

asked on

PHP Fatal Error & GitHub Incomplete Download

Hi Experts,

I had this question after viewing How Do I "Install the Google Client Library".

I guess I closed the above too early, but after downloading from https://github.com/google/google-api-php-client by clicking Clone or Download, then Extracting the .zip, I noticed that all files and folders don't get downloaded (I tried twice),  such as examples/, styles/, tests/, and most files under the root directory when compared to the following screenshot of what is actually downloaded.

User generated image
Why aren't all files and folders getting downloaded?

Secondly, and most importantly, after extracting the download into my project director, and running the following code,

<!DOCTYPE html>
<?php

require_once 'google-api/src/Google/autoload.php';


define('APPLICATION_NAME', 'Google Calendar API PHP Quickstart');
define('CREDENTIALS_PATH', '~/.credentials/calendar-php-quickstart.json');
define('CLIENT_SECRET_PATH', __DIR__ . '/client_secret.json');
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/calendar-php-quickstart.json
define('SCOPES', implode(' ', array(
  Google_Service_Calendar::CALENDAR_READONLY)
));

if (php_sapi_name() != 'cli') {
  throw new Exception('This application must be run on the command line.');
}

/**
 * Returns an authorized API client.
 * @return Google_Client the authorized client object
 */
function getClient() {
  $client = new Google_Client();
  $client->setApplicationName(APPLICATION_NAME);
  $client->setScopes(SCOPES);
  $client->setAuthConfig(CLIENT_SECRET_PATH);
  $client->setAccessType('offline');

  // Load previously authorized credentials from a file.
  $credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);
  if (file_exists($credentialsPath)) {
    $accessToken = json_decode(file_get_contents($credentialsPath), true);
  } else {
    // Request authorization from the user.
    $authUrl = $client->createAuthUrl();
    printf("Open the following link in your browser:\n%s\n", $authUrl);
    print 'Enter verification code: ';
    $authCode = trim(fgets(STDIN));

    // Exchange authorization code for an access token.
    $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);

    // Store the credentials to disk.
    if(!file_exists(dirname($credentialsPath))) {
      mkdir(dirname($credentialsPath), 0700, true);
    }
    file_put_contents($credentialsPath, json_encode($accessToken));
    printf("Credentials saved to %s\n", $credentialsPath);
  }
  $client->setAccessToken($accessToken);

  // Refresh the token if it's expired.
  if ($client->isAccessTokenExpired()) {
    $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
    file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
  }
  return $client;
}

/**
 * Expands the home directory alias '~' to the full path.
 * @param string $path the path to expand.
 * @return string the expanded path.
 */
function expandHomeDirectory($path) {
  $homeDirectory = getenv('HOME');
  if (empty($homeDirectory)) {
    $homeDirectory = getenv('HOMEDRIVE') . getenv('HOMEPATH');
  }
  return str_replace('~', realpath($homeDirectory), $path);
}

// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Calendar($client);

// Print the next 10 events on the user's calendar.
$calendarId = 'primary';
$optParams = array(
  'maxResults' => 10,
  'orderBy' => 'startTime',
  'singleEvents' => TRUE,
  'timeMin' => date('c'),
);
$results = $service->events->listEvents($calendarId, $optParams);

if (count($results->getItems()) == 0) {
  print "No upcoming events found.\n";
} else {
  print "Upcoming events:\n";
  foreach ($results->getItems() as $event) {
    $start = $event->start->dateTime;
    if (empty($start)) {
      $start = $event->start->date;
    }
    printf("%s (%s)\n", $event->getSummary(), $start);
  }
}


?>
<html>
    <head>
        <meta charset="UTF-8">
        <title>GMail Calendar Testing</title>
    </head>
    <body>
        
        <h1>GMail Calendar Testing</h1>
        
    </body>
</html>

Open in new window


...I get

PHP Fatal error:  Uncaught Exception: This library must be installed via composer or by downloading the full package. See the instructions at https://github.com/google/google-api-php-client#installation. in C:\inetpub\wwwroot\test\gmail_calendar\google-api\src\Google\autoload.php:14
Stack trace:
#0 C:\inetpub\wwwroot\test\gmail_calendar\index.php(4): require_once()
#1 {main}
  thrown in C:\inetpub\wwwroot\test\gmail_calendar\google-api\src\Google\autoload.php on line 14

Open in new window


If you refer to my original post, you will see  that I'm on a Windows environment and never needed to use GitHub, but I didn't have a chance to test the above until now.

Thank you.
SOLUTION
Avatar of Scott Fell
Scott Fell
Flag of United States of America image

Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
See answer
Avatar of APD Toronto

ASKER

Thanks Scott, I have gone through https://developers.google.com/api-client-library/php/start/get_started, which is a good refresher, but is only theory and does not pprovide detailed instructions.

I think you are saying that I need to install the Composer, then install the SDK through the composer.

Based on that, what is the Composer, is that Google, what does it do, and where do I get it?

What is
composer require google/apiclient:^2.0

Open in new window


Remember, I'm not familiar with MAC, Linux and GitHub - do I need to be?
With a little research, I found that Composer is a dependency manager, that takes care of updates. Plus, composer needs to be installed on the server, but this particular application is going on a shared hosting.  What if they don't have Composer?

Can I not use the Google Calendar SDK (or, just API) without using Composer?

I understand that using Composer might be preferred and a personal preference, but can I not just download the files and just use them, similar  to PHPMailer or TCPDF?
You're correct in your assumption that Composer is a dependency manager. The download you've grabbed is just the src folder and doesn't include the dependencies which is why they suggest installing it via Composer. That's part of the beauty of Composer - devs don't need to ship the project dependencies - just a composer.json file.

Generally with raw source code like this, the idea is that you clone the repo and then run Composer - you then have the full stack set up and ready to go.

As for running it on a server, you could if you wanted to, just install it locally using Composer - that would pull all the relevant deps into your local environment, and you could then develop and test locally. Once your dev is done, you could upload all relevant files to the Server manually.

Alternatively, there is a Releases page available for the API which includes all the relevant dependencies, so it may be better for you to just download a Release that's already packaged - heres the page you need -> https://github.com/google/google-api-php-client/releases - you'll probably want 2.2.0
I downloaded the packaged release, and received the following error

PHP Fatal error:  Uncaught Exception: This application must be run on the command line. in C:\inetpub\wwwroot\test\gmail_calendar\index.php:17
Stack trace:
#0 {main}
  thrown in C:\inetpub\wwwroot\test\gmail_calendar\index.php on line 17

Open in new window


I, then deleted all API folders from my project, installed Composer, then installed the Google API through the Composer, and I got the same error.
OK - the error should be fairly self-explanatory. You're trying to call your page in a web browser when you should be calling it from the command line (CLI). If you have PHP setup correctly on your windows machine, then from the CLI you need to type the following:

php index.php
From the command line, when I run it it is asking me for verification code? Where do I get that?

As well, why is it only working on the command line, when it is a web application?
OK. Reading through your code, it looks like it should ask you to visit a URL ("Open the following link in your browser"). When you open that link, it will ask you to log in to Google and Authorise your application (using oAuth). Once you've done that it will redirect back to whatever URL you setup as the callback when you created the API Credentials in your Google API Console. That URL will include a querystring that contains the verification code (yourCallback.php?code=xxxxxxxxxxx).

The reason it's only working on the command line is because that's what your code tells it to do!!

if (php_sapi_name() != 'cli') {
  throw new Exception('This application must be run on the command line.');
}

Open in new window

Copying that oAth in my command line worked, but:

1- When I comment out throw new exception...and run it in my browser I get

PHP Notice:  Use of undefined constant STDIN - assumed 'STDIN' in C:\inetpub\wwwroot\test\gmail_calendar\index.php on line 40
PHP Warning:  fgets() expects parameter 1 to be resource, string given in C:\inetpub\wwwroot\test\gmail_calendar\index.php on line 40
PHP Fatal error:  Uncaught InvalidArgumentException: Invalid code in C:\inetpub\wwwroot\test\gmail_calendar\vendor\google\apiclient\src\Google\Client.php:176
Stack trace:
#0 C:\inetpub\wwwroot\test\gmail_calendar\index.php(43): Google_Client->fetchAccessTokenWithAuthCode('')
#1 C:\inetpub\wwwroot\test\gmail_calendar\index.php(76): getClient()
#2 {main}
  thrown in C:\inetpub\wwwroot\test\gmail_calendar\vendor\google\apiclient\src\Google\Client.php on line 176

Why is this, and why is it a part of the original sample code provided at
https://developers.google.com/google-apps/calendar/quickstart/php

I mean...it should be intended to be a web application, so why it is looking for the command line by default, should it not be a quick start sample to get you going?
ASKER CERTIFIED SOLUTION
Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
Thanks Chris, I'll continue with your recommended link.