SQLStore.php

Go to the documentation of this file.
00001 <?php
00002 
00023 global $__Auth_OpenID_PEAR_AVAILABLE;
00024 $__Auth_OpenID_PEAR_AVAILABLE = @include_once 'DB.php';
00025 
00029 require_once 'Auth/OpenID/Interface.php';
00030 require_once 'Auth/OpenID/Nonce.php';
00031 
00035 require_once 'Auth/OpenID.php';
00036 
00040 require_once 'Auth/OpenID/Nonce.php';
00041 
00067 class Auth_OpenID_SQLStore extends Auth_OpenID_OpenIDStore {
00068 
00088     function Auth_OpenID_SQLStore($connection,
00089                                   $associations_table = null,
00090                                   $nonces_table = null)
00091     {
00092         global $__Auth_OpenID_PEAR_AVAILABLE;
00093 
00094         $this->associations_table_name = "oid_associations";
00095         $this->nonces_table_name = "oid_nonces";
00096 
00097         // Check the connection object type to be sure it's a PEAR
00098         // database connection.
00099         if (!(is_object($connection) &&
00100               (is_subclass_of($connection, 'db_common') ||
00101                is_subclass_of($connection,
00102                               'auth_openid_databaseconnection')))) {
00103             trigger_error("Auth_OpenID_SQLStore expected PEAR connection " .
00104                           "object (got ".get_class($connection).")",
00105                           E_USER_ERROR);
00106             return;
00107         }
00108 
00109         $this->connection = $connection;
00110 
00111         // Be sure to set the fetch mode so the results are keyed on
00112         // column name instead of column index.  This is a PEAR
00113         // constant, so only try to use it if PEAR is present.  Note
00114         // that Auth_Openid_Databaseconnection instances need not
00115         // implement ::setFetchMode for this reason.
00116         if ($__Auth_OpenID_PEAR_AVAILABLE) {
00117             $this->connection->setFetchMode(DB_FETCHMODE_ASSOC);
00118         }
00119 
00120         if ($associations_table) {
00121             $this->associations_table_name = $associations_table;
00122         }
00123 
00124         if ($nonces_table) {
00125             $this->nonces_table_name = $nonces_table;
00126         }
00127 
00128         $this->max_nonce_age = 6 * 60 * 60;
00129 
00130         // Be sure to run the database queries with auto-commit mode
00131         // turned OFF, because we want every function to run in a
00132         // transaction, implicitly.  As a rule, methods named with a
00133         // leading underscore will NOT control transaction behavior.
00134         // Callers of these methods will worry about transactions.
00135         $this->connection->autoCommit(false);
00136 
00137         // Create an empty SQL strings array.
00138         $this->sql = array();
00139 
00140         // Call this method (which should be overridden by subclasses)
00141         // to populate the $this->sql array with SQL strings.
00142         $this->setSQL();
00143 
00144         // Verify that all required SQL statements have been set, and
00145         // raise an error if any expected SQL strings were either
00146         // absent or empty.
00147         list($missing, $empty) = $this->_verifySQL();
00148 
00149         if ($missing) {
00150             trigger_error("Expected keys in SQL query list: " .
00151                           implode(", ", $missing),
00152                           E_USER_ERROR);
00153             return;
00154         }
00155 
00156         if ($empty) {
00157             trigger_error("SQL list keys have no SQL strings: " .
00158                           implode(", ", $empty),
00159                           E_USER_ERROR);
00160             return;
00161         }
00162 
00163         // Add table names to queries.
00164         $this->_fixSQL();
00165     }
00166 
00167     function tableExists($table_name)
00168     {
00169         return !$this->isError(
00170                       $this->connection->query(
00171                           sprintf("SELECT * FROM %s LIMIT 0",
00172                                   $table_name)));
00173     }
00174 
00179     function isError($value)
00180     {
00181         return PEAR::isError($value);
00182     }
00183 
00189     function resultToBool($obj)
00190     {
00191         if ($this->isError($obj)) {
00192             return false;
00193         } else {
00194             return true;
00195         }
00196     }
00197 
00203     function setSQL()
00204     {
00205     }
00206 
00211     function reset()
00212     {
00213         $this->connection->query(sprintf("DELETE FROM %s",
00214                                          $this->associations_table_name));
00215 
00216         $this->connection->query(sprintf("DELETE FROM %s",
00217                                          $this->nonces_table_name));
00218     }
00219 
00223     function _verifySQL()
00224     {
00225         $missing = array();
00226         $empty = array();
00227 
00228         $required_sql_keys = array(
00229                                    'nonce_table',
00230                                    'assoc_table',
00231                                    'set_assoc',
00232                                    'get_assoc',
00233                                    'get_assocs',
00234                                    'remove_assoc'
00235                                    );
00236 
00237         foreach ($required_sql_keys as $key) {
00238             if (!array_key_exists($key, $this->sql)) {
00239                 $missing[] = $key;
00240             } else if (!$this->sql[$key]) {
00241                 $empty[] = $key;
00242             }
00243         }
00244 
00245         return array($missing, $empty);
00246     }
00247 
00251     function _fixSQL()
00252     {
00253         $replacements = array(
00254                               array(
00255                                     'value' => $this->nonces_table_name,
00256                                     'keys' => array('nonce_table',
00257                                                     'add_nonce',
00258                                                     'clean_nonce')
00259                                     ),
00260                               array(
00261                                     'value' => $this->associations_table_name,
00262                                     'keys' => array('assoc_table',
00263                                                     'set_assoc',
00264                                                     'get_assoc',
00265                                                     'get_assocs',
00266                                                     'remove_assoc',
00267                                                     'clean_assoc')
00268                                     )
00269                               );
00270 
00271         foreach ($replacements as $item) {
00272             $value = $item['value'];
00273             $keys = $item['keys'];
00274 
00275             foreach ($keys as $k) {
00276                 if (is_array($this->sql[$k])) {
00277                     foreach ($this->sql[$k] as $part_key => $part_value) {
00278                         $this->sql[$k][$part_key] = sprintf($part_value,
00279                                                             $value);
00280                     }
00281                 } else {
00282                     $this->sql[$k] = sprintf($this->sql[$k], $value);
00283                 }
00284             }
00285         }
00286     }
00287 
00288     function blobDecode($blob)
00289     {
00290         return $blob;
00291     }
00292 
00293     function blobEncode($str)
00294     {
00295         return $str;
00296     }
00297 
00298     function createTables()
00299     {
00300         $this->connection->autoCommit(true);
00301         $n = $this->create_nonce_table();
00302         $a = $this->create_assoc_table();
00303         $this->connection->autoCommit(false);
00304 
00305         if ($n && $a) {
00306             return true;
00307         } else {
00308             return false;
00309         }
00310     }
00311 
00312     function create_nonce_table()
00313     {
00314         if (!$this->tableExists($this->nonces_table_name)) {
00315             $r = $this->connection->query($this->sql['nonce_table']);
00316             return $this->resultToBool($r);
00317         }
00318         return true;
00319     }
00320 
00321     function create_assoc_table()
00322     {
00323         if (!$this->tableExists($this->associations_table_name)) {
00324             $r = $this->connection->query($this->sql['assoc_table']);
00325             return $this->resultToBool($r);
00326         }
00327         return true;
00328     }
00329 
00333     function _set_assoc($server_url, $handle, $secret, $issued,
00334                         $lifetime, $assoc_type)
00335     {
00336         return $this->connection->query($this->sql['set_assoc'],
00337                                         array(
00338                                               $server_url,
00339                                               $handle,
00340                                               $secret,
00341                                               $issued,
00342                                               $lifetime,
00343                                               $assoc_type));
00344     }
00345 
00346     function storeAssociation($server_url, $association)
00347     {
00348         if ($this->resultToBool($this->_set_assoc(
00349                                             $server_url,
00350                                             $association->handle,
00351                                             $this->blobEncode(
00352                                                   $association->secret),
00353                                             $association->issued,
00354                                             $association->lifetime,
00355                                             $association->assoc_type
00356                                             ))) {
00357             $this->connection->commit();
00358         } else {
00359             $this->connection->rollback();
00360         }
00361     }
00362 
00366     function _get_assoc($server_url, $handle)
00367     {
00368         $result = $this->connection->getRow($this->sql['get_assoc'],
00369                                             array($server_url, $handle));
00370         if ($this->isError($result)) {
00371             return null;
00372         } else {
00373             return $result;
00374         }
00375     }
00376 
00380     function _get_assocs($server_url)
00381     {
00382         $result = $this->connection->getAll($this->sql['get_assocs'],
00383                                             array($server_url));
00384 
00385         if ($this->isError($result)) {
00386             return array();
00387         } else {
00388             return $result;
00389         }
00390     }
00391 
00392     function removeAssociation($server_url, $handle)
00393     {
00394         if ($this->_get_assoc($server_url, $handle) == null) {
00395             return false;
00396         }
00397 
00398         if ($this->resultToBool($this->connection->query(
00399                               $this->sql['remove_assoc'],
00400                               array($server_url, $handle)))) {
00401             $this->connection->commit();
00402         } else {
00403             $this->connection->rollback();
00404         }
00405 
00406         return true;
00407     }
00408 
00409     function getAssociation($server_url, $handle = null)
00410     {
00411         if ($handle !== null) {
00412             $assoc = $this->_get_assoc($server_url, $handle);
00413 
00414             $assocs = array();
00415             if ($assoc) {
00416                 $assocs[] = $assoc;
00417             }
00418         } else {
00419             $assocs = $this->_get_assocs($server_url);
00420         }
00421 
00422         if (!$assocs || (count($assocs) == 0)) {
00423             return null;
00424         } else {
00425             $associations = array();
00426 
00427             foreach ($assocs as $assoc_row) {
00428                 $assoc = new Auth_OpenID_Association($assoc_row['handle'],
00429                                                      $assoc_row['secret'],
00430                                                      $assoc_row['issued'],
00431                                                      $assoc_row['lifetime'],
00432                                                      $assoc_row['assoc_type']);
00433 
00434                 $assoc->secret = $this->blobDecode($assoc->secret);
00435 
00436                 if ($assoc->getExpiresIn() == 0) {
00437                     $this->removeAssociation($server_url, $assoc->handle);
00438                 } else {
00439                     $associations[] = array($assoc->issued, $assoc);
00440                 }
00441             }
00442 
00443             if ($associations) {
00444                 $issued = array();
00445                 $assocs = array();
00446                 foreach ($associations as $key => $assoc) {
00447                     $issued[$key] = $assoc[0];
00448                     $assocs[$key] = $assoc[1];
00449                 }
00450 
00451                 array_multisort($issued, SORT_DESC, $assocs, SORT_DESC,
00452                                 $associations);
00453 
00454                 // return the most recently issued one.
00455                 list($issued, $assoc) = $associations[0];
00456                 return $assoc;
00457             } else {
00458                 return null;
00459             }
00460         }
00461     }
00462 
00466     function _add_nonce($server_url, $timestamp, $salt)
00467     {
00468         $sql = $this->sql['add_nonce'];
00469         $result = $this->connection->query($sql, array($server_url,
00470                                                        $timestamp,
00471                                                        $salt));
00472         if ($this->isError($result)) {
00473             $this->connection->rollback();
00474         } else {
00475             $this->connection->commit();
00476         }
00477         return $this->resultToBool($result);
00478     }
00479 
00480     function useNonce($server_url, $timestamp, $salt)
00481     {
00482         global $Auth_OpenID_SKEW;
00483 
00484         if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
00485             return False;
00486         }
00487 
00488         return $this->_add_nonce($server_url, $timestamp, $salt);
00489     }
00490 
00498     function _octify($str)
00499     {
00500         $result = "";
00501         for ($i = 0; $i < Auth_OpenID::bytes($str); $i++) {
00502             $ch = substr($str, $i, 1);
00503             if ($ch == "\\") {
00504                 $result .= "\\\\\\\\";
00505             } else if (ord($ch) == 0) {
00506                 $result .= "\\\\000";
00507             } else {
00508                 $result .= "\\" . strval(decoct(ord($ch)));
00509             }
00510         }
00511         return $result;
00512     }
00513 
00520     function _unoctify($str)
00521     {
00522         $result = "";
00523         $i = 0;
00524         while ($i < strlen($str)) {
00525             $char = $str[$i];
00526             if ($char == "\\") {
00527                 // Look to see if the next char is a backslash and
00528                 // append it.
00529                 if ($str[$i + 1] != "\\") {
00530                     $octal_digits = substr($str, $i + 1, 3);
00531                     $dec = octdec($octal_digits);
00532                     $char = chr($dec);
00533                     $i += 4;
00534                 } else {
00535                     $char = "\\";
00536                     $i += 2;
00537                 }
00538             } else {
00539                 $i += 1;
00540             }
00541 
00542             $result .= $char;
00543         }
00544 
00545         return $result;
00546     }
00547 
00548     function cleanupNonces()
00549     {
00550         global $Auth_OpenID_SKEW;
00551         $v = time() - $Auth_OpenID_SKEW;
00552 
00553         $this->connection->query($this->sql['clean_nonce'], array($v));
00554         $num = $this->connection->affectedRows();
00555         $this->connection->commit();
00556         return $num;
00557     }
00558 
00559     function cleanupAssociations()
00560     {
00561         $this->connection->query($this->sql['clean_assoc'],
00562                                  array(time()));
00563         $num = $this->connection->affectedRows();
00564         $this->connection->commit();
00565         return $num;
00566     }
00567 }
00568 
00569 ?>

Generated on Thu Feb 19 15:02:21 2009 for OXID eShop CE by  doxygen 1.5.5