Google 客户端 API - 缺少要求参数:redirect_uri

Google Client API - Missing require parameter: redirect_uri

所以我遵循 quickstart 指南并决定将其分解为一个 class 调度程序。我正在处理身份验证代码,但我不断收到此消息:"Error 400 (OAuth 2 Error) Error Invalid Request Missing required Parameter: redirect_uri".

class scheduler{

//The Google Client object
private $googleClient;

//the Google Calendar Service ojbect
private $calendarService;

/*
*   Google Calendar Setup
*
*   This creates a Google Client object so that you may create a Google Calendar object.
*
*/
function __construct(){
    //set the application name
    define("APPLICATION_NAME", "Web client 1");
    //
    define("CREDENTIALS_PATH", "~/scheduler/credentials.json");
    //
    define("CLIENT_SECRET_PATH", __DIR__ . "/scheduler/client_secret.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");    
    }*/

    //create the google client
    $this->googleClient = new Google_Client();

    //setup the client
    $this->googleClient->setApplicationName(APPLICATION_NAME);
    $this->googleClient->setDeveloperKey("AIzaSyBmJLvNdMYuFhVpWalkUdyStrEBoVEayYM");
    $this->googleClient->setScopes(SCOPES);
    $this->googleClient->setAuthConfigFile(CLIENT_SECRET_PATH);
    $this->googleClient->setAccessType("offline");

    //get the credentials file path
    $credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);

    //if the file exists
    if(file_exists($credentialsPath)){

        //get the credentials from the file
        $accessToken = file_get_contents($credentialsPath); 

    }//if it does not
    else{

        //request the authorization url
        $authURL = $this->googleClient->createAuthUrl();
        //print the authorization ulr
        echo "<a href=\"$authURL\">Press Me</a><br /><br />";

        //prompt the user to enter the auth code
        print("Enter authentication code: ");

        //
        $authCode = trim(fgets(STDIN));

        //exchange authorization for an access token
        $accessToken = $this->googleClient->authenticate($authCode);

        //store credentials to disk
        if(!file_exists(dirname($credentialsPath))){
            mkdir(dirname($credentialsPath), 0700, true);   
        }

        //put the contents into the credential files
        file_put_contents($credentialsPath, $accessToken);
    }

    $this->googleClient->setAccessToken($accessToken);

    //refresh token if its expired
    if($this->googleClient->isAccessTokenExpired()){
        $this->googleClient->refreshToken($client->getRefreshToken());

        file_put_contents($credentialsPath, $this->googleClient->getAccessToken()); 
    }
}

我找到了问题的原因,目前还没有解决办法。在我的 Google 开发者控制台下,我尝试将“http://localhost/”放入授权重定向 URI 部分。它给了我这个错误 "Sorry, there’s a problem. If you entered information, check it and try again. Otherwise, the problem might clear up on its own, so check back later." 有没有办法让 Google 开发人员控制台接受本地主机服务器的重定向 uri?

我让它工作了。我必须做的是返回 Google Developer Console 并删除我创建的项目。然后在制作一个新项目时,它允许我保存我的本地主机 url。发生的问题是当我去将我的本地主机 url 添加到重定向 url 时,它会说目前不可能。当我在点击创建按钮之前设置重定向 url 时,它接受它就好了。

只需在客户端对象上使用方法 setRedirectUri($absoluteUrl)

$client = new Google_Client();
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');

通过:

https://developers.google.com/api-client-library/php/auth/web-app

Google 的 "PHP Quick Start" Sheet API 文档似乎在 https://developers.google.com/sheets/api/quickstart/php.

时已过时

为了让他们的演示与 PHP 7.2+ 一起工作,我不得不进行相当多的修改,而且还不是很清楚发生了什么。下面是他们快速入门的评论更新版本,可能对使用 Google Sheets API 和 PHP.[=12= 有困难的其他人有所帮助]

<?php
/**
 * Updated Google Sheets Quickstart
 *
 * https://developers.google.com/sheets/api/quickstart/php
 */
require __DIR__ . '/vendor/autoload.php';

/**
* Appends one slash at the end, and removes any extra slashes
* 
*
* @return string $path with the slash appended
*/
function addTrailingSlash ($path)
{
    return rtrim ($path, '/') . '/';
}

/**
 * Returns an authorized API client.
 * @return Google_Client the authorized client object
 */
