Home | History | Annotate | Download | only in hello-php
      1 <?php
      2 /**
      3  * A "Hello world!" for the Chrome Web Store Licensing API, in PHP. This
      4  * program logs the user in with Google's Federated Login API (OpenID), fetches
      5  * their license state with OAuth, and prints one of these greetings as
      6  * appropriate:
      7  *
      8  *   1. This user has FREE_TRIAL access to this application ( appId: 1 )
      9  *   2. This user has FULL access to this application ( appId: 1 )
     10  *   3. This user has NO access to this application ( appId: 1 )
     11  *
     12  * This code makes use of a popup ui extension to the OpenID protocol. Instead
     13  * of the user being redirected to the Google login page, a popup window opens
     14  * to the login page, keeping the user on the main application page. See
     15  * popuplib.js
     16  *
     17  * Copyright 2010 the Chromium Authors
     18  *
     19  * Use of this source code is governed by a BSD-style license that can be found
     20  * in the "LICENSE" file.
     21  *
     22  * Eric Bidelman <ericbidelman (at) chromium.org>
     23  */
     24 
     25 session_start();
     26 
     27 require_once 'lib/oauth/OAuth.php';
     28 require_once 'lib/lightopenid/openid.php';
     29 
     30 // Full URL of the current application is running under.
     31 $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on') ? 'http' :
     32                                                                      'https';
     33 $selfUrl = "$scheme://{$_SERVER['HTTP_HOST']}{$_SERVER['PHP_SELF']}";
     34 
     35 
     36 /**
     37  * Wrapper class to make calls to the Chrome Web Store License Server.
     38  */
     39 class LicenseServerClient {
     40 
     41   const LICENSE_SERVER_HOST = 'https://www.googleapis.com';
     42   const CONSUMER_KEY = 'anonymous';
     43   const CONSUMER_SECRET = 'anonymous';
     44   const APP_ID = '1';  // Change to the correct id of your application.
     45   const TOKEN = '[REPLACE THIS WITH YOUR OAUTH TOKEN]';
     46   const TOKEN_SECRET = '[REPLACE THIS WITH YOUR OAUTH TOKEN SECRET]';
     47   public $consumer;
     48   public $token;
     49   public $signatureMethod;
     50 
     51   public function __construct() {
     52     $this->consumer = new OAuthConsumer(
     53         self::CONSUMER_KEY, self::CONSUMER_SECRET, NULL);
     54     $this->token = new OAuthToken(self::TOKEN, self::TOKEN_SECRET);
     55     $this->signatureMethod = new OAuthSignatureMethod_HMAC_SHA1();
     56   }
     57 
     58   /**
     59    * Makes an HTTP GET request to the specified URL.
     60    *
     61    * @param string $url Full URL of the resource to access
     62    * @param string $request OAuthRequest containing the signed request to make.
     63    * @param array $extraHeaders (optional) Array of headers.
     64    * @param bool $returnResponseHeaders True if resp headers should be returned.
     65    * @return string Response body from the server.
     66    */
     67   protected function send_signed_get($request, $extraHeaders=NULL,
     68                                      $returnRequestHeaders=false,
     69                                      $returnResponseHeaders=false) {
     70     $url = explode('?', $request->to_url());
     71     $curl = curl_init($url[0]);
     72     curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
     73     curl_setopt($curl, CURLOPT_FAILONERROR, false);
     74     curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
     75 
     76     // Return request headers in the response.
     77     curl_setopt($curl, CURLINFO_HEADER_OUT, $returnRequestHeaders);
     78 
     79     // Return response headers in the response?
     80     if ($returnResponseHeaders) {
     81       curl_setopt($curl, CURLOPT_HEADER, true);
     82     }
     83 
     84     $headers = array($request->to_header());
     85     if (is_array($extraHeaders)) {
     86       $headers = array_merge($headers, $extraHeaders);
     87     }
     88     curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
     89 
     90     // Execute the request.  If an error occurs fill the response body with it.
     91     $response = curl_exec($curl);
     92     if (!$response) {
     93       $response = curl_error($curl);
     94     }
     95 
     96     // Add server's response headers to our response body
     97     $response = curl_getinfo($curl, CURLINFO_HEADER_OUT) . $response;
     98 
     99     curl_close($curl);
    100 
    101     return $response;
    102   }
    103 
    104   public function checkLicense($userId) {
    105     $url = self::LICENSE_SERVER_HOST . '/chromewebstore/v1/licenses/' .
    106            self::APP_ID . '/' . urlencode($userId);
    107 
    108     $request = OAuthRequest::from_consumer_and_token(
    109         $this->consumer, $this->token, 'GET', $url, array());
    110 
    111     $request->sign_request($this->signatureMethod, $this->consumer,
    112                            $this->token);
    113 
    114     return $this->send_signed_get($request);
    115   }
    116 }
    117 
    118 try {
    119   $openid = new LightOpenID();
    120   $userId = $openid->identity;
    121   if (!isset($_GET['openid_mode'])) {
    122     // This section performs the OpenID dance with the normal redirect. Use it
    123     // if you want an alternative to the popup UI.
    124     if (isset($_GET['login'])) {
    125       $openid->identity = 'https://www.google.com/accounts/o8/id';
    126       $openid->required = array('namePerson/first', 'namePerson/last',
    127                                 'contact/email');
    128       header('Location: ' . $openid->authUrl());
    129     }
    130   } else if ($_GET['openid_mode'] == 'cancel') {
    131     echo 'User has canceled authentication!';
    132   } else {
    133     $userId = $openid->validate() ? $openid->identity : '';
    134     $_SESSION['userId'] = $userId;
    135     $attributes = $openid->getAttributes();
    136     $_SESSION['attributes'] = $attributes;
    137   }
    138 } catch(ErrorException $e) {
    139   echo $e->getMessage();
    140   exit;
    141 }
    142 
    143 if (isset($_REQUEST['popup']) && !isset($_SESSION['redirect_to'])) {
    144   $_SESSION['redirect_to'] = $selfUrl;
    145   echo '<script type = "text/javascript">window.close();</script>';
    146   exit;
    147 } else if (isset($_SESSION['redirect_to'])) {
    148   $redirect = $_SESSION['redirect_to'];
    149   unset($_SESSION['redirect_to']);
    150   header('Location: ' . $redirect);
    151 } else if (isset($_REQUEST['queryLicenseServer'])) {
    152   $ls = new LicenseServerClient();
    153   echo $ls->checkLicense($_REQUEST['user_id']);
    154   exit;
    155 } else if (isset($_GET['logout'])) {
    156   unset($_SESSION['attributes']);
    157   unset($_SESSION['userId']);
    158   header('Location: ' . $selfUrl);
    159 }
    160 ?>
    161 
    162 <!DOCTYPE html>
    163 <html>
    164   <head>
    165   <meta charset="utf-8" />
    166   <link href="main.css" type="text/css" rel="stylesheet" />
    167   <script type="text/javascript" src="popuplib.js"></script>
    168   <script type="text/html" id="ls_tmpl">
    169     <div id="access-level">
    170       <% if (result.toLowerCase() == 'yes') { %>
    171         This user has <span class="<%= accessLevel.toLowerCase() %>"><%= accessLevel %></span> access to this application ( appId: <%= appId %> )
    172       <% } else { %>
    173         This user has <span class="<%= result.toLowerCase() %>"><%= result %></span> access to this application ( appId: <%= appId %> )
    174       <% } %>
    175     </div>
    176   </script>
    177   </head>
    178   <body>
    179     <nav>
    180       <?php if (!isset($_SESSION['userId'])): ?>
    181         <a href="javascript:" onclick="openPopup(450, 500, this);">Sign in</a>
    182       <?php else: ?>
    183         <span>Welcome <?php echo @$_SESSION['attributes']['namePerson/first'] ?> <?php echo @$_SESSION['attributes']['namePerson/last'] ?> ( <?php echo $_SESSION['attributes']['contact/email'] ?> )</span>
    184         <a href="?logout">Sign out</a>
    185       <?php endif; ?>
    186     </nav>
    187     <?php if (isset($_SESSION['attributes'])): ?>
    188       <div id="container">
    189         <form action="<?php echo "$selfUrl?queryLicenseServer" ?>" onsubmit="return queryLicenseServer(this);">
    190           <input type="hidden" id="user_id" name="user_id" value="<?php echo $_SESSION['userId'] ?>" />
    191           <input type="submit" value="Check user's access" />
    192         </form>
    193         <div id="license-server-response"></div>
    194       </div>
    195     <?php endif; ?>
    196     <script>
    197       // Simple JavaScript Templating
    198       // John Resig - http://ejohn.org/ - MIT Licensed
    199       (function(){
    200         var cache = {};
    201 
    202         this.tmpl = function tmpl(str, data){
    203           // Figure out if we're getting a template, or if we need to
    204           // load the template - and be sure to cache the result.
    205           var fn = !/\W/.test(str) ?
    206             cache[str] = cache[str] ||
    207               tmpl(document.getElementById(str).innerHTML) :
    208 
    209             // Generate a reusable function that will serve as a template
    210             // generator (and which will be cached).
    211             new Function("obj",
    212               "var p=[],print=function(){p.push.apply(p,arguments);};" +
    213 
    214               // Introduce the data as local variables using with(){}
    215               "with(obj){p.push('" +
    216 
    217               // Convert the template into pure JavaScript
    218               str
    219                 .replace(/[\r\t\n]/g, " ")
    220                 .split("<%").join("\t")
    221                 .replace(/((^|%>)[^\t]*)'/g, "$1\r")
    222                 .replace(/\t=(.*?)%>/g, "',$1,'")
    223                 .split("\t").join("');")
    224                 .split("%>").join("p.push('")
    225                 .split("\r").join("\\'")
    226             + "');}return p.join('');");
    227 
    228           // Provide some basic currying to the user
    229           return data ? fn( data ) : fn;
    230         };
    231       })();
    232 
    233       function queryLicenseServer(form) {
    234         var userId = form.user_id.value;
    235 
    236         if (!userId) {
    237           alert('No OpenID specified!');
    238           return false;
    239         }
    240 
    241         var req = new XMLHttpRequest();
    242         req.onreadystatechange = function(e) {
    243           if (this.readyState == 4) {
    244             var resp = JSON.parse(this.responseText);
    245             var el = document.getElementById('license-server-response');
    246             if (resp.error) {
    247               el.innerHTML = ['<div class="error">Error ', resp.error.code,
    248                               ': ', resp.error.message, '</div>'].join('');
    249             } else {
    250               el.innerHTML = tmpl('ls_tmpl', resp);
    251             }
    252           }
    253         };
    254         var url =
    255             [form.action, '&user_id=', encodeURIComponent(userId)].join('');
    256         req.open('GET', url, true);
    257         req.send(null);
    258 
    259         return false;
    260       }
    261 
    262       function openPopup(w, h, link) {
    263         var extensions = {
    264           'openid.ns.ext1': 'http://openid.net/srv/ax/1.0',
    265           'openid.ext1.mode': 'fetch_request',
    266           'openid.ext1.type.email': 'http://axschema.org/contact/email',
    267           'openid.ext1.type.first': 'http://axschema.org/namePerson/first',
    268           'openid.ext1.type.last': 'http://axschema.org/namePerson/last',
    269           'openid.ext1.required': 'email,first,last',
    270           'openid.ui.icon': 'true'
    271         };
    272 
    273         var googleOpener = popupManager.createPopupOpener({
    274           opEndpoint: 'https://www.google.com/accounts/o8/ud',
    275           returnToUrl: '<?php echo "$selfUrl?popup=true" ?>',
    276           onCloseHandler: function() {
    277             window.location = '<?php echo $selfUrl ?>';
    278           },
    279           shouldEncodeUrls: false,
    280           extensions: extensions
    281         });
    282         link.parentNode.appendChild(
    283             document.createTextNode('Authenticating...'));
    284         link.parentNode.removeChild(link);
    285         googleOpener.popup(w, h);
    286       }
    287     </script>
    288   </body>
    289 </html>
    290