diff options
Diffstat (limited to 'zend/demos/Zend/Gdata')
27 files changed, 9785 insertions, 0 deletions
diff --git a/zend/demos/Zend/Gdata/3LeggedOAuth/Gdata_OAuth_Helper.php b/zend/demos/Zend/Gdata/3LeggedOAuth/Gdata_OAuth_Helper.php new file mode 100755 index 0000000..f0edd57 --- /dev/null +++ b/zend/demos/Zend/Gdata/3LeggedOAuth/Gdata_OAuth_Helper.php @@ -0,0 +1,109 @@ +<?php +require_once 'Zend/Oauth/Consumer.php'; +require_once 'Zend/Gdata/Query.php'; + +/** + * Wrapper class for Google's OAuth implementation. In particular, this helper + * bundles the token endpoints and manages the Google-specific parameters such + * as the hd and scope parameter. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +class Gdata_OAuth_Helper extends Zend_Oauth_Consumer { + // Google's default oauth parameters/constants. + private $_defaultOptions = array( + 'requestScheme' => Zend_Oauth::REQUEST_SCHEME_HEADER, + 'version' => '1.0', + 'requestTokenUrl' => 'https://www.google.com/accounts/OAuthGetRequestToken', + 'userAuthorizationUrl' => 'https://www.google.com/accounts/OAuthAuthorizeToken', + 'accessTokenUrl' => 'https://www.google.com/accounts/OAuthGetAccessToken' + ); + + /** + * Create Gdata_OAuth_Helper object + * + * @param string $consumerKey OAuth consumer key (domain). + * @param string $consumerSecret (optional) OAuth consumer secret. Required if + * using HMAC-SHA1 for a signature method. + * @param string $sigMethod (optional) The oauth_signature method to use. + * Defaults to HMAC-SHA1. RSA-SHA1 is also supported. + */ + public function __construct($consumerKey, $consumerSecret=null, + $sigMethod='HMAC-SHA1') { + $this->_defaultOptions['consumerKey'] = $consumerKey; + $this->_defaultOptions['consumerSecret'] = $consumerSecret; + $this->_defaultOptions['signatureMethod'] = $sigMethod; + parent::__construct($this->_defaultOptions); + } + + /** + * Getter for the oauth options array. + * + * @return array + */ + public function getOauthOptions() { + return $this->_defaultOptions; + } + + /** + * Fetches a request token. + * + * @param string $scope The API scope or scopes separated by spaces to + * restrict data access to. + * @param mixed $callback The URL to redirect the user to after they have + * granted access on the approval page. Either a string or + * Zend_Gdata_Query object. + * @return Zend_OAuth_Token_Request|null + */ + public function fetchRequestToken($scope, $callback) { + if ($callback instanceof Zend_Gdata_Query) { + $uri = $callback->getQueryUrl(); + } else { + $uri = $callback; + } + + $this->_defaultOptions['callbackUrl'] = $uri; + $this->_config->setCallbackUrl($uri); + if (!isset($_SESSION['ACCESS_TOKEN'])) { + return parent::getRequestToken(array('scope' => $scope)); + } + return null; + } + + /** + * Redirects the user to the approval page + * + * @param string $domain (optional) The Google Apps domain to logged users in + * under or 'default' for Google Accounts. Leaving this parameter off + * will give users the universal login to choose an account to login + * under. + * @return void + */ + public function authorizeRequestToken($domain=null) { + $params = array(); + if ($domain != null) { + $params = array('hd' => $domain); + } + $this->redirect($params); + } + + /** + * Upgrades an authorized request token to an access token. + * + * @return Zend_OAuth_Token_Access||null + */ + public function fetchAccessToken() { + if (!isset($_SESSION['ACCESS_TOKEN'])) { + if (!empty($_GET) && isset($_SESSION['REQUEST_TOKEN'])) { + return parent::getAccessToken( + $_GET, unserialize($_SESSION['REQUEST_TOKEN'])); + } + } + return null; + } +} diff --git a/zend/demos/Zend/Gdata/3LeggedOAuth/data-api-72.png b/zend/demos/Zend/Gdata/3LeggedOAuth/data-api-72.png Binary files differnew file mode 100755 index 0000000..e77c523 --- /dev/null +++ b/zend/demos/Zend/Gdata/3LeggedOAuth/data-api-72.png diff --git a/zend/demos/Zend/Gdata/3LeggedOAuth/doclist-72.png b/zend/demos/Zend/Gdata/3LeggedOAuth/doclist-72.png Binary files differnew file mode 100755 index 0000000..39de3a1 --- /dev/null +++ b/zend/demos/Zend/Gdata/3LeggedOAuth/doclist-72.png diff --git a/zend/demos/Zend/Gdata/3LeggedOAuth/index.php b/zend/demos/Zend/Gdata/3LeggedOAuth/index.php new file mode 100755 index 0000000..59aab08 --- /dev/null +++ b/zend/demos/Zend/Gdata/3LeggedOAuth/index.php @@ -0,0 +1,190 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Sample code to demonstrate accessing a Google Data feed using OAuth for + * authorization. Utilizes the Zend Framework Zend_OAuth components to + * communicate with the API(s). + * + * NOTE: As this is sample code, not all of the functions do full error + * handling. + */ + +require_once 'Zend/Gdata/Docs.php'; +require_once 'Zend/Gdata/Spreadsheets.php'; + +require_once 'Gdata_OAuth_Helper.php'; + +session_start(); + +// Application constants. Replace these values with your own. +$APP_NAME = 'google-ZendGData3LOSample-1.0'; +$APP_URL = getAppURL(); +$scopes = array( + 'https://docs.google.com/feeds/', + 'http://spreadsheets.google.com/feeds/' +); + +// Setup OAuth consumer. Thes values should be replaced with your registered +// app's consumer key/secret. +$CONSUMER_KEY = 'anonymous'; +$CONSUMER_SECRET = 'anonymous'; +$consumer = new Gdata_OAuth_Helper($CONSUMER_KEY, $CONSUMER_SECRET); + +// Main controller logic. +switch (@$_REQUEST['action']) { + case 'logout': + logout($APP_URL); + break; + case 'request_token': + $_SESSION['REQUEST_TOKEN'] = serialize($consumer->fetchRequestToken( + implode(' ', $scopes), $APP_URL . '?action=access_token')); + $consumer->authorizeRequestToken(); + break; + case 'access_token': + $_SESSION['ACCESS_TOKEN'] = serialize($consumer->fetchAccessToken()); + header('Location: ' . $APP_URL); + break; + default: + if (isset($_SESSION['ACCESS_TOKEN'])) { + $accessToken = unserialize($_SESSION['ACCESS_TOKEN']); + + $httpClient = $accessToken->getHttpClient( + $consumer->getOauthOptions()); + $docsService = new Zend_Gdata_Docs($httpClient, $APP_NAME); + $spreadsheetsService = new Zend_Gdata_Spreadsheets($httpClient, + $APP_NAME); + + // Retrieve user's list of Google Docs and spreadsheet list. + $docsFeed = $docsService->getDocumentListFeed(); + $spreadsheetFeed = $spreadsheetsService->getSpreadsheetFeed( + 'http://spreadsheets.google.com/feeds/spreadsheets/private/full?max-results=100'); + + renderHTML($accessToken, array($docsFeed, $spreadsheetFeed)); + } else { + renderHTML(); + } +} + +/** + * Returns a the base URL of the current running web app. + * + * @return string + */ +function getAppURL() { + $pageURL = 'http'; + if ($_SERVER['HTTPS'] == 'on') { + $pageURL .= 's'; + } + $pageURL .= '://'; + if ($_SERVER['SERVER_PORT'] != '80') { + $pageURL .= $_SERVER['SERVER_NAME'] . ':' . + $_SERVER['SERVER_PORT'] . $_SERVER['PHP_SELF']; + } else { + $pageURL .= $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF']; + } + return $pageURL; +} + +/** + * Removes session data and redirects the user to a URL. + * + * @param string $redirectUrl The URL to direct the user to after session data + * is destroyed. + * @return void + */ +function logout($redirectUrl) { + session_destroy(); + header('Location: ' . $redirectUrl); + exit; +} + +/** + * Prints the token string and secret of the token passed in. + * + * @param Zend_OAuth_Token $token An access or request token object to print. + * @return void + */ +function printToken($token) { + echo '<b>Token:</b>' . $token->getToken() . '<br>'; + echo '<b>Token secret:</b>' . $token->getTokenSecret() . '<br>'; +} + +/** + * Prints basic properties of a Google Data feed. + * + * @param Zend_Gdata_Feed $feed A feed object to print. + * @return void + */ +function printFeed($feed) { + echo '<ol>'; + foreach ($feed->entries as $entry) { + $alternateLink = ''; + foreach ($entry->link as $link) { + if ($link->getRel() == 'alternate') { + $alternateLink = $link->getHref(); + } + } + echo "<li><a href=\"$alternateLink\" target=\"_new\">$entry->title</a></li>"; + } + echo '</ol>'; +} + +/** + * Renders the page's HTML. + * + * @param Zend_OAuth_Token $token (optional) The user's current OAuth token. + * @param array $feeds (optional) An array of Zend_Gdata_Feed to print + * information for. + * @return void + */ +function renderHTML($token=null, $feeds=null) { +?> +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset=utf-8 /> +<link href="style.css" type="text/css" rel="stylesheet"/> +</head> +<body> + <?php if (!isset($_SESSION['ACCESS_TOKEN'])) { ?> + <button onclick="location.href='<?php echo "$APP_URL?action=request_token" ?>';">Grant Access to this app!</button> + <?php } else { ?> + <div id="token_info"> + <span style="float:left;"><img src="http://code.google.com/apis/accounts/images/oauth_icon.png"></span> + <div id="token"><?php printToken($token); ?></div> + </div> + <div id="logout"><a href="<?php echo "$APP_URL?action=logout"; ?>">Logout</a></div> + <div style="clear:both;"> + <div id="doclist"> + <h4>First 100 documents from the <a href="http://code.google.com/apis/documents/" target="_new">Documents List Data API</a>:</h4> + <div class="feed"><?php printFeed($feeds[0]); ?></div> + </div> + <div id="spreadsheets"> + <h4>First 100 spreadsheets from the <a href="http://code.google.com/apis/spreadsheets/" target="_new">Spreadsheets Data API</a>:</h4> + <div class="feed"><?php printFeed($feeds[1]); ?></div> + </div> + </div> + <?php } ?> +</body> +</html> +<?php +} diff --git a/zend/demos/Zend/Gdata/3LeggedOAuth/style.css b/zend/demos/Zend/Gdata/3LeggedOAuth/style.css new file mode 100755 index 0000000..f572f60 --- /dev/null +++ b/zend/demos/Zend/Gdata/3LeggedOAuth/style.css @@ -0,0 +1,43 @@ +body { + font-family: Verdana, Arial, sans-serif; + font-size: 12px; +} +ul, ol { + padding: 0 0 0 15px; + margin: 0; +} +#logout { + text-align: right; +} +#token_info { + float: left; +} +#token { + margin-top: 12px; + padding: 10px 10px 10px 85px; + width: 500px; + border: 1px solid #ccc; + border-radius : 5px; + -moz-border-radius: 5px; + background-color: #eee; +} +#doclist, #spreadsheets { + float: left; + width: 450px; + margin-right: 10px; +} +#doclist .feed { + background: transparent url('doclist-72.png') no-repeat top right; +} +#spreadsheets .feed { + background: transparent url('data-api-72.png') no-repeat top right; +} +.feed { + border: 1px solid #ccc; + border-radius: 10px; + -moz-border-radius: 10px; + padding: 25px; +} +.feed h4 { + text-align: center; +} diff --git a/zend/demos/Zend/Gdata/Blogger.php b/zend/demos/Zend/Gdata/Blogger.php new file mode 100644 index 0000000..457984a --- /dev/null +++ b/zend/demos/Zend/Gdata/Blogger.php @@ -0,0 +1,373 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/* +* This sample utilizes the Zend Gdata Client Library, which can be +* downloaded from: http://framework.zend.com/download +* +* This sample is meant to show basic CRUD (Create, Retrieve, Update +* and Delete) functionality of the Blogger data API, and can only +* be run from the command line. +* +* To run the sample: +* php Blogger.php --user=email@email.com --pass=password +*/ + +/** + * @see Zend_Loader + */ +require_once 'Zend/Loader.php'; + +/** + * @see Zend_Gdata + */ +Zend_Loader::loadClass('Zend_Gdata'); + +/** + * @see Zend_Gdata_Query + */ +Zend_Loader::loadClass('Zend_Gdata_Query'); + +/** + * @see Zend_Gdata_ClientLogin + */ +Zend_Loader::loadClass('Zend_Gdata_ClientLogin'); + + +/** + * Class that contains all simple CRUD operations for Blogger. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class SimpleCRUD +{ + /** + * $blogID - Blog ID used for demo operations + * + * @var string + */ + public $blogID; + + /** + * $gdClient - Client class used to communicate with the Blogger service + * + * @var Zend_Gdata_Client + */ + public $gdClient; + + + /** + * Constructor for the class. Takes in user credentials and generates the + * the authenticated client object. + * + * @param string $email The user's email address. + * @param string $password The user's password. + * @return void + */ + public function __construct($email, $password) + { + $client = Zend_Gdata_ClientLogin::getHttpClient($email, $password, 'blogger'); + $this->gdClient = new Zend_Gdata($client); + } + + /** + * This function retrieves all the blogs associated with the authenticated + * user and prompts the user to choose which to manipulate. + * + * Once the index is selected by the user, the corresponding blogID is + * extracted and stored for easy access. + * + * @return void + */ + public function promptForBlogID() + { + $query = new Zend_Gdata_Query('http://www.blogger.com/feeds/default/blogs'); + $feed = $this->gdClient->getFeed($query); + $this->printFeed($feed); + $input = getInput("\nSelection"); + + //id text is of the form: tag:blogger.com,1999:user-blogID.blogs + $idText = explode('-', $feed->entries[$input]->id->text); + $this->blogID = $idText[2]; + } + + /** + * This function creates a new Zend_Gdata_Entry representing a blog + * post, and inserts it into the user's blog. It also checks for + * whether the post should be added as a draft or as a published + * post. + * + * @param string $title The title of the blog post. + * @param string $content The body of the post. + * @param boolean $isDraft Whether the post should be added as a draft or as a published post + * @return string The newly created post's ID + */ + public function createPost($title, $content, $isDraft=False) + { + // We're using the magic factory method to create a Zend_Gdata_Entry. + // http://framework.zend.com/manual/en/zend.gdata.html#zend.gdata.introdduction.magicfactory + $entry = $this->gdClient->newEntry(); + + $entry->title = $this->gdClient->newTitle(trim($title)); + $entry->content = $this->gdClient->newContent(trim($content)); + $entry->content->setType('text'); + $uri = "http://www.blogger.com/feeds/" . $this->blogID . "/posts/default"; + + if ($isDraft) + { + $control = $this->gdClient->newControl(); + $draft = $this->gdClient->newDraft('yes'); + $control->setDraft($draft); + $entry->control = $control; + } + + $createdPost = $this->gdClient->insertEntry($entry, $uri); + //format of id text: tag:blogger.com,1999:blog-blogID.post-postID + $idText = explode('-', $createdPost->id->text); + $postID = $idText[2]; + + return $postID; + } + + /** + * Prints the titles of all the posts in the user's blog. + * + * @return void + */ + public function printAllPosts() + { + $query = new Zend_Gdata_Query('http://www.blogger.com/feeds/' . $this->blogID . '/posts/default'); + $feed = $this->gdClient->getFeed($query); + $this->printFeed($feed); + } + + /** + * Retrieves the specified post and updates the title and body. Also sets + * the post's draft status. + * + * @param string $postID The ID of the post to update. PostID in <id> field: + * tag:blogger.com,1999:blog-blogID.post-postID + * @param string $updatedTitle The new title of the post. + * @param string $updatedContent The new body of the post. + * @param boolean $isDraft Whether the post will be published or saved as a draft. + * @return Zend_Gdata_Entry The updated post. + */ + public function updatePost($postID, $updatedTitle, $updatedContent, $isDraft) + { + $query = new Zend_Gdata_Query('http://www.blogger.com/feeds/' . $this->blogID . '/posts/default/' . $postID); + $postToUpdate = $this->gdClient->getEntry($query); + $postToUpdate->title->text = $this->gdClient->newTitle(trim($updatedTitle)); + $postToUpdate->content->text = $this->gdClient->newContent(trim($updatedContent)); + + if ($isDraft) { + $draft = $this->gdClient->newDraft('yes'); + } else { + $draft = $this->gdClient->newDraft('no'); + } + + $control = $this->gdClient->newControl(); + $control->setDraft($draft); + $postToUpdate->control = $control; + $updatedPost = $postToUpdate->save(); + + return $updatedPost; + } + + /** + * This function uses query parameters to retrieve and print all posts + * within a specified date range. + * + * @param string $startDate Beginning date, inclusive. Preferred format is a RFC-3339 date, + * though other formats are accepted. + * @param string $endDate End date, exclusive. + * @return void + */ + public function printPostsInDateRange($startDate, $endDate) + { + $query = new Zend_Gdata_Query('http://www.blogger.com/feeds/' . $this->blogID . '/posts/default'); + $query->setParam('published-min', $startDate); + $query->setParam('published-max', $endDate); + + $feed = $this->gdClient->getFeed($query); + $this->printFeed($feed); + } + + /** + * This function creates a new comment and adds it to the specified post. + * A comment is created as a Zend_Gdata_Entry. + * + * @param string $postID The ID of the post to add the comment to. PostID + * in the <id> field: tag:blogger.com,1999:blog-blogID.post-postID + * @param string $commentText The text of the comment to add. + * @return string The ID of the newly created comment. + */ + public function createComment($postID, $commentText) + { + $uri = 'http://www.blogger.com/feeds/' . $this->blogID . '/' . $postID . '/comments/default'; + + $newComment = $this->gdClient->newEntry(); + $newComment->content = $this->gdClient->newContent($commentText); + $newComment->content->setType('text'); + $createdComment = $this->gdClient->insertEntry($newComment, $uri); + + echo 'Added new comment: ' . $createdComment->content->text . "\n"; + // Edit link follows format: /feeds/blogID/postID/comments/default/commentID + $editLink = explode('/', $createdComment->getEditLink()->href); + $commentID = $editLink[8]; + + return $commentID; + } + + /** + * This function prints all comments associated with the specified post. + * + * @param string $postID The ID of the post whose comments we'll print. + * @return void + */ + public function printAllComments($postID) + { + $query = new Zend_Gdata_Query('http://www.blogger.com/feeds/' . $this->blogID . '/' . $postID . '/comments/default'); + $feed = $this->gdClient->getFeed($query); + $this->printFeed($feed); + } + + /** + * This function deletes the specified comment from a post. + * + * @param string $postID The ID of the post where the comment is. PostID in + * the <id> field: tag:blogger.com,1999:blog-blogID.post-postID + * @param string $commentID The ID of the comment to delete. The commentID + * in the editURL: /feeds/blogID/postID/comments/default/commentID + * @return void + */ + public function deleteComment($postID, $commentID) + { + $uri = 'http://www.blogger.com/feeds/' . $this->blogID . '/' . $postID . '/comments/default/' . $commentID; + $this->gdClient->delete($uri); + } + + /** + * This function deletes the specified post. + * + * @param string $postID The ID of the post to delete. + * @return void + */ + public function deletePost($postID) + { + $uri = 'http://www.blogger.com/feeds/' . $this->blogID . '/posts/default/' . $postID; + $this->gdClient->delete($uri); + } + + /** + * Helper function to print out the titles of all supplied Blogger + * feeds. + * + * @param Zend_Gdata_Feed The feed to print. + * @return void + */ + public function printFeed($feed) + { + $i = 0; + foreach($feed->entries as $entry) + { + echo "\t" . $i ." ". $entry->title->text . "\n"; + $i++; + } + } + + /** + * Runs the sample. + * + * @return void + */ + public function run() + { + echo "Note: This sample may Create, Read, Update and Delete data " . + "stored in the account provided. Please exit now if you provided " . + "an account which contains important data.\n\n"; + $this->promptForBlogID(); + + echo "Creating a post.\n"; + $this->createPost('Hello, world!', 'I am on the intarweb!', False); + + echo "Creating a draft post.\n"; + $postID = $this->createPost('Salutations, world!', 'Does not sound right.. must work on title.', True); + + echo "Updating the previous post and publishing it.\n"; + $updatedPost = $this->updatePost($postID, 'Hello, world, it is.', 'There we go.', False); + echo "The new title of the post is: " . $updatedPost->title->text . "\n"; + echo "The new body of the post is: " . $updatedPost->content->text . "\n"; + + echo "Adding a comment to the previous post.\n"; + $this->createComment($postID, 'I am so glad this is public now.'); + + echo "Adding another comment.\n"; + $commentID = $this->createComment($postID, 'This is a spammy comment.'); + + echo "Deleting the previous comment.\n"; + $this->deleteComment($postID, $commentID); + + echo "Printing all posts.\n"; + $this->printAllPosts(); + + echo "Printing posts between 2007-01-01 and 2007-03-01.\n"; + $this->printPostsInDateRange('2007-01-01','2007-06-30'); + + echo "Deleting the post titled: " . $updatedPost->title->text . "\n"; + $this->deletePost($postID); + } +} + +/** + * Gets credentials from user. + * + * @param string $text + * @return string Index of the blog the user has chosen. + */ +function getInput($text) +{ + echo $text.': '; + return trim(fgets(STDIN)); +} + +$user = null; +$pass = null; + +// process command line options +foreach ($argv as $argument) { + $argParts = explode('=', $argument); + if ($argParts[0] == '--user') { + $user = $argParts[1]; + } else if ($argParts[0] == '--pass') { + $pass = $argParts[1]; + } +} + +if (($user == null) || ($pass == null)) { + exit("php Blogger.php --user=[username] --pass=[password]\n"); +} + +$sample = new SimpleCRUD($user, $pass); +$sample->run(); diff --git a/zend/demos/Zend/Gdata/BooksBrowser/books_browser.css b/zend/demos/Zend/Gdata/BooksBrowser/books_browser.css new file mode 100755 index 0000000..6ad2bbe --- /dev/null +++ b/zend/demos/Zend/Gdata/BooksBrowser/books_browser.css @@ -0,0 +1,136 @@ +body { + background-color: white; + color: black; + font-family: Arial, sans-serif; + font-size: small; + margin: 8px; + margin-top: 3px; +} + +.thumbnail img { + border-color:black; + border-width:1; + border-style:solid; +} + +table { + border-collapse: collapse; +} + +th, td { + padding: 0; + vertical-align: top; + text-align: left; + font-size: small; +} + +a:link { + color: #0000cc; +} + +a:active { + color: #cc0000; +} + +a:visited { + color: #551a8b; +} + +h1 { + font-size: x-large; + margin-top: 0px; + margin-bottom: 5px; +} + +h2 { + font-size: large; +} + +form { + display: inline; + margin: 0; + padding: 0; +} + +.volumeList td { + padding-bottom: 5px; + padding-right: 5px; +} + +#titleBar { + border: 1px solid silver; + background-color: #e5ecf9; + font-size: large; + font-weight: bold; + margin: 0; + padding: 0; + padding-top: 5px; + padding-bottom: 10px; + padding-left: 10px; + padding-right: 10px; + margin-top: 5px; + margin-bottom: 15px; +} + +#titleText { + float: left; +} + +#mainSearchBox { + background-color: #e5ecf9; + border: 1px solid silver; + width: 300; + padding-top: 5px; + padding-bottom: 10px; + padding-left: 10px; + padding-right: 10px; +} + +#searchResults { + width: 100%; +} + +.volumeList td +{ + border-top: 1px solid #aaaaaa; + padding: 6px; +} + +.thumbnail +{ + height: 80px; + padding: 3px; +} + +.previewbutton +{ + border: 0px; + margin: 6px 0px 6px 0px; +} + +#resultcell +{ + padding-right: 20px; +} + +#previewcell +{ + border-left: 1px dotted #aaa; + padding-left: 20px; + display: none; + padding-right: 20px; +} + +#viewport { + height: 500px; + width: 100%; + border: 1px solid #aaa; + +} + +/* Google Preview: Boilerplate styling */ +#viewport { font-size: 16px; line-height: 1; } +#viewport img, #viewport table, #viewport div, #viewport td +{ border: 0; padding: 0; margin: 0; background: none } +#viewport td { vertical-align: middle } + diff --git a/zend/demos/Zend/Gdata/BooksBrowser/index.php b/zend/demos/Zend/Gdata/BooksBrowser/index.php new file mode 100755 index 0000000..8d5e9ad --- /dev/null +++ b/zend/demos/Zend/Gdata/BooksBrowser/index.php @@ -0,0 +1,155 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Loader + */ +require_once 'Zend/Loader.php'; + +/** + * @see Zend_Gdata_Books + */ +Zend_Loader::loadClass('Zend_Gdata_Books'); + +/** + * Return a comma separated string representing the elements of an array + * + * @param Array $elements The array of elements + * @return string Comma separated string + */ +function printArray($elements) { + $result = ''; + foreach ($elements as $element) { + if (!empty($result)) $result = $result.', '; + $result = $result.$element; + } + return $result; +} + + +/** + * Echo the list of videos in the specified feed. + * + * @param Zend_Gdata_Books_BookFeed $feed The video feed + * @return void + */ +function echoBookList($feed) +{ + print <<<HTML + <table><tr><td id="resultcell"> + <div id="searchResults"> + <table class="volumeList"><tbody width="100%"> +HTML; + $flipflop = false; + foreach ($feed as $entry) { + $title = printArray($entry->getTitles()); + $volumeId = $entry->getVolumeId(); + if ($thumbnailLink = $entry->getThumbnailLink()) { + $thumbnail = $thumbnailLink->href; + } else { + $thumbnail = null; + } + $preview = $entry->getPreviewLink()->href; + $embeddability = $entry->getEmbeddability()->getValue(); + $creators = printArray($entry->getCreators()); + if (!empty($creators)) $creators = "by " . $creators; + if ($embeddability == + "http://schemas.google.com/books/2008#embeddable") { + $preview_link = '<a href="javascript:load_viewport(\''. + $preview.'\',\'viewport\');">'. + '<img class="previewbutton" src="http://code.google.com/' . + 'apis/books/images/gbs_preview_button1.png" />' . + '</a><br>'; + } else { + $preview_link = ''; + } + $thumbnail_img = (!$thumbnail) ? '' : '<a href="'.$preview. + '"><img src="'.$thumbnail.'"/></a>'; + + print <<<HTML + <tr> + <td><div class="thumbnail"> + $thumbnail_img + </div></td> + <td width="100%"> + <a href="${preview}">$title</a><br> + $creators<br> + $preview_link + </td></tr> +HTML; + } + print <<<HTML + </table></div></td> + <td width=50% id="previewcell"><div id="viewport"></div> + </td></tr></table><br></body></html> +HTML; +} + +/* + * The main controller logic of the Books volume browser demonstration app. + */ +$queryType = isset($_GET['queryType']) ? $_GET['queryType'] : null; + +include 'interface.html'; + +if ($queryType === null) { + /* display the entire interface */ +} else { + $books = new Zend_Gdata_Books(); + $query = $books->newVolumeQuery(); + + /* display a list of volumes */ + if (isset($_GET['searchTerm'])) { + $searchTerm = $_GET['searchTerm']; + $query->setQuery($searchTerm); + } + if (isset($_GET['startIndex'])) { + $startIndex = $_GET['startIndex']; + $query->setStartIndex($startIndex); + } + if (isset($_GET['maxResults'])) { + $maxResults = $_GET['maxResults']; + $query->setMaxResults($maxResults); + } + if (isset($_GET['minViewability'])) { + $minViewability = $_GET['minViewability']; + $query->setMinViewability($minViewability); + } + + /* check for one of the restricted feeds, or list from 'all' videos */ + switch ($queryType) { + case 'full_view': + case 'partial_view': + $query->setMinViewability($queryType); + echo 'Requesting feed: ' . ($query->getQueryUrl()) . '<br><br>'; + $feed = $books->getVolumeFeed($query); + break; + case 'all': + echo 'Requesting feed: ' . ($query->getQueryUrl()) . '<br><br>'; + $feed = $books->getVolumeFeed($query); + break; + default: + echo 'ERROR - unknown queryType - "' . $queryType . '"'; + break; + } + echoBookList($feed); +} + diff --git a/zend/demos/Zend/Gdata/BooksBrowser/interface.html b/zend/demos/Zend/Gdata/BooksBrowser/interface.html new file mode 100644 index 0000000..55530c9 --- /dev/null +++ b/zend/demos/Zend/Gdata/BooksBrowser/interface.html @@ -0,0 +1,81 @@ +<!--- +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * + */ +--> +<html> +<head> + <title>Books Data API Browser in PHP</title> + <link href="books_browser.css" type="text/css" rel="stylesheet"/> + <script type="text/javascript" src="http://www.google.com/jsapi"> + </script> + <script type="text/javascript"> + function load_viewport(identifier, viewport_div_id) { + var viewport_div = document.getElementById(viewport_div_id); + var rightpane_div = viewport_div.parentNode; + rightpane_div.style.display = 'table-cell'; + viewport_div.innerHTML = 'Loading...'; + + var viewer = new google.books.DefaultViewer(viewport_div); + viewer.load(identifier, handle_not_found); + } + + function on_load() { + } + + function handle_not_found() { + var viewport_div = document.getElementById(viewport_div_id); + viewport_div.parentNode.style.display = 'none'; + } + + google.load('books', '0'); + google.setOnLoadCallback(on_load); + </script> + +</head> +<body> + <script> + </script> +<div id="titleBar"> + <div id="titleText"><h1>Books Data API Browser in PHP</h1></div> + <br /> +</div> +<br clear="all" /> +<div id="mainSearchBox"> + <h2>Search Books:</h2> + <form id="mainSearchForm" action="index.php"> + <select name="queryType"> + <option value="all" selected="true">All Books</option> + <option value="partial_view">Limited preview and full view</option> + <option value="full_view">Full view books only</option> + </select> + <input name="maxResults" type="hidden" value="6"> + <input name="searchTerm" type="text" value=""> + <input type="submit" value="Search"> + <a href="http://www.google.com"><img + src="http://books.google.com/googlebooks/images/poweredby.png" + border="0" width="62" height="30" align="absbottom" + style="position:relative; top: 6px; padding-left: 10px"></a> + </form> +</div> +<br> +<br clear="all" /> + + diff --git a/zend/demos/Zend/Gdata/Calendar.php b/zend/demos/Zend/Gdata/Calendar.php new file mode 100644 index 0000000..1094343 --- /dev/null +++ b/zend/demos/Zend/Gdata/Calendar.php @@ -0,0 +1,841 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * PHP sample code for the Google Calendar data API. Utilizes the + * Zend Framework Gdata components to communicate with the Google API. + * + * Requires the Zend Framework Gdata components and PHP >= 5.2.11 + * + * You can run this sample both from the command line (CLI) and also + * from a web browser. When running through a web browser, only + * AuthSub and outputting a list of calendars is demonstrated. When + * running via CLI, all functionality except AuthSub is available and dependent + * upon the command line options passed. Run this script without any + * command line options to see usage, eg: + * /usr/local/bin/php -f Calendar.php + * + * More information on the Command Line Interface is available at: + * http://www.php.net/features.commandline + * + * NOTE: You must ensure that the Zend Framework is in your PHP include + * path. You can do this via php.ini settings, or by modifying the + * argument to set_include_path in the code below. + * + * NOTE: As this is sample code, not all of the functions do full error + * handling. Please see getEvent for an example of how errors could + * be handled and the online code samples for additional information. + */ + +/** + * @see Zend_Loader + */ +require_once 'Zend/Loader.php'; + +/** + * @see Zend_Gdata + */ +Zend_Loader::loadClass('Zend_Gdata'); + +/** + * @see Zend_Gdata_AuthSub + */ +Zend_Loader::loadClass('Zend_Gdata_AuthSub'); + +/** + * @see Zend_Gdata_ClientLogin + */ +Zend_Loader::loadClass('Zend_Gdata_ClientLogin'); + +/** + * @see Zend_Gdata_HttpClient + */ +Zend_Loader::loadClass('Zend_Gdata_HttpClient'); + +/** + * @see Zend_Gdata_Calendar + */ +Zend_Loader::loadClass('Zend_Gdata_Calendar'); + +/** + * @var string Location of AuthSub key file. include_path is used to find this + */ +$_authSubKeyFile = null; // Example value for secure use: 'mykey.pem' + +/** + * @var string Passphrase for AuthSub key file. + */ +$_authSubKeyFilePassphrase = null; + +/** + * Returns the full URL of the current page, based upon env variables + * + * Env variables used: + * $_SERVER['HTTPS'] = (on|off|) + * $_SERVER['HTTP_HOST'] = value of the Host: header + * $_SERVER['SERVER_PORT'] = port number (only used if not http/80,https/443) + * $_SERVER['REQUEST_URI'] = the URI after the method of the HTTP request + * + * @return string Current URL + */ +function getCurrentUrl() +{ + global $_SERVER; + + /** + * Filter php_self to avoid a security vulnerability. + */ + $php_request_uri = htmlentities(substr($_SERVER['REQUEST_URI'], 0, strcspn($_SERVER['REQUEST_URI'], "\n\r")), ENT_QUOTES); + + if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') { + $protocol = 'https://'; + } else { + $protocol = 'http://'; + } + $host = $_SERVER['HTTP_HOST']; + if ($_SERVER['SERVER_PORT'] != '' && + (($protocol == 'http://' && $_SERVER['SERVER_PORT'] != '80') || + ($protocol == 'https://' && $_SERVER['SERVER_PORT'] != '443'))) { + $port = ':' . $_SERVER['SERVER_PORT']; + } else { + $port = ''; + } + return $protocol . $host . $port . $php_request_uri; +} + +/** + * Returns the AuthSub URL which the user must visit to authenticate requests + * from this application. + * + * Uses getCurrentUrl() to get the next URL which the user will be redirected + * to after successfully authenticating with the Google service. + * + * @return string AuthSub URL + */ +function getAuthSubUrl() +{ + global $_authSubKeyFile; + $next = getCurrentUrl(); + $scope = 'http://www.google.com/calendar/feeds/'; + $session = true; + if ($_authSubKeyFile != null) { + $secure = true; + } else { + $secure = false; + } + return Zend_Gdata_AuthSub::getAuthSubTokenUri($next, $scope, $secure, + $session); +} + +/** + * Outputs a request to the user to login to their Google account, including + * a link to the AuthSub URL. + * + * Uses getAuthSubUrl() to get the URL which the user must visit to authenticate + * + * @return void + */ +function requestUserLogin($linkText) +{ + $authSubUrl = getAuthSubUrl(); + echo "<a href=\"{$authSubUrl}\">{$linkText}</a>"; +} + +/** + * Returns a HTTP client object with the appropriate headers for communicating + * with Google using AuthSub authentication. + * + * Uses the $_SESSION['sessionToken'] to store the AuthSub session token after + * it is obtained. The single use token supplied in the URL when redirected + * after the user succesfully authenticated to Google is retrieved from the + * $_GET['token'] variable. + * + * @return Zend_Http_Client + */ +function getAuthSubHttpClient() +{ + global $_SESSION, $_GET, $_authSubKeyFile, $_authSubKeyFilePassphrase; + $client = new Zend_Gdata_HttpClient(); + if ($_authSubKeyFile != null) { + // set the AuthSub key + $client->setAuthSubPrivateKeyFile($_authSubKeyFile, $_authSubKeyFilePassphrase, true); + } + if (!isset($_SESSION['sessionToken']) && isset($_GET['token'])) { + $_SESSION['sessionToken'] = + Zend_Gdata_AuthSub::getAuthSubSessionToken($_GET['token'], $client); + } + $client->setAuthSubToken($_SESSION['sessionToken']); + return $client; +} + +/** + * Processes loading of this sample code through a web browser. Uses AuthSub + * authentication and outputs a list of a user's calendars if succesfully + * authenticated. + * + * @return void + */ +function processPageLoad() +{ + global $_SESSION, $_GET; + if (!isset($_SESSION['sessionToken']) && !isset($_GET['token'])) { + requestUserLogin('Please login to your Google Account.'); + } else { + $client = getAuthSubHttpClient(); + outputCalendarList($client); + } +} + +/** + * Returns a HTTP client object with the appropriate headers for communicating + * with Google using the ClientLogin credentials supplied. + * + * @param string $user The username, in e-mail address format, to authenticate + * @param string $pass The password for the user specified + * @return Zend_Http_Client + */ +function getClientLoginHttpClient($user, $pass) +{ + $service = Zend_Gdata_Calendar::AUTH_SERVICE_NAME; + + $client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service); + return $client; +} + +/** + * Outputs an HTML unordered list (ul), with each list item representing an event + * in the user's calendar. The calendar is retrieved using the magic cookie + * which allows read-only access to private calendar data using a special token + * available from within the Calendar UI. + * + * @param string $user The username or address of the calendar to be retrieved. + * @param string $magicCookie The magic cookie token + * @return void + */ +function outputCalendarMagicCookie($user, $magicCookie) +{ + $gdataCal = new Zend_Gdata_Calendar(); + $query = $gdataCal->newEventQuery(); + $query->setUser($user); + $query->setVisibility('private-' . $magicCookie); + $query->setProjection('full'); + $eventFeed = $gdataCal->getCalendarEventFeed($query); + echo "<ul>\n"; + foreach ($eventFeed as $event) { + echo "\t<li>" . $event->title->text . "</li>\n"; + $sl = $event->getLink('self')->href; + } + echo "</ul>\n"; +} + +/** + * Outputs an HTML unordered list (ul), with each list item representing a + * calendar in the authenticated user's calendar list. + * + * @param Zend_Http_Client $client The authenticated client object + * @return void + */ +function outputCalendarList($client) +{ + $gdataCal = new Zend_Gdata_Calendar($client); + $calFeed = $gdataCal->getCalendarListFeed(); + echo "<h1>" . $calFeed->title->text . "</h1>\n"; + echo "<ul>\n"; + foreach ($calFeed as $calendar) { + echo "\t<li>" . $calendar->title->text . "</li>\n"; + } + echo "</ul>\n"; +} + +/** + * Outputs an HTML unordered list (ul), with each list item representing an + * event on the authenticated user's calendar. Includes the start time and + * event ID in the output. Events are ordered by starttime and include only + * events occurring in the future. + * + * @param Zend_Http_Client $client The authenticated client object + * @return void + */ +function outputCalendar($client) +{ + $gdataCal = new Zend_Gdata_Calendar($client); + $query = $gdataCal->newEventQuery(); + $query->setUser('default'); + $query->setVisibility('private'); + $query->setProjection('full'); + $query->setOrderby('starttime'); + $query->setFutureevents(true); + $eventFeed = $gdataCal->getCalendarEventFeed($query); + // option 2 + // $eventFeed = $gdataCal->getCalendarEventFeed($query->getQueryUrl()); + echo "<ul>\n"; + foreach ($eventFeed as $event) { + echo "\t<li>" . $event->title->text . " (" . $event->id->text . ")\n"; + // Zend_Gdata_App_Extensions_Title->__toString() is defined, so the + // following will also work on PHP >= 5.2.0 + //echo "\t<li>" . $event->title . " (" . $event->id . ")\n"; + echo "\t\t<ul>\n"; + foreach ($event->when as $when) { + echo "\t\t\t<li>Starts: " . $when->startTime . "</li>\n"; + } + echo "\t\t</ul>\n"; + echo "\t</li>\n"; + } + echo "</ul>\n"; +} + +/** + * Outputs an HTML unordered list (ul), with each list item representing an + * event on the authenticated user's calendar which occurs during the + * specified date range. + * + * To query for all events occurring on 2006-12-24, you would query for + * a startDate of '2006-12-24' and an endDate of '2006-12-25' as the upper + * bound for date queries is exclusive. See the 'query parameters reference': + * http://code.google.com/apis/gdata/calendar.html#Parameters + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $startDate The start date in YYYY-MM-DD format + * @param string $endDate The end date in YYYY-MM-DD format + * @return void + */ +function outputCalendarByDateRange($client, $startDate='2007-05-01', + $endDate='2007-08-01') +{ + $gdataCal = new Zend_Gdata_Calendar($client); + $query = $gdataCal->newEventQuery(); + $query->setUser('default'); + $query->setVisibility('private'); + $query->setProjection('full'); + $query->setOrderby('starttime'); + $query->setStartMin($startDate); + $query->setStartMax($endDate); + $eventFeed = $gdataCal->getCalendarEventFeed($query); + echo "<ul>\n"; + foreach ($eventFeed as $event) { + echo "\t<li>" . $event->title->text . " (" . $event->id->text . ")\n"; + echo "\t\t<ul>\n"; + foreach ($event->when as $when) { + echo "\t\t\t<li>Starts: " . $when->startTime . "</li>\n"; + } + echo "\t\t</ul>\n"; + echo "\t</li>\n"; + } + echo "</ul>\n"; +} + +/** + * Outputs an HTML unordered list (ul), with each list item representing an + * event on the authenticated user's calendar which matches the search string + * specified as the $fullTextQuery parameter + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $fullTextQuery The string for which you are searching + * @return void + */ +function outputCalendarByFullTextQuery($client, $fullTextQuery='tennis') +{ + $gdataCal = new Zend_Gdata_Calendar($client); + $query = $gdataCal->newEventQuery(); + $query->setUser('default'); + $query->setVisibility('private'); + $query->setProjection('full'); + $query->setQuery($fullTextQuery); + $eventFeed = $gdataCal->getCalendarEventFeed($query); + echo "<ul>\n"; + foreach ($eventFeed as $event) { + echo "\t<li>" . $event->title->text . " (" . $event->id->text . ")\n"; + echo "\t\t<ul>\n"; + foreach ($event->when as $when) { + echo "\t\t\t<li>Starts: " . $when->startTime . "</li>\n"; + echo "\t\t</ul>\n"; + echo "\t</li>\n"; + } + } + echo "</ul>\n"; +} + +/** + * Creates an event on the authenticated user's default calendar with the + * specified event details. + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $title The event title + * @param string $desc The detailed description of the event + * @param string $where + * @param string $startDate The start date of the event in YYYY-MM-DD format + * @param string $startTime The start time of the event in HH:MM 24hr format + * @param string $endDate The end date of the event in YYYY-MM-DD format + * @param string $endTime The end time of the event in HH:MM 24hr format + * @param string $tzOffset The offset from GMT/UTC in [+-]DD format (eg -08) + * @return string The ID URL for the event. + */ +function createEvent ($client, $title = 'Tennis with Beth', + $desc='Meet for a quick lesson', $where = 'On the courts', + $startDate = '2008-01-20', $startTime = '10:00', + $endDate = '2008-01-20', $endTime = '11:00', $tzOffset = '-08') +{ + $gc = new Zend_Gdata_Calendar($client); + $newEntry = $gc->newEventEntry(); + $newEntry->title = $gc->newTitle(trim($title)); + $newEntry->where = array($gc->newWhere($where)); + + $newEntry->content = $gc->newContent($desc); + $newEntry->content->type = 'text'; + + $when = $gc->newWhen(); + $when->startTime = "{$startDate}T{$startTime}:00.000{$tzOffset}:00"; + $when->endTime = "{$endDate}T{$endTime}:00.000{$tzOffset}:00"; + $newEntry->when = array($when); + + $createdEntry = $gc->insertEvent($newEntry); + return $createdEntry->id->text; +} + +/** + * Creates an event on the authenticated user's default calendar using + * the specified QuickAdd string. + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $quickAddText The QuickAdd text for the event + * @return string The ID URL for the event + */ +function createQuickAddEvent ($client, $quickAddText) { + $gdataCal = new Zend_Gdata_Calendar($client); + $event = $gdataCal->newEventEntry(); + $event->content = $gdataCal->newContent($quickAddText); + $event->quickAdd = $gdataCal->newQuickAdd(true); + + $newEvent = $gdataCal->insertEvent($event); + return $newEvent->id->text; +} + +/** + * Creates a new web content event on the authenticated user's default + * calendar with the specified event details. For simplicity, the event + * is created as an all day event and does not include a description. + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $title The event title + * @param string $startDate The start date of the event in YYYY-MM-DD format + * @param string $endDate The end time of the event in HH:MM 24hr format + * @param string $icon URL pointing to a 16x16 px icon representing the event. + * @param string $url The URL containing the web content for the event. + * @param string $height The desired height of the web content pane. + * @param string $width The desired width of the web content pane. + * @param string $type The MIME type of the web content. + * @return string The ID URL for the event. + */ +function createWebContentEvent ($client, $title = 'World Cup 2006', + $startDate = '2006-06-09', $endDate = '2006-06-09', + $icon = 'http://www.google.com/calendar/images/google-holiday.gif', + $url = 'http://www.google.com/logos/worldcup06.gif', + $height = '120', $width = '276', $type = 'image/gif' + ) +{ + $gc = new Zend_Gdata_Calendar($client); + $newEntry = $gc->newEventEntry(); + $newEntry->title = $gc->newTitle(trim($title)); + + $when = $gc->newWhen(); + $when->startTime = $startDate; + $when->endTime = $endDate; + $newEntry->when = array($when); + + $wc = $gc->newWebContent(); + $wc->url = $url; + $wc->height = $height; + $wc->width = $width; + + $wcLink = $gc->newLink(); + $wcLink->rel = "http://schemas.google.com/gCal/2005/webContent"; + $wcLink->title = $title; + $wcLink->type = $type; + $wcLink->href = $icon; + + $wcLink->webContent = $wc; + $newEntry->link = array($wcLink); + + $createdEntry = $gc->insertEvent($newEntry); + return $createdEntry->id->text; +} + +/** + * Creates a recurring event on the authenticated user's default calendar with + * the specified event details. + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $title The event title + * @param string $desc The detailed description of the event + * @param string $where + * @param string $recurData The iCalendar recurring event syntax (RFC2445) + * @return void + */ +function createRecurringEvent ($client, $title = 'Tennis with Beth', + $desc='Meet for a quick lesson', $where = 'On the courts', + $recurData = null) +{ + $gc = new Zend_Gdata_Calendar($client); + $newEntry = $gc->newEventEntry(); + $newEntry->title = $gc->newTitle(trim($title)); + $newEntry->where = array($gc->newWhere($where)); + + $newEntry->content = $gc->newContent($desc); + $newEntry->content->type = 'text'; + + /** + * Due to the length of this recurrence syntax, we did not specify + * it as a default parameter value directly + */ + if ($recurData == null) { + $recurData = + "DTSTART;VALUE=DATE:20070501\r\n" . + "DTEND;VALUE=DATE:20070502\r\n" . + "RRULE:FREQ=WEEKLY;BYDAY=Tu;UNTIL=20070904\r\n"; + } + + $newEntry->recurrence = $gc->newRecurrence($recurData); + + $gc->post($newEntry->saveXML()); +} + +/** + * Returns an entry object representing the event with the specified ID. + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $eventId The event ID string + * @return Zend_Gdata_Calendar_EventEntry|null if the event is found, null if it's not + */ +function getEvent($client, $eventId) +{ + $gdataCal = new Zend_Gdata_Calendar($client); + $query = $gdataCal->newEventQuery(); + $query->setUser('default'); + $query->setVisibility('private'); + $query->setProjection('full'); + $query->setEvent($eventId); + + try { + $eventEntry = $gdataCal->getCalendarEventEntry($query); + return $eventEntry; + } catch (Zend_Gdata_App_Exception $e) { + var_dump($e); + return null; + } +} + +/** + * Updates the title of the event with the specified ID to be + * the title specified. Also outputs the new and old title + * with HTML br elements separating the lines + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $eventId The event ID string + * @param string $newTitle The new title to set on this event + * @return Zend_Gdata_Calendar_EventEntry|null The updated entry + */ +function updateEvent ($client, $eventId, $newTitle) +{ + $gdataCal = new Zend_Gdata_Calendar($client); + if ($eventOld = getEvent($client, $eventId)) { + echo "Old title: " . $eventOld->title->text . "<br />\n"; + $eventOld->title = $gdataCal->newTitle($newTitle); + try { + $eventOld->save(); + } catch (Zend_Gdata_App_Exception $e) { + var_dump($e); + return null; + } + $eventNew = getEvent($client, $eventId); + echo "New title: " . $eventNew->title->text . "<br />\n"; + return $eventNew; + } else { + return null; + } +} + +/** + * Adds an extended property to the event specified as a parameter. + * An extended property is an arbitrary name/value pair that can be added + * to an event and retrieved via the API. It is not accessible from the + * calendar web interface. + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $eventId The event ID string + * @param string $name The name of the extended property + * @param string $value The value of the extended property + * @return Zend_Gdata_Calendar_EventEntry|null The updated entry + */ +function addExtendedProperty ($client, $eventId, + $name='http://www.example.com/schemas/2005#mycal.id', $value='1234') +{ + $gc = new Zend_Gdata_Calendar($client); + if ($event = getEvent($client, $eventId)) { + $extProp = $gc->newExtendedProperty($name, $value); + $extProps = array_merge($event->extendedProperty, array($extProp)); + $event->extendedProperty = $extProps; + $eventNew = $event->save(); + return $eventNew; + } else { + return null; + } +} + + +/** + * Adds a reminder to the event specified as a parameter. + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $eventId The event ID string + * @param integer $minutes Minutes before event to set reminder + * @return Zend_Gdata_Calendar_EventEntry|null The updated entry + */ +function setReminder($client, $eventId, $minutes=15) +{ + $gc = new Zend_Gdata_Calendar($client); + $method = "alert"; + if ($event = getEvent($client, $eventId)) { + $times = $event->when; + foreach ($times as $when) { + $reminder = $gc->newReminder(); + $reminder->setMinutes($minutes); + $reminder->setMethod($method); + $when->reminders = array($reminder); + } + $eventNew = $event->save(); + return $eventNew; + } else { + return null; + } +} + +/** + * Deletes the event specified by retrieving the atom entry object + * and calling Zend_Feed_EntryAtom::delete() method. This is for + * example purposes only, as it is inefficient to retrieve the entire + * atom entry only for the purposes of deleting it. + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $eventId The event ID string + * @return void + */ +function deleteEventById ($client, $eventId) +{ + $event = getEvent($client, $eventId); + $event->delete(); +} + +/** + * Deletes the event specified by calling the Zend_Gdata::delete() + * method. The URL is typically in the format of: + * http://www.google.com/calendar/feeds/default/private/full/<eventId> + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $url The url for the event to be deleted + * @return void + */ +function deleteEventByUrl ($client, $url) +{ + $gdataCal = new Zend_Gdata_Calendar($client); + $gdataCal->delete($url); +} + +/** + * Main logic for running this sample code via the command line or, + * for AuthSub functionality only, via a web browser. The output of + * many of the functions is in HTML format for demonstration purposes, + * so you may wish to pipe the output to Tidy when running from the + * command-line for clearer results. + * + * Run without any arguments to get usage information + */ +if (isset($argc) && $argc >= 2) { + switch ($argv[1]) { + case 'outputCalendar': + if ($argc == 4) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + outputCalendar($client); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} " . + "<username> <password>\n"; + } + break; + case 'outputCalendarMagicCookie': + if ($argc == 4) { + outputCalendarMagicCookie($argv[2], $argv[3]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} " . + "<username> <magicCookie>\n"; + } + break; + case 'outputCalendarByDateRange': + if ($argc == 6) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + outputCalendarByDateRange($client, $argv[4], $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} " . + "<username> <password> <startDate> <endDate>\n"; + } + break; + case 'outputCalendarByFullTextQuery': + if ($argc == 5) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + outputCalendarByFullTextQuery($client, $argv[4]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} " . + "<username> <password> <fullTextQuery>\n"; + } + break; + case 'outputCalendarList': + if ($argc == 4) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + outputCalendarList($client); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} " . + "<username> <password>\n"; + } + break; + case 'updateEvent': + if ($argc == 6) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + updateEvent($client, $argv[4], $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <password> " . + "<eventId> <newTitle>\n"; + } + break; + case 'setReminder': + if ($argc == 6) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + setReminder($client, $argv[4], $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <password> " . + "<eventId> <minutes>\n"; + } + break; + case 'addExtendedProperty': + if ($argc == 7) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + addExtendedProperty($client, $argv[4], $argv[5], $argv[6]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <password> " . + "<eventId> <name> <value>\n"; + } + break; + case 'deleteEventById': + if ($argc == 5) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + deleteEventById($client, $argv[4]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <password> " . + "<eventId>\n"; + } + break; + case 'deleteEventByUrl': + if ($argc == 5) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + deleteEventByUrl($client, $argv[4]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <password> " . + "<eventUrl>\n"; + } + break; + case 'createEvent': + if ($argc == 12) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + $id = createEvent($client, $argv[4], $argv[5], $argv[6], $argv[7], + $argv[8], $argv[9], $argv[10], $argv[11]); + print "Event created with ID: $id\n"; + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <password> " . + "<title> <description> <where> " . + "<startDate> <startTime> <endDate> <endTime> <tzOffset>\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <password> " . + "'Tennis with Beth' 'Meet for a quick lesson' 'On the courts' " . + "'2008-01-01' '10:00' '2008-01-01' '11:00' '-08'\n"; + } + break; + case 'createQuickAddEvent': + if ($argc == 5) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + $id = createQuickAddEvent($client, $argv[4]); + print "Event created with ID: $id\n"; + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <password> " . + "<quickAddText>\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <password> " . + "'Dinner at the beach on Thursday 8 PM'\n"; + } + break; + case 'createWebContentEvent': + if ($argc == 12) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + $id = createWebContentEvent($client, $argv[4], $argv[5], $argv[6], + $argv[7], $argv[8], $argv[9], $argv[10], $argv[11]); + print "Event created with ID: $id\n"; + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <password> " . + "<title> <startDate> <endDate> <icon> <url> <height> <width> <type>\n\n"; + echo "This creates a web content event on 2007/06/09.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <password> " . + "'World Cup 2006' '2007-06-09' '2007-06-10' " . + "'http://www.google.com/calendar/images/google-holiday.gif' " . + "'http://www.google.com/logos/worldcup06.gif' " . + "'120' '276' 'image/gif'\n"; + } + break; + case 'createRecurringEvent': + if ($argc == 7) { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + createRecurringEvent($client, $argv[4], $argv[5], $argv[6]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <password> " . + "<title> <description> <where>\n\n"; + echo "This creates an all-day event which occurs first on 2007/05/01" . + "and repeats weekly on Tuesdays until 2007/09/04\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <password> " . + "'Tennis with Beth' 'Meet for a quick lesson' 'On the courts'\n"; + } + break; + } +} else if (!isset($_SERVER["HTTP_HOST"])) { + // running from command line, but action left unspecified + echo "Usage: php {$argv[0]} <action> [<username>] [<password>] " . + "[<arg1> <arg2> ...]\n\n"; + echo "Possible action values include:\n" . + "outputCalendar\n" . + "outputCalendarMagicCookie\n" . + "outputCalendarByDateRange\n" . + "outputCalendarByFullTextQuery\n" . + "outputCalendarList\n" . + "updateEvent\n" . + "deleteEventById\n" . + "deleteEventByUrl\n" . + "createEvent\n" . + "createQuickAddEvent\n" . + "createWebContentEvent\n" . + "createRecurringEvent\n" . + "setReminder\n" . + "addExtendedProperty\n"; +} else { + // running through web server - demonstrate AuthSub + processPageLoad(); +} diff --git a/zend/demos/Zend/Gdata/Docs.php b/zend/demos/Zend/Gdata/Docs.php new file mode 100755 index 0000000..2d61ecc --- /dev/null +++ b/zend/demos/Zend/Gdata/Docs.php @@ -0,0 +1,940 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * PHP sample code for the Google Documents List data API. Utilizes the + * Zend Framework Gdata components to communicate with the Google API. + * + * Requires the Zend Framework Gdata components and PHP >= 5.2.11 + * + * You can run this sample both from the command line (CLI) and also + * from a web browser. When running through a web browser, only + * AuthSub and outputting a list of documents is demonstrated. When + * running via CLI, all functionality except AuthSub is available and dependent + * upon the command line options passed. Run this script without any + * command line options to see usage, eg: + * /usr/local/bin/php -f Docs.php + * + * More information on the Command Line Interface is available at: + * http://www.php.net/features.commandline + * + * NOTE: You must ensure that Zend Framework is in your PHP include + * path. You can do this via php.ini settings, or by modifying the + * argument to set_include_path in the code below. + * + * NOTE: As this is sample code, not all of the functions do full error + * handling. + */ + +/** + * @see Zend_Loader + */ +require_once 'Zend/Loader.php'; + +/** + * @see Zend_Gdata + */ +Zend_Loader::loadClass('Zend_Gdata'); + +/** + * @see Zend_Gdata_AuthSub + */ +Zend_Loader::loadClass('Zend_Gdata_AuthSub'); + +/** + * @see Zend_Gdata_ClientLogin + */ +Zend_Loader::loadClass('Zend_Gdata_ClientLogin'); + +/** + * @see Zend_Gdata_Docs + */ +Zend_Loader::loadClass('Zend_Gdata_Docs'); + +/** + * Returns a HTTP client object with the appropriate headers for communicating + * with Google using the ClientLogin credentials supplied. + * + * @param string $user The username, in e-mail address format, to authenticate + * @param string $pass The password for the user specified + * @return Zend_Http_Client + */ +function getClientLoginHttpClient($user, $pass) +{ + $service = Zend_Gdata_Docs::AUTH_SERVICE_NAME; + $client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service); + return $client; +} + +// ************************ BEGIN CLI SPECIFIC CODE ************************ + +/** + * Display list of valid commands. + * + * @param string $executable The name of the current script. This is usually available as $argv[0]. + * @return void + */ +function displayHelp($executable) +{ + echo "Usage: php {$executable} <action> [<username>] [<password>] " . + "[<arg1> <arg2> ...]\n\n"; + echo "Possible action values include:\n" . + "retrieveAllDocuments\n" . + "retrieveWPDocs\n" . + "retrieveSpreadsheets\n" . + "fullTextSearch\n" . + "uploadDocument\n"; +} + +/** + * Parse command line arguments and execute appropriate function when + * running from the command line. + * + * If no arguments are provided, usage information will be provided. + * + * @param array $argv The array of command line arguments provided by PHP. + * $argv[0] should be the current executable name or '-' if not available. + * @param integer $argc The size of $argv. + * @return void + */ +function runCLIVersion($argv, $argc) +{ + if (isset($argc) && $argc >= 2) { + # Prepare a server connection + if ($argc >= 4) { + try { + $client = getClientLoginHttpClient($argv[2], $argv[3]); + $docs = new Zend_Gdata_Docs($client); + } catch (Zend_Gdata_App_AuthException $e) { + echo "Error: Unable to authenticate. Please check your"; + echo " credentials.\n"; + exit(1); + } + } + + # Dispatch arguments to the desired method + switch ($argv[1]) { + case 'retrieveAllDocuments': + if ($argc >= 4) { + retrieveAllDocuments($docs, false); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username>"; + echo " <password>\n\n"; + echo "This lists all of the documents in the user's"; + echo " account.\n"; + } + break; + case 'retrieveWPDocs': + if ($argc >= 4) { + //echo "!WP Docs:"; + //var_dump($docs); + retrieveWPDocs($docs, false); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username>"; + echo " <password>\n\n"; + echo "This lists all of the word processing documents in"; + echo " the user's account.\n"; + } + break; + case 'retrieveSpreadsheets': + if ($argc >= 4) { + retrieveAllDocuments($docs, false); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username>"; + echo " <password>\n\n"; + echo "This lists all of the spreadsheets in the user's"; + echo " account.\n"; + } + break; + case 'fullTextSearch': + if ($argc >= 4) { + // Combine all of the query args into one query string. + // The command line split the query string on space + // characters. + $queryString = implode(' ', array_slice($argv, 4)); + fullTextSearch($docs, false, $queryString); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username>"; + echo " <password> <query string>\n\n"; + echo "This lists all of the documents which contain the"; + echo " query string.\n"; + } + break; + case 'uploadDocument': + if ($argc >= 5) { + // Pass in the file name of the document to be uploaded. + // Since the document is on this machine, we do not need + // to set the temporary file name. The temp file name is + // used only when uploading to a webserver. + uploadDocument($docs, false, $argv[4], null); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username>"; + echo " <password> <file_with_path>\n\n"; + echo "This lists all of the documents which contain the"; + echo " query string.\n"; + echo "\nExample: php {$argv[0]} {$argv[1]} <username>"; + echo " <password> /tmp/testSpreadsheet.ods\n"; + } + break; + default: + // Invalid action entered + displayHelp($argv[0]); + // End switch block + } + } else { + // action left unspecified + displayHelp($argv[0]); + } +} + +/** + * Displays the titles for the Google Documents entries in the feed. In HTML + * mode, the titles are links which point to the HTML version of the document. + * + * @param Zend_Gdata_Docs_DocumentListFeed $feed + * @param boolean $html True if output should be formatted for display in + * a web browser + * @return void + */ +function printDocumentsFeed($feed, $html) +{ + if ($html) {echo "<ul>\n";} + + // Iterate over the document entries in the feed and display each document's + // title. + foreach ($feed->entries as $entry) { + + if ($html) { + // Find the URL of the HTML view of the document. + $alternateLink = ''; + foreach ($entry->link as $link) { + if ($link->getRel() === 'alternate') { + $alternateLink = $link->getHref(); + } + } + // Make the title link to the document on docs.google.com. + echo "<li><a href=\"$alternateLink\">\n"; + } + + echo "$entry->title\n"; + + if ($html) {echo "</a></li>\n";} + } + + if ($html) {echo "</ul>\n";} +} + +/** + * Obtain a list of all of a user's docs.google.com documents and print the + * titles to the command line. + * + * @param Zend_Gdata_Docs $client The service object to use for communicating with the Google + * Documents server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @return void + */ +function retrieveAllDocuments($client, $html) +{ + if ($html) {echo "<h2>Your documents</h2>\n";} + + $feed = $client->getDocumentListFeed(); + + printDocumentsFeed($feed, $html); +} + +/** + * Obtain a list of all of a user's docs.google.com word processing + * documents and print the titles to the command line. + * + * @param Zend_Gdata_Docs $client The service object to use for communicating with the Google + * Documents server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @return void + */ +function retrieveWPDocs($client, $html) +{ + if ($html) {echo "<h2>Your word processing documents</h2>\n";} + + $feed = $client->getDocumentListFeed( + 'http://docs.google.com/feeds/documents/private/full/-/document'); + + printDocumentsFeed($feed, $html); +} + +/** + * Obtain a list of all of a user's docs.google.com spreadsheets + * documents and print the titles to the command line. + * + * @param Zend_Gdata_Docs $client The service object to use for communicating with the Google + * Documents server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @return void + */ +function retrieveSpreadsheets($client, $html) +{ + if ($html) {echo "<h2>Your spreadsheets</h2>\n";} + + $feed = $client->getDocumentListFeed( + 'http://docs.google.com/feeds/documents/private/full/-/spreadsheet'); + + printDocumentsFeed($feed, $html); +} + +/** + * Obtain a list of all of a user's docs.google.com documents + * which match the specified search criteria and print the titles to the + * command line. + * + * @param Zend_Gdata_Docs $client The service object to use for communicating with the Google + * Documents server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $query The search query to use + * @return void + */ +function fullTextSearch($client, $html, $query) +{ + if ($html) {echo "<h2>Documents containing $query</h2>\n";} + + $feed = $client->getDocumentListFeed( + 'http://docs.google.com/feeds/documents/private/full?q=' . $query); + + printDocumentsFeed($feed, $html); +} + +/** + * Upload the specified document + * + * @param Zend_Gdata_Docs $docs The service object to use for communicating with + * the Google Documents server. + * @param boolean $html True if output should be formatted for display in + * a web browser. + * @param string $originalFileName The name of the file to be uploaded. The mime type + * of the file is determined from the extension on + * this file name. For example, test.csv is uploaded + * as a comma seperated volume and converted into a + * spreadsheet. + * @param string $temporaryFileLocation (optional) The file in which the data for the + * document is stored. This is used when the file has + * been uploaded from the client's machine to the + * server and is stored in a temporary file which + * does not have an extension. If this parameter is + * null, the file is read from the originalFileName. + * @return void + */ +function uploadDocument($docs, $html, $originalFileName, + $temporaryFileLocation) { + $fileToUpload = $originalFileName; + if ($temporaryFileLocation) { + $fileToUpload = $temporaryFileLocation; + } + + // Upload the file and convert it into a Google Document. The original + // file name is used as the title of the document and the mime type + // is determined based on the extension on the original file name. + $newDocumentEntry = $docs->uploadFile($fileToUpload, $originalFileName, + null, Zend_Gdata_Docs::DOCUMENTS_LIST_FEED_URI); + + echo "New Document Title: "; + + if ($html) { + // Find the URL of the HTML view of this document. + $alternateLink = ''; + foreach ($newDocumentEntry->link as $link) { + if ($link->getRel() === 'alternate') { + $alternateLink = $link->getHref(); + } + } + // Make the title link to the document on docs.google.com. + echo "<a href=\"$alternateLink\">\n"; + } + echo $newDocumentEntry->title."\n"; + if ($html) {echo "</a>\n";} +} + +// ************************ BEGIN WWW SPECIFIC CODE ************************ + +/** + * Writes the HTML prologue for this app. + * + * NOTE: We would normally keep the HTML/CSS markup separate from the business + * logic above, but have decided to include it here for simplicity of + * having a single-file sample. + * + * + * @param boolean $displayMenu (optional) If set to true, a navigation menu is displayed at the top + * of the page. Default is true. + * @return void + */ +function startHTML($displayMenu = true) +{ +?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + + <title>Documents List API Demo</title> + + <style type="text/css" media="screen"> + body { + font-family: Arial, Helvetica, sans-serif; + font-size: small; + } + + #header { + background-color: #9cF; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding-left: 5px; + height: 2.4em; + } + + #header h1 { + width: 49%; + display: inline; + float: left; + margin: 0; + padding: 0; + font-size: 2em; + } + + #header p { + width: 49%; + margin: 0; + padding-right: 15px; + float: right; + line-height: 2.4em; + text-align: right; + } + + .clear { + clear:both; + } + + h2 { + background-color: #ccc; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + margin-top: 1em; + padding-left: 5px; + } + + .error { + color: red; + } + + form { + width: 500px; + background: #ddf8cc; + border: 1px solid #80c605; + padding: 0 1em; + margin: 1em auto; + } + + .warning { + width: 500px; + background: #F4B5B4; + border: 1px solid #900; + padding: 0 1em; + margin: 1em auto; + } + + label { + display: block; + width: 130px; + float: left; + text-align: right; + padding-top: 0.3em; + padding-right: 3px; + } + + .radio { + margin: 0; + padding-left: 130px; + } + + #menuSelect { + padding: 0; + } + + #menuSelect li { + display: block; + width: 500px; + background: #ddf8cc; + border: 1px solid #80c605; + margin: 1em auto; + padding: 0; + font-size: 1.3em; + text-align: center; + list-style-type: none; + } + + #menuSelect li:hover { + background: #c4faa2; + } + + #menuSelect a { + display: block; + height: 2em; + margin: 0px; + padding-top: 0.75em; + padding-bottom: -0.25em; + text-decoration: none; + } + #content { + width: 600px; + margin: 0 auto; + padding: 0; + text-align: left; + } + </style> + +</head> + +<body> + +<div id="header"> + <h1>Documents List API Demo</h1> + <?php if ($displayMenu === true) { ?> + <p><a href="?">Main</a> | <a href="?menu=logout">Logout</a></p> + <?php } ?> + <div class="clear"></div> +</div> + +<div id="content"> +<?php +} + +/** + * Writes the HTML epilogue for this app and exit. + * + * @param boolean $displayBackButton (optional) If true, displays a link to go back at the bottom + * of the page. Defaults to false. + * @return void + */ +function endHTML($displayBackButton = false) +{ + if ($displayBackButton === true) { + echo '<div style="clear: both;">'; + echo '<a href="javascript:history.go(-1)">← Back</a></div>'; + } +?> +</div> +</body> +</html> +<?php +exit(); +} + +/** + * Displays a notice indicating that a login password needs to be + * set before continuing. + * + * @return void + */ +function displayPasswordNotSetNotice() +{ +?> + <div class="warning"> + <h3>Almost there...</h3> + <p>Before using this demo, you must set an application password + to protect your account. You will also need to set your + Google Apps credentials in order to communicate with the Google + Apps servers.</p> + <p>To continue, open this file in a text editor and fill + out the information in the configuration section.</p> + </div> +<?php +} + +/** + * Displays a notice indicating that authentication to Google Apps failed. + * + * @return void + */ +function displayAuthenticationFailedNotice() +{ +?> + <div class="warning"> + <h3>Google Docs Authentication Failed</h3> + <p>Authentication with the Google Apps servers failed.</p> + <p>Please open this file in a text editor and make + sure your credentials are correct.</p> + </div> +<?php +} + +/** + * Outputs a request to the user to login to their Google account, including + * a link to the AuthSub URL. + * + * Uses getAuthSubUrl() to get the URL which the user must visit to authenticate + * + * @param string $linkText + * @return void + */ +function requestUserLogin($linkText) +{ + $authSubUrl = getAuthSubUrl(); + echo "<a href=\"{$authSubUrl}\">{$linkText}</a>"; +} + +/** + * Returns the AuthSub URL which the user must visit to authenticate requests + * from this application. + * + * Uses getCurrentUrl() to get the next URL which the user will be redirected + * to after successfully authenticating with the Google service. + * + * @return string AuthSub URL + */ +function getAuthSubUrl() +{ + $next = getCurrentUrl(); + $scope = 'http://docs.google.com/feeds/documents'; + $secure = false; + $session = true; + return Zend_Gdata_AuthSub::getAuthSubTokenUri($next, $scope, $secure, + $session); +} + +/** + * Returns a HTTP client object with the appropriate headers for communicating + * with Google using AuthSub authentication. + * + * Uses the $_SESSION['sessionToken'] to store the AuthSub session token after + * it is obtained. The single use token supplied in the URL when redirected + * after the user succesfully authenticated to Google is retrieved from the + * $_GET['token'] variable. + * + * @return Zend_Http_Client + */ +function getAuthSubHttpClient() +{ + global $_SESSION, $_GET; + if (!isset($_SESSION['docsSampleSessionToken']) && isset($_GET['token'])) { + $_SESSION['docsSampleSessionToken'] = + Zend_Gdata_AuthSub::getAuthSubSessionToken($_GET['token']); + } + $client = Zend_Gdata_AuthSub::getHttpClient($_SESSION['docsSampleSessionToken']); + return $client; +} + +/** + * Returns the full URL of the current page, based upon env variables + * + * Env variables used: + * $_SERVER['HTTPS'] = (on|off|) + * $_SERVER['HTTP_HOST'] = value of the Host: header + * $_SERVER['SERVER_PORT'] = port number (only used if not http/80,https/443) + * $_SERVER['REQUEST_URI'] = the URI after the method of the HTTP request + * + * @return string Current URL + */ +function getCurrentUrl() +{ + global $_SERVER; + + /** + * Filter php_self to avoid a security vulnerability. + */ + $php_request_uri = htmlentities(substr($_SERVER['REQUEST_URI'], 0, + strcspn($_SERVER['REQUEST_URI'], "\n\r")), ENT_QUOTES); + + if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') { + $protocol = 'https://'; + } else { + $protocol = 'http://'; + } + $host = $_SERVER['HTTP_HOST']; + if ($_SERVER['SERVER_PORT'] != '' && + (($protocol == 'http://' && $_SERVER['SERVER_PORT'] != '80') || + ($protocol == 'https://' && $_SERVER['SERVER_PORT'] != '443'))) { + $port = ':' . $_SERVER['SERVER_PORT']; + } else { + $port = ''; + } + return $protocol . $host . $port . $php_request_uri; +} + +/** + * Display the main menu for running in a web browser. + * + * @return void + */ +function displayMenu() +{ +?> +<h2>Main Menu</h2> + +<p>Welcome to the Google Documents List API demo page. Please select + from one of the following three options to see a list of commands.</p> + + <ul id="menuSelect"> + <li><a class="menuSelect" href="?menu=list">List Documents</a></li> + <li><a class="menuSelect" href="?menu=query">Query your Documents</a></li> + <li><a class="menuSelect" href="?menu=upload">Upload a new document</a></li> + </ul> + +<p>Tip: You can also run this demo from the command line if your system + has PHP CLI support enabled.</p> +<?php +} + +/** + * Log the current user out of the application. + * + * @return void + */ +function logout() +{ +session_destroy(); +?> +<h2>Logout</h2> + +<p>Logout successful.</p> + +<ul id="menuSelect"> + <li><a class="menuSelect" href="?">Login</a></li> +</ul> +<?php +} + + +/** + * Processes loading of this sample code through a web browser. + * + * @return void + */ +function runWWWVersion() +{ + session_start(); + + // Note that all calls to endHTML() below end script execution! + + global $_SESSION, $_GET; + if (!isset($_SESSION['docsSampleSessionToken']) && !isset($_GET['token'])) { + requestUserLogin('Please login to your Google Account.'); + } else { + $client = getAuthSubHttpClient(); + $docs = new Zend_Gdata_Docs($client); + + // First we check for commands that can be submitted either though + // POST or GET (they don't make any changes). + if (!empty($_REQUEST['command'])) { + switch ($_REQUEST['command']) { + case 'retrieveAllDocuments': + startHTML(); + retrieveAllDocuments($docs, true); + endHTML(true); + case 'retrieveWPDocs': + startHTML(); + retrieveWPDocs($docs, true); + endHTML(true); + case 'retrieveSpreadsheets': + startHTML(); + retrieveSpreadsheets($docs, true); + endHTML(true); + case 'fullTextSearch': + startHTML(); + fullTextSearch($docs, true, $_REQUEST['query']); + endHTML(true); + + } + } + + // Now we handle the potentially destructive commands, which have to + // be submitted by POST only. + if (!empty($_POST['command'])) { + switch ($_POST['command']) { + case 'uploadDocument': + startHTML(); + uploadDocument($docs, true, + $_FILES['uploadedFile']['name'], + $_FILES['uploadedFile']['tmp_name']); + endHTML(true); + case 'modifySubscription': + if ($_POST['mode'] == 'subscribe') { + startHTML(); + endHTML(true); + } elseif ($_POST['mode'] == 'unsubscribe') { + startHTML(); + endHTML(true); + } else { + header('HTTP/1.1 400 Bad Request'); + startHTML(); + echo "<h2>Invalid mode.</h2>\n"; + echo "<p>Please check your request and try again.</p>"; + endHTML(true); + } + } + } + + // Check for an invalid command. If so, display an error and exit. + if (!empty($_REQUEST['command'])) { + header('HTTP/1.1 400 Bad Request'); + startHTML(); + echo "<h2>Invalid command.</h2>\n"; + echo "<p>Please check your request and try again.</p>"; + endHTML(true); + } + // If a menu parameter is available, display a submenu. + + if (!empty($_REQUEST['menu'])) { + switch ($_REQUEST['menu']) { + case 'list': + startHTML(); + displayListMenu(); + endHTML(); + case 'query': + startHTML(); + displayQueryMenu(); + endHTML(); + case 'upload': + startHTML(); + displayUploadMenu(); + endHTML(); + case 'logout': + startHTML(false); + logout(); + endHTML(); + default: + header('HTTP/1.1 400 Bad Request'); + startHTML(); + echo "<h2>Invalid menu selection.</h2>\n"; + echo "<p>Please check your request and try again.</p>"; + endHTML(true); + } + } + // If we get this far, that means there's nothing to do. Display + // the main menu. + // If no command was issued and no menu was selected, display the + // main menu. + startHTML(); + displayMenu(); + endHTML(); + } +} + +/** + * Display the menu for running in a web browser. + * + * @return void + */ +function displayListMenu() +{ +?> +<h2>List Documents Menu</h2> + +<form method="get" accept-charset="utf-8"> + <h3>Retrieve Google Documents Feed</h3> + <p>Retrieve the feed for all of your documents.</p> + <p> + <input type="hidden" name="command" value="retrieveAllDocuments" /> + </p> + <p><input type="submit" value="Retrieve Documents Feed →"></p> +</form> + +<form method="get" accept-charset="utf-8"> + <h3>Retrieve Google Word Processing Documents</h3> + <p>Query the documents list feed for all word processing documents.</p> + <p> + <input type="hidden" name="command" value="retrieveWPDocs" /> + </p> + <p><input type="submit" value="Retrieve Word Processing Documents →"></p> +</form> + +<form method="get" accept-charset="utf-8"> + <h3>Retrieve Google Spreadsheets</h3> + <p>Query the documents list feed for all spreadsheets.</p> + <p> + <input type="hidden" name="command" value="retrieveSpreadsheets" /> + </p> + <p><input type="submit" value="Retrieve Spreadsheets →"></p> +</form> +<?php +} + +/** + * Display the menu for running in a web browser. + * + * @return void + */ +function displayQueryMenu() +{ +?> +<h2>Query the Documents List Feed</h2> + +<form method="get" accept-charset="utf-8"> + <h3>Search the Documents List Feed</h3> + <p>Find documents which contain the desired text.</p> + <p> + <input type="hidden" name="command" value="fullTextSearch" /> + <input type="text" name="query" /> + </p> + <p><input type="submit" value="Search Documents Feed →"></p> +</form> + +<?php +} + +/** + * Display the menu for running in a web browser. + * + * @return void + */ +function displayUploadMenu() +{ +?> +<h2>Upload a document</h2> + +<form method="post" enctype="multipart/form-data"> + <h3>Select a Document to Upload</h3> + <p>Upload a file from your computer to <a href="http://docs.google.com">Google Documents</a>.</p> + <p> + <input type="hidden" name="command" value="uploadDocument" /> + <input name="uploadedFile" type="file" /> + </p> + <p><input type="submit" value="Upload the Document →"></p> +</form> + +<?php +} + +// ************************** PROGRAM ENTRY POINT ************************** + +if (!isset($_SERVER["HTTP_HOST"])) { + // running through command line + runCLIVersion($argv, $argc); +} else { + // running through web server + try { + runWWWVersion(); + } catch (Zend_Gdata_Gapps_ServiceException $e) { + // Try to recover gracefully from a service exception. + // The HTML prologue will have already been sent. + echo "<p><strong>Service Error Encountered</strong></p>\n"; + echo "<pre>" . htmlspecialchars($e->__toString()) . "</pre>"; + endHTML(true); + } +} diff --git a/zend/demos/Zend/Gdata/Gapps.php b/zend/demos/Zend/Gdata/Gapps.php new file mode 100644 index 0000000..4f15ffe --- /dev/null +++ b/zend/demos/Zend/Gdata/Gapps.php @@ -0,0 +1,1992 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * PHP sample code for the Google Calendar data API. Utilizes the + * Zend Framework Gdata components to communicate with the Google API. + * + * Requires the Zend Framework Gdata components and PHP >= 5.2.11 + * + * You can run this sample both from the command line (CLI) and also + * from a web browser. Run this script without any command line options to + * see usage, eg: + * /usr/bin/env php Gapps.php + * + * More information on the Command Line Interface is available at: + * http://www.php.net/features.commandline + * + * When running this code from a web browser, be sure to fill in your + * Google Apps credentials below and choose a password for authentication + * via the web browser. + * + * Since this is a demo, only minimal error handling and input validation + * are performed. THIS CODE IS FOR DEMONSTRATION PURPOSES ONLY. NOT TO BE + * USED IN A PRODUCTION ENVIRONMENT. + * + * NOTE: You must ensure that Zend Framework is in your PHP include + * path. You can do this via php.ini settings, or by modifying the + * argument to set_include_path in the code below. + */ + +// ************************ BEGIN WWW CONFIGURATION ************************ + +/** + * Google Apps username. This is the username (without domain) used + * to administer your Google Apps account. This value is only + * used when accessing this demo on a web server. + * + * For example, if you login to Google Apps as 'foo@bar.com.inavlid', + * your username is 'foo'. + */ +define('GAPPS_USERNAME', 'username'); + +/** + * Google Apps domain. This is the domain associated with your + * Google Apps account. This value is only used when accessing this demo + * on a web server. + * + * For example, if you login to Google Apps as foo@bar.com.inavlid, + * your domain is 'bar.com.invalid'. + */ +define('GAPPS_DOMAIN', 'example.com.invalid'); + +/** + * Google Apps password. This is the password associated with the above + * username. This value is only used when accessing this demo on a + * web server. + */ +define('GAPPS_PASSWORD', 'your password here'); + +/** + * Login password. This password is used to protect your account from + * unauthorized access when running this demo on a web server. + * + * If this field is blank, all access will be denied. A blank password + * field is not the same as no password (which is disallowed for + * security reasons). + * + * NOTE: While we could technically just ask the user for their Google Apps + * credentials, the ClientLogin API is not intended for direct use by + * web applications. If you are the only user of the application, this + * is fine--- but you should not ask other users to enter their + * credentials via your web application. + */ +define('LOGIN_PASSWORD', ''); + +// ************************* END WWW CONFIGURATION ************************* + +/** + * @see Zend_Loader + */ +require_once 'Zend/Loader.php'; + +/** + * @see Zend_Gdata + */ +Zend_Loader::loadClass('Zend_Gdata'); + +/** + * @see Zend_Gdata_ClientLogin + */ +Zend_Loader::loadClass('Zend_Gdata_ClientLogin'); + +/** + * @see Zend_Gdata_Gapps + */ +Zend_Loader::loadClass('Zend_Gdata_Gapps'); + +/** + * Returns a HTTP client object with the appropriate headers for communicating + * with Google using the ClientLogin credentials supplied. + * + * @param string $user The username, in e-mail address format, to authenticate + * @param string $pass The password for the user specified + * @return Zend_Http_Client + */ +function getClientLoginHttpClient($user, $pass) +{ + $service = Zend_Gdata_Gapps::AUTH_SERVICE_NAME; + $client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service); + return $client; +} + +/** + * Creates a new user for the current domain. The user will be created + * without admin privileges. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The desired username for the user. + * @param string $givenName The given name for the user. + * @param string $familyName The family name for the user. + * @param string $password The plaintext password for the user. + * @return void + */ +function createUser($gapps, $html, $username, $givenName, $familyName, + $password) +{ + if ($html) {echo "<h2>Create User</h2>\n";} + $gapps->createUser($username, $givenName, $familyName, + $password); + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Retrieves a user for the current domain by username. Information about + * that user is then output. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The desired username for the user. + * @return void + */ +function retrieveUser($gapps, $html, $username) +{ + if ($html) {echo "<h2>User Information</h2>\n";} + + $user = $gapps->retrieveUser($username); + + if ($html) {echo '<p>';} + + if ($user !== null) { + echo ' Username: ' . $user->login->username; + if ($html) {echo '<br />';} + echo "\n"; + + echo ' Given Name: '; + if ($html) { + echo htmlspecialchars($user->name->givenName); + } else { + echo $user->name->givenName; + } + if ($html) {echo '<br />';} + echo "\n"; + + echo ' Family Name: '; + if ($html) { + echo htmlspecialchars($user->name->familyName); + } else { + echo $user->name->familyName; + } + if ($html) {echo '<br />';} + echo "\n"; + + echo ' Suspended: ' . ($user->login->suspended ? 'Yes' : 'No'); + if ($html) {echo '<br />';} + echo "\n"; + + echo ' Admin: ' . ($user->login->admin ? 'Yes' : 'No'); + if ($html) {echo '<br />';} + echo "\n"; + + echo ' Must Change Password: ' . + ($user->login->changePasswordAtNextLogin ? 'Yes' : 'No'); + if ($html) {echo '<br />';} + echo "\n"; + + echo ' Has Agreed To Terms: ' . + ($user->login->agreedToTerms ? 'Yes' : 'No'); + + } else { + echo 'Error: Specified user not found.'; + } + if ($html) {echo '</p>';} + echo "\n"; +} + +/** + * Retrieves the list of users for the current domain and outputs + * that list. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @return void + */ +function retrieveAllUsers($gapps, $html) +{ + if ($html) {echo "<h2>Registered Users</h2>\n";} + + $feed = $gapps->retrieveAllUsers(); + + if ($html) {echo "<ul>\n";} + + foreach ($feed as $user) { + if ($html) { + echo " <li>"; + } else { + echo " * "; + } + echo $user->login->username . ' ('; + if ($html) { + echo htmlspecialchars($user->name->givenName . ' ' . + $user->name->familyName); + } else { + echo $user->name->givenName . ' ' . $user->name->familyName; + } + echo ')'; + if ($html) {echo '</li>';} + echo "\n"; + } + if ($html) {echo "</ul>\n";} +} + +/** + * Change the name for an existing user. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The username which should be updated + * @param string $newGivenName The new given name for the user. + * @param string $newFamilyName The new family name for the user. + * @return void + */ +function updateUserName($gapps, $html, $username, $newGivenName, $newFamilyName) +{ + if ($html) {echo "<h2>Update User Name</h2>\n";} + + $user = $gapps->retrieveUser($username); + + if ($user !== null) { + $user->name->givenName = $newGivenName; + $user->name->familyName = $newFamilyName; + $user->save(); + } else { + if ($html) {echo '<p>';} + echo 'Error: Specified user not found.'; + if ($html) {echo '</p>';} + echo "\n"; + } + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Change the password for an existing user. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The username which should be updated + * @param string $newPassword The new password for the user. + * @return void + */ +function updateUserPassword($gapps, $html, $username, $newPassword) +{ + if ($html) {echo "<h2>Update User Password</h2>\n";} + + $user = $gapps->retrieveUser($username); + + if ($user !== null) { + $user->login->password = $newPassword; + $user->save(); + } else { + if ($html) {echo '<p>';} + echo 'Error: Specified user not found.'; + if ($html) {echo '</p>';} + echo "\n"; + } + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Suspend a given user. The user will not be able to login until restored. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The username which should be updated. + * @return void + */ +function suspendUser($gapps, $html, $username) +{ + if ($html) {echo "<h2>Suspend User</h2>\n";} + + $user = $gapps->retrieveUser($username); + + if ($user !== null) { + $user->login->suspended = true; + $user->save(); + } else { + if ($html) {echo '<p>';} + echo 'Error: Specified user not found.'; + if ($html) {echo '</p>';} + echo "\n"; + } + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Restore a given user after being suspended. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The username which should be updated. + * @return void + */ +function restoreUser($gapps, $html, $username) +{ + if ($html) {echo "<h2>Restore User</h2>\n";} + + $user = $gapps->retrieveUser($username); + + if ($user !== null) { + $user->login->suspended = false; + $user->save(); + } else { + if ($html) {echo '<p>';} + echo 'Error: Specified user not found.'; + if ($html) {echo '</p>';} + echo "\n"; + } + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Give a user admin rights. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The username which should be updated. + * @return void + */ +function giveUserAdminRights($gapps, $html, $username) +{ + if ($html) {echo "<h2>Grant Administrative Rights</h2>\n";} + + $user = $gapps->retrieveUser($username); + + if ($user !== null) { + $user->login->admin = true; + $user->save(); + } else { + if ($html) {echo '<p>';} + echo 'Error: Specified user not found.'; + if ($html) {echo '</p>';} + echo "\n"; + } + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Revoke a user's admin rights. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The username which should be updated. + * @return void + */ +function revokeUserAdminRights($gapps, $html, $username) +{ + if ($html) {echo "<h2>Revoke Administrative Rights</h2>\n";} + + $user = $gapps->retrieveUser($username); + + if ($user !== null) { + $user->login->admin = false; + $user->save(); + } else { + if ($html) {echo '<p>';} + echo 'Error: Specified user not found.'; + if ($html) {echo '</p>';} + echo "\n"; + } + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Force a user to change their password at next login. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The username which should be updated. + * @return void + */ +function setUserMustChangePassword($gapps, $html, $username) +{ + if ($html) {echo "<h2>Force User To Change Password</h2>\n";} + + $user = $gapps->retrieveUser($username); + + if ($user !== null) { + $user->login->changePasswordAtNextLogin = true; + $user->save(); + } else { + if ($html) {echo '<p>';} + echo 'Error: Specified user not found.'; + if ($html) {echo '</p>';} + echo "\n"; + } + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Undo forcing a user to change their password at next login. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The username which should be updated. + * @return void + */ +function clearUserMustChangePassword($gapps, $html, $username) +{ + if ($html) {echo "<h2>Undo Force User To Change Password</h2>\n";} + + $user = $gapps->retrieveUser($username); + + if ($user !== null) { + $user->login->changePasswordAtNextLogin = false; + $user->save(); + } else { + if ($html) {echo '<p>';} + echo 'Error: Specified user not found.'; + if ($html) {echo '</p>';} + echo "\n"; + } + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Delete the user who owns a given username. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The username which should be deleted. + * @return void + */ +function deleteUser($gapps, $html, $username) +{ + if ($html) {echo "<h2>Delete User</h2>\n";} + + $gapps->deleteUser($username); + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Create a new nickname. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The username to which the nickname should be assigned. + * @param string $nickname The name of the nickname to be created. + * @return void + */ +function createNickname($gapps, $html, $username, $nickname) +{ + if ($html) {echo "<h2>Create Nickname</h2>\n";} + + $gapps->createNickname($username, $nickname); + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Retrieve a specified nickname and output its ownership information. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $nickname The name of the nickname to be retrieved. + * @return void + */ +function retrieveNickname($gapps, $html, $nickname) +{ + if ($html) {echo "<h2>Nickname Information</h2>\n";} + + $nickname = $gapps->retrieveNickname($nickname); + + if ($html) {echo '<p>';} + + if ($nickname !== null) { + echo ' Nickname: ' . $nickname->nickname->name; + if ($html) {echo '<br />';} + echo "\n"; + + echo ' Owner: ' . $nickname->login->username; + } else { + echo 'Error: Specified nickname not found.'; + } + if ($html) {echo '</p>';} + echo "\n"; +} + +/** + * Outputs all nicknames owned by a specific username. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $username The username whose nicknames should be displayed. + * @return void + */ +function retrieveNicknames($gapps, $html, $username) +{ + if ($html) {echo "<h2>Registered Nicknames For {$username}</h2>\n";} + + $feed = $gapps->retrieveNicknames($username); + + if ($html) {echo "<ul>\n";} + + foreach ($feed as $nickname) { + if ($html) { + echo " <li>"; + } else { + echo " * "; + } + echo $nickname->nickname->name; + if ($html) {echo '</li>';} + echo "\n"; + } + if ($html) {echo "</ul>\n";} +} + + +/** + * Retrieves the list of nicknames for the current domain and outputs + * that list. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @return void + */ +function retrieveAllNicknames($gapps, $html) +{ + if ($html) {echo "<h2>Registered Nicknames</h2>\n";} + + $feed = $gapps->retrieveAllNicknames(); + + if ($html) {echo "<ul>\n";} + + foreach ($feed as $nickname) { + if ($html) { + echo " <li>"; + } else { + echo " * "; + } + echo $nickname->nickname->name . ' => ' . $nickname->login->username; + if ($html) {echo '</li>';} + echo "\n"; + } + if ($html) {echo "</ul>\n";} +} + +/** + * Delete's a specific nickname from the current domain. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $nickname The nickname that should be deleted. + * @return void + */ +function deleteNickname($gapps, $html, $nickname) +{ + if ($html) {echo "<h2>Delete Nickname</h2>\n";} + + $gapps->deleteNickname($nickname); + + if ($html) {echo "<p>Done.</p>\n";} + +} + +/** + * Create a new email list. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $emailList The name of the email list to be created. + * @return void + */ +function createEmailList($gapps, $html, $emailList) +{ + if ($html) {echo "<h2>Create Email List</h2>\n";} + + $gapps->createEmailList($emailList); + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Outputs the list of email lists to which the specified address is + * subscribed. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $recipient The email address of the recipient whose subscriptions should + * be retrieved. Only a username is required if the recipient is a + * member of the current domain. + * @return void + */ +function retrieveEmailLists($gapps, $html, $recipient) +{ + if ($html) {echo "<h2>Email List Subscriptions For {$recipient}</h2>\n";} + + $feed = $gapps->retrieveEmailLists($recipient); + + if ($html) {echo "<ul>\n";} + + foreach ($feed as $list) { + if ($html) { + echo " <li>"; + } else { + echo " * "; + } + echo $list->emailList->name; + if ($html) {echo '</li>';} + echo "\n"; + } + if ($html) {echo "</ul>\n";} +} + +/** + * Outputs the list of all email lists on the current domain. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @return void + */ +function retrieveAllEmailLists($gapps, $html) +{ + if ($html) {echo "<h2>Registered Email Lists</h2>\n";} + + $feed = $gapps->retrieveAllEmailLists(); + + if ($html) {echo "<ul>\n";} + + foreach ($feed as $list) { + if ($html) { + echo " <li>"; + } else { + echo " * "; + } + echo $list->emailList->name; + if ($html) {echo '</li>';} + echo "\n"; + } + if ($html) {echo "</ul>\n";} +} + +/** + * Delete's a specific email list from the current domain. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $emailList The email list that should be deleted. + * @return void + */ +function deleteEmailList($gapps, $html, $emailList) +{ + if ($html) {echo "<h2>Delete Email List</h2>\n";} + + $gapps->deleteEmailList($emailList); + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Add a recipient to an existing email list. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the + * Google Apps server. + * @param boolean $html True if output should be formatted for display in a + * web browser. + * @param string $recipientAddress The address of the recipient who should be added. + * @param string $emailList The name of the email address the recipient be added to. + * @return void + */ +function addRecipientToEmailList($gapps, $html, $recipientAddress, + $emailList) +{ + if ($html) {echo "<h2>Subscribe Recipient</h2>\n";} + + $gapps->addRecipientToEmailList($recipientAddress, $emailList); + + if ($html) {echo "<p>Done.</p>\n";} +} + +/** + * Outputs the list of all recipients for a given email list. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the Google + * Apps server. + * @param boolean $html True if output should be formatted for display in a web browser. + * @param string $emailList The email list whose recipients should be output. + * @return void + */ +function retrieveAllRecipients($gapps, $html, $emailList) +{ + if ($html) {echo "<h2>Email List Recipients For {$emailList}</h2>\n";} + + $feed = $gapps->retrieveAllRecipients($emailList); + + if ($html) {echo "<ul>\n";} + + foreach ($feed as $recipient) { + if ($html) { + echo " <li>"; + } else { + echo " * "; + } + echo $recipient->who->email; + if ($html) {echo '</li>';} + echo "\n"; + } + if ($html) {echo "</ul>\n";} +} + +/** + * Remove an existing recipient from an email list. + * + * @param Zend_Gdata_Gapps $gapps The service object to use for communicating with the + * Google Apps server. + * @param boolean $html True if output should be formatted for display in a + * web browser. + * @param string $recipientAddress The address of the recipient who should be removed. + * @param string $emailList The email list from which the recipient should be removed. + * @return void + */ +function removeRecipientFromEmailList($gapps, $html, $recipientAddress, + $emailList) +{ + if ($html) {echo "<h2>Unsubscribe Recipient</h2>\n";} + + $gapps->removeRecipientFromEmailList($recipientAddress, $emailList); + + if ($html) {echo "<p>Done.</p>\n";} + +} + +// ************************ BEGIN CLI SPECIFIC CODE ************************ + +/** + * Display list of valid commands. + * + * @param string $executable The name of the current script. This is usually available as $argv[0]. + * @return void + */ +function displayHelp($executable) +{ + echo "Usage: php {$executable} <action> [<username>] [<password>] " . + "[<arg1> <arg2> ...]\n\n"; + echo "Possible action values include:\n" . + "createUser\n" . + "retrieveUser\n" . + "retrieveAllUsers\n" . + "updateUserName\n" . + "updateUserPassword\n" . + "suspendUser\n" . + "restoreUser\n" . + "giveUserAdminRights\n" . + "revokeUserAdminRights\n" . + "setUserMustChangePassword\n" . + "clearUserMustChangePassword\n" . + "deleteUser\n" . + "createNickname\n" . + "retrieveNickname\n" . + "retrieveNicknames\n" . + "retrieveAllNicknames\n" . + "deleteNickname\n" . + "createEmailList\n" . + "retrieveEmailLists\n" . + "retrieveAllEmailLists\n" . + "deleteEmailList\n" . + "addRecipientToEmailList\n" . + "retrieveAllRecipients\n" . + "removeRecipientFromEmailList\n"; +} + +/** + * Parse command line arguments and execute appropriate function when + * running from the command line. + * + * If no arguments are provided, usage information will be provided. + * + * @param array $argv The array of command line arguments provided by PHP. + * $argv[0] should be the current executable name or '-' if not available. + * @param integer $argc The size of $argv. + * @return void + */ +function runCLIVersion($argv, $argc) +{ + if (isset($argc) && $argc >= 2) { + # Prepare a server connection + if ($argc >= 5) { + try { + $client = getClientLoginHttpClient($argv[2] . '@' . $argv[3], $argv[4]); + $gapps = new Zend_Gdata_Gapps($client, $argv[3]); + } catch (Zend_Gdata_App_AuthException $e) { + echo "Error: Unable to authenticate. Please check your credentials.\n"; + exit(1); + } + } + + # Dispatch arguments to the desired method + switch ($argv[1]) { + case 'createUser': + if ($argc == 9) { + createUser($gapps, false, $argv[5], $argv[6], $argv[7], $argv[8]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username> <given name> <family name> <user's password>\n\n"; + echo "This creates a new user with the given username.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe John Doe p4ssw0rd\n"; + } + break; + case 'retrieveUser': + if ($argc == 6) { + retrieveUser($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username>\n\n"; + echo "This retrieves the user with the specified " . + "username and displays information about that user.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe\n"; + } + break; + case 'retrieveAllUsers': + if ($argc == 5) { + retrieveAllUsers($gapps, false); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "\n\n"; + echo "This lists all users on the current domain.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password>\n"; + } + break; + case 'updateUserName': + if ($argc == 8) { + updateUserName($gapps, false, $argv[5], $argv[6], $argv[7]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username> <new given name> <new family name>\n\n"; + echo "Renames an existing user.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe Jane Doe\n"; + } + break; + case 'updateUserPassword': + if ($argc == 7) { + updateUserPassword($gapps, false, $argv[5], $argv[6]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username> <new user password>\n\n"; + echo "Changes the password for an existing user.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe password1\n"; + } + break; + case 'suspendUser': + if ($argc == 6) { + suspendUser($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username>\n\n"; + echo "This suspends the given user.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe\n"; + } + break; + case 'restoreUser': + if ($argc == 6) { + restoreUser($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username>\n\n"; + echo "This restores the given user after being suspended.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe\n"; + } + break; + case 'giveUserAdminRights': + if ($argc == 6) { + giveUserAdminRights($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username>\n\n"; + echo "Give a user admin rights for this domain.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe\n"; + } + break; + case 'revokeUserAdminRights': + if ($argc == 6) { + revokeUserAdminRights($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username>\n\n"; + echo "Remove a user's admin rights for this domain.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe\n"; + } + break; + case 'setUserMustChangePassword': + if ($argc == 6) { + setUserMustChangePassword($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username>\n\n"; + echo "Force a user to change their password at next login.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe\n"; + } + break; + case 'clearUserMustChangePassword': + if ($argc == 6) { + clearUserMustChangePassword($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username>\n\n"; + echo "Clear the flag indicating that a user must change " . + "their password at next login.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe\n"; + } + break; + case 'deleteUser': + if ($argc == 6) { + deleteUser($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username>\n\n"; + echo "Delete the user who owns a given username.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe\n"; + } + break; + case 'createNickname': + if ($argc == 7) { + createNickname($gapps, false, $argv[5], $argv[6]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username> <nickname>\n\n"; + echo "Create a new nickname for the specified user.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe johnny\n"; + } + break; + case 'retrieveNickname': + if ($argc == 6) { + retrieveNickname($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<nickname>\n\n"; + echo "Retrieve a nickname and display its ownership " . + "information.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "johnny\n"; + } + break; + case 'retrieveNicknames': + if ($argc == 6) { + retrieveNicknames($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<user's username>\n\n"; + echo "Output all nicknames owned by a specific username.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "jdoe\n"; + } + break; + case 'retrieveAllNicknames': + if ($argc == 5) { + retrieveAllNicknames($gapps, false); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "\n\n"; + echo "Output all registered nicknames on the system.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "\n"; + } + break; + case 'deleteNickname': + if ($argc == 6) { + deleteNickname($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<nickname>\n\n"; + echo "Delete a specific nickname.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "johnny\n"; + } + break; + case 'createEmailList': + if ($argc == 6) { + createEmailList($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<email list>\n\n"; + echo "Create a new email list with the specified name.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "friends\n"; + } + break; + case 'retrieveEmailLists': + if ($argc == 6) { + retrieveEmailLists($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<recipient>\n\n"; + echo "Retrieve all email lists to which the specified " . + "address is subscribed.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "johnny@somewhere.com.invalid\n"; + } + break; + case 'retrieveAllEmailLists': + if ($argc == 5) { + retrieveAllEmailLists($gapps, false); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "\n\n"; + echo "Retrieve a list of all email lists on the current " . + "domain.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "\n"; + } + break; + case 'deleteEmailList': + if ($argc == 6) { + deleteEmailList($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<email list>\n\n"; + echo "Delete a specified email list.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "friends\n"; + } + break; + case 'addRecipientToEmailList': + if ($argc == 7) { + addRecipientToEmailList($gapps, false, $argv[5], $argv[6]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<recipient> <email list>\n\n"; + echo "Add a recipient to an existing email list.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "johnny@somewhere.com.invalid friends\n"; + } + break; + case 'retrieveAllRecipients': + if ($argc == 6) { + retrieveAllRecipients($gapps, false, $argv[5]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<email list>\n\n"; + echo "Retrieve all recipients for an existing email list.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "friends\n"; + } + break; + case 'removeRecipientFromEmailList': + if ($argc == 7) { + removeRecipientFromEmailList($gapps, false, $argv[5], $argv[6]); + } else { + echo "Usage: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "<recipient> <email list>\n\n"; + echo "Remove an existing recipient from an email list.\n"; + echo "EXAMPLE: php {$argv[0]} {$argv[1]} <username> <domain> <password> " . + "johnny@somewhere.com.invalid friends\n"; + } + break; + default: + // Invalid action entered + displayHelp($argv[0]); + // End switch block + } + } else { + // action left unspecified + displayHelp($argv[0]); + } +} + +// ************************ BEGIN WWW SPECIFIC CODE ************************ + +/** + * Writes the HTML prologue for this app. + * + * NOTE: We would normally keep the HTML/CSS markup separate from the business + * logic above, but have decided to include it here for simplicity of + * having a single-file sample. + * + * + * @param boolean $displayMenu (optional) If set to true, a navigation + * menu is displayed at the top of the page. Default is true. + * @return void + */ +function startHTML($displayMenu = true) +{ +?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + + <title>Google Apps Provisioning API Demo</title> + + <style type="text/css" media="screen"> + body { + font-family: Arial, Helvetica, sans-serif; + font-size: small; + } + + #header { + background-color: #9cF; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding-left: 5px; + height: 2.4em; + } + + #header h1 { + width: 49%; + display: inline; + float: left; + margin: 0; + padding: 0; + font-size: 2em; + } + + #header p { + width: 49%; + margin: 0; + padding-right: 15px; + float: right; + line-height: 2.4em; + text-align: right; + } + + .clear { + clear:both; + } + + h2 { + background-color: #ccc; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + margin-top: 1em; + padding-left: 5px; + } + + .error { + color: red; + } + + form { + width: 500px; + background: #ddf8cc; + border: 1px solid #80c605; + padding: 0 1em; + margin: 1em auto; + } + + .warning { + width: 500px; + background: #F4B5B4; + border: 1px solid #900; + padding: 0 1em; + margin: 1em auto; + } + + label { + display: block; + width: 130px; + float: left; + text-align: right; + padding-top: 0.3em; + padding-right: 3px; + } + + .radio { + margin: 0; + padding-left: 130px; + } + + #menuSelect { + padding: 0; + } + + #menuSelect li { + display: block; + width: 500px; + background: #ddf8cc; + border: 1px solid #80c605; + margin: 1em auto; + padding: 0; + font-size: 1.3em; + text-align: center; + list-style-type: none; + } + + #menuSelect li:hover { + background: #c4faa2; + } + + #menuSelect a { + display: block; + height: 2em; + margin: 0px; + padding-top: 0.75em; + padding-bottom: -0.25em; + text-decoration: none; + } + + #content { + width: 600px; + margin: 0 auto; + padding: 0; + text-align: left; + } + </style> + +</head> + +<body> + +<div id="header"> + <h1>Google Apps API Demo</h1> + <?php if ($displayMenu === true) { ?> + <p><?php echo GAPPS_DOMAIN ?> | <a href="?">Main</a> | <a href="?menu=logout">Logout</a></p> + <?php } ?> + <div class="clear"></div> +</div> + +<div id="content"> +<?php +} + +/** + * Writes the HTML epilogue for this app and exit. + * + * @param boolean $displayBackButton (optional) If true, displays a + * link to go back at the bottom of the page. Defaults to false. + * @return void + */ +function endHTML($displayBackButton = false) +{ + if ($displayBackButton === true) { + echo '<a href="javascript:history.go(-1)">← Back</a>'; + } +?> +</div> +</body> +</html> +<?php +exit(); +} + +/** + * Displays a notice indicating that a login password needs to be + * set before continuing. + * + * @return void + */ +function displayPasswordNotSetNotice() +{ +?> + <div class="warning"> + <h3>Almost there...</h3> + <p>Before using this demo, you must set an application password + to protect your account. You will also need to set your + Google Apps credentials in order to communicate with the Google + Apps servers.</p> + <p>To continue, open this file in a text editor and fill + out the information in the configuration section.</p> + </div> +<?php +} + +/** + * Displays a notice indicating that authentication to Google Apps failed. + * + * @return void + */ +function displayAuthenticationFailedNotice() +{ +?> + <div class="warning"> + <h3>Google Apps Authentication Failed</h3> + <p>Authentication with the Google Apps servers failed.</p> + <p>Please open this file in a text editor and make + sure your credentials are correct.</p> + </div> +<?php +} + +/** + * Outputs a request to the user to enter their login password. + * + * @param string $errorText (optional) Error text to be displayed next to the login form. + * @return void + */ +function requestUserLogin($errorText = null) +{ +?> + <form method="post" accept-charset="utf-8"> + <h3>Authentication Required</h3> + <?php + if ($errorText !== null) { + echo '<span class="error">' . $errorText . "</span>\n"; + } + ?> + <p>Please enter your login password to continue.</p> + <p><label for="password">Password: </label> + <input type="password" name="password" value="" /></p> + <p><strong>Notice:</strong> This application is for demonstration + purposes only. Not for use in a production environment.</p> + <p><input type="submit" value="Continue →"></p> + </form> +<?php +} + +/** + * Display the main menu for running in a web browser. + * + * @return void + */ +function displayMenu() +{ +?> +<h2>Main Menu</h2> + +<p>Welcome to the Google Apps Provisioning API demo page. Please select + from one of the following three options to see a list of commands.</p> + + <ul id="menuSelect"> + <li><a class="menuSelect" href="?menu=user">User Maintenance Menu</a></li> + <li><a class="menuSelect" href="?menu=nickname">Nickname Maintenance Menu</a></li> + <li><a class="menuSelect" href="?menu=emailList">Email List Maintenance Menu</a></li> + </ul> + +<p>Tip: You can also run this demo from the command line if your system + has PHP CLI support enabled.</p> +<?php +} + +/** + * Display the user maintenance menu for running in a web browser. + * + * @return void + */ +function displayUserMenu() +{ +?> +<h2>User Maintenance Menu</h2> + +<form method="post" accept-charset="utf-8"> + <h3>Create User</h3> + <p>Create a new user with the given properties.</p> + <p> + <input type="hidden" name="command" value="createUser" /> + <label for="user">Username: </label> + <input type="text" name="user" value="" /><br /> + <label for="givenName">Given Name: </label> + <input type="text" name="givenName" value="" /><br /> + <label for="familyName">Family Name: </label> + <input type="text" name="familyName" value="" /><br /> + <label for="pass">Password: </label> + <input type="password" name="pass" value="" /> + </p> + + <p><input type="submit" value="Create User →"></p> +</form> +<form method="get" accept-charset="utf-8"> + <h3>Retrieve User</h3> + <p>Retrieve the information for an existing user.</p> + <p> + <input type="hidden" name="command" value="retrieveUser" /> + <label for="user">Username: </label> + <input type="text" name="user" value="" /><br /> + </p> + + <p><input type="submit" value="Retrieve User →"></p> +</form> +<form method="get" accept-charset="utf-8"> + <h3>Retrieve All Users</h3> + <p>Retrieve the list of all users on the current domain.</p> + <p> + <input type="hidden" name="command" value="retrieveAllUsers" /> + </p> + + <p><input type="submit" value="Retrieve Users →"></p> +</form> +<form method="post" accept-charset="utf-8"> + <h3>Update Name</h3> + <p>Update the name for an existing user.</p> + <p> + <input type="hidden" name="command" value="updateUserName" /> + <label for="user">Username: </label> + <input type="text" name="user" value="" /><br /> + <label for="givenName">New Given Name: </label> + <input type="text" name="givenName" value="" /><br /> + <label for="familyName">New Family Name: </label> + <input type="text" name="familyName" value="" /><br /> + </p> + + <p><input type="submit" value="Update User →"></p> +</form> +<form method="post" accept-charset="utf-8"> + <h3>Update Password</h3> + <p>Update the password for an existing user.</p> + <p> + <input type="hidden" name="command" value="updateUserPassword" /> + <label for="user">Username: </label> + <input type="text" name="user" value="" /><br /> + <label for="pass">New Password: </label> + <input type="password" name="pass" value="" /></p> + </p> + + <p><input type="submit" value="Update User →"></p> +</form> +<form method="post" accept-charset="utf-8"> + <h3>Suspend/Restore User</h3> + <p>Mark an existing user as suspended or restore a suspended user. + While suspended, the user will be prohibited from logging into + this domain.</p> + <p> + <input type="hidden" name="command" value="setUserSuspended" /> + <label for="user">Username: </label> + <input type="text" name="user" value="" /> + </p> + <div class="radio"> + <input type="radio" name="mode" value="restore">User may log into + this domain.</input><br /> + <input type="radio" name="mode" value="suspend" checked="true">User + may <strong>not</strong> log into this domain.</input> + </div> + + <p><input type="submit" value="Update User →"></p> +</form> +<form method="post" accept-charset="utf-8"> + <h3>Issue/Revoke Admin Rights</h3> + <p>Set whether an existing user has administrative rights for the current + domain.</p> + <p> + <input type="hidden" name="command" value="setUserAdmin" /> + <label for="user">Username: </label> + <input type="text" name="user" value="" /> + </p> + <div class="radio"> + <input type="radio" name="mode" value="issue">User + may administer this domain.</input><br /> + <input type="radio" name="mode" value="revoke" checked="true">User + may <strong>not</strong> administer this domain.</input> + </div> + + <p><input type="submit" value="Update User →"></p> +</form> +<form method="post" accept-charset="utf-8"> + <h3>Force User To Change Password</h3> + <p>Set whether an existing user must change their password at + their next login.</p> + <p> + <input type="hidden" name="command" value="setForceChangePassword" /> + <label for="user">Username: </label> + <input type="text" name="user" value="" /> + </p> + <div class="radio"> + <input type="radio" name="mode" value="set">User is required to + change their password at next login.</input><br /> + <input type="radio" name="mode" value="clear" checked="true">User is + <strong>not</strong> required to change their password at next + login.</input> + </div> + + <p><input type="submit" value="Update User →"></p> +</form> +<form method="post" accept-charset="utf-8"> + <h3>Delete User</h3> + <p>Delete an existing user on the current domain.</p> + <p> + <input type="hidden" name="command" value="deleteUser" /> + <label for="user">Username: </label> + <input type="text" name="user" value="" /><br /> + </p> + + <p><input type="submit" value="Delete User →"></p> +</form> +<?php +} + +/** + * Display the nickname maintenance menu for running in a web browser. + * + * @return void + */ +function displayNicknameMenu() +{ +?> +<h2>Nickname Maintenance Menu</h2> + +<form method="post" accept-charset="utf-8"> + <h3>Create Nickname</h3> + <p>Create a nickname for an existing user.</p> + <p> + <input type="hidden" name="command" value="createNickname" /> + <label for="user">Username: </label> + <input type="text" name="user" value="" /><br /> + <label for="nickname">Nickname: </label> + <input type="text" name="nickname" value="" /><br /> + </p> + + <p><input type="submit" value="Create Nickname →"></p> +</form> +<form method="get" accept-charset="utf-8"> + <h3>Retrieve Nickname</h3> + <p>Retrieve the information for an existing nickname.</p> + <p> + <input type="hidden" name="command" value="retrieveNickname" /> + <label for="nickname">Nickname: </label> + <input type="text" name="nickname" value="" /><br /> + </p> + + <p><input type="submit" value="Retrieve Nickname →"></p> +</form> +<form method="get" accept-charset="utf-8"> + <h3>Retrieve Nicknames</h3> + <p>Retrieve the nicknames associated with an existing username.</p> + <p> + <input type="hidden" name="command" value="retrieveNicknames" /> + <label for="user">Username: </label> + <input type="text" name="user" value="" /><br /> + </p> + + <p><input type="submit" value="Retrieve Nicknames →"></p> +</form> +<form method="get" accept-charset="utf-8"> + <h3>Retrieve All Nicknames</h3> + <p>Retrieve the nicknames on the current domain.</p> + <p> + <input type="hidden" name="command" value="retrieveAllNicknames" /> + </p> + + <p><input type="submit" value="Retrieve Nicknames →"></p> +</form> +<form method="post" accept-charset="utf-8"> + <h3>Delete Nickname</h3> + <p>Delete an existing nickname from the current domain.</p> + <p> + <input type="hidden" name="command" value="deleteNickname" /> + <label for="nickname">Nickname: </label> + <input type="text" name="nickname" value="" /><br /> + </p> + + <p><input type="submit" value="Delete Nickname →"></p> +</form> +<?php +} + +/** + * Display the email list maintenance menu for running in a web browser. + * + * @return void + */ +function displayEmailListMenu() +{ +?> +<h2>Email List Maintenance Menu</h2> + +<form method="post" accept-charset="utf-8"> + <h3>Create Email List</h3> + <p>Create a new email list for the current domain.</p> + <p> + <input type="hidden" name="command" value="createEmailList" /> + <label for="emailList">List Name: </label> + <input type="text" name="emailList" value="" /><br /> + </p> + + <p><input type="submit" value="Create List →"></p> +</form> +<form method="get" accept-charset="utf-8"> + <h3>Retrieve Email Lists</h3> + <p>Retrieve all email lists to which a given email address is + subscribed.</p> + <p> + <input type="hidden" name="command" value="retrieveEmailLists" /> + <label for="recipient">Recipient Address: </label> + <input type="text" name="recipient" value="" /><br /> + </p> + + <p><input type="submit" value="Retrieve Lists →"></p> +</form> +<form method="get" accept-charset="utf-8"> + <h3>Retrieve All Email Lists</h3> + <p>Retrieve all email lists on the current domain.</p> + <p> + <input type="hidden" name="command" value="retrieveAllEmailLists" /> + </p> + + <p><input type="submit" value="Retrieve Lists →"></p> +</form> +<form method="post" accept-charset="utf-8"> + <h3>Delete Email List</h3> + <p>Delete an existing email list from the current domain.</p> + <p> + <input type="hidden" name="command" value="deleteEmailList" /> + <label for="emailList">List Name: </label> + <input type="text" name="emailList" value="" /><br /> + </p> + + <p><input type="submit" value="Delete List →"></p> +</form> +<form method="post" accept-charset="utf-8"> + <h3>Add Recipient To Email List</h3> + <p>Add or remove a recipient from an existing email list. A complete + email address is required for recipients outside the current + domain.</p> + <p> + <input type="hidden" name="command" value="modifySubscription" /> + <label for="emailList">List Name: </label> + <input type="text" name="emailList" value="" /><br /> + <label for="recipient">Recipient Address: </label> + <input type="text" name="recipient" value="" /><br /> + <div class="radio"> + <input type="radio" name="mode" value="subscribe">Subscribe + recipient.</input><br /> + <input type="radio" name="mode" value="unsubscribe" + checked="true">Unsubscribe recipient.</input> + </div> + </p> + + <p><input type="submit" value="Update Subscription →"></p> +</form> +<form method="get" accept-charset="utf-8"> + <h3>Retrieve All Recipients</h3> + <p>Retrieve all recipients subscribed to an existing email list.</p> + <p> + <input type="hidden" name="command" value="retrieveAllRecipients" /> + <label for="emailList">List Name: </label> + <input type="text" name="emailList" value="" /><br /> + </p> + + <p><input type="submit" value="Retrieve Recipients →"></p> +</form> +<?php +} + +/** + * Log the current user out of the application. + * + * @return void + */ +function logout() +{ +session_destroy(); +?> +<h2>Logout</h2> + +<p>Logout successful.</p> + +<ul id="menuSelect"> + <li><a class="menuSelect" href="?">Login</a></li> +</ul> +<?php +} + + +/** + * Processes loading of this sample code through a web browser. + * + * @return void + */ +function runWWWVersion() +{ + session_start(); + + // Note that all calls to endHTML() below end script execution! + + // Check to make sure that the user has set a password. + $p = LOGIN_PASSWORD; + if (empty($p)) { + startHTML(false); + displayPasswordNotSetNotice(); + endHTML(); + } + + // Grab any login credentials that might be waiting in the request + if (!empty($_POST['password'])) { + if ($_POST['password'] == LOGIN_PASSWORD) { + $_SESSION['authenticated'] = 'true'; + } else { + // Invalid password. Stop and display a login screen. + startHTML(false); + requestUserLogin("Incorrect password."); + endHTML(); + } + } + + // If the user isn't authenticated, display a login screen + if (!isset($_SESSION['authenticated'])) { + startHTML(false); + requestUserLogin(); + endHTML(); + } + + // Try to login. If login fails, log the user out and display an + // error message. + try { + $client = getClientLoginHttpClient(GAPPS_USERNAME . '@' . + GAPPS_DOMAIN, GAPPS_PASSWORD); + $gapps = new Zend_Gdata_Gapps($client, GAPPS_DOMAIN); + } catch (Zend_Gdata_App_AuthException $e) { + session_destroy(); + startHTML(false); + displayAuthenticationFailedNotice(); + endHTML(); + } + + // Success! We're logged in. + // First we check for commands that can be submitted either though + // POST or GET (they don't make any changes). + if (!empty($_REQUEST['command'])) { + switch ($_REQUEST['command']) { + case 'retrieveUser': + startHTML(); + retrieveUser($gapps, true, $_REQUEST['user']); + endHTML(true); + case 'retrieveAllUsers': + startHTML(); + retrieveAllUsers($gapps, true); + endHTML(true); + case 'retrieveNickname': + startHTML(); + retrieveNickname($gapps, true, $_REQUEST['nickname']); + endHTML(true); + case 'retrieveNicknames': + startHTML(); + retrieveNicknames($gapps, true, $_REQUEST['user']); + endHTML(true); + case 'retrieveAllNicknames': + startHTML(); + retrieveAllNicknames($gapps, true); + endHTML(true); + case 'retrieveEmailLists': + startHTML(); + retrieveEmailLists($gapps, true, $_REQUEST['recipient']); + endHTML(true); + case 'retrieveAllEmailLists': + startHTML(); + retrieveAllEmailLists($gapps, true); + endHTML(true); + case 'retrieveAllRecipients': + startHTML(); + retrieveAllRecipients($gapps, true, $_REQUEST['emailList']); + endHTML(true); + } + } + + // Now we handle the potentially destructive commands, which have to + // be submitted by POST only. + if (!empty($_POST['command'])) { + switch ($_POST['command']) { + case 'createUser': + startHTML(); + createUser($gapps, true, $_POST['user'], + $_POST['givenName'], $_POST['familyName'], + $_POST['pass']); + endHTML(true); + case 'updateUserName': + startHTML(); + updateUserName($gapps, true, $_POST['user'], + $_POST['givenName'], $_POST['familyName']); + endHTML(true); + case 'updateUserPassword': + startHTML(); + updateUserPassword($gapps, true, $_POST['user'], + $_POST['pass']); + endHTML(true); + case 'setUserSuspended': + if ($_POST['mode'] == 'suspend') { + startHTML(); + suspendUser($gapps, true, $_POST['user']); + endHTML(true); + } elseif ($_POST['mode'] == 'restore') { + startHTML(); + restoreUser($gapps, true, $_POST['user']); + endHTML(true); + } else { + header('HTTP/1.1 400 Bad Request'); + startHTML(); + echo "<h2>Invalid mode.</h2>\n"; + echo "<p>Please check your request and try again.</p>"; + endHTML(true); + } + case 'setUserAdmin': + if ($_POST['mode'] == 'issue') { + startHTML(); + giveUserAdminRights($gapps, true, $_POST['user']); + endHTML(true); + } elseif ($_POST['mode'] == 'revoke') { + startHTML(); + revokeUserAdminRights($gapps, true, $_POST['user']); + endHTML(true); + } else { + header('HTTP/1.1 400 Bad Request'); + startHTML(); + echo "<h2>Invalid mode.</h2>\n"; + echo "<p>Please check your request and try again.</p>"; + endHTML(true); + } + case 'setForceChangePassword': + if ($_POST['mode'] == 'set') { + startHTML(); + setUserMustChangePassword($gapps, true, $_POST['user']); + endHTML(true); + } elseif ($_POST['mode'] == 'clear') { + startHTML(); + clearUserMustChangePassword($gapps, true, $_POST['user']); + endHTML(true); + } else { + header('HTTP/1.1 400 Bad Request'); + startHTML(); + echo "<h2>Invalid mode.</h2>\n"; + echo "<p>Please check your request and try again.</p>"; + endHTML(true); + } + case 'deleteUser': + startHTML(); + deleteUser($gapps, true, $_POST['user']); + endHTML(true); + case 'createNickname': + startHTML(); + createNickname($gapps, true, $_POST['user'], + $_POST['nickname']); + endHTML(true); + case 'deleteNickname': + startHTML(); + deleteNickname($gapps, true, $_POST['nickname']); + endHTML(true); + case 'createEmailList': + startHTML(); + createEmailList($gapps, true, $_POST['emailList']); + endHTML(true); + case 'deleteEmailList': + startHTML(); + deleteEmailList($gapps, true, $_POST['emailList']); + endHTML(true); + case 'modifySubscription': + if ($_POST['mode'] == 'subscribe') { + startHTML(); + addRecipientToEmailList($gapps, true, $_POST['recipient'], + $_POST['emailList']); + endHTML(true); + } elseif ($_POST['mode'] == 'unsubscribe') { + startHTML(); + removeRecipientFromEmailList($gapps, true, + $_POST['recipient'], $_POST['emailList']); + endHTML(true); + } else { + header('HTTP/1.1 400 Bad Request'); + startHTML(); + echo "<h2>Invalid mode.</h2>\n"; + echo "<p>Please check your request and try again.</p>"; + endHTML(true); + } + } + } + + // Check for an invalid command. If so, display an error and exit. + if (!empty($_REQUEST['command'])) { + header('HTTP/1.1 400 Bad Request'); + startHTML(); + echo "<h2>Invalid command.</h2>\n"; + echo "<p>Please check your request and try again.</p>"; + endHTML(true); + } + + // If a menu parameter is available, display a submenu. + if (!empty($_REQUEST['menu'])) { + switch ($_REQUEST['menu']) { + case 'user': + startHTML(); + displayUserMenu(); + endHTML(); + case 'nickname': + startHTML(); + displayNicknameMenu(); + endHTML(); + case 'emailList': + startHTML(); + displayEmailListMenu(); + endHTML(); + case 'logout': + startHTML(false); + logout(); + endHTML(); + default: + header('HTTP/1.1 400 Bad Request'); + startHTML(); + echo "<h2>Invalid menu selection.</h2>\n"; + echo "<p>Please check your request and try again.</p>"; + endHTML(true); + } + } + + // If we get this far, that means there's nothing to do. Display + // the main menu. + // If no command was issued and no menu was selected, display the + // main menu. + startHTML(); + displayMenu(); + endHTML(); +} + +// ************************** PROGRAM ENTRY POINT ************************** + +if (!isset($_SERVER["HTTP_HOST"])) { + // running through command line + runCLIVersion($argv, $argc); +} else { + // running through web server + try { + runWWWVersion(); + } catch (Zend_Gdata_Gapps_ServiceException $e) { + // Try to recover gracefully from a service exception. + // The HTML prologue will have already been sent. + echo "<p><strong>Service Error Encountered</strong></p>\n"; + echo "<pre>" . htmlspecialchars($e->__toString()) . "</pre>"; + endHTML(true); + } +} diff --git a/zend/demos/Zend/Gdata/InstallationChecker.php b/zend/demos/Zend/Gdata/InstallationChecker.php new file mode 100644 index 0000000..ab975a2 --- /dev/null +++ b/zend/demos/Zend/Gdata/InstallationChecker.php @@ -0,0 +1,386 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Simple class to verify that the server that this is run on has a correct + * installation of the Zend Framework Gdata component. + */ +class InstallationChecker { + + const CSS_WARNING = '.warning { color: #fff; background-color: #AF0007;}'; + const CSS_SUCCESS = '.success { color: #000; background-color: #69FF4F;}'; + const CSS_ERROR = '.error { color: #fff; background-color: #FF9FA3;}'; + const PHP_EXTENSION_ERRORS = 'PHP Extension Errors'; + const PHP_MANUAL_LINK_FRAGMENT = 'http://us.php.net/manual/en/book.'; + const PHP_REQUIREMENT_CHECKER_ID = 'PHP Requirement checker v0.1'; + const SSL_CAPABILITIES_ERRORS = 'SSL Capabilities Errors'; + const YOUTUBE_API_CONNECTIVITY_ERRORS = 'YouTube API Connectivity Errors'; + const ZEND_GDATA_INSTALL_ERRORS = 'Zend Framework Installation Errors'; + const ZEND_SUBVERSION_URI = 'http://framework.zend.com/download/subversion'; + + private static $REQUIRED_EXTENSIONS = array( + 'ctype', 'dom', 'libxml', 'spl', 'standard', 'openssl'); + + private $_allErrors = array( + self::PHP_EXTENSION_ERRORS => array( + 'tested' => false, 'errors' => null), + self::ZEND_GDATA_INSTALL_ERRORS => array( + 'tested' => false, 'errors' => null), + self::SSL_CAPABILITIES_ERRORS => array( + 'tested' => false, 'errors' => null), + self::YOUTUBE_API_CONNECTIVITY_ERRORS => array( + 'tested' => false, 'errors' => null) + ); + + private $_sapiModeCLI = null; + + /** + * Create a new InstallationChecker object and run verifications. + * @return void + */ + public function __construct() + { + $this->determineIfInCLIMode(); + $this->runAllVerifications(); + $this->outputResults(); + } + + /** + * Set the sapiModeCLI variable to true if we are running CLI mode. + * + * @return void + */ + private function determineIfInCLIMode() + { + if (php_sapi_name() == 'cli') { + $this->_sapiModeCLI = true; + } + } + + /** + * Getter for sapiModeCLI variable. + * + * @return boolean True if we are running in CLI mode. + */ + public function runningInCLIMode() + { + if ($this->_sapiModeCLI) { + return true; + } else { + return false; + } + } + + /** + * Run verifications, stopping at each step if there is a failure. + * + * @return void + */ + public function runAllVerifications() + { + if (!$this->validatePHPExtensions()) { + return; + } + if (!$this->validateZendFrameworkInstallation()) { + return; + } + if (!$this->testSSLCapabilities()) { + return; + } + if (!$this->validateYouTubeAPIConnectivity()) { + return; + } + } + + /** + * Validate that the required PHP Extensions are installed and available. + * + * @return boolean False if there were errors. + */ + private function validatePHPExtensions() + { + $phpExtensionErrors = array(); + foreach (self::$REQUIRED_EXTENSIONS as $requiredExtension) { + if (!extension_loaded($requiredExtension)) { + $requiredExtensionError = $requiredExtension . + ' extension missing'; + $documentationLink = null; + if ($requiredExtension != 'standard') { + $documentationLink = self::PHP_MANUAL_LINK_FRAGMENT . + $requiredExtension . '.php'; + $documentationLink = + $this->checkAndAddHTMLLink($documentationLink); + } else { + $documentationLink = self::PHP_MANUAL_LINK_FRAGMENT . + 'spl.php'; + $documentationLink = + $this->checkAndAddHTMLLink($documentationLink); + } + + if ($documentationLink) { + $phpExtensionErrors[] = $requiredExtensionError . + ' - refer to ' . $documentationLink; + } + } + } + $this->_allErrors[self::PHP_EXTENSION_ERRORS]['tested'] = true; + if (count($phpExtensionErrors) > 0) { + $this->_allErrors[self::PHP_EXTENSION_ERRORS]['errors'] = + $phpExtensionErrors; + return false; + } + return true; + } + + /** + * Validate that the Gdata component of Zend Framework is installed + * properly. Also checks that the required YouTube API helper methods are + * found. + * + * @return boolean False if there were errors. + */ + private function validateZendFrameworkInstallation() + { + $zendFrameworkInstallationErrors = array(); + $zendLoaderPresent = false; + try { + $zendLoaderPresent = @fopen('Zend/Loader.php', 'r', true); + } catch (Exception $e) { + $zendFrameworkInstallationErrors[] = 'Exception thrown trying to ' . + 'access Zend/Loader.php using \'use_include_path\' = true ' . + 'Make sure you include the Zend Framework in your ' . + 'include_path which currently contains: "' . + ini_get('include_path') . '"'; + } + + if ($zendLoaderPresent) { + @fclose($zendLoaderPresent); + require_once('Zend/Loader.php'); + require_once('Zend/Version.php'); + Zend_Loader::loadClass('Zend_Gdata_YouTube'); + Zend_Loader::loadClass('Zend_Gdata_YouTube_VideoEntry'); + $yt = new Zend_Gdata_YouTube(); + $videoEntry = $yt->newVideoEntry(); + if (!method_exists($videoEntry, 'setVideoTitle')) { + $zendFrameworkMessage = 'Your version of the ' . + 'Zend Framework ' . Zend_Version::VERSION . ' is too old' . + ' to run the YouTube demo application and does not' . + ' contain the new helper methods. Please check out a' . + ' newer version from Zend\'s repository: ' . + checkAndAddHTMLLink(self::ZEND_SUBVERSION_URI); + $zendFrameworkInstallationErrors[] = $zendFrameworkMessage; + } + } else { + if (count($zendFrameworkInstallationErrors) < 1) { + $zendFrameworkInstallationErrors[] = 'Exception thrown trying' . + ' to access Zend/Loader.php using \'use_include_path\' =' . + ' true. Make sure you include Zend Framework in your' . + ' include_path which currently contains: ' . + ini_get('include_path'); + } + } + + $this->_allErrors[self::ZEND_GDATA_INSTALL_ERRORS]['tested'] = true; + + if (count($zendFrameworkInstallationErrors) > 0) { + $this->_allErrors[self::ZEND_GDATA_INSTALL_ERRORS]['errors'] = + $zendFrameworkInstallationErrors; + return false; + } + return true; + } + + /** + * Create HTML link from an input string if not in CLI mode. + * + * @param string The error message to be converted to a link. + * @return string Either the original error message or an HTML version. + */ + private function checkAndAddHTMLLink($inputString) { + if (!$this->runningInCLIMode()) { + return $this->makeHTMLLink($inputString); + } else { + return $inputString; + } + } + + /** + * Create an HTML link from a string. + * + * @param string The string to be made into link text and anchor target. + * @return string HTML link. + */ + private function makeHTMLLink($inputString) + { + return '<a href="'. $inputString . '" target="_blank">' . + $inputString . '</a>'; + } + + /** + * Validate that SSL Capabilities are available. + * + * @return boolean False if there were errors. + */ + private function testSSLCapabilities() + { + $sslCapabilitiesErrors = array(); + require_once 'Zend/Loader.php'; + Zend_Loader::loadClass('Zend_Http_Client'); + + $httpClient = new Zend_Http_Client( + 'https://www.google.com/accounts/AuthSubRequest'); + $response = $httpClient->request(); + $this->_allErrors[self::SSL_CAPABILITIES_ERRORS]['tested'] = true; + + if ($response->isError()) { + $sslCapabilitiesErrors[] = 'Response from trying to access' . + ' \'https://www.google.com/accounts/AuthSubRequest\' ' . + $response->getStatus() . ' - ' . $response->getMessage(); + } + + if (count($sslCapabilitiesErrors) > 0) { + $this->_allErrors[self::SSL_CAPABILITIES_ERRORS]['errors'] = + $sslCapabilitiesErrors; + return false; + } + return true; + } + + /** + * Validate that we can connect to the YouTube API. + * + * @return boolean False if there were errors. + */ + private function validateYouTubeAPIConnectivity() + { + $connectivityErrors = array(); + require_once 'Zend/Loader.php'; + Zend_Loader::loadClass('Zend_Gdata_YouTube'); + $yt = new Zend_Gdata_YouTube(); + $topRatedFeed = $yt->getTopRatedVideoFeed(); + if ($topRatedFeed instanceof Zend_Gdata_YouTube_VideoFeed) { + if ($topRatedFeed->getTotalResults()->getText() < 1) { + $connectivityErrors[] = 'There was less than 1 video entry' . + ' in the \'Top Rated Video Feed\''; + } + } else { + $connectivityErrors[] = 'The call to \'getTopRatedVideoFeed()\' ' . + 'did not result in a Zend_Gdata_YouTube_VideoFeed object'; + } + + $this->_allErrors[self::YOUTUBE_API_CONNECTIVITY_ERRORS]['tested'] = + true; + if (count($connectivityErrors) > 0) { + $this->_allErrors[self::YOUTUBE_API_CONNECTIVITY_ERRORS]['tested'] = + $connectivityErrors; + return false; + } + return true; + } + + /** + * Dispatch a call to outputResultsInHTML or outputResultsInText pending + * the current SAPI mode. + * + * @return void + */ + public function outputResults() + { + if ($this->_sapiModeCLI) { + print $this->getResultsInText(); + } else { + print $this->getResultsInHTML(); + } + } + + + /** + * Return a string representing the results of the verifications. + * + * @return string A string representing the results. + */ + private function getResultsInText() + { + $output = "== Ran PHP Installation Checker using CLI ==\n"; + + $error_count = 0; + foreach($this->_allErrors as $key => $value) { + $output .= $key . ' -- '; + if (($value['tested'] == true) && (count($value['errors']) == 0)) { + $output .= "No errors found\n"; + } elseif ($value['tested'] == true) { + $output .= "Tested\n"; + $error_count = 0; + foreach ($value['errors'] as $error) { + $output .= "Error number: " . $error_count . "\n--" . + $error . "\n"; + } + } else { + $output .= "Not tested\n"; + } + $error_count++; + } + return $output; + } + + /** + * Return an HTML table representing the results of the verifications. + * + * @return string An HTML string representing the results. + */ + private function getResultsInHTML() + { + $html = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" " . + "\"http://www.w3.org/TR/html4/strict.dtd\">\n". + "<html><head>\n<title>PHP Installation Checker</title>\n" . + "<style type=\"text/css\">\n" . + self::CSS_WARNING . "\n" . + self::CSS_SUCCESS . "\n" . + self::CSS_ERROR . "\n" . + "</style></head>\n" . + "<body>\n<table class=\"verification_table\">" . + "<caption>Ran PHP Installation Checker on " . + gmdate('c') . "</caption>\n"; + + $error_count = 0; + foreach($this->_allErrors as $key => $value) { + $html .= "<tr><td class=\"verification_type\">" . $key . "</td>"; + if (($value['tested'] == true) && (count($value['errors']) == 0)) { + $html .= "<td class=\"success\">Tested</td></tr>\n" . + "<tr><td colspan=\"2\">No errors found</td></tr>\n"; + } elseif ($value['tested'] == true) { + $html .= "<td class=\"warning\">Tested</td></tr>\n"; + $error_count = 0; + foreach ($value['errors'] as $error) { + $html .= "<tr><td class=\"error\">" . $error_count . "</td>" . + "<td class=\"error\">" . $error . "</td></tr>\n"; + } + } else { + $html .= "<td class=\"warning\">Not tested</td></tr>\n"; + } + $error_count++; + } + $html .= "</body></html>"; + return $html; + } +} + +$installationChecker = new InstallationChecker(); diff --git a/zend/demos/Zend/Gdata/MyLibrary/demo.php b/zend/demos/Zend/Gdata/MyLibrary/demo.php new file mode 100755 index 0000000..33045c5 --- /dev/null +++ b/zend/demos/Zend/Gdata/MyLibrary/demo.php @@ -0,0 +1,226 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Loader + */ +require_once 'Zend/Loader.php'; + +/** + * @see Zend_Gdata_Books + */ +Zend_Loader::loadClass('Zend_Gdata_Books'); + +/** + * @see Zend_Gdata_ClientLogin + */ +Zend_Loader::loadClass('Zend_Gdata_ClientLogin'); + +/** + * @see Zend_Gdata_App_AuthException + */ +Zend_Loader::loadClass('Zend_Gdata_App_AuthException'); + + +class SimpleDemo { + /** + * Constructor + * + * @param string $email + * @param string $password + * @return void + */ + public function __construct($email, $password) + { + try { + $client = Zend_Gdata_ClientLogin::getHttpClient($email, $password, + Zend_Gdata_Books::AUTH_SERVICE_NAME); + } catch (Zend_Gdata_App_AuthException $ae) { + exit("Error: ". $ae->getMessage() ."\nCredentials provided were ". + "email: [$email] and password [$password].\n"); + } + $this->gdClient = new Zend_Gdata_Books($client); + } + + /** + * Print the content of a feed + * + * @param Zend_Gdata_Gbase_Feed $feed + * @return void + */ + public function printFeed($feed) + { + $i = 0; + foreach($feed as $entry) { + $titles = $entry->getTitles(); + $rating = $entry->getRating(); + if (count($titles)) { + if (!is_object($rating)) { + $rating_str = "?"; + } else { + $rating_str = $rating->getAverage(); + } + print $i." ".$titles[0]->getText(). + ", Rating: ".$rating_str."\n"; + $i++; + } + } + } + + /** + * List books in the My library feed + * + * @return void + */ + public function listLibrary() + { + $feed = $this->gdClient->getUserLibraryFeed(); + print "== Books in my library ==\n"; + $this->printFeed($feed); + print "\n"; + } + + /** + * List books in the annotation feed. + * + * @return void + */ + public function listReviewed() + { + $feed = $this->gdClient->getUserLibraryFeed( + Zend_Gdata_Books::MY_ANNOTATION_FEED_URI); + print "== Books I annotated ==\n"; + $this->printFeed($feed); + print "\n"; + } + + /** + * Add an arbitrary book to the library feed. + * + * @param string $volumeId Volume to the library + * @return void + */ + public function addBookToLibrary($volumeId) + { + $entry = new Zend_Gdata_Books_VolumeEntry(); + $entry->setId( + new Zend_Gdata_App_Extension_Id($volumeId)); + print "Inserting ".$volumeId."\n\n"; + return $this->gdClient->insertVolume($entry); + } + + /** + * Add an arbitrary book to the library feed. + * + * @param string $volumeId Volume to add a rating to + * @param float $rating Numeric rating from 0 to 5 + * @return void + */ + public function addRating($volumeId, $rating) + { + $entry = new Zend_Gdata_Books_VolumeEntry(); + $entry->setId( + new Zend_Gdata_App_Extension_Id($volumeId)); + $entry->setRating( + new Zend_Gdata_Extension_Rating($rating, "0", 5, 1)); + print "Inserting a rating of ".$rating." for ".$volumeId."\n\n"; + return $this->gdClient->insertVolume($entry, + Zend_Gdata_Books::MY_ANNOTATION_FEED_URI); + } + + /** + * Remove an an arbitrary book from a feed (either remove + * from library feed or remove the annotations from annotation + * feed). + * + * @param Zend_Gdata_Books_VolumeEntry $entry + * @return void + */ + public function removeBook($entry) + { + print "Deleting ".$entry->getId()->getText()."\n\n"; + $this->gdClient->deleteVolume($entry); + } + + /** + * Main logic for the demo. + * + * @return void + */ + public function run() + { + $test_volume = "8YEAAAAAYAAJ"; + + // Playing with the library feed + $this->listLibrary(); + + $entry = $this->addBookToLibrary($test_volume); + $this->listLibrary(); + + $this->removeBook($entry); + $this->listLibrary(); + + // Playing with the annotation feed + $this->listReviewed(); + + $entry = $this->addRating($test_volume, 4.0); + $this->listReviewed(); + + $this->removeBook($entry); + $this->listReviewed(); + } +} + +/** + * getInput + * + * @param string $text + * @return string + */ +function getInput($text) +{ + echo $text.': '; + return trim(fgets(STDIN)); +} + +echo "Books Gdata API - my library demo\n\n"; +$email = null; +$pass = null; + +// process command line options +foreach ($argv as $argument) { + $argParts = explode('=', $argument); + if ($argParts[0] == '--email') { + $email = $argParts[1]; + } else if ($argParts[0] == '--pass') { + $pass = $argParts[1]; + } +} + +if (($email == null) || ($pass == null)) { + $email = getInput( + "Please enter your email address [example: username@gmail.com]"); + $pass = getInput( + "Please enter your password [example: mypassword]"); +} + +$demo = new SimpleDemo($email, $pass); +$demo->run(); diff --git a/zend/demos/Zend/Gdata/Photos.php b/zend/demos/Zend/Gdata/Photos.php new file mode 100755 index 0000000..4c3e257 --- /dev/null +++ b/zend/demos/Zend/Gdata/Photos.php @@ -0,0 +1,904 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * PHP sample code for the Photos data API. Utilizes the + * Zend Framework Gdata components to communicate with the Google API. + * + * Requires the Zend Framework Gdata components and PHP >= 5.2.11 + * + * You can run this sample from a web browser. + * + * NOTE: You must ensure that Zend Framework is in your PHP include + * path. You can do this via php.ini settings, or by modifying the + * argument to set_include_path in the code below. + * + * NOTE: As this is sample code, not all of the functions do full error + * handling. + */ + +/** + * @see Zend_Loader + */ +require_once 'Zend/Loader.php'; + +/** + * @see Zend_Gdata + */ +Zend_Loader::loadClass('Zend_Gdata'); + +/** + * @see Zend_Gdata_AuthSub + */ +Zend_Loader::loadClass('Zend_Gdata_AuthSub'); + +/** + * @see Zend_Gdata_Photos + */ +Zend_Loader::loadClass('Zend_Gdata_Photos'); + +/** + * @see Zend_Gdata_Photos_UserQuery + */ +Zend_Loader::loadClass('Zend_Gdata_Photos_UserQuery'); + +/** + * @see Zend_Gdata_Photos_AlbumQuery + */ +Zend_Loader::loadClass('Zend_Gdata_Photos_AlbumQuery'); + +/** + * @see Zend_Gdata_Photos_PhotoQuery + */ +Zend_Loader::loadClass('Zend_Gdata_Photos_PhotoQuery'); + +/** + * @see Zend_Gdata_App_Extension_Category + */ +Zend_Loader::loadClass('Zend_Gdata_App_Extension_Category'); + +session_start(); + + +/** + * Adds a new photo to the specified album + * + * @param Zend_Http_Client $client The authenticated client + * @param string $user The user's account name + * @param integer $albumId The album's id + * @param array $photo The uploaded photo + * @return void + */ +function addPhoto($client, $user, $albumId, $photo) +{ + $photos = new Zend_Gdata_Photos($client); + + $fd = $photos->newMediaFileSource($photo["tmp_name"]); + $fd->setContentType($photo["type"]); + + $entry = new Zend_Gdata_Photos_PhotoEntry(); + $entry->setMediaSource($fd); + $entry->setTitle($photos->newTitle($photo["name"])); + + $albumQuery = new Zend_Gdata_Photos_AlbumQuery; + $albumQuery->setUser($user); + $albumQuery->setAlbumId($albumId); + + $albumEntry = $photos->getAlbumEntry($albumQuery); + + $result = $photos->insertPhotoEntry($entry, $albumEntry); + if ($result) { + outputAlbumFeed($client, $user, $albumId); + } else { + echo "There was an issue with the file upload."; + } +} + +/** + * Deletes the specified photo + * + * @param Zend_Http_Client $client The authenticated client + * @param string $user The user's account name + * @param integer $albumId The album's id + * @param integer $photoId The photo's id + * @return void + */ +function deletePhoto($client, $user, $albumId, $photoId) +{ + $photos = new Zend_Gdata_Photos($client); + + $photoQuery = new Zend_Gdata_Photos_PhotoQuery; + $photoQuery->setUser($user); + $photoQuery->setAlbumId($albumId); + $photoQuery->setPhotoId($photoId); + $photoQuery->setType('entry'); + + $entry = $photos->getPhotoEntry($photoQuery); + + $photos->deletePhotoEntry($entry, true); + + outputAlbumFeed($client, $user, $albumId); +} + +/** + * Adds a new album to the specified user's album + * + * @param Zend_Http_Client $client The authenticated client + * @param string $user The user's account name + * @param string $name The name of the new album + * @return void + */ +function addAlbum($client, $user, $name) +{ + $photos = new Zend_Gdata_Photos($client); + + $entry = new Zend_Gdata_Photos_AlbumEntry(); + $entry->setTitle($photos->newTitle($name)); + + $result = $photos->insertAlbumEntry($entry); + if ($result) { + outputUserFeed($client, $user); + } else { + echo "There was an issue with the album creation."; + } +} + +/** + * Deletes the specified album + * + * @param Zend_Http_Client $client The authenticated client + * @param string $user The user's account name + * @param integer $albumId The album's id + * @return void + */ +function deleteAlbum($client, $user, $albumId) +{ + $photos = new Zend_Gdata_Photos($client); + + $albumQuery = new Zend_Gdata_Photos_AlbumQuery; + $albumQuery->setUser($user); + $albumQuery->setAlbumId($albumId); + $albumQuery->setType('entry'); + + $entry = $photos->getAlbumEntry($albumQuery); + + $photos->deleteAlbumEntry($entry, true); + + outputUserFeed($client, $user); +} + +/** + * Adds a new comment to the specified photo + * + * @param Zend_Http_Client $client The authenticated client + * @param string $user The user's account name + * @param integer $albumId The album's id + * @param integer $photoId The photo's id + * @param string $comment The comment to add + * @return void + */ +function addComment($client, $user, $album, $photo, $comment) +{ + $photos = new Zend_Gdata_Photos($client); + + $entry = new Zend_Gdata_Photos_CommentEntry(); + $entry->setTitle($photos->newTitle($comment)); + $entry->setContent($photos->newContent($comment)); + + $photoQuery = new Zend_Gdata_Photos_PhotoQuery; + $photoQuery->setUser($user); + $photoQuery->setAlbumId($album); + $photoQuery->setPhotoId($photo); + $photoQuery->setType('entry'); + + $photoEntry = $photos->getPhotoEntry($photoQuery); + + $result = $photos->insertCommentEntry($entry, $photoEntry); + if ($result) { + outputPhotoFeed($client, $user, $album, $photo); + } else { + echo "There was an issue with the comment creation."; + } +} + +/** + * Deletes the specified comment + * + * @param Zend_Http_Client $client The authenticated client + * @param string $user The user's account name + * @param integer $albumId The album's id + * @param integer $photoId The photo's id + * @param integer $commentId The comment's id + * @return void + */ +function deleteComment($client, $user, $albumId, $photoId, $commentId) +{ + $photos = new Zend_Gdata_Photos($client); + + $photoQuery = new Zend_Gdata_Photos_PhotoQuery; + $photoQuery->setUser($user); + $photoQuery->setAlbumId($albumId); + $photoQuery->setPhotoId($photoId); + $photoQuery->setType('entry'); + + $path = $photoQuery->getQueryUrl() . '/commentid/' . $commentId; + + $entry = $photos->getCommentEntry($path); + + $photos->deleteCommentEntry($entry, true); + + outputPhotoFeed($client, $user, $albumId, $photoId); +} + +/** + * Adds a new tag to the specified photo + * + * @param Zend_Http_Client $client The authenticated client + * @param string $user The user's account name + * @param integer $album The album's id + * @param integer $photo The photo's id + * @param string $tag The tag to add to the photo + * @return void + */ +function addTag($client, $user, $album, $photo, $tag) +{ + $photos = new Zend_Gdata_Photos($client); + + $entry = new Zend_Gdata_Photos_TagEntry(); + $entry->setTitle($photos->newTitle($tag)); + + $photoQuery = new Zend_Gdata_Photos_PhotoQuery; + $photoQuery->setUser($user); + $photoQuery->setAlbumId($album); + $photoQuery->setPhotoId($photo); + $photoQuery->setType('entry'); + + $photoEntry = $photos->getPhotoEntry($photoQuery); + + $result = $photos->insertTagEntry($entry, $photoEntry); + if ($result) { + outputPhotoFeed($client, $user, $album, $photo); + } else { + echo "There was an issue with the tag creation."; + } +} + +/** + * Deletes the specified tag + * + * @param Zend_Http_Client $client The authenticated client + * @param string $user The user's account name + * @param integer $albumId The album's id + * @param integer $photoId The photo's id + * @param string $tagContent The name of the tag to be deleted + * @return void + */ +function deleteTag($client, $user, $albumId, $photoId, $tagContent) +{ + $photos = new Zend_Gdata_Photos($client); + + $photoQuery = new Zend_Gdata_Photos_PhotoQuery; + $photoQuery->setUser($user); + $photoQuery->setAlbumId($albumId); + $photoQuery->setPhotoId($photoId); + $query = $photoQuery->getQueryUrl() . "?kind=tag"; + + $photoFeed = $photos->getPhotoFeed($query); + + foreach ($photoFeed as $entry) { + if ($entry instanceof Zend_Gdata_Photos_TagEntry) { + if ($entry->getContent() == $tagContent) { + $tagEntry = $entry; + } + } + } + + $photos->deleteTagEntry($tagEntry, true); + + outputPhotoFeed($client, $user, $albumId, $photoId); +} + +/** + * Returns the path to the current script, without any query params + * + * Env variables used: + * $_SERVER['PHP_SELF'] + * + * @return string Current script path + */ +function getCurrentScript() +{ + global $_SERVER; + return $_SERVER["PHP_SELF"]; +} + +/** + * Returns the full URL of the current page, based upon env variables + * + * Env variables used: + * $_SERVER['HTTPS'] = (on|off|) + * $_SERVER['HTTP_HOST'] = value of the Host: header + * $_SERVER['SERVER_PORT'] = port number (only used if not http/80,https/443) + * $_SERVER['REQUEST_URI'] = the URI after the method of the HTTP request + * + * @return string Current URL + */ +function getCurrentUrl() +{ + global $_SERVER; + + /** + * Filter php_self to avoid a security vulnerability. + */ + $php_request_uri = htmlentities(substr($_SERVER['REQUEST_URI'], 0, + strcspn($_SERVER['REQUEST_URI'], "\n\r")), ENT_QUOTES); + + if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') { + $protocol = 'https://'; + } else { + $protocol = 'http://'; + } + $host = $_SERVER['HTTP_HOST']; + if ($_SERVER['SERVER_PORT'] != '' && + (($protocol == 'http://' && $_SERVER['SERVER_PORT'] != '80') || + ($protocol == 'https://' && $_SERVER['SERVER_PORT'] != '443'))) { + $port = ':' . $_SERVER['SERVER_PORT']; + } else { + $port = ''; + } + return $protocol . $host . $port . $php_request_uri; +} + +/** + * Returns the AuthSub URL which the user must visit to authenticate requests + * from this application. + * + * Uses getCurrentUrl() to get the next URL which the user will be redirected + * to after successfully authenticating with the Google service. + * + * @return string AuthSub URL + */ +function getAuthSubUrl() +{ + $next = getCurrentUrl(); + $scope = 'http://picasaweb.google.com/data'; + $secure = false; + $session = true; + return Zend_Gdata_AuthSub::getAuthSubTokenUri($next, $scope, $secure, + $session); +} + +/** + * Outputs a request to the user to login to their Google account, including + * a link to the AuthSub URL. + * + * Uses getAuthSubUrl() to get the URL which the user must visit to authenticate + * + * @return void + */ +function requestUserLogin($linkText) +{ + $authSubUrl = getAuthSubUrl(); + echo "<a href=\"{$authSubUrl}\">{$linkText}</a>"; +} + +/** + * Returns a HTTP client object with the appropriate headers for communicating + * with Google using AuthSub authentication. + * + * Uses the $_SESSION['sessionToken'] to store the AuthSub session token after + * it is obtained. The single use token supplied in the URL when redirected + * after the user succesfully authenticated to Google is retrieved from the + * $_GET['token'] variable. + * + * @return Zend_Http_Client + */ +function getAuthSubHttpClient() +{ + global $_SESSION, $_GET; + if (!isset($_SESSION['sessionToken']) && isset($_GET['token'])) { + $_SESSION['sessionToken'] = + Zend_Gdata_AuthSub::getAuthSubSessionToken($_GET['token']); + } + $client = Zend_Gdata_AuthSub::getHttpClient($_SESSION['sessionToken']); + return $client; +} + +/** + * Processes loading of this sample code through a web browser. Uses AuthSub + * authentication and outputs a list of a user's albums if succesfully + * authenticated. + * + * @return void + */ +function processPageLoad() +{ + global $_SESSION, $_GET; + if (!isset($_SESSION['sessionToken']) && !isset($_GET['token'])) { + requestUserLogin('Please login to your Google Account.'); + } else { + $client = getAuthSubHttpClient(); + if (!empty($_REQUEST['command'])) { + switch ($_REQUEST['command']) { + case 'retrieveSelf': + outputUserFeed($client, "default"); + break; + case 'retrieveUser': + outputUserFeed($client, $_REQUEST['user']); + break; + case 'retrieveAlbumFeed': + outputAlbumFeed($client, $_REQUEST['user'], $_REQUEST['album']); + break; + case 'retrievePhotoFeed': + outputPhotoFeed($client, $_REQUEST['user'], $_REQUEST['album'], + $_REQUEST['photo']); + break; + } + } + + // Now we handle the potentially destructive commands, which have to + // be submitted by POST only. + if (!empty($_POST['command'])) { + switch ($_POST['command']) { + case 'addPhoto': + addPhoto($client, $_POST['user'], $_POST['album'], $_FILES['photo']); + break; + case 'deletePhoto': + deletePhoto($client, $_POST['user'], $_POST['album'], + $_POST['photo']); + break; + case 'addAlbum': + addAlbum($client, $_POST['user'], $_POST['name']); + break; + case 'deleteAlbum': + deleteAlbum($client, $_POST['user'], $_POST['album']); + break; + case 'addComment': + addComment($client, $_POST['user'], $_POST['album'], $_POST['photo'], + $_POST['comment']); + break; + case 'addTag': + addTag($client, $_POST['user'], $_POST['album'], $_POST['photo'], + $_POST['tag']); + break; + case 'deleteComment': + deleteComment($client, $_POST['user'], $_POST['album'], + $_POST['photo'], $_POST['comment']); + break; + case 'deleteTag': + deleteTag($client, $_POST['user'], $_POST['album'], $_POST['photo'], + $_POST['tag']); + break; + default: + break; + } + } + + // If a menu parameter is available, display a submenu. + if (!empty($_REQUEST['menu'])) { + switch ($_REQUEST['menu']) { + case 'user': + displayUserMenu(); + break; + case 'photo': + displayPhotoMenu(); + break; + case 'album': + displayAlbumMenu(); + break; + case 'logout': + logout(); + break; + default: + header('HTTP/1.1 400 Bad Request'); + echo "<h2>Invalid menu selection.</h2>\n"; + echo "<p>Please check your request and try again.</p>"; + } + } + + if (empty($_REQUEST['menu']) && empty($_REQUEST['command'])) { + displayMenu(); + } + } +} + +/** + * Displays the main menu, allowing the user to select from a list of actions. + * + * @return void + */ +function displayMenu() +{ +?> +<h2>Main Menu</h2> + +<p>Welcome to the Photos API demo page. Please select + from one of the following four options to fetch information.</p> + + <ul> + <li><a href="?command=retrieveSelf">Your Feed</a></li> + <li><a href="?menu=user">User Menu</a></li> + <li><a href="?menu=photo">Photos Menu</a></li> + <li><a href="?menu=album">Albums Menu</a></li> + </ul> +<?php +} + +/** + * Outputs an HTML link to return to the previous page. + * + * @return void + */ +function displayBackLink() +{ + echo "<br><br>"; + echo "<a href='javascript: history.go(-1);'><< Back</a>"; +} + +/** + * Displays the user menu, allowing the user to request a specific user's feed. + * + * @return void + */ +function displayUserMenu() +{ +?> +<h2>User Menu</h2> + +<div class="menuForm"> + <form method="get" accept-charset="utf-8"> + <h3 class='nopad'>Retrieve User Feed</h3> + <p>Retrieve the feed for an existing user.</p> + <p> + <input type="hidden" name="command" value="retrieveUser" /> + <label for="user">Username: </label> + <input type="text" name="user" value="" /><br /> + </p> + + <p><input type="submit" value="Retrieve User →"></p> + </form> +</div> +<?php + + displayBackLink(); +} + +/** + * Displays the photo menu, allowing the user to request a specific photo's feed. + * + * @return void + */ +function displayPhotoMenu() +{ +?> +<h2>Photo Menu</h2> + +<div class="menuForm"> + <form method="get" accept-charset="utf-8"> + <h3 class='nopad'>Retrieve Photo Feed</h3> + <p>Retrieve the feed for an existing photo.</p> + <p> + <input type="hidden" name="command" value="retrievePhotoFeed" /> + <label for="user">User: </label> + <input type="text" name="user" value="" /><br /> + <label for="album">Album ID: </label> + <input type="text" name="album" value="" /><br /> + <label for="photoid">Photo ID: </label> + <input type="text" name="photo" value="" /><br /> + </p> + + <p><input type="submit" value="Retrieve Photo Feed →"></p> + </form> +</div> +<?php + + displayBackLink(); +} + +/** + * Displays the album menu, allowing the user to request a specific album's feed. + * + * @return void + */ +function displayAlbumMenu() +{ +?> +<h2>Album Menu</h2> + +<div class="menuForm"> + <form method="get" accept-charset="utf-8"> + <h3 class='nopad'>Retrieve Album Feed</h3> + <p>Retrieve the feed for an existing album.</p> + <p> + <input type="hidden" name="command" value="retrieveAlbumFeed" /> + <label for="user">User: </label> + <input type="text" name="user" value="" /><br /> + <label for="album">Album ID: </label> + <input type="text" name="album" value="" /><br /> + </p> + + <p><input type="submit" value="Retrieve Album Feed →"></p> + </form> +</div> +<?php + + displayBackLink(); +} + +/** + * Outputs an HTML unordered list (ul), with each list item representing an + * album in the user's feed. + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $user The user's account name + * @return void + */ +function outputUserFeed($client, $user) +{ + $photos = new Zend_Gdata_Photos($client); + + $query = new Zend_Gdata_Photos_UserQuery(); + $query->setUser($user); + + $userFeed = $photos->getUserFeed(null, $query); + echo "<h2>User Feed for: " . $userFeed->getTitle() . "</h2>"; + echo "<ul class='user'>\n"; + foreach ($userFeed as $entry) { + if ($entry instanceof Zend_Gdata_Photos_AlbumEntry) { + echo "\t<li class='user'>"; + echo "<a href='?command=retrieveAlbumFeed&user="; + echo $userFeed->getTitle() . "&album=" . $entry->getGphotoId(); + echo "'>"; + $thumb = $entry->getMediaGroup()->getThumbnail(); + echo "<img class='thumb' src='" . $thumb[0]->getUrl() . "' /><br />"; + echo $entry->getTitle() . "</a>"; + echo "<form action='" . getCurrentScript() . "'' method='post' class='deleteForm'>"; + echo "<input type='hidden' name='user' value='" . $user . "' />"; + echo "<input type='hidden' name='album' value='" . $entry->getGphotoId(); + echo "' />"; + echo "<input type='hidden' name='command' value='deleteAlbum' />"; + echo "<input type='submit' value='Delete' /></form>"; + echo "</li>\n"; + } + } + echo "</ul><br />\n"; + + echo "<h3>Add an Album</h3>"; +?> + <form method="POST" action="<?php echo getCurrentScript(); ?>"> + <input type="hidden" name="command" value="addAlbum" /> + <input type="hidden" name="user" value="<?php echo $user; ?>" /> + <input type="text" name="name" /> + <input type="submit" name="Add Album" /> + </form> +<?php + + displayBackLink(); +} + +/** + * Outputs an HTML unordered list (ul), with each list item representing a + * photo in the user's album feed. + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $user The user's account name + * @param integer $albumId The album's id + * @return void + */ +function outputAlbumFeed($client, $user, $albumId) +{ + $photos = new Zend_Gdata_Photos($client); + + $query = new Zend_Gdata_Photos_AlbumQuery(); + $query->setUser($user); + $query->setAlbumId($albumId); + + $albumFeed = $photos->getAlbumFeed($query); + echo "<h2>Album Feed for: " . $albumFeed->getTitle() . "</h2>"; + echo "<ul class='albums'>\n"; + foreach ($albumFeed as $entry) { + if ($entry instanceof Zend_Gdata_Photos_PhotoEntry) { + echo "\t<li class='albums'>"; + echo "<a href='" . getCurrentScript() . "?command=retrievePhotoFeed&user=" . $user; + echo "&album=" . $albumId . "&photo=" . $entry->getGphotoId() . "'>"; + $thumb = $entry->getMediaGroup()->getThumbnail(); + echo "<img class='thumb' src='" . $thumb[1]->getUrl() . "' /><br />"; + echo $entry->getTitle() . "</a>"; + echo "<form action='" . getCurrentScript() . "' method='post' class='deleteForm'>"; + echo "<input type='hidden' name='user' value='" . $user . "' />"; + echo "<input type='hidden' name='album' value='" . $albumId . "' />"; + echo "<input type='hidden' name='photo' value='" . $entry->getGphotoId(); + echo "' /><input type='hidden' name='command' value='deletePhoto' />"; + echo "<input type='submit' value='Delete' /></form>"; + echo "</li>\n"; + } + } + echo "</ul><br />\n"; + + echo "<h3>Add a Photo</h3>"; +?> + <form enctype="multipart/form-data" method="POST" action="<?php echo getCurrentScript(); ?>"> + <input type="hidden" name="MAX_FILE_SIZE" value="20971520" /> + <input type="hidden" name="command" value="addPhoto" /> + <input type="hidden" name="user" value="<?php echo $user; ?>" /> + <input type="hidden" name="album" value="<?php echo $albumId; ?>" /> + Please select a photo to upload: <input name="photo" type="file" /><br /> + <input type="submit" name="Upload" /> + </form> +<?php + + displayBackLink(); +} + +/** + * Outputs the feed of the specified photo + * + * @param Zend_Http_Client $client The authenticated client object + * @param string $user The user's account name + * @param integer $albumId The album's id + * @param integer $photoId The photo's id + * @return void + */ +function outputPhotoFeed($client, $user, $albumId, $photoId) +{ + $photos = new Zend_Gdata_Photos($client); + + $query = new Zend_Gdata_Photos_PhotoQuery(); + $query->setUser($user); + $query->setAlbumId($albumId); + $query->setPhotoId($photoId); + $query = $query->getQueryUrl() . "?kind=comment,tag"; + + $photoFeed = $photos->getPhotoFeed($query); + echo "<h2>Photo Feed for: " . $photoFeed->getTitle() . "</h2>"; + $thumbs = $photoFeed->getMediaGroup()->getThumbnail(); + echo "<img src='" . $thumbs[2]->url . "' />"; + + echo "<h3 class='nopad'>Comments:</h3>"; + echo "<ul>\n"; + foreach ($photoFeed as $entry) { + if ($entry instanceof Zend_Gdata_Photos_CommentEntry) { + echo "\t<li>" . $entry->getContent(); + echo "<form action='" . getCurrentScript() . "' method='post' class='deleteForm'>"; + echo "<input type='hidden' name='user' value='" . $user . "' />"; + echo "<input type='hidden' name='album' value='" . $albumId . "' />"; + echo "<input type='hidden' name='photo' value='" . $photoId . "' />"; + echo "<input type='hidden' name='comment' value='" . $entry->getGphotoId(); + echo "' />"; + echo "<input type='hidden' name='command' value='deleteComment' />"; + echo "<input type='submit' value='Delete' /></form>"; + echo "</li>\n"; + } + } + echo "</ul>\n"; + echo "<h4>Add a Comment</h4>"; +?> + <form method="POST" action="<?php echo getCurrentScript(); ?>"> + <input type="hidden" name="command" value="addComment" /> + <input type="hidden" name="user" value="<?php echo $user; ?>" /> + <input type="hidden" name="album" value="<?php echo $albumId; ?>" /> + <input type="hidden" name="photo" value="<?php echo $photoId; ?>" /> + <input type="text" name="comment" /> + <input type="submit" name="Comment" value="Comment" /> + </form> +<?php + echo "<br />"; + echo "<h3 class='nopad'>Tags:</h3>"; + echo "<ul>\n"; + foreach ($photoFeed as $entry) { + if ($entry instanceof Zend_Gdata_Photos_TagEntry) { + echo "\t<li>" . $entry->getTitle(); + echo "<form action='" . getCurrentScript() . "' method='post' class='deleteForm'>"; + echo "<input type='hidden' name='user' value='" . $user . "' />"; + echo "<input type='hidden' name='album' value='" . $albumId . "' />"; + echo "<input type='hidden' name='photo' value='" . $photoId . "' />"; + echo "<input type='hidden' name='tag' value='" . $entry->getContent(); + echo "' />"; + echo "<input type='hidden' name='command' value='deleteTag' />"; + echo "<input type='submit' value='Delete' /></form>"; + echo "</li>\n"; + } + } + echo "</ul>\n"; + echo "<h4>Add a Tag</h4>"; +?> + <form method="POST" action="<?php echo getCurrentScript(); ?>"> + <input type="hidden" name="command" value="addTag" /> + <input type="hidden" name="user" value="<?php echo $user; ?>" /> + <input type="hidden" name="album" value="<?php echo $albumId; ?>" /> + <input type="hidden" name="photo" value="<?php echo $photoId; ?>" /> + <input type="text" name="tag" /> + <input type="submit" name="Tag" value="Tag" /> + </form> +<?php + + displayBackLink(); +} + +/** + * Output the CSS for the page + */ + +?> +<style type="text/css"> + h2 { + color: #0056FF; + } + h3 { + color: #0056FF; + padding-top: 15px; + clear: left; + } + h3.nopad { + padding: 0px; + } + ul { + background-color: #E0EAFF; + color: #191D1D; + margin: 10px; + padding: 10px 10px 10px 25px; + border: 1px solid #515B5C; + } + ul.user, ul.albums { + background-color: #FFFFFF; + border: 0px; + padding: 0px; + } + li.user, li.albums { + display: block; + float: left; + margin: 5px; + padding: 5px; + text-align: center; + background-color: #E0EAFF; + border: 1px solid #515B5C; + } + a { + color: #0056FF; + font-weight: bold; + text-decoration: none; + } + a:hover { + text-decoration: underline; + color: #E00000; + } + div.menuForm { + margin: 10px; + padding: 0px 10px; + background-color: #E0EAFF; + border: 1px solid #515B5C; + } + form.deleteForm { + padding-left: 10px; + display: inline; + } + img.thumb { + margin: 5px; + border: 0px; + } +</style> +<?php + +/** + * Calls the main processing function for running in a browser + */ + +processPageLoad(); diff --git a/zend/demos/Zend/Gdata/Spreadsheet-ClientLogin.php b/zend/demos/Zend/Gdata/Spreadsheet-ClientLogin.php new file mode 100644 index 0000000..6309b0c --- /dev/null +++ b/zend/demos/Zend/Gdata/Spreadsheet-ClientLogin.php @@ -0,0 +1,454 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Loader + */ +require_once 'Zend/Loader.php'; + +/** + * @see Zend_Gdata + */ +Zend_Loader::loadClass('Zend_Gdata'); + +/** + * @see Zend_Gdata_ClientLogin + */ +Zend_Loader::loadClass('Zend_Gdata_ClientLogin'); + +/** + * @see Zend_Gdata_Spreadsheets + */ +Zend_Loader::loadClass('Zend_Gdata_Spreadsheets'); + +/** + * @see Zend_Gdata_App_AuthException + */ +Zend_Loader::loadClass('Zend_Gdata_App_AuthException'); + +/** + * @see Zend_Http_Client + */ +Zend_Loader::loadClass('Zend_Http_Client'); + + +/** + * SimpleCRUD + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class SimpleCRUD +{ + /** + * Constructor + * + * @param string $email + * @param string $password + * @return void + */ + public function __construct($email, $password) + { + try { + $client = Zend_Gdata_ClientLogin::getHttpClient($email, $password, + Zend_Gdata_Spreadsheets::AUTH_SERVICE_NAME); + } catch (Zend_Gdata_App_AuthException $ae) { + exit("Error: ". $ae->getMessage() ."\nCredentials provided were email: [$email] and password [$password].\n"); + } + + $this->gdClient = new Zend_Gdata_Spreadsheets($client); + $this->currKey = ''; + $this->currWkshtId = ''; + $this->listFeed = ''; + $this->rowCount = 0; + $this->columnCount = 0; + } + + /** + * promptForSpreadsheet + * + * @return void + */ + public function promptForSpreadsheet() + { + $feed = $this->gdClient->getSpreadsheetFeed(); + print "== Available Spreadsheets ==\n"; + $this->printFeed($feed); + $input = getInput("\nSelection"); + $currKey = explode('/', $feed->entries[$input]->id->text); + $this->currKey = $currKey[5]; + } + + /** + * promptForWorksheet + * + * @return void + */ + public function promptForWorksheet() + { + $query = new Zend_Gdata_Spreadsheets_DocumentQuery(); + $query->setSpreadsheetKey($this->currKey); + $feed = $this->gdClient->getWorksheetFeed($query); + print "== Available Worksheets ==\n"; + $this->printFeed($feed); + $input = getInput("\nSelection"); + $currWkshtId = explode('/', $feed->entries[$input]->id->text); + $this->currWkshtId = $currWkshtId[8]; + + } + + /** + * promptForCellsAction + * + * @return void + */ + public function promptForCellsAction() + { + echo "Pick a command:\n"; + echo "\ndump -- dump cell information\nupdate {row} {col} {input_value} -- update cell information\n"; + $input = getInput('Command'); + $command = explode(' ', $input); + if ($command[0] == 'dump') { + $this->cellsGetAction(); + } else if (($command[0] == 'update') && (count($command) > 2)) { + $this->getRowAndColumnCount(); + if (count($command) == 4) { + $this->cellsUpdateAction($command[1], $command[2], $command[3]); + } elseif (count($command) > 4) { + $newValue = implode(' ', array_slice($command,3)); + $this->cellsUpdateAction($command[1], $command[2], $newValue); + } else { + $this->cellsUpdateAction($command[1], $command[2], ''); + } + } else { + $this->invalidCommandError($input); + } + } + + /** + * promptToResize + * + * @param integer $newRowCount + * @param integer $newColumnCount + * @return boolean + */ + public function promptToResize($newRowCount, $newColumnCount) { + $input = getInput('Would you like to resize the worksheet? [yes | no]'); + if ($input == 'yes') { + return $this->resizeWorksheet($newRowCount, $newColumnCount); + } else { + return false; + } + } + + /** + * resizeWorksheet + * + * @param integer $newRowCount + * @param integer $newColumnCount + * @return boolean + */ + public function resizeWorksheet($newRowCount, $newColumnCount) { + $query = new Zend_Gdata_Spreadsheets_DocumentQuery(); + $query->setSpreadsheetKey($this->currKey); + $query->setWorksheetId($this->currWkshtId); + $currentWorksheet = $this->gdClient->getWorksheetEntry($query); + $currentWorksheet = $currentWorksheet->setRowCount(new Zend_Gdata_Spreadsheets_Extension_RowCount($newRowCount)); + $currentWorksheet = $currentWorksheet->setColumnCount(new Zend_Gdata_Spreadsheets_Extension_ColCount($newColumnCount)); + $currentWorksheet->save(); + $this->getRowAndColumnCount(); + print "Worksheet has been resized to $this->rowCount rows and $this->columnCount columns.\n"; + return true; + } + + /** + * promptForListAction + * + * @return void + */ + public function promptForListAction() + { + echo "\n== Options ==\n". + "dump -- dump row information\n". + "insert {row_data} -- insert data in the next available cell in a given column (example: insert column_header=content)\n". + "update {row_index} {row_data} -- update data in the row provided (example: update row-number column-header=newdata\n". + "delete {row_index} -- delete a row\n\n"; + + $input = getInput('Command'); + $command = explode(' ', $input); + if ($command[0] == 'dump') { + $this->listGetAction(); + } else if ($command[0] == 'insert') { + $this->listInsertAction(array_slice($command, 1)); + } else if ($command[0] == 'update') { + $this->listUpdateAction($command[1], array_slice($command, 2)); + } else if ($command[0] == 'delete') { + $this->listDeleteAction($command[1]); + } else { + $this->invalidCommandError($input); + } + } + + /** + * cellsGetAction + * + * @return void + */ + public function cellsGetAction() + { + $query = new Zend_Gdata_Spreadsheets_CellQuery(); + $query->setSpreadsheetKey($this->currKey); + $query->setWorksheetId($this->currWkshtId); + $feed = $this->gdClient->getCellFeed($query); + $this->printFeed($feed); + } + + /** + * cellsUpdateAction + * + * @param integer $row + * @param integer $col + * @param string $inputValue + * @return void + */ + public function cellsUpdateAction($row, $col, $inputValue) + { + if (($row > $this->rowCount) || ($col > $this->columnCount)) { + print "Current worksheet only has $this->rowCount rows and $this->columnCount columns.\n"; + if (!$this->promptToResize($row, $col)) { + return; + } + } + $entry = $this->gdClient->updateCell($row, $col, $inputValue, + $this->currKey, $this->currWkshtId); + if ($entry instanceof Zend_Gdata_Spreadsheets_CellEntry) { + echo "Success!\n"; + } + } + + /** + * listGetAction + * + * @return void + */ + public function listGetAction() + { + $query = new Zend_Gdata_Spreadsheets_ListQuery(); + $query->setSpreadsheetKey($this->currKey); + $query->setWorksheetId($this->currWkshtId); + $this->listFeed = $this->gdClient->getListFeed($query); + print "entry id | row-content in column A | column-header: cell-content\n". + "Please note: The 'dump' command on the list feed only dumps data until the first blank row is encountered.\n\n"; + + $this->printFeed($this->listFeed); + print "\n"; + } + + /** + * listInsertAction + * + * @param mixed $rowData + * @return void + */ + public function listInsertAction($rowData) + { + $rowArray = $this->stringToArray($rowData); + $entry = $this->gdClient->insertRow($rowArray, $this->currKey, $this->currWkshtId); + if ($entry instanceof Zend_Gdata_Spreadsheets_ListEntry) { + foreach ($rowArray as $column_header => $value) { + echo "Success! Inserted '$value' in column '$column_header' at row ". substr($entry->getTitle()->getText(), 5) ."\n"; + } + } + } + + /** + * listUpdateAction + * + * @param integer $index + * @param mixed $rowData + * @return void + */ + public function listUpdateAction($index, $rowData) + { + $query = new Zend_Gdata_Spreadsheets_ListQuery(); + $query->setSpreadsheetKey($this->currKey); + $query->setWorksheetId($this->currWkshtId); + $this->listFeed = $this->gdClient->getListFeed($query); + $rowArray = $this->stringToArray($rowData); + $entry = $this->gdClient->updateRow($this->listFeed->entries[$index], $rowArray); + if ($entry instanceof Zend_Gdata_Spreadsheets_ListEntry) { + echo "Success!\n"; $response = $entry->save(); + + } + } + + /** + * listDeleteAction + * + * @param integer $index + * @return void + */ + public function listDeleteAction($index) + { + $query = new Zend_Gdata_Spreadsheets_ListQuery(); + $query->setSpreadsheetKey($this->currKey); + $query->setWorksheetId($this->currWkshtId); + $this->listFeed = $this->gdClient->getListFeed($query); + $this->gdClient->deleteRow($this->listFeed->entries[$index]); + } + + /** + * stringToArray + * + * @param string $rowData + * @return array + */ + public function stringToArray($rowData) + { + $arr = array(); + foreach ($rowData as $row) { + $temp = explode('=', $row); + $arr[$temp[0]] = $temp[1]; + } + return $arr; + } + + /** + * printFeed + * + * @param Zend_Gdata_Gbase_Feed $feed + * @return void + */ + public function printFeed($feed) + { + $i = 0; + foreach($feed->entries as $entry) { + if ($entry instanceof Zend_Gdata_Spreadsheets_CellEntry) { + print $entry->title->text .' '. $entry->content->text . "\n"; + } else if ($entry instanceof Zend_Gdata_Spreadsheets_ListEntry) { + print $i .' '. $entry->title->text .' | '. $entry->content->text . "\n"; + } else { + print $i .' '. $entry->title->text . "\n"; + } + $i++; + } + } + + /** + * getRowAndColumnCount + * + * @return void + */ + public function getRowAndColumnCount() + { + $query = new Zend_Gdata_Spreadsheets_CellQuery(); + $query->setSpreadsheetKey($this->currKey); + $query->setWorksheetId($this->currWkshtId); + $feed = $this->gdClient->getCellFeed($query); + + if ($feed instanceOf Zend_Gdata_Spreadsheets_CellFeed) { + $this->rowCount = $feed->getRowCount(); + $this->columnCount = $feed->getColumnCount(); + } + } + + /** + * invalidCommandError + * + * @param string $input + * @return void + */ + public function invalidCommandError($input) + { + echo 'Invalid input: '.$input."\n"; + } + + /** + * promtForFeedtype + * + * @return void + */ + public function promptForFeedtype() { + + $input = getInput('Select to use either the cell or the list feed [cells or list]'); + + if ($input == 'cells') { + while(1) { + $this->promptForCellsAction(); + } + } else if ($input == 'list') { + while(1) { + $this->promptForListAction(); + } + } else { + print "Invalid input. Please try again.\n"; + $this->promptForFeedtype(); + } + } + + /** + * run + * + * @return void + */ + public function run() + { + $this->promptForSpreadsheet(); + $this->promptForWorksheet(); + $this->promptForFeedtype(); + } +} + +/** + * getInput + * + * @param string $text + * @return string + */ +function getInput($text) +{ + echo $text.': '; + return trim(fgets(STDIN)); +} + +$email = null; +$pass = null; + +// process command line options +foreach ($argv as $argument) { + $argParts = explode('=', $argument); + if ($argParts[0] == '--email') { + $email = $argParts[1]; + } else if ($argParts[0] == '--pass') { + $pass = $argParts[1]; + } +} + +if (($email == null) || ($pass == null)) { + $email = getInput("Please enter your email address [example: username@gmail.com]"); + $pass = getInput("Please enter your password [example: mypassword]"); +} + +$sample = new SimpleCRUD($email, $pass); +$sample->run(); diff --git a/zend/demos/Zend/Gdata/YouTubeVideoApp/README.txt b/zend/demos/Zend/Gdata/YouTubeVideoApp/README.txt new file mode 100644 index 0000000..3cea242 --- /dev/null +++ b/zend/demos/Zend/Gdata/YouTubeVideoApp/README.txt @@ -0,0 +1,44 @@ +== YouTube data API Video App in PHP == + +PHP sample code for the YouTube data API. Utilizes the Zend Framework +Zend_Gdata component to communicate with the YouTube data API. + +Requires the Zend Framework Zend_Gdata component and PHP >= 5.2.11 +This sample is run from within a web browser. These files are required: + +session_details.php - a script to view log output and session variables +operations.php - the main logic, which interfaces with the YouTube API +index.php - the HTML to represent the web UI, contains some PHP +video_app.css - the CSS to define the interface style +video_app.js - the JavaScript used to provide the video list AJAX interface + +-------------- + +NOTE: If using in production, some additional precautions with regards +to filtering the input data should be used. This code is designed only +for demonstration purposes. + +-------------- + +Please be sure to obtain a Developer Key from YouTube prior to using +this application by visiting this site: + +http://code.google.com/apis/youtube/dashboard/ + +More information on the YouTube Data API and Tools is available here: + +http://code.google.com/apis/youtube + +For a video explaining the basics of how this application works, please +visit this link: + +http://www.youtube.com/watch?v=iIp7OnHXBlo + +To see this application running live, please visit: + +http://googlecodesamples.com + +== UPDATES == + +3/2009 - Removed functionality to set the Developer Key in a form. Instead, + it is now hard-coded in the index.php page. This reduces complexity. diff --git a/zend/demos/Zend/Gdata/YouTubeVideoApp/index.php b/zend/demos/Zend/Gdata/YouTubeVideoApp/index.php new file mode 100755 index 0000000..45cee26 --- /dev/null +++ b/zend/demos/Zend/Gdata/YouTubeVideoApp/index.php @@ -0,0 +1,193 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * PHP sample code for the YouTube data API. Utilizes the Zend Framework + * Zend_Gdata component to communicate with the YouTube data API. + * + * Requires the Zend Framework Zend_Gdata component and PHP >= 5.2.11 + * This sample is run from within a web browser. These files are required: + * session_details.php - a script to view log output and session variables + * operations.php - the main logic, which interfaces with the YouTube API + * index.php - the HTML to represent the web UI, contains some PHP + * video_app.css - the CSS to define the interface style + * video_app.js - the JavaScript used to provide the video list AJAX interface + * + * NOTE: If using in production, some additional precautions with regards + * to filtering the input data should be used. This code is designed only + * for demonstration purposes. + */ +session_start(); + +/** + * Set your developer key here. + * + * NOTE: In a production application you may want to store this information in + * an external file. + */ +$_SESSION['developerKey'] = '<YOUR DEVELOPER KEY>'; + +/** + * Convert HTTP status into normal text. + * + * @param number $status HTTP status received after posting syndicated upload + * @param string $code Alphanumeric description of error + * @param string $videoId (optional) Video id received back to which the status + * code refers to + */ +function uploadStatus($status, $code = null, $videoId = null) +{ + switch ($status) { + case $status < 400: + echo 'Success ! Entry created (id: '. $videoId . + ') <a href="#" onclick=" ytVideoApp.checkUploadDetails(\''. + $videoId .'\'); ">(check details)</a>'; + break; + default: + echo 'There seems to have been an error: '. $code . + '<a href="#" onclick=" ytVideoApp.checkUploadDetails(\''. + $videoId . '\'); ">(check details)</a>'; + } +} + +/** + * Helper function to check whether a session token has been set + * + * @return boolean Returns true if a session token has been set + */ +function authenticated() +{ + if (isset($_SESSION['sessionToken'])) { + return true; + } +} + +/** + * Helper function to print a list of authenticated actions for a user. + */ +function printAuthenticatedActions() +{ + print <<<END + <div id="actions"><h3>Authenticated Actions</h3> + <ul> + <li><a href="#" onclick="ytVideoApp.listVideos('search_owner', '', 1); + return false;">retrieve my videos</a></li> + <li><a href="#" onclick="ytVideoApp.prepareUploadForm(); + return false;">upload a video</a><br /> + <div id="syndicatedUploadDiv"></div><div id="syndicatedUploadStatusDiv"> + </div></li> + <li><a href="#" onclick="ytVideoApp.retrievePlaylists(); + return false;">manage my playlists</a><br /></li> + </ul></div> +END; +} +?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> + <title>YouTube data API Video Browser in PHP</title> + <link href="video_app.css" type="text/css" rel="stylesheet" /> + <script src="video_app.js" type="text/javascript"></script> +</head> + +<body> + <div id="main"> + <div id="titleBar"> + <h2>YouTube data API Video App in PHP</h2> + <a href="session_details.php">click to examine session variables</a><br/> + <div id="searchBox"> + <form id="searchForm" onsubmit="ytVideoApp.listVideos(this.queryType.value, this.searchTerm.value, 1); return false;" action="javascript:void();" > + <div id="searchBoxTop"><select name="queryType" onchange="ytVideoApp.queryTypeChanged(this.value, this.form.searchTerm);" > + <option value="search_all" selected="selected">All Videos</option> + <option value="search_top_rated">Top Rated Videos</option> + <option value="search_most_viewed">Most Viewed Videos</option> + <option value="search_recently_featured">Recently Featured Videos</option> + <option value="search_username">Videos from a specific user</option> + <?php + if (authenticated()) { + echo '<option value="search_owner">Display my videos</option>'; + } + ?> + </select></div> + <div><input name="searchTerm" type="text" value="YouTube Data API" /> + <input type="submit" value="Search" /></div> + </form> + </div> + <br /> + + </div> + <br /> + <!-- Authentication status --> + <div id="authStatus">Authentication status: + <?php + if (authenticated()) { + print <<<END + authenticated <br /> +END; + } else { + print <<<END + <div id="generateAuthSubLink"><a href="#" + onclick="ytVideoApp.presentAuthLink(); + return false;">Click here to generate authentication link</a> + </div> +END; + } + ?> + </div> + <!-- end Authentication status --> + <br clear="all" /> + <?php + // if $_GET['status'] is populated then we have a response + // about a syndicated upload from YouTube's servers + if (isset($_GET['status'])) { + (isset($_GET['code']) ? $code = $_GET['code'] : $code = null); + (isset($_GET['id']) ? $id = $_GET['id'] : $id = null); + print '<div id="generalStatus">' . + uploadStatus($_GET['status'], $code, $id) . + '<div id="detailedUploadStatus"></div></div>'; + } + ?> + <!-- General status --> + <?php + if (authenticated()) { + printAuthenticatedActions(); + } + ?> + <!-- end General status --> + <br clear="all" /> + <div id="searchResults"> + <div id="searchResultsListColumn"> + <div id="searchResultsVideoList"></div> + <div id="searchResultsNavigation"> + <form id="navigationForm" action="javascript:void();"> + <input type="button" id="previousPageButton" onclick="ytVideoApp.listVideos(ytVideoApp.previousQueryType, ytVideoApp.previousSearchTerm, ytVideoApp.previousPage);" value="Back" style="display: none;" /> + <input type="button" id="nextPageButton" onclick="ytVideoApp.listVideos(ytVideoApp.previousQueryType, ytVideoApp.previousSearchTerm, ytVideoApp.nextPage);" value="Next" style="display: none;" /> + </form> + </div> + </div> + <div id="searchResultsVideoColumn"> + <div id="videoPlayer"></div> + </div> + </div> +</div> +</body> +</html> diff --git a/zend/demos/Zend/Gdata/YouTubeVideoApp/notfound.jpg b/zend/demos/Zend/Gdata/YouTubeVideoApp/notfound.jpg Binary files differnew file mode 100755 index 0000000..76ec81c --- /dev/null +++ b/zend/demos/Zend/Gdata/YouTubeVideoApp/notfound.jpg diff --git a/zend/demos/Zend/Gdata/YouTubeVideoApp/operations.php b/zend/demos/Zend/Gdata/YouTubeVideoApp/operations.php new file mode 100755 index 0000000..c149583 --- /dev/null +++ b/zend/demos/Zend/Gdata/YouTubeVideoApp/operations.php @@ -0,0 +1,1097 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * PHP sample code for the YouTube data API. Utilizes the Zend Framework + * Zend_Gdata component to communicate with the YouTube data API. + * + * Requires the Zend Framework Zend_Gdata component and PHP >= 5.2.11 + * This sample is run from within a web browser. These files are required: + * session_details.php - a script to view log output and session variables + * operations.php - the main logic, which interfaces with the YouTube API + * index.php - the HTML to represent the web UI, contains some PHP + * video_app.css - the CSS to define the interface style + * video_app.js - the JavaScript used to provide the video list AJAX interface + * + * NOTE: If using in production, some additional precautions with regards + * to filtering the input data should be used. This code is designed only + * for demonstration purposes. + */ +require_once 'Zend/Loader.php'; +Zend_Loader::loadClass('Zend_Gdata_YouTube'); +Zend_Loader::loadClass('Zend_Gdata_AuthSub'); +Zend_Loader::loadClass('Zend_Gdata_App_Exception'); + +/* + * The main controller logic. + * + * POST used for all authenticated requests + * otherwise use GET for retrieve and supplementary values + */ +session_start(); +setLogging('on'); +generateUrlInformation(); + +if (!isset($_POST['operation'])) { + // if a GET variable is set then process the token upgrade + if (isset($_GET['token'])) { + updateAuthSubToken($_GET['token']); + } else { + if (loggingEnabled()) { + logMessage('reached operations.php without $_POST or $_GET variables set', 'error'); + header('Location: index.php'); + } + } +} + +$operation = $_POST['operation']; + +switch ($operation) { + + case 'create_upload_form': + createUploadForm($_POST['videoTitle'], + $_POST['videoDescription'], + $_POST['videoCategory'], + $_POST['videoTags']); + break; + + case 'edit_meta_data': + editVideoData($_POST['newVideoTitle'], + $_POST['newVideoDescription'], + $_POST['newVideoCategory'], + $_POST['newVideoTags'], + $_POST['videoId']); + break; + + case 'check_upload_status': + checkUpload($_POST['videoId']); + break; + + case 'delete_video': + deleteVideo($_POST['videoId']); + break; + + case 'auth_sub_request': + generateAuthSubRequestLink(); + break; + + case 'auth_sub_token_upgrade': + updateAuthSubToken($_GET['token']); + break; + + case 'clear_session_var': + clearSessionVar($_POST['name']); + break; + + case 'retrieve_playlists': + retrievePlaylists(); + break; + + case 'create_playlist': + createPlaylist($_POST['playlistTitle'], $_POST['playlistDescription']); + break; + + case 'delete_playlist': + deletePlaylist($_POST['playlistTitle']); + break; + + case 'update_playlist': + updatePlaylist($_POST['newPlaylistTitle'], + $_POST['newPlaylistDescription'], + $_POST['oldPlaylistTitle']); + break; + + case (strcmp(substr($operation, 0, 7), 'search_') == 0): + // initialize search specific information + $searchType = substr($operation, 7); + searchVideos($searchType, $_POST['searchTerm'], $_POST['startIndex'], + $_POST['maxResults']); + break; + + case 'show_video': + echoVideoPlayer($_POST['videoId']); + break; + + default: + unsupportedOperation($_POST); + break; +} + +/** + * Perform a search on youtube. Passes the result feed to echoVideoList. + * + * @param string $searchType The type of search to perform. + * If set to 'owner' then attempt to authenticate. + * @param string $searchTerm The term to search on. + * @param string $startIndex Start retrieving search results from this index. + * @param string $maxResults The number of results to retrieve. + * @return void + */ +function searchVideos($searchType, $searchTerm, $startIndex, $maxResults) +{ + // create an unauthenticated service object + $youTubeService = new Zend_Gdata_YouTube(); + $query = $youTubeService->newVideoQuery(); + $query->setQuery($searchTerm); + $query->setStartIndex($startIndex); + $query->setMaxResults($maxResults); + + switch ($searchType) { + case 'most_viewed': + $query->setFeedType('most viewed'); + $query->setTime('this_week'); + $feed = $youTubeService->getVideoFeed($query); + break; + case 'most_recent': + $query->setFeedType('most recent'); + $query->setTime('this_week'); + $feed = $youTubeService->getVideoFeed($query); + break; + case 'recently_featured': + $query->setFeedType('recently featured'); + $feed = $youTubeService->getVideoFeed($query); + break; + case 'top_rated': + $query->setFeedType('top rated'); + $query->setTime('this_week'); + $feed = $youTubeService->getVideoFeed($query); + break; + case 'username': + $feed = $youTubeService->getUserUploads($searchTerm); + break; + case 'all': + $feed = $youTubeService->getVideoFeed($query); + break; + case 'owner': + $httpClient = getAuthSubHttpClient(); + $youTubeService = new Zend_Gdata_YouTube($httpClient); + try { + $feed = $youTubeService->getUserUploads('default'); + if (loggingEnabled()) { + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), + 'response'); + } + } catch (Zend_Gdata_App_HttpException $httpException) { + print 'ERROR ' . $httpException->getMessage() + . ' HTTP details<br /><textarea cols="100" rows="20">' + . $httpException->getRawResponseBody() + . '</textarea><br />' + . '<a href="session_details.php">' + . 'click here to view details of last request</a><br />'; + return; + } catch (Zend_Gdata_App_Exception $e) { + print 'ERROR - Could not retrieve users video feed: ' + . $e->getMessage() . '<br />'; + return; + } + echoVideoList($feed, true); + return; + + default: + echo 'ERROR - Unknown search type - \'' . $searchType . '\''; + return; + } + + if (loggingEnabled()) { + $httpClient = $youTubeService->getHttpClient(); + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), 'response'); + } + echoVideoList($feed); +} + +/** + * Finds the URL for the flash representation of the specified video. + * + * @param Zend_Gdata_YouTube_VideoEntry $entry The video entry + * @return (string|null) The URL or null, if the URL is not found + */ +function findFlashUrl($entry) +{ + foreach ($entry->mediaGroup->content as $content) { + if ($content->type === 'application/x-shockwave-flash') { + return $content->url; + } + } + return null; +} + +/** + * Check the upload status of a video + * + * @param string $videoId The video to check. + * @return string A message about the video's status. + */ +function checkUpload($videoId) +{ + $httpClient = getAuthSubHttpClient(); + $youTubeService = new Zend_Gdata_YouTube($httpClient); + + $feed = $youTubeService->getuserUploads('default'); + $message = 'No further status information available yet.'; + + foreach($feed as $videoEntry) { + if ($videoEntry->getVideoId() == $videoId) { + // check if video is in draft status + try { + $control = $videoEntry->getControl(); + } catch (Zend_Gdata_App_Exception $e) { + print 'ERROR - not able to retrieve control element ' + . $e->getMessage(); + return; + } + + if ($control instanceof Zend_Gdata_App_Extension_Control) { + if (($control->getDraft() != null) && + ($control->getDraft()->getText() == 'yes')) { + $state = $videoEntry->getVideoState(); + if ($state instanceof Zend_Gdata_YouTube_Extension_State) { + $message = 'Upload status: ' . $state->getName() . ' ' + . $state->getText(); + } else { + print $message; + } + } + } + } + } + print $message; +} + +/** + * Store location of the demo application into session variables. + * + * @return void + */ +function generateUrlInformation() +{ + if (!isset($_SESSION['operationsUrl']) || !isset($_SESSION['homeUrl'])) { + $_SESSION['operationsUrl'] = 'http://'. $_SERVER['HTTP_HOST'] + . $_SERVER['PHP_SELF']; + $path = explode('/', $_SERVER['PHP_SELF']); + $path[count($path)-1] = 'index.php'; + $_SESSION['homeUrl'] = 'http://'. $_SERVER['HTTP_HOST'] + . implode('/', $path); + } +} + +/** + * Log a message to the session variable array. + * + * @param string $message The message to log. + * @param string $messageType The type of message to log. + * @return void + */ +function logMessage($message, $messageType) +{ + if (!isset($_SESSION['log_maxLogEntries'])) { + $_SESSION['log_maxLogEntries'] = 20; + } + + if (!isset($_SESSION['log_currentCounter'])) { + $_SESSION['log_currentCounter'] = 0; + } + + $currentCounter = $_SESSION['log_currentCounter']; + $currentCounter++; + + if ($currentCounter > $_SESSION['log_maxLogEntries']) { + $_SESSION['log_currentCounter'] = 0; + } + + $logLocation = 'log_entry_'. $currentCounter . '_' . $messageType; + $_SESSION[$logLocation] = $message; + $_SESSION['log_currentCounter'] = $currentCounter; +} + +/** + * Update an existing video's meta-data. + * + * @param string $newVideoTitle The new title for the video entry. + * @param string $newVideoDescription The new description for the video entry. + * @param string $newVideoCategory The new category for the video entry. + * @param string $newVideoTags The new set of tags for the video entry (whitespace separated). + * @param string $videoId The video id for the video to be edited. + * @return void + */ +function editVideoData($newVideoTitle, $newVideoDescription, $newVideoCategory, $newVideoTags, $videoId) +{ + $httpClient = getAuthSubHttpClient(); + $youTubeService = new Zend_Gdata_YouTube($httpClient); + $feed = $youTubeService->getVideoFeed('https://gdata.youtube.com/feeds/users/default/uploads'); + $videoEntryToUpdate = null; + + foreach($feed as $entry) { + if ($entry->getVideoId() == $videoId) { + $videoEntryToUpdate = $entry; + break; + } + } + + if (!$videoEntryToUpdate instanceof Zend_Gdata_YouTube_VideoEntry) { + print 'ERROR - Could not find a video entry with id ' . $videoId + . '<br />' . printCacheWarning(); + return; + } + + try { + $putUrl = $videoEntryToUpdate->getEditLink()->getHref(); + } catch (Zend_Gdata_App_Exception $e) { + print 'ERROR - Could not obtain video entry\'s edit link: ' + . $e->getMessage() . '<br />'; + return; + } + + $videoEntryToUpdate->setVideoTitle($newVideoTitle); + $videoEntryToUpdate->setVideoDescription($newVideoDescription); + $videoEntryToUpdate->setVideoCategory($newVideoCategory); + + // convert tags from space separated to comma separated + $videoTagsArray = explode(' ', trim($newVideoTags)); + + // strip out empty array elements + foreach($videoTagsArray as $key => $value) { + if (strlen($value) < 2) { + unset($videoTagsArray[$key]); + } + } + + $videoEntryToUpdate->setVideoTags(implode(', ', $videoTagsArray)); + + try { + $updatedEntry = $youTubeService->updateEntry($videoEntryToUpdate, $putUrl); + if (loggingEnabled()) { + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), 'response'); + } + } catch (Zend_Gdata_App_HttpException $httpException) { + print 'ERROR ' . $httpException->getMessage() + . ' HTTP details<br /><textarea cols="100" rows="20">' + . $httpException->getRawResponseBody() + . '</textarea><br />' + . '<a href="session_details.php">' + . 'click here to view details of last request</a><br />'; + return; + } catch (Zend_Gdata_App_Exception $e) { + print 'ERROR - Could not post video meta-data: ' . $e->getMessage(); + return; + } + print 'Entry updated successfully.<br /><a href="#" onclick="' + . 'ytVideoApp.presentFeed(\'search_owner\', 5, 0, \'none\'); ' + . 'ytVideoApp.refreshSearchResults();" >' + . '(refresh your video listing)</a><br />' + . printCacheWarning(); +} + +/** + * Create upload form by sending the incoming video meta-data to youtube and + * retrieving a new entry. Prints form HTML to page. + * + * @param string $VideoTitle The title for the video entry. + * @param string $VideoDescription The description for the video entry. + * @param string $VideoCategory The category for the video entry. + * @param string $VideoTags The set of tags for the video entry (whitespace separated). + * @param string $nextUrl (optional) The URL to redirect back to after form upload has completed. + * @return void + */ +function createUploadForm($videoTitle, $videoDescription, $videoCategory, $videoTags, $nextUrl = null) +{ + $httpClient = getAuthSubHttpClient(); + $youTubeService = new Zend_Gdata_YouTube($httpClient); + $newVideoEntry = new Zend_Gdata_YouTube_VideoEntry(); + + $newVideoEntry->setVideoTitle($videoTitle); + $newVideoEntry->setVideoDescription($videoDescription); + + //make sure first character in category is capitalized + $videoCategory = strtoupper(substr($videoCategory, 0, 1)) + . substr($videoCategory, 1); + $newVideoEntry->setVideoCategory($videoCategory); + + // convert videoTags from whitespace separated into comma separated + $videoTagsArray = explode(' ', trim($videoTags)); + $newVideoEntry->setVideoTags(implode(', ', $videoTagsArray)); + + $tokenHandlerUrl = 'https://gdata.youtube.com/action/GetUploadToken'; + try { + $tokenArray = $youTubeService->getFormUploadToken($newVideoEntry, $tokenHandlerUrl); + if (loggingEnabled()) { + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), 'response'); + } + } catch (Zend_Gdata_App_HttpException $httpException) { + print 'ERROR ' . $httpException->getMessage() + . ' HTTP details<br /><textarea cols="100" rows="20">' + . $httpException->getRawResponseBody() + . '</textarea><br />' + . '<a href="session_details.php">' + . 'click here to view details of last request</a><br />'; + return; + } catch (Zend_Gdata_App_Exception $e) { + print 'ERROR - Could not retrieve token for syndicated upload. ' + . $e->getMessage() + . '<br /><a href="session_details.php">' + . 'click here to view details of last request</a><br />'; + return; + } + + $tokenValue = $tokenArray['token']; + $postUrl = $tokenArray['url']; + + // place to redirect user after upload + if (!$nextUrl) { + $nextUrl = $_SESSION['homeUrl']; + } + + print <<< END + <br /><form action="${postUrl}?nexturl=${nextUrl}" + method="post" enctype="multipart/form-data"> + <input name="file" type="file"/> + <input name="token" type="hidden" value="${tokenValue}"/> + <input value="Upload Video File" type="submit" /> + </form> +END; +} + +/** + * Deletes a Video. + * + * @param string $videoId Id of the video to be deleted. + * @return void + */ +function deleteVideo($videoId) +{ + $httpClient = getAuthSubHttpClient(); + $youTubeService = new Zend_Gdata_YouTube($httpClient); + $feed = $youTubeService->getVideoFeed('https://gdata.youtube.com/feeds/users/default/uploads'); + $videoEntryToDelete = null; + + foreach($feed as $entry) { + if ($entry->getVideoId() == $videoId) { + $videoEntryToDelete = $entry; + break; + } + } + + // check if videoEntryToUpdate was found + if (!$videoEntryToDelete instanceof Zend_Gdata_YouTube_VideoEntry) { + print 'ERROR - Could not find a video entry with id ' . $videoId . '<br />'; + return; + } + + try { + $httpResponse = $youTubeService->delete($videoEntryToDelete); + if (loggingEnabled()) { + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), 'response'); + } + + } catch (Zend_Gdata_App_HttpException $httpException) { + print 'ERROR ' . $httpException->getMessage() + . ' HTTP details<br /><textarea cols="100" rows="20">' + . $httpException->getRawResponseBody() + . '</textarea><br />' + . '<a href="session_details.php">' + . 'click here to view details of last request</a><br />'; + return; + } catch (Zend_Gdata_App_Exception $e) { + print 'ERROR - Could not delete video: '. $e->getMessage(); + return; + } + + print 'Entry deleted succesfully.<br />' . $httpResponse->getBody() + . '<br /><a href="#" onclick="' + . 'ytVideoApp.presentFeed(\'search_owner\', 5, 0, \'none\');"' + . '">(refresh your video listing)</a><br />' + . printCacheWarning(); +} + +/** + * Enables logging. + * + * @param string $loggingOption 'on' to turn logging on, 'off' to turn logging off. + * @param integer|null $maxLogItems Maximum items to log, default is 10. + * @return void + */ +function setLogging($loggingOption, $maxLogItems = 10) +{ + switch ($loggingOption) { + case 'on' : + $_SESSION['logging'] = 'on'; + $_SESSION['log_currentCounter'] = 0; + $_SESSION['log_maxLogEntries'] = $maxLogItems; + break; + + case 'off': + $_SESSION['logging'] = 'off'; + break; + } +} + +/** + * Check whether logging is enabled. + * + * @return boolean Return true if session variable for logging is set to 'on'. + */ +function loggingEnabled() +{ + if ($_SESSION['logging'] == 'on') { + return true; + } +} + +/** + * Unset a specific session variable. + * + * @param string $name Name of the session variable to delete. + * @return void + */ +function clearSessionVar($name) +{ + if (isset($_SESSION[$name])) { + unset($_SESSION[$name]); + } + header('Location: session_details.php'); +} + +/** + * Generate an AuthSub request Link and print it to the page. + * + * @param string $nextUrl URL to redirect to after performing the authentication. + * @return void + */ +function generateAuthSubRequestLink($nextUrl = null) +{ + $scope = 'https://gdata.youtube.com'; + $secure = false; + $session = true; + + if (!$nextUrl) { + generateUrlInformation(); + $nextUrl = $_SESSION['operationsUrl']; + } + + $url = Zend_Gdata_AuthSub::getAuthSubTokenUri($nextUrl, $scope, $secure, $session); + echo '<a href="' . $url + . '"><strong>Click here to authenticate with YouTube</strong></a>'; +} + +/** + * Upgrade the single-use token to a session token. + * + * @param string $singleUseToken A valid single use token that is upgradable to a session token. + * @return void + */ +function updateAuthSubToken($singleUseToken) +{ + try { + $sessionToken = Zend_Gdata_AuthSub::getAuthSubSessionToken($singleUseToken); + } catch (Zend_Gdata_App_Exception $e) { + print 'ERROR - Token upgrade for ' . $singleUseToken + . ' failed : ' . $e->getMessage(); + return; + } + + $_SESSION['sessionToken'] = $sessionToken; + generateUrlInformation(); + header('Location: ' . $_SESSION['homeUrl']); +} + +/** + * Convenience method to obtain an authenticted Zend_Http_Client object. + * + * @return Zend_Http_Client An authenticated client. + */ +function getAuthSubHttpClient() +{ + try { + $httpClient = Zend_Gdata_AuthSub::getHttpClient($_SESSION['sessionToken']); + } catch (Zend_Gdata_App_Exception $e) { + print 'ERROR - Could not obtain authenticated Http client object. ' + . $e->getMessage(); + return; + } + $httpClient->setHeaders('X-GData-Key', 'key='. $_SESSION['developerKey']); + return $httpClient; +} + +/** + * Echo img tags for the first thumbnail representing each video in the + * specified video feed. Upon clicking the thumbnails, the video should + * be presented. + * + * @param Zend_Gdata_YouTube_VideoFeed $feed The video feed + * @return void + */ +function echoThumbnails($feed) +{ + foreach ($feed as $entry) { + $videoId = $entry->getVideoId(); + $firstThumbnail = htmlspecialchars( + $entry->mediaGroup->thumbnail[0]->url); + echo '<img id="' . $videoId . '" class="thumbnail" src="' + . $firstThumbnail .'" width="130" height="97" onclick="' + . 'ytVideoApp.presentVideo(\'' . $videoId . '\', 1);" ' + . 'title="click to watch: ' . + htmlspecialchars($entry->getVideoTitle()) . '" />'; + } +} + +/** + * Echo the list of videos in the specified feed. + * + * @param Zend_Gdata_YouTube_VideoFeed $feed The video feed. + * @param boolean|null $authenticated If true then the videoList will + * attempt to create additional forms to edit video meta-data. + * @return void + */ +function echoVideoList($feed, $authenticated = false) +{ + $table = '<table id="videoResultList" class="videoList"><tbody>'; + $results = 0; + + foreach ($feed as $entry) { + $videoId = $entry->getVideoId(); + $thumbnailUrl = 'notfound.jpg'; + if (count($entry->mediaGroup->thumbnail) > 0) { + $thumbnailUrl = htmlspecialchars( + $entry->mediaGroup->thumbnail[0]->url); + } + + $videoTitle = htmlspecialchars($entry->getVideoTitle()); + $videoDescription = htmlspecialchars($entry->getVideoDescription()); + $videoCategory = htmlspecialchars($entry->getVideoCategory()); + $videoTags = $entry->getVideoTags(); + + $table .= '<tr id="video_' . $videoId . '">' + . '<td width="130"><img onclick="ytVideoApp.presentVideo(\'' + . $videoId. '\')" src="' . $thumbnailUrl. '" /></td>' + . '<td><a href="#" onclick="ytVideoApp.presentVideo(\'' + . $videoId . '\')">'. stripslashes($videoTitle) . '</a>' + . '<p class="videoDescription">' + . stripslashes($videoDescription) . '</p>' + . '<p class="videoCategory">category: ' . $videoCategory + . '</p><p class="videoTags">tagged: ' + . htmlspecialchars(implode(', ', $videoTags)) . '</p>'; + + if ($authenticated) { + $table .= '<p class="edit">' + . '<a onclick="ytVideoApp.presentMetaDataEditForm(\'' + . addslashes($videoTitle) . '\', \'' + . addslashes($videoDescription) . '\', \'' + . $videoCategory . '\', \'' + . addslashes(implode(', ', $videoTags)) . '\', \'' + . $videoId . '\');" href="#">edit video data</a> | ' + . '<a href="#" onclick="ytVideoApp.confirmDeletion(\'' + . $videoId + . '\');">delete this video</a></p><br clear="all">'; + } + + $table .= '</td></tr>'; + $results++; + } + + if ($results < 1) { + echo '<br />No results found<br /><br />'; + } else { + echo $table .'</tbody></table><br />'; + } +} + +/** + * Echo the video embed code, related videos and videos owned by the same user + * as the specified videoId. + * + * @param string $videoId The video + * @return void + */ +function echoVideoPlayer($videoId) +{ + $youTubeService = new Zend_Gdata_YouTube(); + + try { + $entry = $youTubeService->getVideoEntry($videoId); + } catch (Zend_Gdata_App_HttpException $httpException) { + print 'ERROR ' . $httpException->getMessage() + . ' HTTP details<br /><textarea cols="100" rows="20">' + . $httpException->getRawResponseBody() + . '</textarea><br />' + . '<a href="session_details.php">' + . 'click here to view details of last request</a><br />'; + return; + } + + $videoTitle = htmlspecialchars($entry->getVideoTitle()); + $videoUrl = htmlspecialchars(findFlashUrl($entry)); + $relatedVideoFeed = getRelatedVideos($entry->getVideoId()); + $topRatedFeed = getTopRatedVideosByUser($entry->author[0]->name); + + print <<<END + <b>$videoTitle</b><br /> + <object width="425" height="350"> + <param name="movie" value="${videoUrl}&autoplay=1"></param> + <param name="wmode" value="transparent"></param> + <embed src="${videoUrl}&autoplay=1" type="application/x-shockwave-flash" wmode="transparent" + width="425" height="350"></embed> + </object> +END; + + echo '<br />'; + echoVideoMetadata($entry); + echo '<br /><b>Related:</b><br />'; + echoThumbnails($relatedVideoFeed); + echo '<br /><b>Top rated videos by user:</b><br />'; + echoThumbnails($topRatedFeed); +} + +/** + * Returns a feed of videos related to the specified video + * + * @param string $videoId The video + * @return Zend_Gdata_YouTube_VideoFeed The feed of related videos + */ +function getRelatedVideos($videoId) +{ + $youTubeService = new Zend_Gdata_YouTube(); + $ytQuery = $youTubeService->newVideoQuery(); + // show videos related to the specified video + $ytQuery->setFeedType('related', $videoId); + // order videos by rating + $ytQuery->setOrderBy('rating'); + // retrieve a maximum of 5 videos + $ytQuery->setMaxResults(5); + // retrieve only embeddable videos + $ytQuery->setFormat(5); + return $youTubeService->getVideoFeed($ytQuery); +} + +/** + * Returns a feed of top rated videos for the specified user + * + * @param string $user The username + * @return Zend_Gdata_YouTube_VideoFeed The feed of top rated videos + */ +function getTopRatedVideosByUser($user) +{ + $userVideosUrl = 'https://gdata.youtube.com/feeds/users/' . + $user . '/uploads'; + $youTubeService = new Zend_Gdata_YouTube(); + $ytQuery = $youTubeService->newVideoQuery($userVideosUrl); + // order by the rating of the videos + $ytQuery->setOrderBy('rating'); + // retrieve a maximum of 5 videos + $ytQuery->setMaxResults(5); + // retrieve only embeddable videos + $ytQuery->setFormat(5); + return $youTubeService->getVideoFeed($ytQuery); +} + +/** + * Echo video metadata + * + * @param Zend_Gdata_YouTube_VideoEntry $entry The video entry + * @return void + */ +function echoVideoMetadata($entry) +{ + $title = htmlspecialchars($entry->getVideoTitle()); + $description = htmlspecialchars($entry->getVideoDescription()); + $authorUsername = htmlspecialchars($entry->author[0]->name); + $authorUrl = 'http://www.youtube.com/profile?user=' . + $authorUsername; + $tags = htmlspecialchars(implode(', ', $entry->getVideoTags())); + $duration = htmlspecialchars($entry->getVideoDuration()); + $watchPage = htmlspecialchars($entry->getVideoWatchPageUrl()); + $viewCount = htmlspecialchars($entry->getVideoViewCount()); + $rating = 0; + if (isset($entry->rating->average)) { + $rating = $entry->rating->average; + } + $numRaters = 0; + if (isset($entry->rating->numRaters)) { + $numRaters = $entry->rating->numRaters; + } + $flashUrl = htmlspecialchars(findFlashUrl($entry)); + print <<<END + <b>Title:</b> ${title}<br /> + <b>Description:</b> ${description}<br /> + <b>Author:</b> <a href="${authorUrl}">${authorUsername}</a><br /> + <b>Tags:</b> ${tags}<br /> + <b>Duration:</b> ${duration} seconds<br /> + <b>View count:</b> ${viewCount}<br /> + <b>Rating:</b> ${rating} (${numRaters} ratings)<br /> + <b>Flash:</b> <a href="${flashUrl}">${flashUrl}</a><br /> + <b>Watch page:</b> <a href="${watchPage}">${watchPage}</a> <br /> +END; +} + +/** + * Print message about YouTube caching. + * + * @return string A message + */ +function printCacheWarning() +{ + return '<p class="note">' + . 'Please note that the change may not be reflected in the API ' + . 'immediately due to caching.<br/>' + . 'Please refer to the API documentation for more details.</p>'; +} + +/** + * Retrieve playlists for the currently authenticated user and print. + * @return void + */ +function retrievePlaylists() +{ + $httpClient = getAuthSubHttpClient(); + $youTubeService = new Zend_Gdata_YouTube($httpClient); + $feed = $youTubeService->getPlaylistListFeed('default'); + + if (loggingEnabled()) { + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), 'response'); + } + + if (!$feed instanceof Zend_Gdata_YouTube_PlaylistListFeed) { + print 'ERROR - Could not retrieve playlists<br />'. + printCacheWarning(); + return; + } + + $playlistEntries = '<ul>'; + $entriesFound = 0; + foreach($feed as $entry) { + $playlistTitle = $entry->getTitleValue(); + $playlistDescription = $entry->getDescription()->getText(); + $playlistEntries .= '<li><h3>' . $playlistTitle + . '</h3>' . $playlistDescription . ' | ' + . '<a href="#" onclick="ytVideoApp.prepareUpdatePlaylistForm(\'' + . $playlistTitle . '\', \'' . $playlistDescription + . '\'); ">update</a> | ' + . '<a href="#" onclick="ytVideoApp.confirmPlaylistDeletion(\'' + . $playlistTitle . '\');">delete</a></li>'; + $entriesFound++; + } + + $playlistEntries .= '</ul><br /><a href="#" ' + . 'onclick="ytVideoApp.prepareCreatePlaylistForm(); ' + . 'return false;">' + . 'Add new playlist</a><br />' + . '<div id="addNewPlaylist"></div>'; + + if (loggingEnabled()) { + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), 'response'); + } + if ($entriesFound > 0) { + print $playlistEntries; + } else { + print 'No playlists found'; + } +} + +/** + * Create a new playlist for the currently authenticated user + * + * @param string $playlistTitle Title of the new playlist + * @param string $playlistDescription Description for the new playlist + * @return void + */ +function createPlaylist($playlistTitle, $playlistDescription) +{ + $httpClient = getAuthSubHttpClient(); + $youTubeService = new Zend_Gdata_YouTube($httpClient); + $feed = $youTubeService->getPlaylistListFeed('default'); + if (loggingEnabled()) { + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), 'response'); + } + + $newPlaylist = $youTubeService->newPlaylistListEntry(); + $newPlaylist->description = $youTubeService->newDescription()->setText($playlistDescription); + $newPlaylist->title = $youTubeService->newTitle()->setText($playlistDescription); + + if (!$feed instanceof Zend_Gdata_YouTube_PlaylistListFeed) { + print 'ERROR - Could not retrieve playlists<br />' + . printCacheWarning(); + return; + } + + $playlistFeedUrl = 'https://gdata.youtube.com/feeds/users/default/playlists'; + + try { + $updatedEntry = $youTubeService->insertEntry($newPlaylist, $playlistFeedUrl); + if (loggingEnabled()) { + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), 'response'); + } + } catch (Zend_Gdata_App_HttpException $httpException) { + print 'ERROR ' . $httpException->getMessage() + . ' HTTP details<br /><textarea cols="100" rows="20">' + . $httpException->getRawResponseBody() + . '</textarea><br />' + . '<a href="session_details.php">' + . 'click here to view details of last request</a><br />'; + return; + } catch (Zend_Gdata_App_Exception $e) { + print 'ERROR - Could not create new playlist: ' . $e->getMessage(); + return; + } + + print 'Playlist added succesfully.<br /><a href="#" onclick="' + . 'ytVideoApp.retrievePlaylists();"' + . '">(refresh your playlist listing)</a><br />' + . printCacheWarning(); +} + +/** + * Delete a playlist + * + * @param string $playlistTitle Title of the playlist to be deleted + * @return void + */ +function deletePlaylist($playlistTitle) +{ + $httpClient = getAuthSubHttpClient(); + $youTubeService = new Zend_Gdata_YouTube($httpClient); + $feed = $youTubeService->getPlaylistListFeed('default'); + if (loggingEnabled()) { + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), 'response'); + } + + $playlistEntryToDelete = null; + + foreach($feed as $playlistEntry) { + if ($playlistEntry->getTitleValue() == $playlistTitle) { + $playlistEntryToDelete = $playlistEntry; + break; + } + } + + if (!$playlistEntryToDelete instanceof Zend_Gdata_YouTube_PlaylistListEntry) { + print 'ERROR - Could not retrieve playlist to be deleted<br />' + . printCacheWarning(); + return; + } + + try { + $response = $playlistEntryToDelete->delete(); + if (loggingEnabled()) { + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), 'response'); + } + } catch (Zend_Gdata_App_HttpException $httpException) { + print 'ERROR ' . $httpException->getMessage() + . ' HTTP details<br /><textarea cols="100" rows="20">' + . $httpException->getRawResponseBody() + . '</textarea><br />' + . '<a href="session_details.php">' + . 'click here to view details of last request</a><br />'; + return; + } catch (Zend_Gdata_App_Exception $e) { + print 'ERROR - Could not delete the playlist: ' . $e->getMessage(); + return; + } + + print 'Playlist deleted succesfully.<br />' + . '<a href="#" onclick="ytVideoApp.retrievePlaylists();">' + . '(refresh your playlist listing)</a><br />' . printCacheWarning(); +} + +/** + * Delete a playlist + * + * @param string $newplaylistTitle New title for the playlist to be updated + * @param string $newPlaylistDescription New description for the playlist to be updated + * @param string $oldPlaylistTitle Title of the playlist to be updated + * @return void + */ +function updatePlaylist($newPlaylistTitle, $newPlaylistDescription, $oldPlaylistTitle) +{ + $httpClient = getAuthSubHttpClient(); + $youTubeService = new Zend_Gdata_YouTube($httpClient); + $feed = $youTubeService->getPlaylistListFeed('default'); + + if (loggingEnabled()) { + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), 'response'); + } + + $playlistEntryToDelete = null; + + foreach($feed as $playlistEntry) { + if ($playlistEntry->getTitleValue() == $oldplaylistTitle) { + $playlistEntryToDelete = $playlistEntry; + break; + } + } + + if (!$playlistEntryToDelete instanceof Zend_Gdata_YouTube_PlaylistListEntry) { + print 'ERROR - Could not retrieve playlist to be updated<br />' + . printCacheWarning(); + return; + } + + try { + $response = $playlistEntryToDelete->delete(); + if (loggingEnabled()) { + logMessage($httpClient->getLastRequest(), 'request'); + logMessage($httpClient->getLastResponse()->getBody(), 'response'); + } + } catch (Zend_Gdata_App_HttpException $httpException) { + print 'ERROR ' . $httpException->getMessage() + . ' HTTP details<br /><textarea cols="100" rows="20">' + . $httpException->getRawResponseBody() + . '</textarea><br />' + . '<a href="session_details.php">' + . 'click here to view details of last request</a><br />'; + return; + } catch (Zend_Gdata_App_Exception $e) { + print 'ERROR - Could not delete the playlist: ' . $e->getMessage(); + return; + } + + print 'Playlist deleted succesfully.<br /><a href="#" onclick="' . + 'ytVideoApp.retrievePlaylists();"'. + '">(refresh your playlist listing)</a><br />'. + printCacheWarning(); +} + +/** + * Helper function if an unsupported operation is passed into this files main loop. + * + * @param array $post (Optional) The post variables that accompanied the operation, if available. + * @return void + */ +function unsupportedOperation($post) +{ + $message = 'ERROR An unsupported operation has been called - post variables received ' + . print_r($post, true); + + if (loggingEnabled()) { + logMessage($message, 'error'); + } + print $message; +} + +?> diff --git a/zend/demos/Zend/Gdata/YouTubeVideoApp/session_details.php b/zend/demos/Zend/Gdata/YouTubeVideoApp/session_details.php new file mode 100755 index 0000000..dd4e996 --- /dev/null +++ b/zend/demos/Zend/Gdata/YouTubeVideoApp/session_details.php @@ -0,0 +1,66 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * PHP sample code for the YouTube data API. Utilizes the Zend Framework + * Zend_Gdata component to communicate with the YouTube data API. + * + * Requires the Zend Framework Zend_Gdata component and PHP >= 5.2.11 + * This sample is run from within a web browser. These files are required: + * session_details.php - a script to view log output and session variables + * operations.php - the main logic, which interfaces with the YouTube API + * index.php - the HTML to represent the web UI, contains some PHP + * video_app.css - the CSS to define the interface style + * video_app.js - the JavaScript used to provide the video list AJAX interface + * + * NOTE: If using in production, some additional precautions with regards + * to filtering the input data should be used. This code is designed only + * for demonstration purposes. + */ +session_start(); +?> +<html> +<head> + <title>YouTube data API Video Browser in PHP - Session Viewer</title> + <link href="video_app.css" type="text/css" rel="stylesheet"/> + <script src="video_app.js" type="text/javascript"></script> +</head> +<body> +<div id="mainSessions"> + <div id="titleBar"> + <div id="titleText"><h3>Session variables</h3></div><br clear="all" /> + </div> +<?php + +$session_copy = $_SESSION; +ksort($session_copy); + +foreach($session_copy as $key => $value) { + + print '<h3>'. $key . '</h3><div id="sessionVariable" >'. $value .'</div><br />'. + '<form method="POST" action="operations.php">' . + '<input type="hidden" value="clear_session_var" name="operation"/>'. + '<input type="hidden" name="name" value="'. $key .'"/>'. + '<input type="submit" value="click to delete"/></form><hr />'; +} +?> +<br clear="both" /> +<a href="index.php">back</a> + </div></body></html> diff --git a/zend/demos/Zend/Gdata/YouTubeVideoApp/video_app.css b/zend/demos/Zend/Gdata/YouTubeVideoApp/video_app.css new file mode 100755 index 0000000..0e4a743 --- /dev/null +++ b/zend/demos/Zend/Gdata/YouTubeVideoApp/video_app.css @@ -0,0 +1,236 @@ +body { + background-color: #fff; + color: #232323; + font-family: Arial, sans-serif; + font-size: small; + margin: 8px; + margin-top: 3px; +} + +/* TODO jhartman --> swap out with css from app engine apps +*/ + + +img { + border: 0; +} + +table { + border-collapse: collapse; +} + +th, td { + padding: 0; + vertical-align: top; + text-align: left; +} + +a:link { + color: #0000cc; +} + +a:active { + color: #cc0000; +} + +a:visited { + color: #551a8b; +} + +h1 { + font-size: x-large; + margin-top: 0px; + margin-bottom: 5px; +} + +h2 { + font-size: large; +} + +h3 { + font-size: medium; +} + +h4 { + font-size: small; +} + +form { + display: inline; + margin: 0; + padding: 0; +} + +li { + margin-bottom: 0.25em; +} + +pre, code { + color: #007000; + font-family: "bogus font here", monospace; + font-size: 100%; +} + +pre { + border: 1px solid silver; + background-color: #f5f5f5; + padding: 0.5em; + overflow: auto; + margin: 2em; +} + +pre ins { + color: #cc0000; + font-weight: bold; + text-decoration: none; +} + +/* forms */ +textarea { + width: 600px; + border: 1px solid #ddd; + padding: 5px; +} + +.submit { + border: 1px solid #ddd; +} + +input, select{ + border: 1px solid #ddd; + margin-bottom: 2px; +} + +hr { + border: none; + border-bottom: 1px solid #ddd; +} + +/* "Selected" links */ +a.selected, .selected a, .selected { + color: black; + font-weight: bold; + text-decoration: none; +} + +a.selected:visited, .selected a:visited { + color: black; +} + +p.videoDescription { + margin: 0; + padding: 0; + overflow: scroll; + font-size: small; +} + +p.videoCategory { + margin: 0; + padding: 0; + /* overflow: scroll; */ + font-size: x-small; +} + +p.videoTags { + margin: 0; + padding: 0; + /* overflow: scroll; */ + font-size: x-small; +} + +p.edit { + font-size: small; +} + +.note { + padding: 2px; + background-color: yellow; + color: #000; +} + +#editForm { + font-size: small; +} + +table.videoList { + width: 100%; +} + +.videoList td { + padding: 10px 0px 5px 5px; + border-bottom: 1px solid silver; +} + +#titleBar { + border: 1px solid silver; + background-color: #e5ecf9; + margin: 0; + padding: 0; + padding-top: 5px; + padding-bottom: 10px; + padding-left: 10px; + padding-right: 10px; + margin-top: 5px; + margin-bottom: 15px; +} + +#titleText { + float: left; +} + +#searchBox { + float: right; +} + +#authStatus { + border-bottom: 1px solid #ddd; + padding: 2px; + margin-bottom: 10px; + +} + +#main { + margin: 10px; +} + +#mainSessions { + background-color: #ddd; + padding: 10px; +} + +#searchResults { + width: 100%; + background-color: silver; +} + +#searchResultsListColumn { + float: left; + width: 47%; + margin-bottom: 20px; + padding-right: 2px; +} + +#searchResultsVideoColumn { + float: right; + width: 47%; + padding-left: 5px; + border-left: 1px solid #ddd; + +} + +#sessionVariable { + font-family: Courier, monospace; + background-color: #fff; + padding: 10px; + width: 80%; + overflow: scroll; +} + +.thumbnail { + padding: 0px 0px 0px 2px; +} + +#imageLoadThumbnail { + padding: 4px; + background-color: #333; +} diff --git a/zend/demos/Zend/Gdata/YouTubeVideoApp/video_app.js b/zend/demos/Zend/Gdata/YouTubeVideoApp/video_app.js new file mode 100755 index 0000000..c01d806 --- /dev/null +++ b/zend/demos/Zend/Gdata/YouTubeVideoApp/video_app.js @@ -0,0 +1,582 @@ +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @fileoverview Provides functions for browsing and searching YouTube + * data API feeds, as well as performing authentication, syndicated uploads + * and playlist management using a PHP backend powered by the Zend_Gdata component + * of Zend Framework. + */ + +/** + * provides namespacing for the YouTube Video Application PHP version (ytVideoApp) + */ +var ytVideoApp = {}; + +/** + * maximum number of results to return for list of videos + * @type Number + */ +ytVideoApp.MAX_RESULTS_LIST = 5; + +/** + * navigation button id used to page to the previous page of + * results in the list of videos + * @type String + */ +ytVideoApp.PREVIOUS_PAGE_BUTTON = 'previousPageButton'; + +/** + * navigation button id used to page to the next page of + * results in the list of videos + * @type String + */ +ytVideoApp.NEXT_PAGE_BUTTON = 'nextPageButton'; + +/** + * container div for navigation elements + * @type String + */ +ytVideoApp.NAVIGATION_DIV = 'navigationForm'; + +/** + * container div id used to hold list of videos + * @type String + */ +ytVideoApp.VIDEO_LIST_CONTAINER_DIV = 'searchResultsVideoList'; + +/** + * container div id used to hold video search results + * @type String + */ +ytVideoApp.VIDEO_SEARCH_RESULTS_DIV = 'searchResultsVideoColumn'; + +/** + * container div id used to hold the video player + * @type String + */ +ytVideoApp.VIDEO_PLAYER_DIV = 'videoPlayer'; + +/** + * container div id used to hold the search box displayed at the top of + * the browser after one search has already been performed + * @type String + */ +ytVideoApp.TOP_SEARCH_CONTAINER_DIV = 'searchBox'; + +/** container div to show detailed upload status + * @type String + */ +ytVideoApp.VIDEO_UPLOAD_STATUS = 'detailedUploadStatus'; + +/** + * container div to hold the form for syndicated upload + * @type String + */ +ytVideoApp.SYNDICATED_UPLOAD_DIV = 'syndicatedUploadDiv'; + +/** + * container div to hold the form to edit video meta-data + * @type String + */ +ytVideoApp.VIDEO_DATA_EDIT_DIV = 'editForm'; + +/** + * containder div to hold authentication link in special cases where auth gets + * set prior to developer key + * @type String + */ +ytVideoApp.AUTHSUB_REQUEST_DIV = 'generateAuthSubLink'; + +/** + * container div to hold the form for editing video meta-data + * @type String + */ +ytVideoApp.VIDEO_META_DATA_EDIT_DIV = 'editVideoMetaDataDiv'; + +/** + * container div to hold the form for adding a new playlist + * @type String + */ +ytVideoApp.PLAYLIST_ADD_DIV = 'addNewPlaylist'; + +/** + * the page number to use for the next page navigation button + * @type Number + */ +ytVideoApp.nextPage = 2; + +/** + * the page number to use for the previous page navigation button + * @type Number + */ +ytVideoApp.previousPage = 0; + +/** + * the last search term used to query - allows for the navigation + * buttons to know what string query to perform when clicked + * @type String + */ +ytVideoApp.previousSearchTerm = ''; + +/** + * the last query type used for querying - allows for the navigation + * buttons to know what type of query to perform when clicked + * @type String + */ +ytVideoApp.previousQueryType = 'all'; + +/** + * Retrieves a list of videos matching the provided criteria. The list of + * videos can be restricted to a particular standard feed or search criteria. + * @param {String} op The type of action to be done. + * for querying all videos, or the name of a standard feed. + * @param {String} searchTerm The search term(s) to use for querying as the + * 'vq' query parameter value + * @param {Number} page The 1-based page of results to return. + */ +ytVideoApp.listVideos = function(op, searchTerm, page) { + ytVideoApp.previousSearchTerm = searchTerm; + ytVideoApp.previousQueryType = op; + var maxResults = ytVideoApp.MAX_RESULTS_LIST; + var startIndex = (((page - 1) * ytVideoApp.MAX_RESULTS_LIST) + 1); + ytVideoApp.presentFeed(op, maxResults, startIndex, searchTerm); + ytVideoApp.updateNavigation(page); +}; + +/** + * Sends an AJAX request to the server to retrieve a list of videos or + * the video player/metadata. Sends the request to the specified filePath + * on the same host, passing the specified params, and filling the specified + * resultDivName with the resutls upon success. + * @param {String} filePath The path to which the request should be sent + * @param {String} params The URL encoded POST params + * @param {String} resultDivName The name of the DIV used to hold the results + */ +ytVideoApp.sendRequest = function(filePath, params, resultDivName) { + if (window.XMLHttpRequest) { + var xmlhr = new XMLHttpRequest(); + } else { + var xmlhr = new ActiveXObject('MSXML2.XMLHTTP.3.0'); + } + + xmlhr.open('POST', filePath); + xmlhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + + xmlhr.onreadystatechange = function() { + var resultDiv = document.getElementById(resultDivName); + if (xmlhr.readyState == 1) { + resultDiv.innerHTML = '<b>Loading...</b>'; + } else if (xmlhr.readyState == 4 && xmlhr.status == 200) { + if (xmlhr.responseText) { + resultDiv.innerHTML = xmlhr.responseText; + } + } else if (xmlhr.readyState == 4) { + alert('Invalid response received - Status: ' + xmlhr.status); + } + } + xmlhr.send(params); +} + +/** + * Uses ytVideoApp.sendRequest to display a YT video player and metadata for the + * specified video ID. + * @param {String} videoId The ID of the YouTube video to show + */ +ytVideoApp.presentVideo = function(videoId, updateThumbnail) { + var params = 'operation=show_video&videoId=' + videoId; + var filePath = 'operations.php'; + ytVideoApp.sendRequest(filePath, params, ytVideoApp.VIDEO_PLAYER_DIV); +} + +/** + * Creates a form to enter video meta-data in preparation for syndicated upload. + */ +ytVideoApp.prepareUploadForm = function() { + var metaDataForm = ['<br clear="all"><form id="uploadForm" ', + 'onsubmit="ytVideoApp.prepareSyndicatedUpload(', + 'this.videoTitle.value, ', + 'this.videoDescription.value, ', + 'this.videoCategory.value, ', + 'this.videoTags.value); ', + 'return false;">', + 'Enter video title:<br /><input size="50" name="videoTitle" ', + 'type="text" /><br />', + 'Enter video description:<br /><textarea cols="50" ', + 'name="videoDescription"></textarea><br />', + 'Select a category: <select name="videoCategory">', + '<option value="Autos">Autos & Vehicles</option>', + '<option value="Music">Music</option>', + '<option value="Animals">Pets & Animals</option>', + '<option value="Sports">Sports</option>', + '<option value="Travel">Travel & Events</option>', + '<option value="Games">Gadgets & Games</option>', + '<option value="Comedy">Comedy</option>', + '<option value="People">People & Blogs</option>', + '<option value="News">News & Politics</option>', + '<option value="Entertainment">Entertainment</option>', + '<option value="Education">Education</option>', + '<option value="Howto">Howto & Style</option>', + '<option value="Nonprofit">Nonprofit & Activism</option>', + '<option value="Tech">Science & Technology</option>', + '</select><br />', + 'Enter some tags to describe your video ', + '<em>(separated by spaces)</em>:<br />', + '<input name="videoTags" type="text" size="50" value="video" /><br />', + '<input type="submit" value="go">', + '</form>'].join(''); + + document.getElementById(ytVideoApp.SYNDICATED_UPLOAD_DIV).innerHTML = metaDataForm; +} + +/** + * Uses ytVideoApp.sendRequest to prepare a syndicated upload. + * + * @param {String} videoTitle The title for new video + * @param {String} videoDescription The video's description + * @param {String} videoCategory The category for the video + * @param {String} videoTags A white-space separated string of Tags + */ +ytVideoApp.prepareSyndicatedUpload = function(videoTitle, videoDescription, videoCategory, videoTags) { + var filePath = 'operations.php'; + var params = 'operation=create_upload_form' + + '&videoTitle=' + videoTitle + + '&videoDescription=' + videoDescription + + '&videoCategory=' + videoCategory + + '&videoTags=' + videoTags; + ytVideoApp.sendRequest(filePath, params, ytVideoApp.SYNDICATED_UPLOAD_DIV); +} + +/** + * Uses ytVideoApp.sendRequest to create the authSub link. + */ +ytVideoApp.presentAuthLink = function() { + var filePath = 'operations.php'; + var params = 'operation=auth_sub_request'; + ytVideoApp.sendRequest(filePath, params, ytVideoApp.AUTHSUB_REQUEST_DIV); +} + + +/** + * Uses ytVideoApp.sendRequest to check a videos upload status. + * + * @param {String} videoId The id of the video to check + */ +ytVideoApp.checkUploadDetails = function(videoId) { + var filePath = 'operations.php'; + var params = 'operation=check_upload_status' + + '&videoId=' + videoId; + ytVideoApp.sendRequest(filePath, params, ytVideoApp.VIDEO_UPLOAD_STATUS); +} + + +/** + * Creates an HTML form to edit a video's meta-data, populated with the + * videos current meta-data. + * + * @param {String} oldVideoTitle The old title of the video + * @param {String} oldVideoDescription The old description of the video + * @param {String} oldVideoCategory The old category of the video + * @param {String} oldVideoTags The old tags for the video (separated by white-space) + * @param {String} videoId The id of the video to be edited + */ +ytVideoApp.presentMetaDataEditForm = function(oldVideoTitle, oldVideoDescription, oldVideoCategory, oldVideoTags, videoId) { + // split oldVideoTags by comma and present as whitespace separated + var oldVideoTagsArray = oldVideoTags.split(','); + oldVideoTags = oldVideoTagsArray.join(' '); + var editMetaDataForm = ['<form id="editForm" ', + 'onsubmit="ytVideoApp.editMetaData(', + 'this.newVideoTitle.value, ', + 'this.newVideoDescription.value, ', + 'this.newVideoCategory.value, ', + 'this.newVideoTags.value, ', + 'this.videoId.value);', + 'return false;">', + 'Enter a new video title:<br />', + '<input size="50" name="newVideoTitle" ', + 'type="text" value="', + oldVideoTitle, + '"/><br />', + 'Enter a new video description:<br />', + '<textarea cols="50" name="newVideoDescription">', + oldVideoDescription, + '</textarea><br />', + 'Select a new category: <select ', + 'name="newVideoCategory">', + '<option value="Autos">Autos & Vehicles</option>', + '<option value="Music">Music</option>', + '<option value="Animals">Pets & Animals</option>', + '<option value="Sports">Sports</option>', + '<option value="Travel">Travel & Events</option>', + '<option value="Games">Gadgets & Games</option>', + '<option value="Comedy">Comedy</option>', + '<option value="People">People & Blogs</option>', + '<option value="News">News & Politics</option>', + '<option value="Entertainment">Entertainment</option>', + '<option value="Education">Education</option>', + '<option value="Howto">Howto & Style</option>', + '<option value="Nonprofit">Nonprofit & Activism</option>', + '<option value="Tech">Science & Technology</option>', + '</select><br />', + 'Enter some new tags to describe your video ', + '<em>(separated by spaces)</em>:<br />', + '<input name="newVideoTags" type="text" size="50" ', + 'value="', + oldVideoTags, + '"/><br />', + '<input name="videoId" type="hidden" value="', + videoId, + '" /><br />', + '<input type="submit" value="go">', + '</form>'].join(''); + + document.getElementById(ytVideoApp.VIDEO_SEARCH_RESULTS_DIV).innerHTML = editMetaDataForm; +} + +/** + * Uses ytVideoApp.sendRequest to submit updated video meta-data. + * + * @param {String} newVideoTitle The new title of the video + * @param {String} newVideoDescription The new description of the video + * @param {String} newVideoCategory The new category of the video + * @param {String} newVideoTags The new tags for the video (separated by white-space) + * @param {String} videoId The id of the video to be edited + */ +ytVideoApp.editMetaData = function(newVideoTitle, newVideoDescription, newVideoCategory, newVideoTags, videoId) { + var filePath = 'operations.php'; + var params = 'operation=edit_meta_data' + + '&newVideoTitle=' + newVideoTitle + + '&newVideoDescription=' + newVideoDescription + + '&newVideoCategory=' + newVideoCategory + + '&newVideoTags=' + newVideoTags + + '&videoId=' + videoId; + ytVideoApp.sendRequest(filePath, params, ytVideoApp.VIDEO_SEARCH_RESULTS_DIV); +}; + + +/** + * Confirms whether user wants to delete a video. + * @param {String} videoId The video Id to be deleted + */ +ytVideoApp.confirmDeletion = function(videoId) { + var answer = confirm('Do you really want to delete the video with id: ' + videoId + ' ?'); + if (answer) { + ytVideoApp.prepareDeletion(videoId); + } +} + +/** + * Uses ytVideoApp.sendRequest to request a video to be deleted. + * @param {String} videoId The video Id to be deleted + */ +ytVideoApp.prepareDeletion = function(videoId) { + var filePath = 'operations.php'; + var params = 'operation=delete_video' + + '&videoId=' + videoId; + + var table = document.getElementById('videoResultList'); + var indexOfRowToBeDeleted = -1; + var tableRows = document.getElementsByTagName('TR'); + for (var i = 0, tableRow; tableRow = tableRows[i]; i++) { + if (tableRow.id == videoId) { + indexOfRowToBeDeleted = i; + } + } + if (indexOfRowToBeDeleted > -1) { + table.deleteRow(indexOfRowToBeDeleted); + } + ytVideoApp.sendRequest(filePath, params, ytVideoApp.VIDEO_SEARCH_RESULTS_DIV); +} + +/** + * Uses ytVideoApp.sendRequest to display a list of of YT videos. + * @param {String} op The operation to perform to retrieve a feed + * @param {Number} maxResults The maximum number of videos to list + * @param {Number} startIndex The first video to include in the list + * @param {String} searchTerm The search terms to pass to the specified feed + */ +ytVideoApp.presentFeed = function(op, maxResults, startIndex, searchTerm){ + var params = 'operation=' + op + + '&maxResults=' + maxResults + + '&startIndex=' + startIndex + + '&searchTerm=' + searchTerm; + var filePath = 'operations.php'; + ytVideoApp.sendRequest(filePath, params, ytVideoApp.VIDEO_LIST_CONTAINER_DIV); +}; + +/** + * Updates the variables used by the navigation buttons and the 'enabled' + * status of the buttons based upon the current page number passed in. + * @param {Number} page The current page number + */ +ytVideoApp.updateNavigation = function(page) { + ytVideoApp.nextPage = page + 1; + ytVideoApp.previousPage = page - 1; + document.getElementById(ytVideoApp.NEXT_PAGE_BUTTON).style.display = 'inline'; + document.getElementById(ytVideoApp.PREVIOUS_PAGE_BUTTON).style.display = 'inline'; + if (ytVideoApp.previousPage < 1) { + document.getElementById(ytVideoApp.PREVIOUS_PAGE_BUTTON).disabled = true; + } else { + document.getElementById(ytVideoApp.PREVIOUS_PAGE_BUTTON).disabled = false; + } + document.getElementById(ytVideoApp.NEXT_PAGE_BUTTON).disabled = false; +}; + +/** + * Hides the navigation. + */ +ytVideoApp.hideNavigation = function() { + document.getElementById(ytVideoApp.NAVIGATION_DIV).style.display = 'none'; +}; + +/** + * Update video results div + */ +ytVideoApp.refreshSearchResults = function() { + document.getElementById(ytVideoApp.VIDEO_SEARCH_RESULTS_DIV).innerHTML = ''; +} + +/** + * Method called when the query type has been changed. Clears out the + * value of the search term input box by default if one of the standard + * feeds is selected. This is to improve usability, as many of the standard + * feeds may not include results for even fairly popular search terms. + * @param {String} op The operation to perform. + * for querying all videos, or the name of one of the standard feeds. + * @param {Node} searchTermInputElement The HTML input element for the input + * element. + */ +ytVideoApp.queryTypeChanged = function(op, searchTermInputElement) { + if (op == 'search_username') { + searchTermInputElement.value = '-- enter username --'; + } else if (op != 'search_all') { + searchTermInputElement.value = ''; + } +}; + +/** + * Create a basic HTML form to use for creating a new playlist. + */ +ytVideoApp.prepareCreatePlaylistForm = function() { + var newPlaylistForm = ['<br /><form id="addPlaylist" ', + 'onsubmit="ytVideoApp.createNewPlaylist(this.newPlaylistTitle.value, ', + 'this.newPlaylistDescription.value); ">', + 'Enter a title for the new playlist:<br />', + '<input size="50" name="newPlaylistTitle" type="text" /><br />', + 'Enter a description:<br />', + '<textarea cols="25" name="newPlaylistDescription" >', + '</textarea><br />', + '<input type="submit" value="go">', + '</form>'].join(''); + + document.getElementById(ytVideoApp.PLAYLIST_ADD_DIV).innerHTML = newPlaylistForm; +} + +/** +* Uses ytVideoApp.sendRequest to create a new playlist. +* +* @param {String} playlistTitle The title of the new playlist +* @param {String} playlistDescription A description of the new playlist +*/ +ytVideoApp.createNewPlaylist = function(playlistTitle, playlistDescription) { + var filePath = 'operations.php'; + var params = 'operation=create_playlist' + + '&playlistTitle=' + playlistTitle + + '&playlistDescription=' + playlistDescription; + ytVideoApp.hideNavigation(); + ytVideoApp.sendRequest(filePath, params, ytVideoApp.VIDEO_SEARCH_RESULTS_DIV); +} + +/** + * Confirm user wants to delete a playlist + * + * @param {String} playlistTitle The title of the playlist to be deleted + */ +ytVideoApp.confirmPlaylistDeletion = function(playlistTitle) { + var answer = confirm('Do you really want to delete the playlist titled : ' + + playlistTitle + ' ?'); + if (answer) { + ytVideoApp.deletePlaylist(playlistTitle); + } +} + +/** +* Uses ytVideoApp.sendRequest to delete a playlist. +* +* @param {String} playlistTitle The title of the new playlist +*/ +ytVideoApp.deletePlaylist = function(playlistTitle) { + var filePath = 'operations.php'; + var params = 'operation=delete_playlist' + + '&playlistTitle=' + playlistTitle; + ytVideoApp.sendRequest(filePath, params, ytVideoApp.VIDEO_SEARCH_RESULTS_DIV); +} + +/** + * Create a basic HTML form to use for modifying a playlist. + * + * @param {String} oldPlaylistTitle The old title of the playlist + * @param {String} oldPlaylistDescription The old description of the playlist + */ +ytVideoApp.prepareUpdatePlaylistForm = function(oldPlaylistTitle, oldPlaylistDescription) { + var playlistUpdateForm = ['<br /><form id="updatePlaylist" ', + 'onsubmit="ytVideoApp.updatePlaylist(this.newPlaylistTitle.value, ', + 'this.newPlaylistDescription.value, this.oldPlaylistTitle.value);">', + 'Enter a title for the new playlist:<br />', + '<input size="50" name="newPlaylistTitle" type="text" value="', + oldPlaylistTitle, + '"/><br />', + 'Enter a description:<br />', + '<textarea cols="25" name="newPlaylistDescription" >', + oldPlaylistDescription, + '</textarea><br />', + '<input type="submit" value="go" />', + '<input type="hidden" value="', + oldPlaylistTitle, + '" name="oldPlaylistTitle" />', + '</form>'].join(''); + + document.getElementById(ytVideoApp.VIDEO_SEARCH_RESULTS_DIV).innerHTML = playlistUpdateForm; +} + +/** +* Uses ytVideoApp.sendRequest to update a playlist. +* +* @param {String} newPlaylistTitle The new title of the playlist +* @param {String} newPlaylistDescription A new description of the playlist +*/ +ytVideoApp.updatePlaylist = function(newPlaylistTitle, newPlaylistDescription, oldPlaylistTitle) { + var filePath = 'operations.php'; + var params = 'operation=update_playlist' + + '&newPlaylistTitle=' + newPlaylistTitle + + '&newPlaylistDescription=' + newPlaylistDescription + + '&oldPlaylistTitle=' + oldPlaylistTitle; + ytVideoApp.sendRequest(filePath, params, ytVideoApp.VIDEO_LIST_CONTAINER_DIV); +} + +/** +* Uses ytVideoApp.sendRequest to retrieve a users playlist. +* +*/ +ytVideoApp.retrievePlaylists = function() { + var filePath = 'operations.php'; + var params = 'operation=retrieve_playlists'; + ytVideoApp.hideNavigation(); + ytVideoApp.sendRequest(filePath, params, ytVideoApp.VIDEO_LIST_CONTAINER_DIV); +} diff --git a/zend/demos/Zend/Gdata/YouTubeVideoBrowser/index.php b/zend/demos/Zend/Gdata/YouTubeVideoBrowser/index.php new file mode 100755 index 0000000..607b905 --- /dev/null +++ b/zend/demos/Zend/Gdata/YouTubeVideoBrowser/index.php @@ -0,0 +1,278 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * PHP sample code for the YouTube data API. Utilizes the Zend Framework + * Zend_Gdata component to communicate with the YouTube data API. + * + * Requires the Zend Framework Zend_Gdata component and PHP >= 5.2.11 + * + * This sample is run from within a web browser. These files are required: + * index.php - the main logic, which interfaces with the YouTube API + * interface.html - the HTML to represent the web UI + * web_browser.css - the CSS to define the interface style + * web_browser.js - the JavaScript used to provide the video list AJAX interface + * + * NOTE: If using in production, some additional precautions with regards + * to filtering the input data should be used. This code is designed only + * for demonstration purposes. + */ + +/** + * @see Zend_Loader + */ +require_once 'Zend/Loader.php'; + +/** + * @see Zend_Gdata_YouTube + */ +Zend_Loader::loadClass('Zend_Gdata_YouTube'); + +/** + * Finds the URL for the flash representation of the specified video + * + * @param Zend_Gdata_YouTube_VideoEntry $entry The video entry + * @return string|null The URL or null, if the URL is not found + */ +function findFlashUrl($entry) +{ + foreach ($entry->mediaGroup->content as $content) { + if ($content->type === 'application/x-shockwave-flash') { + return $content->url; + } + } + return null; +} + +/** + * Returns a feed of top rated videos for the specified user + * + * @param string $user The username + * @return Zend_Gdata_YouTube_VideoFeed The feed of top rated videos + */ +function getTopRatedVideosByUser($user) +{ + $userVideosUrl = 'https://gdata.youtube.com/feeds/users/' . + $user . '/uploads'; + $yt = new Zend_Gdata_YouTube(); + $ytQuery = $yt->newVideoQuery($userVideosUrl); + // order by the rating of the videos + $ytQuery->setOrderBy('rating'); + // retrieve a maximum of 5 videos + $ytQuery->setMaxResults(5); + // retrieve only embeddable videos + $ytQuery->setFormat(5); + return $yt->getVideoFeed($ytQuery); +} + +/** + * Returns a feed of videos related to the specified video + * + * @param string $videoId The video + * @return Zend_Gdata_YouTube_VideoFeed The feed of related videos + */ +function getRelatedVideos($videoId) +{ + $yt = new Zend_Gdata_YouTube(); + $ytQuery = $yt->newVideoQuery(); + // show videos related to the specified video + $ytQuery->setFeedType('related', $videoId); + // order videos by rating + $ytQuery->setOrderBy('rating'); + // retrieve a maximum of 5 videos + $ytQuery->setMaxResults(5); + // retrieve only embeddable videos + $ytQuery->setFormat(5); + return $yt->getVideoFeed($ytQuery); +} + +/** + * Echo img tags for the first thumbnail representing each video in the + * specified video feed. Upon clicking the thumbnails, the video should + * be presented. + * + * @param Zend_Gdata_YouTube_VideoFeed $feed The video feed + * @return void + */ +function echoThumbnails($feed) +{ + foreach ($feed as $entry) { + $videoId = $entry->getVideoId(); + echo '<img src="' . $entry->mediaGroup->thumbnail[0]->url . '" '; + echo 'width="80" height="72" onclick="ytvbp.presentVideo(\'' . $videoId . '\')">'; + } +} + +/** + * Echo the video embed code, related videos and videos owned by the same user + * as the specified videoId. + * + * @param string $videoId The video + * @return void + */ +function echoVideoPlayer($videoId) +{ + $yt = new Zend_Gdata_YouTube(); + + $entry = $yt->getVideoEntry($videoId); + $videoTitle = $entry->mediaGroup->title; + $videoUrl = findFlashUrl($entry); + $relatedVideoFeed = getRelatedVideos($entry->getVideoId()); + $topRatedFeed = getTopRatedVideosByUser($entry->author[0]->name); + + print <<<END + <b>$videoTitle</b><br /> + <object width="425" height="350"> + <param name="movie" value="${videoUrl}&autoplay=1"></param> + <param name="wmode" value="transparent"></param> + <embed src="${videoUrl}&autoplay=1" type="application/x-shockwave-flash" wmode="transparent" + width=425" height="350"></embed> + </object> +END; + echo '<br />'; + echoVideoMetadata($entry); + echo '<br /><b>Related:</b><br />'; + echoThumbnails($relatedVideoFeed); + echo '<br /><b>Top rated videos by user:</b><br />'; + echoThumbnails($topRatedFeed); +} + +/** + * Echo video metadata + * + * @param Zend_Gdata_YouTube_VideoEntry $entry The video entry + * @return void + */ +function echoVideoMetadata($entry) +{ + $title = $entry->mediaGroup->title; + $description = $entry->mediaGroup->description; + $authorUsername = $entry->author[0]->name; + $authorUrl = 'http://www.youtube.com/profile?user=' . $authorUsername; + $tags = $entry->mediaGroup->keywords; + $duration = $entry->mediaGroup->duration->seconds; + $watchPage = $entry->mediaGroup->player[0]->url; + $viewCount = $entry->statistics->viewCount; + $rating = $entry->rating->average; + $numRaters = $entry->rating->numRaters; + $flashUrl = findFlashUrl($entry); + print <<<END + <b>Title:</b> ${title}<br /> + <b>Description:</b> ${description}<br /> + <b>Author:</b> <a href="${authorUrl}">${authorUsername}</a><br /> + <b>Tags:</b> ${tags}<br /> + <b>Duration:</b> ${duration} seconds<br /> + <b>View count:</b> ${viewCount}<br /> + <b>Rating:</b> ${rating} (${numRaters} ratings)<br /> + <b>Flash:</b> <a href="${flashUrl}">${flashUrl}</a><br /> + <b>Watch page:</b> <a href="${watchPage}">${watchPage}</a> <br /> +END; +} + +/** + * Echo the list of videos in the specified feed. + * + * @param Zend_Gdata_YouTube_VideoFeed $feed The video feed + * @return void + */ +function echoVideoList($feed) +{ + echo '<table class="videoList">'; + echo '<tbody width="100%">'; + foreach ($feed as $entry) { + $videoId = $entry->getVideoId(); + $thumbnailUrl = $entry->mediaGroup->thumbnail[0]->url; + $videoTitle = $entry->mediaGroup->title; + $videoDescription = $entry->mediaGroup->description; + print <<<END + <tr onclick="ytvbp.presentVideo('${videoId}')"> + <td width="130"><img src="${thumbnailUrl}" /></td> + <td width="100%"> + <a href="#">${videoTitle}</a> + <p class="videoDescription">${videoDescription}</p> + </td> + </tr> +END; + } + echo '</table>'; +} + +/* + * The main controller logic of the YouTube video browser demonstration app. + */ +$queryType = isset($_POST['queryType']) ? $_POST['queryType'] : null; + +if ($queryType === null) { + /* display the entire interface */ + include 'interface.html'; +} else if ($queryType == 'show_video') { + /* display an individual video */ + if (array_key_exists('videoId', $_POST)) { + $videoId = $_POST['videoId']; + echoVideoPlayer($videoId); + } else if (array_key_exists('videoId', $_GET)) { + $videoId = $_GET['videoId']; + echoVideoPlayer($videoId); + } else { + echo 'No videoId found.'; + exit; + } +} else { + /* display a list of videos */ + $searchTerm = $_POST['searchTerm']; + $startIndex = $_POST['startIndex']; + $maxResults = $_POST['maxResults']; + + $yt = new Zend_Gdata_YouTube(); + $query = $yt->newVideoQuery(); + $query->setQuery($searchTerm); + $query->setStartIndex($startIndex); + $query->setMaxResults($maxResults); + + /* check for one of the standard feeds, or list from 'all' videos */ + switch ($queryType) { + case 'most_viewed': + $query->setFeedType('most viewed'); + $query->setTime('this_week'); + $feed = $yt->getVideoFeed($query); + break; + case 'most_recent': + $query->setFeedType('most recent'); + $feed = $yt->getVideoFeed($query); + break; + case 'recently_featured': + $query->setFeedType('recently featured'); + $feed = $yt->getVideoFeed($query); + break; + case 'top_rated': + $query->setFeedType('top rated'); + $query->setTime('this_week'); + $feed = $yt->getVideoFeed($query); + break; + case 'all': + $feed = $yt->getVideoFeed($query); + break; + default: + echo 'ERROR - unknown queryType - "' . $queryType . '"'; + break; + } + echoVideoList($feed); +} diff --git a/zend/demos/Zend/Gdata/YouTubeVideoBrowser/interface.html b/zend/demos/Zend/Gdata/YouTubeVideoBrowser/interface.html new file mode 100644 index 0000000..cfb7576 --- /dev/null +++ b/zend/demos/Zend/Gdata/YouTubeVideoBrowser/interface.html @@ -0,0 +1,79 @@ +<!--- +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +--> +<html> +<head> + <title>YouTube data API Video Browser in PHP</title> + <link href="video_browser.css" type="text/css" rel="stylesheet"/> + <script src="video_browser.js" type="text/javascript"></script> +</head> +<body> +<div id="main"> + <div id="titleBar"> + <div id="titleText"><h1>YouTube data API Video Browser in PHP</h1></div> + <div id="searchBox" style="display: none;"> + <form id="searchForm" onsubmit="ytvbp.listVideos(this.queryType.value, this.searchTerm.value, 1); return false;"> + <select name="queryType" onchange="ytvbp.queryTypeChanged(this.value, this.form.searchTerm);"> + <option value="all" selected="true">All Videos</option> + <option value="top_rated">Top Rated Videos</option> + <option value="most_viewed">Most Viewed Videos</option> + <option value="recently_featured">Recently Featured Videos</option> + + </select> + <input name="searchTerm" type="text" value="puppy"> + <input type="submit" value="Search"> + </form> + </div> + <br /> + </div> + <br clear="all" /> + <div id="mainSearchBox"> + <h2>Search YouTube:</h2> + <form id="mainSearchForm" onsubmit="ytvbp.listVideos(this.queryType.value, this.searchTerm.value, 1); document.forms.searchForm.searchTerm.value=this.searchTerm.value; ytvbp.hideMainSearch(); document.forms.searchForm.queryType.selectedIndex=this.queryType.selectedIndex; return false;"> + <select name="queryType" onchange="ytvbp.queryTypeChanged(this.value, this.form.searchTerm);"> + <option value="all" selected="true">All Videos</option> + <option value="top_rated">Top Rated Videos</option> + <option value="most_viewed">Most Viewed Videos</option> + <option value="recently_featured">Recently Featured Videos</option> + + </select> + <input name="searchTerm" type="text" value="puppy"> + <input type="submit" value="Search"> + </form> + </div> + <br clear="all" /> + <div id="searchResults"> + <div id="searchResultsListColumn"> + <div id="searchResultsVideoList"></div> + <div id="searchResultsNavigation"> + <form id="navigationForm"> + <input type="button" id="previousPageButton" onclick="ytvbp.listVideos(ytvbp.previousQueryType, ytvbp.previousSearchTerm, ytvbp.previousPage);" value="Back" style="display: none;"></input> + <input type="button" id="nextPageButton" onclick="ytvbp.listVideos(ytvbp.previousQueryType, ytvbp.previousSearchTerm, ytvbp.nextPage);" value="Next" style="display: none;"></input> + </form> + </div> + </div> + <div id="searchResultsVideoColumn"> + <div id="videoPlayer"></div> + </div> + </div> +</div> +</body> +</html> diff --git a/zend/demos/Zend/Gdata/YouTubeVideoBrowser/video_browser.css b/zend/demos/Zend/Gdata/YouTubeVideoBrowser/video_browser.css new file mode 100644 index 0000000..1984ed9 --- /dev/null +++ b/zend/demos/Zend/Gdata/YouTubeVideoBrowser/video_browser.css @@ -0,0 +1,152 @@ +body { + background-color: white; + color: black; + font-family: Arial, sans-serif; + font-size: small; + margin: 8px; + margin-top: 3px; +} + +img { + border: 0; +} + +table { + border-collapse: collapse; +} + +th, td { + padding: 0; + vertical-align: top; + text-align: left; +} + +a:link { + color: #0000cc; +} + +a:active { + color: #cc0000; +} + +a:visited { + color: #551a8b; +} + +h1 { + font-size: x-large; + margin-top: 0px; + margin-bottom: 5px; +} + +h2 { + font-size: large; +} + +h3 { + font-size: medium; +} + +h4 { + font-size: small; +} + +form { + display: inline; + margin: 0; + padding: 0; +} + +li { + margin-bottom: 0.25em; +} + +pre, code { + color: #007000; + font-family: "bogus font here", monospace; + font-size: 100%; +} + +pre { + border: 1px solid silver; + background-color: #f5f5f5; + padding: 0.5em; + overflow: auto; + margin: 2em; +} + +pre ins { + color: #cc0000; + font-weight: bold; + text-decoration: none; +} + +/* "Selected" links */ + +a.selected, .selected a, .selected { + color: black; + font-weight: bold; + text-decoration: none; +} + +a.selected:visited, .selected a:visited { + color: black; +} + +p.videoDescription { + font-size: small; + margin: 0; + padding: 0; +} + +.videoList td { + padding-bottom: 5px; + padding-right: 5px; +} + +#titleBar { + border: 1px solid silver; + background-color: #e5ecf9; + font-size: large; + font-weight: bold; + margin: 0; + padding: 0; + padding-top: 5px; + padding-bottom: 10px; + padding-left: 10px; + padding-right: 10px; + margin-top: 5px; + margin-bottom: 15px; +} + +#titleText { + float: left; +} + +#searchBox { + float: right; +} + +#mainSearchBox { + background-color: #e5ecf9; + border: 1px solid silver; + width: 250; + padding-top: 5px; + padding-bottom: 5px; + padding-left: 10px; + padding-right: 10px; +} + +#searchResults { + width: 100%; +} + +#searchResultsListColumn { + float: left; + width: 47%; +} + +#searchResultsVideoColumn { + float: right; + width: 47%; +} diff --git a/zend/demos/Zend/Gdata/YouTubeVideoBrowser/video_browser.js b/zend/demos/Zend/Gdata/YouTubeVideoBrowser/video_browser.js new file mode 100644 index 0000000..3e91bcc --- /dev/null +++ b/zend/demos/Zend/Gdata/YouTubeVideoBrowser/video_browser.js @@ -0,0 +1,228 @@ +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Gdata + * @subpackage Demos + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @fileoverview Provides functions for browsing and searching YouTube + * data API feeds using a PHP backend powered by the Zend_Gdata component + * of the Zend Framework. + */ + +/** + * provides namespacing for the YouTube Video Browser PHP version (ytvbp) + */ +var ytvbp = {}; + +/** + * maximum number of results to return for list of videos + * @type Number + */ +ytvbp.MAX_RESULTS_LIST = 5; + +/** + * navigation button id used to page to the previous page of + * results in the list of videos + * @type String + */ +ytvbp.PREVIOUS_PAGE_BUTTON = 'previousPageButton'; + +/** + * navigation button id used to page to the next page of + * results in the list of videos + * @type String + */ +ytvbp.NEXT_PAGE_BUTTON = 'nextPageButton'; + +/** + * container div id used to hold list of videos + * @type String + */ +ytvbp.VIDEO_LIST_CONTAINER_DIV = 'searchResultsVideoList'; + +/** + * container div id used to hold the video player + * @type String + */ +ytvbp.VIDEO_PLAYER_DIV = 'videoPlayer'; + +/** + * container div id used to hold the search box which displays when the page + * first loads + * @type String + */ +ytvbp.MAIN_SEARCH_CONTAINER_DIV = 'mainSearchBox'; + +/** + * container div id used to hold the search box displayed at the top of + * the browser after one search has already been performed + * @type String + */ +ytvbp.TOP_SEARCH_CONTAINER_DIV = 'searchBox'; + +/** + * the page number to use for the next page navigation button + * @type Number + */ +ytvbp.nextPage = 2; + +/** + * the page number to use for the previous page navigation button + * @type Number + */ +ytvbp.previousPage = 0; + +/** + * the last search term used to query - allows for the navigation + * buttons to know what string query to perform when clicked + * @type String + */ +ytvbp.previousSearchTerm = ''; + +/** + * the last query type used for querying - allows for the navigation + * buttons to know what type of query to perform when clicked + * @type String + */ +ytvbp.previousQueryType = 'all'; + +/** + * Retrieves a list of videos matching the provided criteria. The list of + * videos can be restricted to a particular standard feed or search criteria. + * @param {String} queryType The type of query to be done - either 'all' + * for querying all videos, or the name of a standard feed. + * @param {String} searchTerm The search term(s) to use for querying as the + * 'vq' query parameter value + * @param {Number} page The 1-based page of results to return. + */ +ytvbp.listVideos = function(queryType, searchTerm, page) { + ytvbp.previousSearchTerm = searchTerm; + ytvbp.previousQueryType = queryType; + var maxResults = ytvbp.MAX_RESULTS_LIST; + var startIndex = (((page - 1) * ytvbp.MAX_RESULTS_LIST) + 1); + ytvbp.presentFeed(queryType, maxResults, startIndex, searchTerm); + ytvbp.updateNavigation(page); +}; + +/** + * Sends an AJAX request to the server to retrieve a list of videos or + * the video player/metadata. Sends the request to the specified filePath + * on the same host, passing the specified params, and filling the specified + * resultDivName with the resutls upon success. + * @param {String} filePath The path to which the request should be sent + * @param {String} params The URL encoded POST params + * @param {String} resultDivName The name of the DIV used to hold the results + */ +ytvbp.sendRequest = function(filePath, params, resultDivName) { + if (window.XMLHttpRequest) { + var xmlhr = new XMLHttpRequest(); + } else { + var xmlhr = new ActiveXObject('MSXML2.XMLHTTP.3.0'); + } + + xmlhr.open('POST', filePath, true); + xmlhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + + xmlhr.onreadystatechange = function() { + var resultDiv = document.getElementById(resultDivName); + if (xmlhr.readyState == 1) { + resultDiv.innerHTML = '<b>Loading...</b>'; + } else if (xmlhr.readyState == 4 && xmlhr.status == 200) { + if (xmlhr.responseText) { + resultDiv.innerHTML = xmlhr.responseText; + } + } else if (xmlhr.readyState == 4) { + alert('Invalid response received - Status: ' + xmlhr.status); + } + } + xmlhr.send(params); +} + +/** + * Uses ytvbp.sendRequest to display a YT video player and metadata for the + * specified video ID. + * @param {String} videoId The ID of the YouTube video to show + */ +ytvbp.presentVideo = function(videoId) { + var params = 'queryType=show_video&videoId=' + videoId; + var filePath = 'index.php'; + ytvbp.sendRequest(filePath, params, ytvbp.VIDEO_PLAYER_DIV); +} + +/** + * Uses ytvbp.sendRequest to display a list of of YT videos. + * @param {String} queryType The name of a standard video feed or 'all' + * @param {Number} maxResults The maximum number of videos to list + * @param {Number} startIndex The first video to include in the list + * @param {String} searchTerm The search terms to pass to the specified feed + */ +ytvbp.presentFeed = function(queryType, maxResults, startIndex, searchTerm){ + var params = 'queryType=' + queryType + + '&maxResults=' + maxResults + + '&startIndex=' + startIndex + + '&searchTerm=' + searchTerm; + var filePath = 'index.php'; + ytvbp.sendRequest(filePath, params, ytvbp.VIDEO_LIST_CONTAINER_DIV); +} + +/** + * Updates the variables used by the navigation buttons and the 'enabled' + * status of the buttons based upon the current page number passed in. + * @param {Number} page The current page number + */ +ytvbp.updateNavigation = function(page) { + ytvbp.nextPage = page + 1; + ytvbp.previousPage = page - 1; + document.getElementById(ytvbp.NEXT_PAGE_BUTTON).style.display = 'inline'; + document.getElementById(ytvbp.PREVIOUS_PAGE_BUTTON).style.display = 'inline'; + if (ytvbp.previousPage < 1) { + document.getElementById(ytvbp.PREVIOUS_PAGE_BUTTON).disabled = true; + } else { + document.getElementById(ytvbp.PREVIOUS_PAGE_BUTTON).disabled = false; + } + document.getElementById(ytvbp.NEXT_PAGE_BUTTON).disabled = false; +}; + +/** + * Hides the main (large) search form and enables one that's in the + * title bar of the application. The main search form is only used + * for the first load. Subsequent searches should use the version in + * the title bar. + */ +ytvbp.hideMainSearch = function() { + document.getElementById(ytvbp.MAIN_SEARCH_CONTAINER_DIV).style.display = + 'none'; + document.getElementById(ytvbp.TOP_SEARCH_CONTAINER_DIV).style.display = + 'inline'; +}; + +/** + * Method called when the query type has been changed. Clears out the + * value of the search term input box by default if one of the standard + * feeds is selected. This is to improve usability, as many of the standard + * feeds may not include results for even fairly popular search terms. + * @param {String} queryType The type of query being done - either 'all' + * for querying all videos, or the name of one of the standard feeds. + * @param {Node} searchTermInputElement The HTML input element for the input + * element. + */ +ytvbp.queryTypeChanged = function(queryType, searchTermInputElement) { + if (queryType != 'all') { + searchTermInputElement.value = ''; + } +}; |