function getClient() {

     // Change this to a secure location where you'll save your config *.json files
     // Make sure it isn't publicly available on the web
    $configPath = addTrailingSlash (getcwd());

    // This get's generated by the script, so don't create it
    $credentialsPath = $configPath . 'credentials.json';

    $client = new Google_Client();

    // Matches the "Application Name" you enter during the "Step 1" wizard
    $client->setApplicationName( 'API App Name' );
    $client->setScopes( Google_Service_Sheets::SPREADSHEETS_READONLY );

    // You need to go through "Step 1" steps to generate this file: https://developers.google.com/sheets/api/quickstart/php
    $client->setAuthConfig( $configPath . 'client_secret.json' );
    $client->setAccessType( 'offline' );

    // This must match the "callback URL" that you enter under "OAuth 2.0 client ID" in the Google APIs console at https://console.developers.google.com/apis/credentials
    $client->setRedirectUri( 'https://' . $_SERVER['HTTP_HOST'] . '/' . basename( __FILE__, '.php' ) );

    // We have a stored credentials file, try using the data from there first
    if ( file_exists( $credentialsPath ) ) {
        $accessToken = json_decode( file_get_contents( $credentialsPath ), true );
    }

    // No stored credentials found, we'll need to request them with OAuth
    else {

        // Request authorization from the user
        $authUrl = $client->createAuthUrl();
        if ( ! isset( $_GET['code'] ) ) {
            header( "Location: $authUrl", true, 302 );
            exit;
        }

        // The authorization code is sent to the callback URL as a GET parameter.
        // We use this "authorization code" to generate an "access token". The
        // "access token" is what's effectively used as a private API key.
        $authCode = $_GET['code'];
        $accessToken = $client->fetchAccessTokenWithAuthCode( $authCode );

        // Create credentials.json if it doesn't already exist (first run)
        if ( ! file_exists( dirname( $credentialsPath ) ) ) {
            mkdir( dirname( $credentialsPath ), 0700, true );
        }

        // Save the $accessToken object to the credentials.json file for re-use
        file_put_contents( $credentialsPath, json_encode( $accessToken ) );
    }

    // Provide client with API access token
    $client->setAccessToken( $accessToken );

    // If the $accessToken is expired then we'll need to refresh it
    if ( $client->isAccessTokenExpired() ) {
        $client->fetchAccessTokenWithRefreshToken( $client->getRefreshToken() );
        file_put_contents( $credentialsPath, json_encode( $client->getAccessToken() ) );
    }

    return $client;
}

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

// Get values from a spreadheet and print
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/get
$spreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms';
$range = 'Class Data!A2:E';
$response = $service->spreadsheets_values->get($spreadsheetId, $range);
$values = $response->getValues();

if (empty($values)) {
    print "No data found.\n";
} else {
    print "Name, Major:\n";
    foreach ($values as $row) {
        // Print columns A and E, which correspond to indices 0 and 4.
        printf("%s, %s\n", $row[0], $row[4]);
    }
}

只是改进@kevinLeary 的答案,使代码看起来更模块化:

