-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit fd66c3f
Showing
8 changed files
with
392 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
sandbox | ||
vendor | ||
composer.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
|
||
# Google Spreadsheet Client for PHP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"name": "mach3/google-spreadsheet", | ||
"description": "Google spreadsheet client", | ||
"require": { | ||
"google/apiclient": "1.*" | ||
}, | ||
"autoload": { | ||
"classmap": ["src"] | ||
}, | ||
"license": "MIT", | ||
"authors": [ | ||
{ | ||
"name": "mach3", | ||
"email": "[email protected]" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
/** | ||
* Google_Spreadsheet | ||
* | ||
* @class Process Google Spreadsheet | ||
*/ | ||
class Google_Spreadsheet { | ||
|
||
/** | ||
* Get Google_Spreadsheet_Client instance | ||
* @param {String|Array} $keys ... Path to json file or array | ||
*/ | ||
static public function getClient($keys = null){ | ||
return new Google_Spreadsheet_Client($keys); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
<?php | ||
|
||
/** | ||
* Google_Spreadsheet_Client | ||
* ------------------------- | ||
* @class Client to authenticate and send request to Google service | ||
*/ | ||
|
||
class Google_Spreadsheet_Client { | ||
|
||
private $client = null; // Google_Client instance | ||
|
||
/** | ||
* Options: | ||
* - session_key {String} ... Session key for access token | ||
* - cache {Boolean} ... Save cache for GET request or not | ||
* - cache_dir {String} ... Directory path to save cache data | ||
* - cache_expires {Integer} ... Cache lifetime | ||
*/ | ||
private $options = array( | ||
"session_key" => "__google_service_token__", | ||
"cache" => false, | ||
"cache_dir" => "cache", | ||
"cache_expires" => 3600 | ||
); | ||
|
||
/** | ||
* @constructor | ||
* @param {String|Array} $keys ... Path to json file or array | ||
*/ | ||
public function __construct($keys = null){ | ||
if(! session_id()){ | ||
session_start(); | ||
} | ||
if($keys){ | ||
$this->auth($keys); | ||
} | ||
} | ||
|
||
/** | ||
* Authenticate connection | ||
* | ||
* @param {String|Array} $keys ... Path to json file or array | ||
* @return {Google_Spreadsheet_Client} ... This | ||
*/ | ||
public function auth($keys){ | ||
if(gettype($keys) === "string"){ | ||
$keys = json_decode(file_get_contents($keys)); | ||
} | ||
$this->client = new Google_Client(); | ||
$cred = new Google_Auth_AssertionCredentials( | ||
$keys->client_email, | ||
array(Google_Service_Drive::DRIVE), | ||
$keys->private_key | ||
); | ||
$this->client->setAssertionCredentials($cred); | ||
return $this; | ||
} | ||
|
||
/** | ||
* Configure options | ||
* | ||
* @param {String|Array} $key|$options | ||
* @param {Mixed} $value | ||
* @return {Mixed} | ||
*/ | ||
public function config(/* $key [,$value] */){ | ||
$args = func_get_args(); | ||
if(! count($args)){ | ||
return $this->options; | ||
} | ||
$type = gettype($args[0]); | ||
if($type === "array"){ | ||
foreach($args[0] as $key => $value){ | ||
$this->config($key, $value); | ||
} | ||
} | ||
else if($type === "string"){ | ||
if(count($args) === 1){ | ||
return array_key_exists($args[0], $this->options) ? | ||
$this->options[$args[0]] : null; | ||
} | ||
$this->options[$args[0]] = $args[1]; | ||
} | ||
return $this; | ||
} | ||
|
||
/** | ||
* Get access token from client connection | ||
* | ||
* @return {String} ... Access token | ||
*/ | ||
public function getAccessToken(){ | ||
$session_key = $this->config("session_key"); | ||
$token = array_key_exists($this->options["session_key"], $_SESSION) ? | ||
$_SESSION[$session_key] : null; | ||
if($token){ | ||
// expired ? | ||
$vars = json_decode($token); | ||
$token = time() >= ($vars->expires_in + $vars->created) ? null : $token; | ||
} | ||
if(! $token){ | ||
$this->client->getAuth()->refreshTokenWithAssertion(); | ||
$token = $this->client->getAccessToken(); | ||
$_SESSION[$session_key] = $token; | ||
} | ||
return json_decode($token)->access_token; | ||
} | ||
|
||
/** | ||
* Send request to google service, return response | ||
* @param {String} $url ... URL to request | ||
* @param {String} $method ... GET or POST | ||
* @param {Array} $header ... Additional headers | ||
* @param {String} $postBody ... Body for POST request | ||
* @param {Boolean} $force ... Ignore cache | ||
*/ | ||
public function request($url, $method = "GET", $headers = array(), $postBody = null, $force = false){ | ||
$cache = $this->config("cache"); | ||
$feed = ($cache && $method === "GET" && ! $force) ? $this->cache($url) : null; | ||
|
||
if(! $feed){ | ||
$headers = array_merge(array( | ||
"Authorization" => sprintf("Bearer %s", $this->getAccessToken()) | ||
), $headers); | ||
$req = new Google_Http_Request($url, $method, $headers, $postBody); | ||
$curl = new Google_IO_Curl($this->client); | ||
$res = $curl->executeRequest($req); | ||
$feed = $res[0]; | ||
if($cache){ | ||
$this->cache($url, $feed); | ||
} | ||
} | ||
return json_decode($feed, true); | ||
} | ||
|
||
/** | ||
* Save or get data from cache data | ||
* @param {String} $url ... URL to request | ||
* @param {String} $content ... Data to save | ||
* @return {Null|String} ... Content data | ||
*/ | ||
private function cache($url, $content = null){ | ||
$path = $this->config("cache_dir") . "/" . urlencode($url); | ||
if($content !== null){ | ||
return file_put_contents($path, $content); | ||
} | ||
if(file_exists($path) && time() < (filemtime($path) + $this->config("cache_expires"))){ | ||
return file_get_contents($path); | ||
} | ||
return null; | ||
} | ||
|
||
/** | ||
* Get Google_Spreadsheet_File instance by id | ||
* @param {String} $file_id | ||
*/ | ||
public function file($file_id){ | ||
return new Google_Spreadsheet_File($file_id, $this); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<?php | ||
|
||
/** | ||
* Google_Spreadsheet_File | ||
* ----------------------- | ||
* @class Instance represents Google Spreadsheet's file | ||
*/ | ||
|
||
class Google_Spreadsheet_File { | ||
|
||
private $client = null; // Google_Spreadsheet_Client | ||
private $id = null; // ID name for file | ||
|
||
// Collection of links | ||
private $link = array( | ||
"sheets" => "https://spreadsheets.google.com/feeds/worksheets/%s/private/full?alt=json" | ||
); | ||
|
||
/** | ||
* Constructor | ||
* | ||
* @param {String} $id | ||
* @param {Google_Spreadsheet_Client} $client | ||
*/ | ||
public function __construct($id, $client){ | ||
$this->id = $id; | ||
$this->client = $client; | ||
} | ||
|
||
/** | ||
* Get sheets list | ||
* | ||
* @return {Array} ... Sheets list of the file | ||
*/ | ||
public function sheets(){ | ||
$data = $this->client->request(sprintf($this->link["sheets"], $this->id)); | ||
return $data ? $data["feed"]["entry"] : null; | ||
} | ||
|
||
/** | ||
* Get Google_Spreadsheet_Sheet instance by sheet's title | ||
* | ||
* @param {String} $title | ||
* @return {Google_Spreadsheet_Sheet} | ||
*/ | ||
public function sheet($title){ | ||
$sheet = null; | ||
foreach($this->sheets() as $item){ | ||
if($title === $item["title"]["\$t"]){ | ||
$sheet = $item; | ||
break; | ||
} | ||
} | ||
return new Google_Spreadsheet_Sheet($sheet, $this->client); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
<?php | ||
|
||
/** | ||
* Google_Spreadsheet_Sheet | ||
* ------------------------ | ||
* @class Instance represents Google Spreadsheet's sheet | ||
*/ | ||
|
||
class Google_Spreadsheet_Sheet { | ||
|
||
private $meta = null; // Meta info of the sheet | ||
private $client = null; // Google_Spreadsheet_Client instance | ||
private $link = array(); // Collection of links | ||
|
||
public $fields = null; // Fields of table | ||
public $items = null; // Data of table | ||
|
||
/** | ||
* Constructor | ||
* | ||
* @param {Array} $meta | ||
* @param {Google_Spreadsheet_Client} $client | ||
*/ | ||
public function __construct($meta, $client){ | ||
$this->meta = $meta; | ||
$this->client = $client; | ||
|
||
foreach($this->meta["link"] as $link){ | ||
switch(true){ | ||
case strstr($link["rel"], "#cellsfeed"): | ||
$this->link["cellsfeed"] = $link["href"] . "?alt=json"; break; | ||
case strstr($link["rel"], "#listfeed"): | ||
$this->link["listfeed"] = $link["href"] . "?alt=json"; break; | ||
default: break; | ||
} | ||
} | ||
|
||
$this->fetch(); | ||
} | ||
|
||
/** | ||
* Fetch the table data | ||
* | ||
* @param {Boolean} $force ... Ignore cache data or not | ||
* @return {Google_Spreadsheet_Sheet} ... This | ||
*/ | ||
public function fetch($force = false){ | ||
$data = $this->client->request($this->link["cellsfeed"], "GET", array(), null, $force); | ||
$this->process($data["feed"]["entry"]); | ||
return $this; | ||
} | ||
|
||
/** | ||
* Update the value of column | ||
* @param {Integer} $row | ||
* @param {Integer|String} $col ... Column number or field's name | ||
* @param {String} $value | ||
* @return {Google_Spreadsheet_Sheet} ... This | ||
*/ | ||
public function update($row, $col, $value){ | ||
$col = is_string($col) ? array_search($col, array_values($this->fields), true) + 1 : $col; | ||
$body = sprintf( | ||
'<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gs="http://schemas.google.com/spreadsheets/2006"> | ||
<gs:cell row="%u" col="%u" inputValue="%s"/> | ||
</entry>', | ||
$row, $col, htmlspecialchars($value) | ||
); | ||
$this->client->request( | ||
$this->link["cellsfeed"], | ||
"POST", | ||
array("Content-Type" => "application/atom+xml"), | ||
$body | ||
); | ||
return $this; | ||
} | ||
|
||
/** | ||
* Insert a row to the table | ||
* @param {Array} $vars | ||
* @return {Google_Spreadsheet_Sheet} ... This | ||
*/ | ||
public function insert($vars){ | ||
$body = '<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gsx="http://schemas.google.com/spreadsheets/2006/extended">'; | ||
foreach($this->fields as $c => $key){ | ||
if(! array_key_exists($key, $vars)){ continue; } | ||
$value = htmlspecialchars($vars[$key]); | ||
$body .= "<gsx:{$key}>{$value}</gsx:{$key}>"; | ||
} | ||
$body .= "</entry>"; | ||
$this->client->request( | ||
$this->link["listfeed"], | ||
"POST", | ||
array("Content-Type" => "application/atom+xml"), | ||
$body | ||
); | ||
return $this; | ||
} | ||
|
||
/** | ||
* Process the entry data fetched from cellfeed API | ||
* Update its `items` property | ||
* | ||
* @param {Array} $entry | ||
*/ | ||
private function process($entry){ | ||
$this->fields = array(); | ||
$this->items = array(); | ||
|
||
foreach($entry as $col){ | ||
$r = ((int) preg_replace("/^[A-Z]+/", "", $col["title"]["\$t"])); | ||
$c = preg_replace("/\d+$/", "", $col["title"]["\$t"]); | ||
if($r === 1){ | ||
$this->fields[$c] = $col["content"]["\$t"]; | ||
continue; | ||
} | ||
if(! $this->items[$r]){ | ||
$this->items[$r] = array(); | ||
} | ||
if($this->fields[$c]){ | ||
$this->items[$r][$this->fields[$c]] = $col["content"]["\$t"]; | ||
} | ||
} | ||
} | ||
|
||
} | ||
|
Oops, something went wrong.