Google API How to connect to receive values from spreadsheet

前端 未结 3 859
花落未央
花落未央 2020-12-02 19:17

I embarked on this project thinking it would be simple. Many hours later I\'m realizing the Google API is a bit of a labyrinth with multiple APIs and libraries. I really nee

相关标签:
3条回答
  • 2020-12-02 19:59

    This answer is meant to be an add-on to jrgd`s answer, and I post it here, as an answer, because it contains code.

    The connection problems themselves hung me up. Here is what I had to do to resolve that: Trying to Get Google accessToken . Also, the spreadsheet has to be shared with the Google-generated e-mail that you find in your code.

    Also, jrgd, to answer your question about that Request object: it doesn't exist with the Google Spreadsheet API; /* I couldn't find it when I used Composer to download the library */ Instead, I ended up doing what GingerDog did:

    $serviceRequest = new Google\Spreadsheet\DefaultServiceRequest($accessToken); Google\Spreadsheet\ServiceRequestFactory::setInstance($serviceRequest);

    There is also a significant probability of the code throwing an Exception when using getSpreadsheets(), due to an HTTP error code being returned that is higher than 300 . The SpreadsheetService class has that method (here is its code: /** * Fetches a list of spreadhsheet spreadsheets from google drive. * * @return \Google\Spreadsheet\SpreadsheetFeed */ public function getSpreadsheets() { return new SpreadsheetFeed( ServiceRequestFactory::getInstance()->get('feeds/spreadsheets/private/full') ); } Notice that there is another class that is "doing the dirty work here": the DefaultServiceRequest class. Here is the get() that is being used:

    /**
         * Perform a get request
         * 
         * @param string $url
         * 
         * @return string
         */
        public function get($url)
        {
            $ch = $this->initRequest($url);
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
            return $this->execute($ch);
        }
        /**
         * Executes the api request.
         * 
         * @return string the xml response
         *
         * @throws \Google\Spreadsheet\Exception If the was a problem with the request.
         *                                       Will throw an exception if the response
         *                                       code is 300 or greater
         *                                       
         * @throws \Google\Spreadsheet\UnauthorizedException
         */
        protected function execute($ch)
        {
            $ret = curl_exec($ch);
    
            $info = curl_getinfo($ch);
            $httpCode = (int)$info['http_code'];
    
            if($httpCode > 299) {
                if($httpCode === 401) {
                    throw new UnauthorizedException('Access token is invalid', 401);
                } else {
                    throw new Exception('Error in Google Request', $info['http_code']);
                }
            }
    
            return $ret;
        }
    

    Notice that the function, from its innermost helper, has a chance to give back an http_code that will cause the code to throw an exception. Not good for business.

    The Solution

    The way I remedied that is to change the following line of code: $spreadsheetFeed = $spreadsheetService->getSpreadsheets();

    to this while-loop:

    /* my way of "making" it work; // I just getSpreadsheets() until there stops being an exception thrown */
        $googleException = new Exception();
        while ($googleException != null)
        {
            try
            {
                $spreadsheetFeed = $spreadsheetService->getSpreadsheets();  # This line randomly throws exception, for some reason. 
                $googleException = null;
            }
            catch (Exception $e)
            {
                $googleException = $e;
            }
        }
        //var_dump($spreadsheetFeed->getArrayCopy());   // test line
    
    0 讨论(0)
  • 2020-12-02 20:12

    I finally got it working, despite all attempts from the documents to make it look like impossible, here is my setup:

    • google api for OAuth2 php lib; here: https://code.google.com/p/google-api-php-client/
    • google spreadsheet api php lib; here: https://github.com/asimlqt/php-google-spreadsheet-client

    You will need to create the credentials on the API Console: https://console.developers.google.com/ There you will need to first create a project and create set of authentified information for your app: in the left menu, click on API & Auth, then Credentials. Click on Create New Client ID (red button), then select Service Account. You will download a file, keep it safe. you will upload it with your script.

    Also, please note: it never worked unless: my document was the 'old spreadsheet'. I also needed to share the spreadsheet document with the user ID (the one that could be an email) generated on Google's console. The document contains a top row that is frozen with the appropriate columns name (name, age).

    Here is the php script I used in combination with the above:

    <?php
    require_once 'php-google-spreadsheet/src/Google/Spreadsheet/Autoloader.php';
    require_once 'google-api-php-client/src/Google_Client.php';
    
    const G_CLIENT_ID       = 'fill_with_info_from_console.apps.googleusercontent.com';
    const G_CLIENT_EMAIL    = 'fill_with_info_from_console@developer.gserviceaccount.com';
    const G_CLIENT_KEY_PATH = 'key/keep_the_complex_filename_here_privatekey.p12';
    const G_CLIENT_KEY_PW   = 'notasecret';
    
    $obj_client_auth  = new Google_Client ();
    $obj_client_auth -> setApplicationName ('test_or_whatever_you_like');
    $obj_client_auth -> setClientId (G_CLIENT_ID);
    $obj_client_auth -> setAssertionCredentials (new Google_AssertionCredentials (
        G_CLIENT_EMAIL, 
        array('https://spreadsheets.google.com/feeds','https://docs.google.com/feeds'), 
        file_get_contents (G_CLIENT_KEY_PATH), 
        G_CLIENT_KEY_PW
    ));
    $obj_client_auth -> getAuth () -> refreshTokenWithAssertion ();
    $obj_token  = json_decode ($obj_client_auth -> getAccessToken ());
    $accessToken = $obj_token->access_token;
    
    $request = new Google\Spreadsheet\Request($accessToken);
    $serviceRequest = new Google\Spreadsheet\DefaultServiceRequest($request);
    Google\Spreadsheet\ServiceRequestFactory::setInstance($serviceRequest);
    $spreadsheetService = new Google\Spreadsheet\SpreadsheetService();
    $spreadsheetFeed = $spreadsheetService->getSpreadsheets();
    $spreadsheet = $spreadsheetFeed->getByTitle('title_of_the_spreadsheet_doc');
    $worksheetFeed = $spreadsheet->getWorksheets();
    $worksheet = $worksheetFeed->getByTitle('title_of_the_tab');
    $listFeed = $worksheet->getListFeed();
    
    // this bit below will create a new row, only if you have a frozen first row adequatly labelled
    
    $row = array('name'=>'John', 'age'=>25);
    $listFeed->insert($row);
    
    ?>
    

    I should also note:

    • All this is still very much work in progress, but hopefully will help someone write amazing instructions for anyone to better understand the nitty gritty

    • It's a compilation of bits and pieces from both the google documentations, some answers on stackoverflow and info from the 2 api libraries

    • It has been an awfully painful to get this working and it really shouldn't; i'm assuming this is because google is transitioning authentification, console interface and api versions all at the same time.

    • EDIT: It seems the columns names in the google doc are restricted: no space allowed(?), no underscore allowed (?), CamelCase seems troublesome. I only managed to get the dashes to work, like in "placement-other", otherwise the api throws some "Uncaught exception"

    • EDIT: I used the exact same setup for a new project and still does work, with the new Spreadsheet model introduced by Google recently. What hold me that i had forgotten: no blank cell allowed, headers must be frozen without spaces, and they are lowercase when queried from PHP.

    Hope this helps!

    0 讨论(0)
  • 2020-12-02 20:12

    I have written a wrapper class for the Google Sheets authentication and sheet cell editing in my recent project. Tested working as of 02 Sep 2015 so it's very up-to-date!

    Prerequisites:

    • Get your Google developer keys etc. ready (This is an excellent and up-to-date article on how to get your API keys etc. - http://konstantinshkut.com/blog/2014/11/01/how_to_get_data_from_google_spreadsheet_in_yii_php_application).
    • Download and install Composer, required for the two necessary libraries google-api-php-client and php-google-spreadsheet-client.
    • Use Composer to install the above two libraries; this is the recommended way to get the libraries working.

    To use the wrapper class:

    // Initialise Google Sheets instance
    $sheets = new GoogleSheets();
    
    $sheets->clientID      = 'YOUR CLIENT ID FROM GOOGLE DEV CONSOLE';
    $sheets->clientEmail   = 'YOUR CLIENT EMAIL FROM GOOGLE DEV CONSOLE';
    $sheets->clientKeyPath = 'PATH TO THE P12 FILE YOU DOWNLOADED FROM GOOGLE DEV CONSOLE';
    $sheets->clientKeyPw   = 'IT IS USUALLY notasecret';
    
    $sheets->appName          = 'WHATEVER NAME YOU WANT';
    $sheets->spreadsheetTitle = 'TITLE FOR THE SPREADSHEET YOU WANT TO EDIT';
    $sheets->worksheetTitle   = 'WORKSHEET TITLE IN THAT SPREADSHEET';
    
    // Authenticate with Google
    $sheets->authenticate();
    
    // Now update the specific row cell
    $sheets->updateListEntry(ROW_HEADER, $submissionID, CELL_HEADER, CELL_VALUE);
    echo "updated!";
    

    And here goes the wrapper class - feel free to modify it - most of the code is pretty much standard, boilerplate code. Tested working!

    // Autoload classes thanks to Composer
    require_once('vendor/autoload.php');
    
    class GoogleSheets {
      // Instance variables
      public $clientID, $clientEmail, $clientKeyPath, $clientKeyPw, $appName, $spreadsheetTitle, $worksheetTitle;
      private $spreadsheetFeed;
    
      // connect to Google using OAuth2, boilerplate code...
      public function authenticate() {
        $obj_client_auth  = new Google_Client ();
        $obj_client_auth -> setApplicationName ($this->appName);
        $obj_client_auth -> setClientId ($this->clientID);
        $obj_client_auth -> setAssertionCredentials (new Google_Auth_AssertionCredentials (
            $this->clientEmail, 
            array('https://spreadsheets.google.com/feeds','https://docs.google.com/feeds'), 
            file_get_contents ($this->clientKeyPath), 
            $this->clientKeyPw
        ));
        $obj_client_auth -> getAuth () -> refreshTokenWithAssertion ();
        $obj_token  = json_decode ($obj_client_auth -> getAccessToken ());
        $accessToken = $obj_token->access_token;
    
        $serviceRequest = new Google\Spreadsheet\DefaultServiceRequest($accessToken);
        Google\Spreadsheet\ServiceRequestFactory::setInstance($serviceRequest);
        $spreadsheetService = new Google\Spreadsheet\SpreadsheetService();
        $this->spreadsheetFeed = $spreadsheetService->getSpreadsheets();
    }
    
    // Find matching row with header $field and cell value $value, and update cell with header $cellHeader to $cellValue
    public function updateListEntry($field, $value, $cellHeader, $cellValue) {
        // Get the required spreadsheet, then worksheet by title
        $spreadsheet = $this->spreadsheetFeed->getByTitle($this->spreadsheetTitle);
        $worksheetFeed = $spreadsheet->getWorksheets();
        $worksheet = $worksheetFeed->getByTitle($this->worksheetTitle);
    
        // sq stands for structured query
        $listFeed = $worksheet->getListFeed(array("sq" => $field . " = " . $value));
        $entries = $listFeed->getEntries();
        $listEntry = $entries[0];
    
        $values = $listEntry->getValues();
        $values[$cellHeader] = $cellValue;
        $listEntry->update($values);
    }
    

    }

    0 讨论(0)
提交回复
热议问题