<?php

    if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
        throw new Exception(sprintf('Please run "composer require google/apiclient:~2.0" in "%s"', __DIR__));
    }

    require_once __DIR__ . '/vendor/autoload.php';

    $redirect_url = 'http://' . $_SERVER['HTTP_HOST'] . '/mydrive/index.php'; // <--- Change it to your web application path, host will be detected automatically  

    $auth_file = __DIR__ . DIRECTORY_SEPARATOR . 'drive-auth.json'; // <--- Your auth2 settings
    $auth_file = str_replace('\', '/', $auth_file);

    $configPath = addTrailingSlash(getcwd());
    $credentials_file = $configPath . 'credentials.json'; // <--- This will generated automatically


    $app_name = 'MY APP NAME';
    $scopes = [
                Google_Service_Sheets::SPREADSHEETS_READONLY, 
            ];

    /**
     * Returns an authorized API client.
     * @return Google_Client the authorized client object
     */
    function getClient($app_name, $auth_file, $credentials_file, $redirect_url, $scopes = array()) {
        // This get's generated by the script, so don't create it
        $credentialsPath = $credentials_file;

        $client = new Google_Client();

        // Matches the "Application Name" you enter during the "Step 1" wizard
        $client->setApplicationName( $app_name );
        $client->setScopes( $scopes );

        // You need to go through "Step 1" steps to generate this file: https://developers.google.com/sheets/api/quickstart/php
        $client->setAuthConfig( $auth_file );
        $client->setAccessType( 'offline' );

        // This must match the "callback URL" that you enter under "OAuth 2.0 client ID" in the Google APIs console at https://console.developers.google.com/apis/credentials
        $client->setRedirectUri( $redirect_url );

        // We have a stored credentials file, try using the data from there first
        if ( file_exists( $credentialsPath ) ) {
            $accessToken = json_decode( file_get_contents( $credentialsPath ), true );
        }

        // No stored credentials found, we'll need to request them with OAuth
        else {

            // Request authorization from the user
            $authUrl = $client->createAuthUrl();
            if ( ! isset( $_GET['code'] ) ) {
                header( "Location: $authUrl", true, 302 );
                exit;
            }

            // The authorization code is sent to the callback URL as a GET parameter.
            // We use this "authorization code" to generate an "access token". The
            // "access token" is what's effectively used as a private API key.
            $authCode = $_GET['code'];
            $accessToken = $client->fetchAccessTokenWithAuthCode( $authCode );

            // Create credentials.json if it doesn't already exist (first run)
            if ( ! file_exists( dirname( $credentialsPath ) ) ) {
                mkdir( dirname( $credentialsPath ), 0700, true );
            }

            // Save the $accessToken object to the credentials.json file for re-use
            file_put_contents( $credentialsPath, json_encode( $accessToken ) );
        }

        // Provide client with API access token
        $client->setAccessToken( $accessToken );

        // If the $accessToken is expired then we'll need to refresh it
        if ( $client->isAccessTokenExpired() ) {
            $client->fetchAccessTokenWithRefreshToken( $client->getRefreshToken() );
            file_put_contents( $credentialsPath, json_encode( $client->getAccessToken() ) );
        }

        return $client;
    }

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

    // Get values from a spreadheet and print
    // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/get
    $spreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms';
    $range = 'Class Data!A2:E';
    $response = $service->spreadsheets_values->get($spreadsheetId, $range);
    $values = $response->getValues();

    if (empty($values)) {
        print "No data found.\n";
    } else {
        print "Name, Major:\n";
        foreach ($values as $row) {
            // Print columns A and E, which correspond to indices 0 and 4.
            printf("%s, %s\n", $row[0], $row[4]);
        }
    }



    function addTrailingSlash ($path)
    {
        return rtrim ($path, '/') . '/';
    }   
?>

我的问题是我没有在 Google 控制台中初始化 URI 解决问题:

1- 转到您的项目 https://console.cloud.google.com/(从顶部开始的Select 项目)

2- 搜索“Google sheet API”确保它已启用

3- 在左侧菜单中单击“凭据”

4- 如果您已经创建了“OAuth 2.0 客户端 ID”,只需单击编辑并添加 URI,否则创建新的“OAuth 2.0 客户端 ID”

5- 请记住 re-download“OAuth 2.0 客户端 ID”,它类似于“client_secret_XXX.apps.googleusercontent.com”,将其重命名为 credentials.json 并将其设置在您的项目

这个答案可能不能完全满足您的需求,但是:

如果您只需要 读取 访问 sheet,您只需要一个 Google 服务帐户凭据文件 (credentials.json) .

可以像这样简单地切出示例的令牌检索部分:

<?php
require __DIR__ . '/vendor/autoload.php';

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('Google Sheets API PHP Quickstart');
    $client->setScopes(Google_Service_Sheets::SPREADSHEETS_READONLY);
    $client->setAuthConfig('credentials.json');
    $client->setAccessType('offline');
    $client->setPrompt('select_account consent');
    return $client;
}


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

// Prints the names and majors of students in a sample spreadsheet:
// https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
$spreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms';
$range = 'Class Data!A2:E';
$response = $service->spreadsheets_values->get($spreadsheetId, $range);
$values = $response->getValues();

if (empty($values)) {
    print "No data found.\n";
} else {
    print "Name, Major:\n";
    foreach ($values as $row) {
        // Print columns A and E, which correspond to indices 0 and 4.
        printf("%s, %s\n", $row[0], $row[4]);
    }
}

Google 应该在他们的示例 IMO 中提到这一点。