cs-webapplibs-commits Mailing List for CS Web Application Libraries (Page 5)
Status: Beta
Brought to you by:
crazedsanity
You can subscribe to this list here.
2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(47) |
Sep
(8) |
Oct
(1) |
Nov
(3) |
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2010 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
(3) |
Jun
(14) |
Jul
(5) |
Aug
|
Sep
(5) |
Oct
(2) |
Nov
|
Dec
|
2011 |
Jan
(15) |
Feb
(7) |
Mar
(1) |
Apr
(1) |
May
(1) |
Jun
|
Jul
(1) |
Aug
|
Sep
|
Oct
(2) |
Nov
(3) |
Dec
(1) |
2012 |
Jan
(1) |
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <cra...@us...> - 2009-08-20 16:21:57
|
Revision: 122 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=122&view=rev Author: crazedsanity Date: 2009-08-20 16:21:45 +0000 (Thu, 20 Aug 2009) Log Message: ----------- Moved cs_versionAbstract to cs-content, abstract class into abstract folder. NOTE::: as stated in a recent commit to cs-content, moving cs_versionAbstract into the cs-content project means the two projects are not inextricably attached to one another, and that this project is truly an extension of cs-content. Previously, since everything in cs-content required cs_versionAbstract{}, this project would ALWAYS have to be available (which wasn't a problem when cs_versionAbstract{} was in it's own project, "cs-versionparse"). /cs_authToken.class.php: * fix location of cs_webapplibsAbstract. /cs_version.abstract.class.php [MOVED]: * moved to cs-content/abstract/ /cs_webdblogger.class.php: * fix location of cs_webapplibsAbstract. /cs_webdbupgrade.class.php: * fix location of cs_webapplibsAbstract. /tests/testOfCSWebAppLibs.php: * test_version_basics() [DELETED] * test_check_higher() [DELETED] * middleTestClass{} [DELETED] /tests/files/version* [DELETED]: * moved to cs-content for testing cs_versionAbstract Modified Paths: -------------- trunk/0.3/cs_authToken.class.php trunk/0.3/cs_webdblogger.class.php trunk/0.3/cs_webdbupgrade.class.php trunk/0.3/tests/testOfCSWebAppLibs.php Added Paths: ----------- trunk/0.3/abstract/ trunk/0.3/abstract/cs_webapplibs.abstract.class.php Removed Paths: ------------- trunk/0.3/cs_version.abstract.class.php trunk/0.3/cs_webapplibs.abstract.class.php trunk/0.3/tests/files/version1 trunk/0.3/tests/files/version2 trunk/0.3/tests/files/version3 Copied: trunk/0.3/abstract/cs_webapplibs.abstract.class.php (from rev 119, trunk/0.3/cs_webapplibs.abstract.class.php) =================================================================== --- trunk/0.3/abstract/cs_webapplibs.abstract.class.php (rev 0) +++ trunk/0.3/abstract/cs_webapplibs.abstract.class.php 2009-08-20 16:21:45 UTC (rev 122) @@ -0,0 +1,20 @@ +<?php +/* + * Created on Aug 19, 2009 + * + * SVN INFORMATION::: + * ------------------- + * Last Author::::::::: $Author$ + * Current Revision:::: $Revision$ + * Repository Location: $HeadURL$ + * Last Updated:::::::: $Date$ + */ + +require_once(constant('LIBDIR') .'/cs-content/abstract/cs_version.abstract.class.php'); + + +abstract class cs_webapplibsAbstract extends cs_versionAbstract { + +} + +?> Modified: trunk/0.3/cs_authToken.class.php =================================================================== --- trunk/0.3/cs_authToken.class.php 2009-08-20 15:52:11 UTC (rev 121) +++ trunk/0.3/cs_authToken.class.php 2009-08-20 16:21:45 UTC (rev 122) @@ -11,7 +11,7 @@ */ -require_once(dirname(__FILE__) .'/cs_webapplibs.abstract.class.php'); +require_once(dirname(__FILE__) .'/abstract/cs_webapplibs.abstract.class.php'); class cs_authToken extends cs_webapplibsAbstract { Deleted: trunk/0.3/cs_version.abstract.class.php =================================================================== --- trunk/0.3/cs_version.abstract.class.php 2009-08-20 15:52:11 UTC (rev 121) +++ trunk/0.3/cs_version.abstract.class.php 2009-08-20 16:21:45 UTC (rev 122) @@ -1,398 +0,0 @@ -<?php -/* - * Created on January 01, 2009 by Dan Falconer - * - * SVN INFORMATION::: - * ------------------- - * Last Author::::::::: $Author$ - * Current Revision:::: $Revision$ - * Repository Location: $HeadURL$ - * Last Updated:::::::: $Date$ - */ - -abstract class cs_versionAbstract { - - public $isTest = FALSE; - - - - private $versionFileLocation=null; - private $fullVersionString; - private $suffixList = array( - 'ALPHA', //very unstable - 'BETA', //kinda unstable, but probably useable - 'RC' //all known bugs fixed, searching for unknown ones - ); - - - - abstract public function __construct(); - - - - //========================================================================= - /** - * Retrieve our version string from the VERSION file. - */ - final public function get_version($asArray=false) { - $retval = NULL; - - $this->auto_set_version_file(); - - if(file_exists($this->versionFileLocation)) { - $myMatches = array(); - $findIt = preg_match('/VERSION: (.+)/', file_get_contents($this->versionFileLocation), $matches); - - if($findIt == 1 && count($matches) == 2) { - $fullVersionString = $matches[1]; - $versionInfo = $this->parse_version_string($fullVersionString); - $this->fullVersionString = $this->build_full_version_string($versionInfo); - - - if($asArray) { - $retval = $versionInfo; - $retval['version_string'] = $this->fullVersionString; - } - else { - $retval = $this->build_full_version_string($versionInfo); - } - } - else { - throw new exception(__METHOD__ .": failed to retrieve version string in file " . - "(". $this->versionFileLocation .")"); - } - } - else { - throw new exception(__METHOD__ .": failed to retrieve version information, file " . - "(". $this->versionFileLocation .") does not exist or was not set"); - } - - return($retval); - }//end get_version() - //========================================================================= - - - - //========================================================================= - public function __get($var) { - return($this->$var); - }//end __get() - //========================================================================= - - - - //========================================================================= - final public function get_project() { - $retval = NULL; - $this->auto_set_version_file(); - if(file_exists($this->versionFileLocation)) { - $myMatches = array(); - $findIt = preg_match('/PROJECT: (.+)/', file_get_contents($this->versionFileLocation), $matches); - - if($findIt == 1 && count($matches) == 2 && strlen($matches[1])) { - $retval = $matches[1]; - } - else { - throw new exception(__METHOD__ .": failed to retrieve project string"); - } - } - else { - throw new exception(__METHOD__ .": failed to retrieve project information"); - } - - return($retval); - }//end get_project() - //========================================================================= - - - - //========================================================================= - public function set_version_file_location($location) { - if(file_exists($location)) { - $this->versionFileLocation = $location; - } - else { - throw new exception(__METHOD__ .": invalid location of VERSION file (". $location .")"); - } - }//end set_version_file_location() - //========================================================================= - - - - //========================================================================= - protected function auto_set_version_file() { - if(!strlen($this->versionFileLocation)) { - $bt = debug_backtrace(); - foreach($bt as $callNum=>$data) { - if(strlen($data['class'])) { - if($data['class'] != __CLASS__) { - $dir = dirname($data['file']); - if(preg_match('/tests$/', $dir)) { - $dir = preg_replace('/\/tests$/', '', $dir); - } - elseif(preg_match('/test$/', $dir)) { - $dir = preg_replace('/\/test$/', '', $dir); - } - break; - } - } - else { - throw new exception(__METHOD__ .": failed to locate the calling class in backtrace"); - } - } - - if(file_exists($dir .'/VERSION')) { - $this->set_version_file_location($dir .'/VERSION'); - } - else { - throw new exception(__METHOD__ .": failed to automatically set version file (tried ". $dir ."/VERSION)"); - } - } - }//end auto_set_version_file() - //========================================================================= - - - - //========================================================================= - /** - * - * TODO: add logic to split apart the suffix (i.e. "-ALPHA5" broken into "ALPHA" and "5"). - */ - public function parse_version_string($version) { - if(is_string($version) && strlen($version) && preg_match('/\./', $version)) { - $version = preg_replace('/ /', '', $version); - - $pieces = explode('.', $version); - $retval = array( - 'version_major' => $pieces[0], - 'version_minor' => $pieces[1] - ); - if(isset($pieces[2]) && strlen($pieces[2])) { - $retval['version_maintenance'] = $pieces[2]; - } - else { - $retval['version_maintenance'] = 0; - } - - if(preg_match('/-/', $retval['version_maintenance'])) { - $bits = explode('-', $retval['version_maintenance']); - $retval['version_maintenance'] = $bits[0]; - $suffix = $bits[1]; - } - elseif(preg_match('/-/', $retval['version_minor'])) { - $bits = explode('-', $retval['version_minor']); - $retval['version_minor'] = $bits[0]; - $suffix = $bits[1]; - } - else { - $suffix = ""; - } - $retval['version_suffix'] = $suffix; - } - else { - throw new exception(__METHOD__ .": invalid version string passed (". $version .")"); - } - - return($retval); - }//end parse_version_string() - //========================================================================= - - - - //========================================================================= - public function build_full_version_string(array $versionInfo) { - $requiredIndexes = array( - 'version_major', 'version_minor', 'version_maintenance', 'version_suffix' - ); - - $missing=""; - $count=0; - foreach($requiredIndexes as $indexName) { - if(isset($versionInfo[$indexName])) { - $count++; - } - else { - if(strlen($missing)) { - $missing .= ", ". $indexName; - } - else { - $missing = $indexName; - } - } - } - - if($count == count($requiredIndexes) && !strlen($missing)) { - $suffix = $versionInfo['version_suffix']; - unset($versionInfo['version_suffix']); - - $retval = ""; - foreach($versionInfo as $name=>$value) { - if(strlen($retval)) { - $retval .= ".". $value; - } - else { - $retval = $value; - } - } - if(strlen($suffix)) { - $retval .= "-". $suffix; - } - } - else { - throw new exception(__METHOD__ .": missing indexes in given array (". $missing .")"); - } - - return($retval); - - }//end build_full_version_string() - //========================================================================= - - - - //========================================================================= - public function is_higher_version($version, $checkIfHigher) { - $retval = FALSE; - $this->gfObj = new cs_globalFunctions; - if(!is_string($version) || !is_string($checkIfHigher)) { - throw new exception(__METHOD__ .": no valid version strings, version=(". $version ."), checkIfHigher=(". $checkIfHigher .")"); - } - elseif($version == $checkIfHigher) { - $retval = FALSE; - } - else { - $curVersionArr = $this->parse_version_string($version); - $checkVersionArr = $this->parse_version_string($checkIfHigher); - - unset($curVersionArr['version_string'], $checkVersionArr['version_string']); - - - $curVersionSuffix = $curVersionArr['version_suffix']; - $checkVersionSuffix = $checkVersionArr['version_suffix']; - - - unset($curVersionArr['version_suffix']); - - foreach($curVersionArr as $index=>$versionNumber) { - $checkThis = $checkVersionArr[$index]; - - if(is_numeric($checkThis) && is_numeric($versionNumber)) { - //set them as integers. - settype($versionNumber, 'int'); - settype($checkThis, 'int'); - - if($checkThis > $versionNumber) { - $retval = TRUE; - break; - } - elseif($checkThis == $versionNumber) { - //they're equal... - } - else { - //TODO: should there maybe be an option to throw an exception (freak out) here? - } - } - else { - throw new exception(__METHOD__ .": ". $index ." is not numeric in one of the strings " . - "(versionNumber=". $versionNumber .", checkThis=". $checkThis .")"); - } - } - - //now deal with those damnable suffixes, but only if the versions are so far identical: if - // the "$checkIfHigher" is actually higher, don't bother (i.e. suffixes don't matter when - // we already know there's a major, minor, or maintenance version that's also higher. - if($retval === FALSE) { - //EXAMPLE: $version="1.0.0-BETA3", $checkIfHigher="1.1.0" - // Moving from a non-suffixed version to a suffixed version isn't supported, but the inverse is: - // i.e. (1.0.0-BETA3 to 1.0.0) is okay, but (1.0.0 to 1.0.0-BETA3) is NOT. - // Also: (1.0.0-BETA3 to 1.0.0-BETA4) is okay, but (1.0.0-BETA4 to 1.0.0-BETA3) is NOT. - if(strlen($curVersionSuffix) && strlen($checkVersionSuffix) && $curVersionSuffix == $checkVersionSuffix) { - //matching suffixes. - } - elseif(strlen($curVersionSuffix) || strlen($checkVersionSuffix)) { - //we know the suffixes are there and DO match. - if(strlen($curVersionSuffix) && strlen($checkVersionSuffix)) { - //okay, here's where we do some crazy things... - $curVersionData = $this->parse_suffix($curVersionSuffix); - $checkVersionData = $this->parse_suffix($checkVersionSuffix); - - if($curVersionData['type'] == $checkVersionData['type']) { - //got the same suffix type (like "BETA"), check the number. - if($checkVersionData['number'] > $curVersionData['number']) { - //new version's suffix number higher than current... - $retval = TRUE; - } - elseif($checkVersionData['number'] == $curVersionData['number']) { - //new version's suffix number is EQUAL TO current... - $retval = FALSE; - } - else { - //new version's suffix number is LESS THAN current... - $retval = FALSE; - } - } - else { - //not the same suffix... see if the new one is higher. - $suffixValues = array_flip($this->suffixList); - if($suffixValues[$checkVersionData['type']] > $suffixValues[$curVersionData['type']]) { - $retval = TRUE; - } - else { - //current suffix type is higher... - } - } - - } - elseif(strlen($curVersionSuffix) && !strlen($checkVersionSuffix)) { - //i.e. "1.0.0-BETA1" to "1.0.0" --->>> OKAY! - $retval = TRUE; - } - elseif(!strlen($curVersionSuffix) && strlen($checkVersionSuffix)) { - //i.e. "1.0.0" to "1.0.0-BETA1" --->>> NOT ACCEPTABLE! - } - } - else { - //no suffix to care about - } - } - } - - return($retval); - - }//end is_higher_version() - //========================================================================= - - - - //========================================================================= - protected function parse_suffix($suffix) { - $retval = NULL; - if(strlen($suffix)) { - //determine what kind it is. - foreach($this->suffixList as $type) { - if(preg_match('/^'. $type .'/', $suffix)) { - $checkThis = preg_replace('/^'. $type .'/', '', $suffix); - if(strlen($checkThis) && is_numeric($checkThis)) { - //oooh... it's something like "BETA3" - $retval = array( - 'type' => $type, - 'number' => $checkThis - ); - } - else { - throw new exception(__METHOD__ .": invalid suffix (". $suffix .")"); - } - break; - } - } - } - else { - throw new exception(__METHOD__ .": invalid suffix (". $suffix .")"); - } - - return($retval); - }//end parse_suffix() - //========================================================================= - - -} -?> \ No newline at end of file Deleted: trunk/0.3/cs_webapplibs.abstract.class.php =================================================================== --- trunk/0.3/cs_webapplibs.abstract.class.php 2009-08-20 15:52:11 UTC (rev 121) +++ trunk/0.3/cs_webapplibs.abstract.class.php 2009-08-20 16:21:45 UTC (rev 122) @@ -1,20 +0,0 @@ -<?php -/* - * Created on Aug 19, 2009 - * - * SVN INFORMATION::: - * ------------------- - * Last Author::::::::: $Author$ - * Current Revision:::: $Revision$ - * Repository Location: $HeadURL$ - * Last Updated:::::::: $Date$ - */ - -require_once(dirname(__FILE__) .'/cs_version.abstract.class.php'); - - -abstract class cs_webapplibsAbstract extends cs_versionAbstract { - -} - -?> Modified: trunk/0.3/cs_webdblogger.class.php =================================================================== --- trunk/0.3/cs_webdblogger.class.php 2009-08-20 15:52:11 UTC (rev 121) +++ trunk/0.3/cs_webdblogger.class.php 2009-08-20 16:21:45 UTC (rev 122) @@ -27,7 +27,7 @@ //NOTE::: this class **REQUIRES** cs-content for its "cs_phpDB" class. -require_once(dirname(__FILE__) .'/cs_webapplibs.abstract.class.php'); +require_once(dirname(__FILE__) .'/abstract/cs_webapplibs.abstract.class.php'); require_once(dirname(__FILE__) .'/cs_webdbupgrade.class.php'); class cs_webdblogger extends cs_webapplibsAbstract { Modified: trunk/0.3/cs_webdbupgrade.class.php =================================================================== --- trunk/0.3/cs_webdbupgrade.class.php 2009-08-20 15:52:11 UTC (rev 121) +++ trunk/0.3/cs_webdbupgrade.class.php 2009-08-20 16:21:45 UTC (rev 122) @@ -12,7 +12,7 @@ * */ -require_once(dirname(__FILE__) .'/cs_webapplibs.abstract.class.php'); +require_once(dirname(__FILE__) .'/abstract/cs_webapplibs.abstract.class.php'); require_once(dirname(__FILE__) .'/cs_webdblogger.class.php'); class cs_webdbupgrade extends cs_webapplibsAbstract { Deleted: trunk/0.3/tests/files/version1 =================================================================== --- trunk/0.3/tests/files/version1 2009-08-20 15:52:11 UTC (rev 121) +++ trunk/0.3/tests/files/version1 2009-08-20 16:21:45 UTC (rev 122) @@ -1,3 +0,0 @@ - -PROJECT: test1 -VERSION: 0.1.2-ALPHA8754 \ No newline at end of file Deleted: trunk/0.3/tests/files/version2 =================================================================== --- trunk/0.3/tests/files/version2 2009-08-20 15:52:11 UTC (rev 121) +++ trunk/0.3/tests/files/version2 2009-08-20 16:21:45 UTC (rev 122) @@ -1,3 +0,0 @@ - -PROJECT: test2 -VERSION: 5.4 \ No newline at end of file Deleted: trunk/0.3/tests/files/version3 =================================================================== --- trunk/0.3/tests/files/version3 2009-08-20 15:52:11 UTC (rev 121) +++ trunk/0.3/tests/files/version3 2009-08-20 16:21:45 UTC (rev 122) @@ -1,3 +0,0 @@ - -PROJECT: test3 stuff -VERSION: 5.4.3-BETA5543 \ No newline at end of file Modified: trunk/0.3/tests/testOfCSWebAppLibs.php =================================================================== --- trunk/0.3/tests/testOfCSWebAppLibs.php 2009-08-20 15:52:11 UTC (rev 121) +++ trunk/0.3/tests/testOfCSWebAppLibs.php 2009-08-20 16:21:45 UTC (rev 122) @@ -11,7 +11,6 @@ * $LastChangedRevision$ */ -require_once(dirname(__FILE__) .'/../cs_version.abstract.class.php'); require_once(dirname(__FILE__) .'/../cs_authToken.class.php'); class testOfCSWebAppLibs extends UnitTestCase { @@ -24,108 +23,8 @@ //-------------------------------------------------------------------------- - //-------------------------------------------------------------------------- - function test_version_basics() { - - $tests = array( - 'files/version1' => array( - '0.1.2-ALPHA8754', - 'test1', - array( - 'version_major' => 0, - 'version_minor' => 1, - 'version_maintenance' => 2, - 'version_suffix' => 'ALPHA8754' - ) - ), - 'files/version2' => array( - '5.4.0', - 'test2', - array( - 'version_major' => 5, - 'version_minor' => 4, - 'version_maintenance' => 0, - 'version_suffix' => null - ) - ), - 'files/version3' => array( - '5.4.3-BETA5543', - 'test3 stuff', - array( - 'version_major' => 5, - 'version_minor' => 4, - 'version_maintenance' => 3, - 'version_suffix' => 'BETA5543' - ) - ) - ); - - foreach($tests as $fileName=>$expectedArr) { - $ver = new middleTestClass(); - $ver->set_version_file_location(dirname(__FILE__) .'/'. $fileName); - - $this->assertEqual($expectedArr[0], $ver->get_version(), "Failed to match string from file (". $fileName .")"); - $this->assertEqual($expectedArr[1], $ver->get_project(), "Failed to match project from file (". $fileName .")"); - - //now check that pulling the version as an array is the same... - $checkItArr = $ver->get_version(true); - $expectThis = $expectedArr[2]; - $expectThis['version_string'] = $expectedArr[0]; - } - }//end test_version_basics() - //-------------------------------------------------------------------------- - - //-------------------------------------------------------------------------- - function test_check_higher() { - - //NOTE: the first item should ALWAYS be higher. - $tests = array( - 'basic, no suffix' => array('1.0.1', '1.0.0'), - 'basic + suffix' => array('1.0.0-ALPHA1', '1.0.0-ALPHA0'), - 'basic w/o maint' => array('1.0.1', '1.0'), - 'suffix check' => array('1.0.0-BETA1', '1.0.0-ALPHA1'), - 'suffix check2' => array('1.0.0-ALPHA10', '1.0.0-ALPHA1'), - 'suffix check3' => array('1.0.1', '1.0.0-RC1') - ); - - foreach($tests as $name=>$checkData) { - $ver = new middleTestClass; - $this->assertTrue($ver->is_higher_version($checkData[1], $checkData[0])); - $this->assertFalse($ver->is_higher_version($checkData[0], $checkData[1])); - } - - //now check to ensure there's no problem with parsing equivalent versions. - $tests = array( - 'no suffix' => array('1.0', '1.0.0'), - 'no maint + suffix' => array('1.0-ALPHA1', '1.0.0-ALPHA1'), - 'no maint + BETA' => array('1.0-BETA5555', '1.0.0-BETA5555'), - 'no maint + RC' => array('1.0-RC33', '1.0.0-RC33'), - 'maint with space' => array('1.0-RC 33', '1.0.0-RC33'), - 'extra spaces' => array(' 1.0 ', '1.0.0') - ); - foreach($tests as $name=>$checkData) { - $ver = new middleTestClass; - - //rip apart & recreate first version to test against the expected... - $derivedFullVersion = $ver->build_full_version_string($ver->parse_version_string($checkData[0])); - $this->assertEqual($derivedFullVersion, $checkData[1], "TEST=(". $name ."): derived version " . - "(". $derivedFullVersion .") doesn't match expected (". $checkData[1] .")"); - - //now rip apart & recreate the expected version (second) and make sure it matches itself. - $derivedFullVersion = $ver->build_full_version_string($ver->parse_version_string($checkData[1])); - $this->assertEqual($derivedFullVersion, $checkData[1], "TEST=(". $name ."): derived version " . - "(". $derivedFullVersion .") doesn't match expected (". $checkData[1] .")"); - } - - - }//end test_check_higher() - //-------------------------------------------------------------------------- - - - - //-------------------------------------------------------------------------- private function create_dbconn() { $dbParams = array( 'host' => constant('DB_PG_HOST'), @@ -249,10 +148,6 @@ } -class middleTestClass extends cs_versionAbstract { - function __construct(){} -} - class authTokenTester extends cs_authToken { public $isTest=true; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-20 15:52:17
|
Revision: 121 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=121&view=rev Author: crazedsanity Date: 2009-08-20 15:52:11 +0000 (Thu, 20 Aug 2009) Log Message: ----------- More tests, add "last_updated" to tokens. /cs_authToken.class.php: * create_token(): -- call _generic_update() to do the update statement. * update_token_uses(): -- call _generic_update() to do the update statement. * get_token_data(): -- ARG CHANGE: NEW ARG: #2 ($onlyNonExpired=true) -- add ability to get ANY token's data (for unit testing & eventually for logging purposes). * remove_expired_tokens() [NEW]: -- destroys tokens that are expired (doesn't do any checking as far as whether or not there are uses left). * _generic_update() [NEW]: -- besides the update string given, it also updates the (new) "last_updated" column. -- NOTE::: this was done so that the cs_sessionDB{} class from cs-content could potentially just call methods in this class to create & expire records... its just an idea for now. /setup/schema.mysql.sql: * cswal_auth_token_table: -- added "last_updated" (timestamp) column. -- NOTE::: didn't set the default as NOW() because MySQL won't allow more than one timestamp field to have that as the default...? /setup/schema.pgsql.sql: * mirrored changes to mysql schema. /tests/testOfCSWebAppLibs.php: * test_token_basics(): -- removed duplicate code into a private method, "basic_token_tests()" -- added test for creating an already-expired token. -- TODO: retrieve the token's data before authenticating, then test to see if it was removed afterward. * basic_token_tests() [NEW]: -- set of tests that are performed for pretty much every token created, so code was moved here so it is more standardized. Modified Paths: -------------- trunk/0.3/cs_authToken.class.php trunk/0.3/setup/schema.mysql.sql trunk/0.3/setup/schema.pgsql.sql trunk/0.3/tests/testOfCSWebAppLibs.php Modified: trunk/0.3/cs_authToken.class.php =================================================================== --- trunk/0.3/cs_authToken.class.php 2009-08-20 14:55:21 UTC (rev 120) +++ trunk/0.3/cs_authToken.class.php 2009-08-20 15:52:11 UTC (rev 121) @@ -105,9 +105,7 @@ //now that we have the ID, let's create the real has string. $finalHash = $this->create_hash_string($tokenId, $uid, $checksum, $stringToHash); - $this->db->run_update("UPDATE ". $this->table ." SET token='". $finalHash ."' WHERE " . - "auth_token_id=". $tokenId); - + $this->_generic_update($tokenId, "token='". $finalHash ."'"); $tokenInfo = array( 'id' => $tokenId, 'hash' => $finalHash @@ -134,11 +132,8 @@ * @return (exception) FAIL: exception denotes problem */ protected function update_token_uses($tokenId) { - try { - $sql = "UPDATE ". $this->table ." SET total_uses= total_uses+1 " . - "WHERE auth_token_id=". $tokenId; - $updateRes = $this->db->run_update($sql); + $updateRes = $this->_generic_update($tokenId, "total_uses= total_uses+1"); } catch(exception $e) { throw new exception(__METHOD__ .": failed to update usage count::: ". $e->getMessage()); @@ -260,10 +255,15 @@ * @return (array) PASS: contains data about the given ID * @return (exception) FAIL: exception contains error details. */ - protected function get_token_data($tokenId) { + protected function get_token_data($tokenId, $onlyNonExpired=true) { try { - $data = $this->db->run_query("SELECT * FROM ". $this->table ." WHERE auth_token_id=". $tokenId - ." AND expiration::date >= CURRENT_DATE", 'auth_token_id'); + $sql = "SELECT * FROM ". $this->table ." WHERE auth_token_id=". $tokenId; + if($onlyNonExpired === true) { + $sql .= " AND expiration::date >= CURRENT_DATE"; + } + + $data = $this->db->run_query($sql, 'auth_token_id'); + if(is_array($data) && count($data) == 1) { $tokenData = $data; } @@ -281,5 +281,49 @@ }//end get_token_data(); //========================================================================= + + + //========================================================================= + /** + * Deletes any tokens that are past expiration (does not test for total vs. + * max uses; authenticate_token() does that). + * + * @param (null) (void) + */ + public function remove_expired_tokens() { + $sql = "SELECT * FROM ". $this->table ." WHERE NOW() > expiration"; + + try { + $data = $this->db->run_query($sql, 'auth_token_id'); + + if(is_array($data)) { + foreach($data as $tokenId => $tokenData) { + //TODO: add logging here? + $this->destroy_token($tokenId); + } + } + } + catch(exception $e) { + throw new exception(__METHOD__ .": error encountered while expiring tokens::: ". $e->getMessage()); + } + }//end remove_expired_tokens() + //========================================================================= + + + + //========================================================================= + private function _generic_update($tokenId, $updateString) { + try { + $sql = "UPDATE ". $this->table ." SET ". $updateString .", last_updated=NOW() " . + "WHERE auth_token_id=". $tokenId; + $updateRes = $this->db->run_update($sql); + } + catch(exception $e) { + throw new exception("failed to update token::: ". $e->getMessage()); + } + return($updateRes); + }//end generic_update() + //========================================================================= + } ?> Modified: trunk/0.3/setup/schema.mysql.sql =================================================================== --- trunk/0.3/setup/schema.mysql.sql 2009-08-20 14:55:21 UTC (rev 120) +++ trunk/0.3/setup/schema.mysql.sql 2009-08-20 15:52:11 UTC (rev 121) @@ -156,5 +156,6 @@ max_uses integer DEFAULT NULL, total_uses integer NOT NULL DEFAULT 0, creation timestamp NOT NULL DEFAULT NOW(), + last_updated timestamp, expiration timestamp NOT NULL ); \ No newline at end of file Modified: trunk/0.3/setup/schema.pgsql.sql =================================================================== --- trunk/0.3/setup/schema.pgsql.sql 2009-08-20 14:55:21 UTC (rev 120) +++ trunk/0.3/setup/schema.pgsql.sql 2009-08-20 15:52:11 UTC (rev 121) @@ -100,6 +100,7 @@ max_uses integer DEFAULT NULL, total_uses integer NOT NULL DEFAULT 0, creation timestamp NOT NULL DEFAULT NOW(), + last_updated timestamp, expiration timestamp NOT NULL ); Modified: trunk/0.3/tests/testOfCSWebAppLibs.php =================================================================== --- trunk/0.3/tests/testOfCSWebAppLibs.php 2009-08-20 14:55:21 UTC (rev 120) +++ trunk/0.3/tests/testOfCSWebAppLibs.php 2009-08-20 15:52:11 UTC (rev 121) @@ -164,6 +164,7 @@ //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- function test_token_basics() { $db = $this->create_dbconn(); @@ -185,12 +186,7 @@ { //Generic test to ensure we get the appropriate data back. $tokenData = $tok->create_token(1, 'test', 'abc123', null, 1); - $this->assertTrue(is_array($tokenData)); - $this->assertTrue((count($tokenData) == 2)); - $this->assertTrue(isset($tokenData['id'])); - $this->assertTrue(isset($tokenData['hash'])); - $this->assertTrue(($tokenData['id'] > 0)); - $this->assertTrue((strlen($tokenData['hash']) == 32)); + $this->basic_token_tests($tokenData, 1, 'test'); if(!$this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1)) { $this->gfObj->debug_print($tok->tokenData($tokenData['id']),1); @@ -205,12 +201,7 @@ { //Generic test to ensure we get the appropriate data back. $tokenData = $tok->create_token(1, 'test', 'abc123', '2 years'); - $this->assertTrue(is_array($tokenData)); - $this->assertTrue((count($tokenData) == 2)); - $this->assertTrue(isset($tokenData['id'])); - $this->assertTrue(isset($tokenData['hash'])); - $this->assertTrue(($tokenData['id'] > 0)); - $this->assertTrue((strlen($tokenData['hash']) == 32)); + $this->basic_token_tests($tokenData, 1, 'test'); $this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1); } @@ -218,17 +209,43 @@ //try to create a token with max_uses of 0. { $tokenData = $tok->create_token(2, 'test', 'xxxxyyyyyxxxx', null, 0); + $this->basic_token_tests($tokenData, 2, 'test'); $checkData = $tok->tokenData($tokenData['id']); $checkData = $checkData[$tokenData['id']]; $this->assertTrue(is_array($checkData)); - if(!$this->assertEqual($tokenData['id'], $checkData['auth_token_id'])) { - $this->gfObj->debug_print($checkData); - } + $this->assertEqual($tokenData['id'], $checkData['auth_token_id']); $this->assertEqual($checkData['max_uses'], null); } + + //try creating a token that is purposely expired, make sure it exists, then make sure authentication fails. + { + $tokenData = $tok->create_token(88, 'test', 'This is a big old TEST', '-3 days'); + if($this->assertTrue(is_array($tokenData))) { + $this->basic_token_tests($tokenData, 88, 'This is a big old TEST'); + $this->assertFalse($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash'])); + } + } }//end test_token_basics() //-------------------------------------------------------------------------- + + + + //-------------------------------------------------------------------------- + private function basic_token_tests(array $tokenData, $uid, $checksum) { + + if($this->assertTrue(is_array($tokenData)) && $this->assertTrue(is_numeric($uid)) && $this->assertTrue(strlen($checksum))) { + + $this->assertTrue(is_array($tokenData)); + $this->assertTrue((count($tokenData) == 2)); + $this->assertTrue(isset($tokenData['id'])); + $this->assertTrue(isset($tokenData['hash'])); + $this->assertTrue(($tokenData['id'] > 0)); + $this->assertTrue((strlen($tokenData['hash']) == 32)); + } + + }//end basic_token_tests() + //-------------------------------------------------------------------------- } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-20 14:55:30
|
Revision: 120 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=120&view=rev Author: crazedsanity Date: 2009-08-20 14:55:21 +0000 (Thu, 20 Aug 2009) Log Message: ----------- Drop tables (instead of DB), extra tests. /cs_authToken.class.php: * __construct(): -- create an instance of cs_webdbupgrade{} to see if an upgrade needs to be performed. -- NOTE::: this can be removed simply by adding logging, as cs_webdblogger::__construct() checks for upgrades. /tests/testOfCSWebAppLibs.php: * create_dbconn() RENAMED FROM create_db() * remove_tables() [NEW]: -- does a DROP ... CASCADE on all tables belonging to cs-webapplibs * test_token_basics(): -- updated references to use create_dbconn() -- move tests around slighly so I can view the database after & know for sure that the record that had only 1 use is actually missing (because there is a gap in auth_token_id's). -- test for creating a token with 0 max uses (to see that the invalid value for max_uses is ignored). Modified Paths: -------------- trunk/0.3/cs_authToken.class.php trunk/0.3/tests/testOfCSWebAppLibs.php Modified: trunk/0.3/cs_authToken.class.php =================================================================== --- trunk/0.3/cs_authToken.class.php 2009-08-20 13:57:54 UTC (rev 119) +++ trunk/0.3/cs_authToken.class.php 2009-08-20 14:55:21 UTC (rev 120) @@ -41,6 +41,8 @@ } $this->gfObj = new cs_globalFunctions(); + $upg = new cs_webdbupgrade(dirname(__FILE__) .'/VERSION', dirname(__FILE__) .'/upgrades/upgrade.xml'); + $upg->check_versions(true); }//end __construct() //========================================================================= Modified: trunk/0.3/tests/testOfCSWebAppLibs.php =================================================================== --- trunk/0.3/tests/testOfCSWebAppLibs.php 2009-08-20 13:57:54 UTC (rev 119) +++ trunk/0.3/tests/testOfCSWebAppLibs.php 2009-08-20 14:55:21 UTC (rev 120) @@ -126,7 +126,7 @@ //-------------------------------------------------------------------------- - private function create_db() { + private function create_dbconn() { $dbParams = array( 'host' => constant('DB_PG_HOST'), 'dbname' => constant('DB_PG_DBNAME'), @@ -141,9 +141,33 @@ //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + private function remove_tables() { + $tableList = array( + 'cswal_auth_token_table', 'cswal_version_table', 'cswdbl_attribute_table', + 'cswdbl_category_table', 'cswdbl_class_table', 'cswdbl_event_table', + 'cswdbl_log_attribute_table', 'cswdbl_log_table', + ); + + $db = $this->create_dbconn(); + foreach($tableList as $name) { + try { + $db->run_update("DROP TABLE ". $name ." CASCADE", true); + } + catch(exception $e) { + //force an error. + $this->assertTrue(false, "Error while dropping (". $name .")::: ". $e->getMessage()); + } + } + }//end remove_tables() + //-------------------------------------------------------------------------- + + + //-------------------------------------------------------------------------- function test_token_basics() { - $db = $this->create_db(); + $db = $this->create_dbconn(); + $this->remove_tables(); $tok = new authTokenTester($db); //Generic test to ensure we get the appropriate data back. @@ -157,11 +181,10 @@ $this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1); - - //now create a token with a maximum lifetime... + //create a token with only 1 available use and try to authenticate it twice. { //Generic test to ensure we get the appropriate data back. - $tokenData = $tok->create_token(1, 'test', 'abc123', '2 years'); + $tokenData = $tok->create_token(1, 'test', 'abc123', null, 1); $this->assertTrue(is_array($tokenData)); $this->assertTrue((count($tokenData) == 2)); $this->assertTrue(isset($tokenData['id'])); @@ -169,13 +192,19 @@ $this->assertTrue(($tokenData['id'] > 0)); $this->assertTrue((strlen($tokenData['hash']) == 32)); - $this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1); + if(!$this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1)) { + $this->gfObj->debug_print($tok->tokenData($tokenData['id']),1); + } + if(!$this->assertTrue(($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']) === null), "Able to authenticate twice on a token with only 1 use")) { + $this->gfObj->debug_print($tok->tokenData($tokenData['id'])); + } } - //create a token with only 1 available use and try to authenticate it twice. + + //now create a token with a maximum lifetime... { //Generic test to ensure we get the appropriate data back. - $tokenData = $tok->create_token(1, 'test', 'abc123', null, 1); + $tokenData = $tok->create_token(1, 'test', 'abc123', '2 years'); $this->assertTrue(is_array($tokenData)); $this->assertTrue((count($tokenData) == 2)); $this->assertTrue(isset($tokenData['id'])); @@ -183,12 +212,20 @@ $this->assertTrue(($tokenData['id'] > 0)); $this->assertTrue((strlen($tokenData['hash']) == 32)); - if(!$this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1)) { - $this->gfObj->debug_print($tok->tokenData($tokenData['id']),1); + $this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1); + } + + //try to create a token with max_uses of 0. + { + $tokenData = $tok->create_token(2, 'test', 'xxxxyyyyyxxxx', null, 0); + $checkData = $tok->tokenData($tokenData['id']); + $checkData = $checkData[$tokenData['id']]; + + $this->assertTrue(is_array($checkData)); + if(!$this->assertEqual($tokenData['id'], $checkData['auth_token_id'])) { + $this->gfObj->debug_print($checkData); } - if(!$this->assertTrue(($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']) === null), "Able to authenticate twice on a token with only 1 use")) { - $this->gfObj->debug_print($tok->tokenData($tokenData['id'])); - } + $this->assertEqual($checkData['max_uses'], null); } }//end test_token_basics() //-------------------------------------------------------------------------- This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-20 13:58:05
|
Revision: 119 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=119&view=rev Author: crazedsanity Date: 2009-08-20 13:57:54 +0000 (Thu, 20 Aug 2009) Log Message: ----------- Combine tests into a single batch of tests: this allows for doing database changes without affecting other tests (and potentially rebuilding the db after every test). Added Paths: ----------- trunk/0.3/tests/testOfCSWebAppLibs.php Removed Paths: ------------- trunk/0.3/tests/testOfAuthToken.php trunk/0.3/tests/testOfCSVersionParse.php Deleted: trunk/0.3/tests/testOfAuthToken.php =================================================================== --- trunk/0.3/tests/testOfAuthToken.php 2009-08-20 02:20:49 UTC (rev 118) +++ trunk/0.3/tests/testOfAuthToken.php 2009-08-20 13:57:54 UTC (rev 119) @@ -1,104 +0,0 @@ -<?php -/* - * Created on Jan 25, 2009 - * - * FILE INFORMATION: - * - * $HeadURL$ - * $Id$ - * $LastChangedDate$ - * $LastChangedBy$ - * $LastChangedRevision$ - */ - -require_once(dirname(__FILE__) .'/../cs_authToken.class.php'); - -class testOfCSAuthToken extends UnitTestCase { - - //-------------------------------------------------------------------------- - function __construct() { - $this->gfObj = new cs_globalFunctions; - $this->gfObj->debugPrintOpt=1; - }//end __construct() - //-------------------------------------------------------------------------- - - - - //-------------------------------------------------------------------------- - private function create_db() { - $dbParams = array( - 'host' => constant('DB_PG_HOST'), - 'dbname' => constant('DB_PG_DBNAME'), - 'user' => constant('DB_PG_DBUSER'), - 'password' => constant('DB_PG_DBPASS'), - 'port' => constant('DB_PG_PORT') - ); - $db = new cs_phpDB(constant('DBTYPE')); - $db->connect($dbParams); - return($db); - }//end create_db() - //-------------------------------------------------------------------------- - - - //-------------------------------------------------------------------------- - function test_basics() { - $db = $this->create_db(); - $tok = new authTokenTester($db); - - //Generic test to ensure we get the appropriate data back. - $tokenData = $tok->create_token(1, 'test', 'abc123'); - $this->assertTrue(is_array($tokenData)); - $this->assertTrue((count($tokenData) == 2)); - $this->assertTrue(isset($tokenData['id'])); - $this->assertTrue(isset($tokenData['hash'])); - $this->assertTrue(($tokenData['id'] > 0)); - $this->assertTrue((strlen($tokenData['hash']) == 32)); - - $this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1); - - - //now create a token with a maximum lifetime... - { - //Generic test to ensure we get the appropriate data back. - $tokenData = $tok->create_token(1, 'test', 'abc123', '2 years'); - $this->assertTrue(is_array($tokenData)); - $this->assertTrue((count($tokenData) == 2)); - $this->assertTrue(isset($tokenData['id'])); - $this->assertTrue(isset($tokenData['hash'])); - $this->assertTrue(($tokenData['id'] > 0)); - $this->assertTrue((strlen($tokenData['hash']) == 32)); - - $this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1); - } - - //create a token with only 1 available use and try to authenticate it twice. - { - //Generic test to ensure we get the appropriate data back. - $tokenData = $tok->create_token(1, 'test', 'abc123', null, 1); - $this->assertTrue(is_array($tokenData)); - $this->assertTrue((count($tokenData) == 2)); - $this->assertTrue(isset($tokenData['id'])); - $this->assertTrue(isset($tokenData['hash'])); - $this->assertTrue(($tokenData['id'] > 0)); - $this->assertTrue((strlen($tokenData['hash']) == 32)); - - if(!$this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1)) { - $this->gfObj->debug_print($tok->tokenData($tokenData['id']),1); - } - if(!$this->assertTrue(($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']) === null), "Able to authenticate twice on a token with only 1 use")) { - $this->gfObj->debug_print($tok->tokenData($tokenData['id'])); - } - } - }//end test_basics() - //-------------------------------------------------------------------------- -} - -class authTokenTester extends cs_authToken { - public $isTest=true; - - public function tokenData($id) { - return($this->get_token_data($id)); - } -} - -?> Deleted: trunk/0.3/tests/testOfCSVersionParse.php =================================================================== --- trunk/0.3/tests/testOfCSVersionParse.php 2009-08-20 02:20:49 UTC (rev 118) +++ trunk/0.3/tests/testOfCSVersionParse.php 2009-08-20 13:57:54 UTC (rev 119) @@ -1,127 +0,0 @@ -<?php -/* - * Created on Jan 25, 2009 - * - * FILE INFORMATION: - * - * $HeadURL$ - * $Id$ - * $LastChangedDate$ - * $LastChangedBy$ - * $LastChangedRevision$ - */ - - - -class testOfCSVersionParse extends UnitTestCase { - - function __construct() { - $this->gfObj = new cs_globalFunctions; - }//end __construct() - - - //-------------------------------------------------------------------------- - function test_basics() { - - $tests = array( - 'files/version1' => array( - '0.1.2-ALPHA8754', - 'test1', - array( - 'version_major' => 0, - 'version_minor' => 1, - 'version_maintenance' => 2, - 'version_suffix' => 'ALPHA8754' - ) - ), - 'files/version2' => array( - '5.4.0', - 'test2', - array( - 'version_major' => 5, - 'version_minor' => 4, - 'version_maintenance' => 0, - 'version_suffix' => null - ) - ), - 'files/version3' => array( - '5.4.3-BETA5543', - 'test3 stuff', - array( - 'version_major' => 5, - 'version_minor' => 4, - 'version_maintenance' => 3, - 'version_suffix' => 'BETA5543' - ) - ) - ); - - foreach($tests as $fileName=>$expectedArr) { - $ver = new middleTestClass(); - $ver->set_version_file_location(dirname(__FILE__) .'/'. $fileName); - - $this->assertEqual($expectedArr[0], $ver->get_version(), "Failed to match string from file (". $fileName .")"); - $this->assertEqual($expectedArr[1], $ver->get_project(), "Failed to match project from file (". $fileName .")"); - - //now check that pulling the version as an array is the same... - $checkItArr = $ver->get_version(true); - $expectThis = $expectedArr[2]; - $expectThis['version_string'] = $expectedArr[0]; - } - }//end test_basics() - //-------------------------------------------------------------------------- - - - - //-------------------------------------------------------------------------- - function test_check_higher() { - - //NOTE: the first item should ALWAYS be higher. - $tests = array( - 'basic, no suffix' => array('1.0.1', '1.0.0'), - 'basic + suffix' => array('1.0.0-ALPHA1', '1.0.0-ALPHA0'), - 'basic w/o maint' => array('1.0.1', '1.0'), - 'suffix check' => array('1.0.0-BETA1', '1.0.0-ALPHA1'), - 'suffix check2' => array('1.0.0-ALPHA10', '1.0.0-ALPHA1'), - 'suffix check3' => array('1.0.1', '1.0.0-RC1') - ); - - foreach($tests as $name=>$checkData) { - $ver = new middleTestClass; - $this->assertTrue($ver->is_higher_version($checkData[1], $checkData[0])); - $this->assertFalse($ver->is_higher_version($checkData[0], $checkData[1])); - } - - //now check to ensure there's no problem with parsing equivalent versions. - $tests = array( - 'no suffix' => array('1.0', '1.0.0'), - 'no maint + suffix' => array('1.0-ALPHA1', '1.0.0-ALPHA1'), - 'no maint + BETA' => array('1.0-BETA5555', '1.0.0-BETA5555'), - 'no maint + RC' => array('1.0-RC33', '1.0.0-RC33'), - 'maint with space' => array('1.0-RC 33', '1.0.0-RC33'), - 'extra spaces' => array(' 1.0 ', '1.0.0') - ); - foreach($tests as $name=>$checkData) { - $ver = new middleTestClass; - - //rip apart & recreate first version to test against the expected... - $derivedFullVersion = $ver->build_full_version_string($ver->parse_version_string($checkData[0])); - $this->assertEqual($derivedFullVersion, $checkData[1], "TEST=(". $name ."): derived version " . - "(". $derivedFullVersion .") doesn't match expected (". $checkData[1] .")"); - - //now rip apart & recreate the expected version (second) and make sure it matches itself. - $derivedFullVersion = $ver->build_full_version_string($ver->parse_version_string($checkData[1])); - $this->assertEqual($derivedFullVersion, $checkData[1], "TEST=(". $name ."): derived version " . - "(". $derivedFullVersion .") doesn't match expected (". $checkData[1] .")"); - } - - - }//end test_check_higher() - //-------------------------------------------------------------------------- -} - - -class middleTestClass extends cs_versionAbstract { - function __construct(){} -} -?> Copied: trunk/0.3/tests/testOfCSWebAppLibs.php (from rev 117, trunk/0.3/tests/testOfCSVersionParse.php) =================================================================== --- trunk/0.3/tests/testOfCSWebAppLibs.php (rev 0) +++ trunk/0.3/tests/testOfCSWebAppLibs.php 2009-08-20 13:57:54 UTC (rev 119) @@ -0,0 +1,209 @@ +<?php +/* + * Created on Jan 25, 2009 + * + * FILE INFORMATION: + * + * $HeadURL$ + * $Id$ + * $LastChangedDate$ + * $LastChangedBy$ + * $LastChangedRevision$ + */ + +require_once(dirname(__FILE__) .'/../cs_version.abstract.class.php'); +require_once(dirname(__FILE__) .'/../cs_authToken.class.php'); + +class testOfCSWebAppLibs extends UnitTestCase { + + //-------------------------------------------------------------------------- + function __construct() { + $this->gfObj = new cs_globalFunctions; + $this->gfObj->debugPrintOpt=1; + }//end __construct() + //-------------------------------------------------------------------------- + + + //-------------------------------------------------------------------------- + function test_version_basics() { + + $tests = array( + 'files/version1' => array( + '0.1.2-ALPHA8754', + 'test1', + array( + 'version_major' => 0, + 'version_minor' => 1, + 'version_maintenance' => 2, + 'version_suffix' => 'ALPHA8754' + ) + ), + 'files/version2' => array( + '5.4.0', + 'test2', + array( + 'version_major' => 5, + 'version_minor' => 4, + 'version_maintenance' => 0, + 'version_suffix' => null + ) + ), + 'files/version3' => array( + '5.4.3-BETA5543', + 'test3 stuff', + array( + 'version_major' => 5, + 'version_minor' => 4, + 'version_maintenance' => 3, + 'version_suffix' => 'BETA5543' + ) + ) + ); + + foreach($tests as $fileName=>$expectedArr) { + $ver = new middleTestClass(); + $ver->set_version_file_location(dirname(__FILE__) .'/'. $fileName); + + $this->assertEqual($expectedArr[0], $ver->get_version(), "Failed to match string from file (". $fileName .")"); + $this->assertEqual($expectedArr[1], $ver->get_project(), "Failed to match project from file (". $fileName .")"); + + //now check that pulling the version as an array is the same... + $checkItArr = $ver->get_version(true); + $expectThis = $expectedArr[2]; + $expectThis['version_string'] = $expectedArr[0]; + } + }//end test_version_basics() + //-------------------------------------------------------------------------- + + + + //-------------------------------------------------------------------------- + function test_check_higher() { + + //NOTE: the first item should ALWAYS be higher. + $tests = array( + 'basic, no suffix' => array('1.0.1', '1.0.0'), + 'basic + suffix' => array('1.0.0-ALPHA1', '1.0.0-ALPHA0'), + 'basic w/o maint' => array('1.0.1', '1.0'), + 'suffix check' => array('1.0.0-BETA1', '1.0.0-ALPHA1'), + 'suffix check2' => array('1.0.0-ALPHA10', '1.0.0-ALPHA1'), + 'suffix check3' => array('1.0.1', '1.0.0-RC1') + ); + + foreach($tests as $name=>$checkData) { + $ver = new middleTestClass; + $this->assertTrue($ver->is_higher_version($checkData[1], $checkData[0])); + $this->assertFalse($ver->is_higher_version($checkData[0], $checkData[1])); + } + + //now check to ensure there's no problem with parsing equivalent versions. + $tests = array( + 'no suffix' => array('1.0', '1.0.0'), + 'no maint + suffix' => array('1.0-ALPHA1', '1.0.0-ALPHA1'), + 'no maint + BETA' => array('1.0-BETA5555', '1.0.0-BETA5555'), + 'no maint + RC' => array('1.0-RC33', '1.0.0-RC33'), + 'maint with space' => array('1.0-RC 33', '1.0.0-RC33'), + 'extra spaces' => array(' 1.0 ', '1.0.0') + ); + foreach($tests as $name=>$checkData) { + $ver = new middleTestClass; + + //rip apart & recreate first version to test against the expected... + $derivedFullVersion = $ver->build_full_version_string($ver->parse_version_string($checkData[0])); + $this->assertEqual($derivedFullVersion, $checkData[1], "TEST=(". $name ."): derived version " . + "(". $derivedFullVersion .") doesn't match expected (". $checkData[1] .")"); + + //now rip apart & recreate the expected version (second) and make sure it matches itself. + $derivedFullVersion = $ver->build_full_version_string($ver->parse_version_string($checkData[1])); + $this->assertEqual($derivedFullVersion, $checkData[1], "TEST=(". $name ."): derived version " . + "(". $derivedFullVersion .") doesn't match expected (". $checkData[1] .")"); + } + + + }//end test_check_higher() + //-------------------------------------------------------------------------- + + + + //-------------------------------------------------------------------------- + private function create_db() { + $dbParams = array( + 'host' => constant('DB_PG_HOST'), + 'dbname' => constant('DB_PG_DBNAME'), + 'user' => constant('DB_PG_DBUSER'), + 'password' => constant('DB_PG_DBPASS'), + 'port' => constant('DB_PG_PORT') + ); + $db = new cs_phpDB(constant('DBTYPE')); + $db->connect($dbParams); + return($db); + }//end create_db() + //-------------------------------------------------------------------------- + + + //-------------------------------------------------------------------------- + function test_token_basics() { + $db = $this->create_db(); + $tok = new authTokenTester($db); + + //Generic test to ensure we get the appropriate data back. + $tokenData = $tok->create_token(1, 'test', 'abc123'); + $this->assertTrue(is_array($tokenData)); + $this->assertTrue((count($tokenData) == 2)); + $this->assertTrue(isset($tokenData['id'])); + $this->assertTrue(isset($tokenData['hash'])); + $this->assertTrue(($tokenData['id'] > 0)); + $this->assertTrue((strlen($tokenData['hash']) == 32)); + + $this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1); + + + //now create a token with a maximum lifetime... + { + //Generic test to ensure we get the appropriate data back. + $tokenData = $tok->create_token(1, 'test', 'abc123', '2 years'); + $this->assertTrue(is_array($tokenData)); + $this->assertTrue((count($tokenData) == 2)); + $this->assertTrue(isset($tokenData['id'])); + $this->assertTrue(isset($tokenData['hash'])); + $this->assertTrue(($tokenData['id'] > 0)); + $this->assertTrue((strlen($tokenData['hash']) == 32)); + + $this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1); + } + + //create a token with only 1 available use and try to authenticate it twice. + { + //Generic test to ensure we get the appropriate data back. + $tokenData = $tok->create_token(1, 'test', 'abc123', null, 1); + $this->assertTrue(is_array($tokenData)); + $this->assertTrue((count($tokenData) == 2)); + $this->assertTrue(isset($tokenData['id'])); + $this->assertTrue(isset($tokenData['hash'])); + $this->assertTrue(($tokenData['id'] > 0)); + $this->assertTrue((strlen($tokenData['hash']) == 32)); + + if(!$this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1)) { + $this->gfObj->debug_print($tok->tokenData($tokenData['id']),1); + } + if(!$this->assertTrue(($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']) === null), "Able to authenticate twice on a token with only 1 use")) { + $this->gfObj->debug_print($tok->tokenData($tokenData['id'])); + } + } + }//end test_token_basics() + //-------------------------------------------------------------------------- +} + + +class middleTestClass extends cs_versionAbstract { + function __construct(){} +} + +class authTokenTester extends cs_authToken { + public $isTest=true; + + public function tokenData($id) { + return($this->get_token_data($id)); + } +} +?> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-20 02:20:56
|
Revision: 118 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=118&view=rev Author: crazedsanity Date: 2009-08-20 02:20:49 +0000 (Thu, 20 Aug 2009) Log Message: ----------- Add missing requirement for cs_webdbupgrade. Modified Paths: -------------- trunk/0.3/cs_webdblogger.class.php Modified: trunk/0.3/cs_webdblogger.class.php =================================================================== --- trunk/0.3/cs_webdblogger.class.php 2009-08-20 01:59:58 UTC (rev 117) +++ trunk/0.3/cs_webdblogger.class.php 2009-08-20 02:20:49 UTC (rev 118) @@ -28,6 +28,7 @@ //NOTE::: this class **REQUIRES** cs-content for its "cs_phpDB" class. require_once(dirname(__FILE__) .'/cs_webapplibs.abstract.class.php'); +require_once(dirname(__FILE__) .'/cs_webdbupgrade.class.php'); class cs_webdblogger extends cs_webapplibsAbstract { /** Database handle */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-20 02:00:08
|
Revision: 117 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=117&view=rev Author: crazedsanity Date: 2009-08-20 01:59:58 +0000 (Thu, 20 Aug 2009) Log Message: ----------- Updated test to work (last commit removed wrong method). Modified Paths: -------------- trunk/0.3/tests/testOfAuthToken.php Modified: trunk/0.3/tests/testOfAuthToken.php =================================================================== --- trunk/0.3/tests/testOfAuthToken.php 2009-08-20 01:50:46 UTC (rev 116) +++ trunk/0.3/tests/testOfAuthToken.php 2009-08-20 01:59:58 UTC (rev 117) @@ -25,18 +25,21 @@ //-------------------------------------------------------------------------- - function setUp() { - $tok = new cs_authToken($this->create_db()); - try { - $tok->load_table(); - } - catch(exception $e) { - } - }//end setUp() + private function create_db() { + $dbParams = array( + 'host' => constant('DB_PG_HOST'), + 'dbname' => constant('DB_PG_DBNAME'), + 'user' => constant('DB_PG_DBUSER'), + 'password' => constant('DB_PG_DBPASS'), + 'port' => constant('DB_PG_PORT') + ); + $db = new cs_phpDB(constant('DBTYPE')); + $db->connect($dbParams); + return($db); + }//end create_db() //-------------------------------------------------------------------------- - //-------------------------------------------------------------------------- function test_basics() { $db = $this->create_db(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-20 01:51:04
|
Revision: 116 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=116&view=rev Author: crazedsanity Date: 2009-08-20 01:50:46 +0000 (Thu, 20 Aug 2009) Log Message: ----------- Incorporate upgrades from cs-webdblogger v0.2.0 into the main schema. Modified Paths: -------------- trunk/0.3/setup/schema.mysql.sql trunk/0.3/setup/schema.pgsql.sql trunk/0.3/upgrades/upgrade.xml Removed Paths: ------------- trunk/0.3/upgrades/sql/ trunk/0.3/upgrades/upgradeTo0.2.0.php trunk/0.3/upgrades/upgradeTo0.2.1.php Modified: trunk/0.3/setup/schema.mysql.sql =================================================================== --- trunk/0.3/setup/schema.mysql.sql 2009-08-20 01:44:14 UTC (rev 115) +++ trunk/0.3/setup/schema.mysql.sql 2009-08-20 01:50:46 UTC (rev 116) @@ -92,6 +92,50 @@ -- ALTER TABLE `cswdbl_log_table` ADD CONSTRAINT `cswdbl_log_table_event_id_fkey` FOREIGN KEY (`event_id`) REFERENCES `cswdbl_event_table` (`event_id`); + + + +-- +-- Table structure for table `cswdbl_log_attribute_table` +-- + +CREATE TABLE `cswdbl_log_attribute_table` ( + `log_attribute_id` int(11) NOT NULL auto_increment, + `log_id` int(11) NOT NULL, + `attribute_id` int(11) NOT NULL, + `value_text` text NOT NULL, + PRIMARY KEY (`log_attribute_id`), + KEY `cswdbl_log_attribute_table_log_id_fkey` (`log_id`), + KEY `cswdbl_log_attribute_table_attribute_id_fkey` (`attribute_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `cswdbl_log_table` +-- + +CREATE TABLE `cswdbl_log_table` ( + `log_id` int(11) NOT NULL auto_increment, + `creation` timestamp NOT NULL default CURRENT_TIMESTAMP, + `event_id` int(11) NOT NULL, + `uid` int(11) NOT NULL, + `affected_uid` int(11) NOT NULL, + `details` text NOT NULL, + PRIMARY KEY (`log_id`), + KEY `cswdbl_log_table_event_id_fkey` (`event_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; + + + +-- +-- Constraints for table `cswdbl_log_attribute_table` +-- +ALTER TABLE `cswdbl_log_attribute_table` + ADD CONSTRAINT `cswdbl_log_attribute_table_attribute_id_fkey` FOREIGN KEY (`attribute_id`) REFERENCES `cswdbl_attribute_table` (`attribute_id`), + ADD CONSTRAINT `cswdbl_log_attribute_table_log_id_fkey` FOREIGN KEY (`log_id`) REFERENCES `cswdbl_log_table` (`log_id`); + + -- This table create statement MUST work in PostgreSQL v8.2.x+ AND MySQL v5.0.x+: Modified: trunk/0.3/setup/schema.pgsql.sql =================================================================== --- trunk/0.3/setup/schema.pgsql.sql 2009-08-20 01:44:14 UTC (rev 115) +++ trunk/0.3/setup/schema.pgsql.sql 2009-08-20 01:50:46 UTC (rev 116) @@ -63,6 +63,25 @@ details text NOT NULL ); + +-- +-- List of distinct attribute names. +-- +CREATE TABLE cswdbl_attribute_table ( + attribute_id serial NOT NULL PRIMARY KEY, + attribute_name text NOT NULL UNIQUE +); + +-- +-- Linkage for attributes to logs. +-- +CREATE TABLE cswdbl_log_attribute_table ( + log_attribute_id serial NOT NULL PRIMARY KEY, + log_id int NOT NULL REFERENCES cswdbl_log_table(log_id), + attribute_id int NOT NULL REFERENCES cswdbl_attribute_table(attribute_id), + value_text text +); + -- This table create statement MUST work in PostgreSQL v8.2.x+ AND MySQL v5.0.x+: -- otherwise separate schema files have to be created and the code will have to -- do extra checking... Modified: trunk/0.3/upgrades/upgrade.xml =================================================================== --- trunk/0.3/upgrades/upgrade.xml 2009-08-20 01:44:14 UTC (rev 115) +++ trunk/0.3/upgrades/upgrade.xml 2009-08-20 01:50:46 UTC (rev 116) @@ -18,12 +18,5 @@ to get skipped, or an exception to be thrown, potentially leaving the system in an unstable state. Unstable is bad, m'kay?</system_note> - <matching> - <v0.2.0> - <target_version>0.2.1</target_version> - <script_name>upgradeTo0.2.1.php</script_name> - <class_name>upgrade_to_0_2_1</class_name> - <call_method>run_upgrade</call_method> - </v0.2.0> - </matching> + <matching /> </upgrade> Deleted: trunk/0.3/upgrades/upgradeTo0.2.0.php =================================================================== --- trunk/0.3/upgrades/upgradeTo0.2.0.php 2009-08-20 01:44:14 UTC (rev 115) +++ trunk/0.3/upgrades/upgradeTo0.2.0.php 2009-08-20 01:50:46 UTC (rev 116) @@ -1,95 +0,0 @@ -<?php - -class upgrade_to_0_2_0 { - - //========================================================================= - public function __construct(cs_phpDB &$db) { - if(!$db->is_connected()) { - throw new exception(__METHOD__ .": database is not connected"); - } - $this->db = $db; - - $this->gfObj = new cs_globalFunctions; - $this->gfObj->debugPrintOpt = 1; - - }//end __construct() - //========================================================================= - - - - //========================================================================= - public function run_upgrade() { - - - $upgradeFilename = dirname(__FILE__) ."/sql/upgradeTo0_2_0.". $this->db->get_dbtype() .".sql"; - if(!file_exists($upgradeFilename)) { - throw new exception(__METHOD__ .": missing upgrade filename (". $upgradeFilename ."), " . - "probably due to unsupported database type (". $this->db->get_dbtype() .")"); - } - - - $tables = array( - 'cat' => array( - 'cswdbl_category_table', - 'log_category_table', - 'category_id' - ), - 'class' => array( - 'cswdbl_class_table', - 'log_class_table', - 'class_id' - ), - 'event' => array( - 'cswdbl_event_table', - 'log_event_table', - 'event_id' - ), - 'log' => array( - 'cswdbl_log_table', - 'log_table', - 'log_id' - ) - ); - - //run the SQL file. - $file = dirname(__FILE__) .'/sql/upgradeTo0_2_0.'. $this->db->get_dbtype() .'.sql'; - $upgradeRes = false; - if(file_exists($file)) { - $this->db->run_update(file_get_contents($file),true); - $totalToSync = count($tables); - $totalSynced = 0; - - //now make sure there's the same amount of data in BOTH tables. - foreach($tables as $key => $tables) { - $c1 = $this->db->run_query("SELECT * FROM ". $tables[0]); - $num1 = $this->db->numRows(); - $c2 = $this->db->run_query("SELECT * FROM ". $tables[1]); - $num2 = $this->db->numRows(); - - if($num1 === $num2) { - $totalSynced++; - $this->db->run_update("DROP TABLE ". $tables[1] ." CASCADE", true); - - if($this->db->get_dbtype() == 'pgsql') { - //Update the sequence... - $seq = $tables[0] .'_'. $tables[2] .'_seq'; - $this->db->run_update("SELECT setval('". $seq ."', (SELECT max(". $tables[2] .") FROM ". $tables[0] ."))",true); - } - } - else { - throw new exception(__METHOD__ .": failed to sync ". $tables[0] ." with ". $tables[1] ." (". $num1 ." != ". $num2 .")"); - } - } - $upgradeRes = true; - } - else { - throw new exception(__METHOD__ .": missing upgrade SQL file (". $file .")"); - } - - return($upgradeRes); - - }//end run_upgrade() - //========================================================================= -} - -?> Deleted: trunk/0.3/upgrades/upgradeTo0.2.1.php =================================================================== --- trunk/0.3/upgrades/upgradeTo0.2.1.php 2009-08-20 01:44:14 UTC (rev 115) +++ trunk/0.3/upgrades/upgradeTo0.2.1.php 2009-08-20 01:50:46 UTC (rev 116) @@ -1,47 +0,0 @@ -<?php - -class upgrade_to_0_2_1 { - - //========================================================================= - public function __construct(cs_phpDB &$db) { - if(!$db->is_connected()) { - throw new exception(__METHOD__ .": database is not connected"); - } - $this->db = $db; - - $this->gfObj = new cs_globalFunctions; - $this->gfObj->debugPrintOpt = 1; - - }//end __construct() - //========================================================================= - - - - //========================================================================= - public function run_upgrade() { - - - $upgradeFilename = dirname(__FILE__) ."/sql/upgradeTo0_2_1.". $this->db->get_dbtype() .".sql"; - if(!file_exists($upgradeFilename)) { - throw new exception(__METHOD__ .": missing upgrade filename (". $upgradeFilename ."), " . - "probably due to unsupported database type (". $this->db->get_dbtype() .")"); - } - - //run the SQL file. - $file = dirname(__FILE__) .'/sql/upgradeTo0_2_1.'. $this->db->get_dbtype() .'.sql'; - $upgradeRes = false; - if(file_exists($file)) { - $this->db->run_update(file_get_contents($file),true); - $upgradeRes = true; - } - else { - throw new exception(__METHOD__ .": missing upgrade SQL file (". $file .")"); - } - - return($upgradeRes); - - }//end run_upgrade() - //========================================================================= -} - -?> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-20 01:44:23
|
Revision: 115 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=115&view=rev Author: crazedsanity Date: 2009-08-20 01:44:14 +0000 (Thu, 20 Aug 2009) Log Message: ----------- Updated schema, tests, & set cs_authToken to be MySQL-compatible. TODO::: incorporate changes in cs-webdbupgrade that include the attribute tables into the main SQL file(s). /cs_authToken.class.php: * load_table() [DELETED]: -- this table should be included in with all the other tables. * create_token(): -- set a default value for expiration so the database doesn't have to set that. -- NOTE::: any tokens with a NULL expiration and unlimited uses will NEVER be automatically removed. /cs_webdbupgrade.class.php: * __construct(): -- set DB_TABLE and DB_PRIMARYKEY to hardcoded values. * load_table(): -- updated location of schema file -- NOTE::: this should probably be named "load_schema()", as it is actually loading several different tables now. /setup/authtoken_schema.pgsql.sql [DELETED]: * incorporated into the pgsql & mysql schema files. /setup/schema.mysql.sql: * changed "cs_version_table" to cswal_version_table (cswal == CS-WebAppLibs), removed unnecessary columns (previously removed in cs-webdbupgrade v0.2.0). * create cswal_auth_token_table. /setup/schema.pgsql.sql: * (same as the mysql version). /tests/testOfAuthToken.php: * remove code for creating & destroying tables (NOTE: my test site actually destroys & rebuilds the entire database... this should probably be changed to a series of "DROP TABLE" statements). Modified Paths: -------------- trunk/0.3/cs_authToken.class.php trunk/0.3/cs_webdbupgrade.class.php trunk/0.3/setup/schema.mysql.sql trunk/0.3/setup/schema.pgsql.sql trunk/0.3/tests/testOfAuthToken.php Removed Paths: ------------- trunk/0.3/setup/authtoken_schema.pgsql.sql Modified: trunk/0.3/cs_authToken.class.php =================================================================== --- trunk/0.3/cs_authToken.class.php 2009-08-19 20:12:33 UTC (rev 114) +++ trunk/0.3/cs_authToken.class.php 2009-08-20 01:44:14 UTC (rev 115) @@ -48,29 +48,6 @@ //========================================================================= /** - * Load table into the database... - */ - public function load_table() { - $file = dirname(__FILE__) .'/setup/authtoken_schema.'. $this->db->get_dbtype() .'.sql'; - - if(file_exists($file)) { - try { - $this->db->run_update(file_get_contents($file), true); - } - catch(exception $e) { - throw new exception(__METHOD__ .": error while trying to load table::: ". $e->getMessage()); - } - } - else { - throw new exception(__METHOD__ .": unsupported database type (". $this->db->get_dbtype() .")"); - } - }//end load_table() - //========================================================================= - - - - //========================================================================= - /** * Standardized method of creating a hash from a string. * * @param $tokenId (int) matches auth_token_id column.... @@ -110,6 +87,8 @@ 'checksum' => $checksum, 'token' => '____INCOMPLETE____' ); + + $insertData['expiration'] = strftime('%Y-%m-%d %T', strtotime('1 day')); if(!is_null($lifetime) && strlen($lifetime)) { $insertData['expiration'] = strftime('%Y-%m-%d %T', strtotime($lifetime)); } Modified: trunk/0.3/cs_webdbupgrade.class.php =================================================================== --- trunk/0.3/cs_webdbupgrade.class.php 2009-08-19 20:12:33 UTC (rev 114) +++ trunk/0.3/cs_webdbupgrade.class.php 2009-08-20 01:44:14 UTC (rev 115) @@ -99,13 +99,8 @@ $this->gfObj->debugPrintOpt = constant('DEBUGPRINTOPT'); } - if(!defined(__CLASS__ .'-DB_PRIMARYKEY') || !defined(__CLASS__ .'-DB_TABLE')) { - throw new exception(__METHOD__ .": no setting for DB_TABLE or DB_PRIMARYKEY, cannot continue"); - } - else { - $this->config['DB_TABLE'] = constant(__CLASS__ .'-DB_TABLE'); - $this->config['DB_PRIMARYKEY'] = constant(__CLASS__ .'-DB_PRIMARYKEY'); - } + $this->config['DB_TABLE'] = 'cswal_version_table'; + $this->config['DB_PRIMARYKEY'] = 'version_id'; $this->sequenceName = $this->config['DB_TABLE'] .'_'. $this->config['DB_PRIMARYKEY'] .'_seq'; if(!defined('DBTYPE')) { @@ -908,7 +903,7 @@ //========================================================================= public function load_table() { - $schemaFileLocation = dirname(__FILE__) .'/schema/schema.sql'; + $schemaFileLocation = dirname(__FILE__) .'/setup/schema.'. $this->db->get_dbtype() .'.sql'; $schema = file_get_contents($schemaFileLocation); $schema = str_replace('{tableName}', $this->config['DB_TABLE'], $schema); $schema = str_replace('{primaryKey}', $this->config['DB_PRIMARYKEY'], $schema); Deleted: trunk/0.3/setup/authtoken_schema.pgsql.sql =================================================================== --- trunk/0.3/setup/authtoken_schema.pgsql.sql 2009-08-19 20:12:33 UTC (rev 114) +++ trunk/0.3/setup/authtoken_schema.pgsql.sql 2009-08-20 01:44:14 UTC (rev 115) @@ -1,20 +0,0 @@ --- --- SVN INFORMATION::: --- --------------- --- SVN Signature::::::: $Id$ --- Last Author::::::::: $Author$ --- Current Revision:::: $Revision$ --- Repository Location: $HeadURL$ --- Last Updated:::::::: $Date$ --- - -CREATE TABLE cswal_auth_token_table ( - auth_token_id serial NOT NULL PRIMARY KEY, - uid integer NOT NULL DEFAULT 0, - checksum text NOT NULL, - token text NOT NULL, - max_uses integer DEFAULT NULL, - total_uses integer NOT NULL DEFAULT 0, - creation timestamp NOT NULL DEFAULT NOW(), - expiration timestamp NOT NULL DEFAULT NOW() + '1 day'::interval -); \ No newline at end of file Modified: trunk/0.3/setup/schema.mysql.sql =================================================================== --- trunk/0.3/setup/schema.mysql.sql 2009-08-19 20:12:33 UTC (rev 114) +++ trunk/0.3/setup/schema.mysql.sql 2009-08-20 01:44:14 UTC (rev 115) @@ -98,14 +98,19 @@ -- otherwise separate schema files have to be created and the code will have to -- do extra checking... -- --- The "{tableName}" portion will be replaced with the value of the configured --- "DB_TABLE" setting. -CREATE TABLE cs_version_table ( +CREATE TABLE cswal_version_table ( version_id int NOT NULL PRIMARY KEY, project_name varchar(30) NOT NULL UNIQUE, - version_string varchar(50) NOT NULL, - version_major integer NOT NULL, - version_minor integer NOT NULL, - version_maintenance integer NOT NULL, - version_suffix varchar(20) NOT NULL + version_string varchar(50) NOT NULL ); + +CREATE TABLE cswal_auth_token_table ( + auth_token_id serial NOT NULL PRIMARY KEY, + uid integer NOT NULL DEFAULT 0, + checksum text NOT NULL, + token text NOT NULL, + max_uses integer DEFAULT NULL, + total_uses integer NOT NULL DEFAULT 0, + creation timestamp NOT NULL DEFAULT NOW(), + expiration timestamp NOT NULL +); \ No newline at end of file Modified: trunk/0.3/setup/schema.pgsql.sql =================================================================== --- trunk/0.3/setup/schema.pgsql.sql 2009-08-19 20:12:33 UTC (rev 114) +++ trunk/0.3/setup/schema.pgsql.sql 2009-08-20 01:44:14 UTC (rev 115) @@ -66,13 +66,21 @@ -- This table create statement MUST work in PostgreSQL v8.2.x+ AND MySQL v5.0.x+: -- otherwise separate schema files have to be created and the code will have to -- do extra checking... -CREATE TABLE cs_version_table ( +CREATE TABLE cswal_version_table ( version_id serial NOT NULL PRIMARY KEY, project_name varchar(30) NOT NULL UNIQUE, - version_string varchar(50) NOT NULL, - version_major integer NOT NULL, - version_minor integer NOT NULL, - version_maintenance integer NOT NULL, - version_suffix varchar(20) NOT NULL + version_string varchar(50) NOT NULL ); + +CREATE TABLE cswal_auth_token_table ( + auth_token_id serial NOT NULL PRIMARY KEY, + uid integer NOT NULL DEFAULT 0, + checksum text NOT NULL, + token text NOT NULL, + max_uses integer DEFAULT NULL, + total_uses integer NOT NULL DEFAULT 0, + creation timestamp NOT NULL DEFAULT NOW(), + expiration timestamp NOT NULL +); + Modified: trunk/0.3/tests/testOfAuthToken.php =================================================================== --- trunk/0.3/tests/testOfAuthToken.php 2009-08-19 20:12:33 UTC (rev 114) +++ trunk/0.3/tests/testOfAuthToken.php 2009-08-20 01:44:14 UTC (rev 115) @@ -38,35 +38,6 @@ //-------------------------------------------------------------------------- - function tearDown() { - $db = $this->create_db(); - try { - $db->run_update('DROP TABLE cswal_auth_token_table', true); - } - catch(exception $e) { - } - }//end - //-------------------------------------------------------------------------- - - - - //-------------------------------------------------------------------------- - private function create_db() { - $dbParams = array( - 'host' => constant('DB_PG_HOST'), - 'dbname' => constant('DB_PG_DBNAME'), - 'user' => constant('DB_PG_DBUSER'), - 'password' => constant('DB_PG_DBPASS'), - 'port' => constant('DB_PG_PORT') - ); - $db = new cs_phpDB(constant('DBTYPE')); - $db->connect($dbParams); - return($db); - }//end create_db() - //-------------------------------------------------------------------------- - - - //-------------------------------------------------------------------------- function test_basics() { $db = $this->create_db(); $tok = new authTokenTester($db); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 20:12:40
|
Revision: 114 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=114&view=rev Author: crazedsanity Date: 2009-08-19 20:12:33 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Changes to work with MySQL. /cs_authToken.class.php: * create_token(): -- use a combination of strftime(strtotime()) to create an appropriate expiration date based on a given lifetime (i.e. "1 day"). -- use "expiration" column instead of duration. * get_token_data(): -- updated to use expiration instead of creation + duration. /setup/authToken_schema.pgsql.sql: * cswal_auth_token_table: -- change creation to a timestamp. -- change duration(interval) to expiration(timestamp) Modified Paths: -------------- trunk/0.3/cs_authToken.class.php trunk/0.3/setup/authtoken_schema.pgsql.sql Modified: trunk/0.3/cs_authToken.class.php =================================================================== --- trunk/0.3/cs_authToken.class.php 2009-08-19 19:24:52 UTC (rev 113) +++ trunk/0.3/cs_authToken.class.php 2009-08-19 20:12:33 UTC (rev 114) @@ -111,7 +111,7 @@ 'token' => '____INCOMPLETE____' ); if(!is_null($lifetime) && strlen($lifetime)) { - $insertData['duration'] = $lifetime; + $insertData['expiration'] = strftime('%Y-%m-%d %T', strtotime($lifetime)); } if(!is_null($maxUses) && is_numeric($maxUses) && $maxUses > 0) { $insertData['max_uses'] = $maxUses; @@ -282,7 +282,7 @@ protected function get_token_data($tokenId) { try { $data = $this->db->run_query("SELECT * FROM ". $this->table ." WHERE auth_token_id=". $tokenId - ." AND (creation + duration)::date >= CURRENT_DATE", 'auth_token_id'); + ." AND expiration::date >= CURRENT_DATE", 'auth_token_id'); if(is_array($data) && count($data) == 1) { $tokenData = $data; } Modified: trunk/0.3/setup/authtoken_schema.pgsql.sql =================================================================== --- trunk/0.3/setup/authtoken_schema.pgsql.sql 2009-08-19 19:24:52 UTC (rev 113) +++ trunk/0.3/setup/authtoken_schema.pgsql.sql 2009-08-19 20:12:33 UTC (rev 114) @@ -15,6 +15,6 @@ token text NOT NULL, max_uses integer DEFAULT NULL, total_uses integer NOT NULL DEFAULT 0, - creation date NOT NULL DEFAULT NOW(), - duration interval NOT NULL DEFAULT '1 day'::interval + creation timestamp NOT NULL DEFAULT NOW(), + expiration timestamp NOT NULL DEFAULT NOW() + '1 day'::interval ); \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 19:25:00
|
Revision: 113 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=113&view=rev Author: crazedsanity Date: 2009-08-19 19:24:52 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Headers, use get_token_data() in authenticate_token(). /cs_authToken.class.php: * ADDED HEADERS: -- __constructor() -- load_table() -- create_hash_string() -- create_token() -- update_token_uses() -- destroy_token() -- authenticate_token() -- get_token_data() * authenticate_token(): -- call get_token_data() -- do extra checking on the return value that was previously in SQL. * get_token_data(): -- updated to only show records that haven't expired. -- extra checking for if it returns boolean false. Modified Paths: -------------- trunk/0.3/cs_authToken.class.php Modified: trunk/0.3/cs_authToken.class.php =================================================================== --- trunk/0.3/cs_authToken.class.php 2009-08-19 19:01:21 UTC (rev 112) +++ trunk/0.3/cs_authToken.class.php 2009-08-19 19:24:52 UTC (rev 113) @@ -28,6 +28,9 @@ private $seq = 'cswal_auth_token_table_auth_token_id_seq'; //========================================================================= + /** + * The CONSTRUCTOR. Sets internal properties & such. + */ public function __construct(cs_phpDB $db) { if($db->is_connected()) { @@ -44,6 +47,9 @@ //========================================================================= + /** + * Load table into the database... + */ public function load_table() { $file = dirname(__FILE__) .'/setup/authtoken_schema.'. $this->db->get_dbtype() .'.sql'; @@ -64,6 +70,17 @@ //========================================================================= + /** + * Standardized method of creating a hash from a string. + * + * @param $tokenId (int) matches auth_token_id column.... + * @param $uid (int) matches uid column... + * @param $checksum (str) This is the value that can be used by the + * calling code to see if the given uid matches + * this data (i.e. using an email address/username). + * @param $stringToHash (str) Data used to help create a hash, usually + * something very unique. + */ protected function create_hash_string($tokenId, $uid, $checksum, $stringToHash=NULL) { return(md5($tokenId ."_". $uid ."_". $checksum ."_". $stringToHash)); }//end create_hash_string() @@ -72,6 +89,20 @@ //========================================================================= + /** + * Build a token record in the database that can be authenticated against later. + * + * @param $uid (int) matches uid column... + * @param $checksum (str) matches checksum column... + * @param $stringToHash (str) unique value to help build hash from. + * @param $lifetime (str,optional) string (interval) representing how + * long the token should last. + * @param $maxUses (int,optional) Number of times it can be authenticated + * against before being removed. + * + * @return (array) PASS: contains id & hash for the token. + * @return (exception) FAIL: exception contains error details. + */ public function create_token($uid, $checksum, $stringToHash, $lifetime=null, $maxUses=null) { $insertData = array( @@ -112,6 +143,15 @@ //========================================================================= + /** + * Update the number of times the given token has been used (even if the + * maximum uses hasn't been set). + * + * @param $tokenId (int) auth_token_id to look up. + * + * @return (int) PASS: updated this many records (should always be 1) + * @return (exception) FAIL: exception denotes problem + */ protected function update_token_uses($tokenId) { try { @@ -129,6 +169,14 @@ //========================================================================= + /** + * Deletes the given token ID from the database. + * + * @param $tokenId (int) auth_token_id to delete + * + * @return (int) PASS: this many were deleted (should always be 1) + * @return (exception) FAIL: exception contains error details + */ protected function destroy_token($tokenId) { try { $sql = "DELETE FROM ". $this->table ." WHERE auth_token_id=". $tokenId; @@ -162,22 +210,23 @@ * if($tokenUid == $realUid) { * //token is truly authentic * } + * + * @param $tokenId (int) auth_token_id to check against + * @param $checksum (str) required 'checksum' value. + * @param $hash (str) required 'token' value. */ public function authenticate_token($tokenId, $checksum, $hash) { $authTokenRes = null; if(is_numeric($tokenId) && strlen($checksum) && strlen($hash) == 32) { - $sql = "SELECT * FROM ". $this->table ." WHERE auth_token_id=". $tokenId - ." AND (creation + duration)::date >= CURRENT_DATE"; - try { - $data = $this->db->run_query($sql, 'auth_token_id'); + $data = $this->get_token_data($tokenId); if(count($data) == 1 && isset($data[$tokenId]) && is_array($data[$tokenId])) { $data = $data[$tokenId]; - if($data['token'] == $hash && $data['checksum'] == $checksum) { + if($data['token'] == $hash && $data['checksum']) { $methodCall = 'update_token_uses'; if(is_numeric($data['max_uses'])) { @@ -220,15 +269,34 @@ //========================================================================= + //========================================================================= + /** + * Retrieve data for the given ID. + * + * @param $tokenId (int) auth_token_id to look up. + * + * @return (array) PASS: contains data about the given ID + * @return (exception) FAIL: exception contains error details. + */ protected function get_token_data($tokenId) { try { - $data = $this->db->run_query("SELECT * FROM ". $this->table ." WHERE auth_token_id=". $tokenId); + $data = $this->db->run_query("SELECT * FROM ". $this->table ." WHERE auth_token_id=". $tokenId + ." AND (creation + duration)::date >= CURRENT_DATE", 'auth_token_id'); + if(is_array($data) && count($data) == 1) { + $tokenData = $data; + } + elseif($data === false) { + $tokenData = false; + } + else { + throw new exception("too many records returned (". count($data) .")"); + } } catch(exception $e) { throw new exception(__METHOD__ .": failed to retrieve tokenId (". $tokenId .")::: ". $e->getMessage()); } - return($data); + return($tokenData); }//end get_token_data(); //========================================================================= This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 19:01:31
|
Revision: 112 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=112&view=rev Author: crazedsanity Date: 2009-08-19 19:01:21 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Can authenticate against a given token. /cs_authToken.class.php: * create_token(): -- ARG CHANGE: NEW ARG: #4 ($lifetime=null) -- ARG CHANGE: NEW ARG: #5 ($maxUses=null) -- allow setting of duration ($lifetime) or max_uses ($maxUses) when creating the token. -- update the $insertData array with 'duration' or 'max_uses' data if appropriate, based on args #4 and #5 * update_token_uses() [NEW]: -- updates the number of times a given token has been used. * destroy_token() [NEW]: -- deletes a specific token. * authenticate_token() [NEW]: -- authenticates the given data against a token. -- this handles updating uses & destroying tokens that have been used their maximum number of times: this means that mass token expiration can be done based purely on creation + duration. * get_token_data() [NEW]: -- returns data about the given token. /setup/authtoken_schema.pgsql.sql: * cswal_auth_token_table: -- changed "use_limit" to "max_uses" for sanity. /tests/testOfAuthToken.php: * additional tests for authentication. Modified Paths: -------------- trunk/0.3/cs_authToken.class.php trunk/0.3/setup/authtoken_schema.pgsql.sql trunk/0.3/tests/testOfAuthToken.php Modified: trunk/0.3/cs_authToken.class.php =================================================================== --- trunk/0.3/cs_authToken.class.php 2009-08-19 17:44:04 UTC (rev 111) +++ trunk/0.3/cs_authToken.class.php 2009-08-19 19:01:21 UTC (rev 112) @@ -72,15 +72,19 @@ //========================================================================= - public function create_token($uid, $checksum, $stringToHash) { + public function create_token($uid, $checksum, $stringToHash, $lifetime=null, $maxUses=null) { - $this->db->beginTrans(); - $insertData = array( 'uid' => $uid, 'checksum' => $checksum, 'token' => '____INCOMPLETE____' ); + if(!is_null($lifetime) && strlen($lifetime)) { + $insertData['duration'] = $lifetime; + } + if(!is_null($maxUses) && is_numeric($maxUses) && $maxUses > 0) { + $insertData['max_uses'] = $maxUses; + } try { $sql = "INSERT INTO cswal_auth_token_table ". $this->gfObj->string_from_array($insertData, 'insert', null, 'sql'); @@ -105,5 +109,128 @@ }//end create_token() //========================================================================= + + + //========================================================================= + protected function update_token_uses($tokenId) { + + try { + $sql = "UPDATE ". $this->table ." SET total_uses= total_uses+1 " . + "WHERE auth_token_id=". $tokenId; + $updateRes = $this->db->run_update($sql); + } + catch(exception $e) { + throw new exception(__METHOD__ .": failed to update usage count::: ". $e->getMessage()); + } + return($updateRes); + }//end update_token_uses() + //========================================================================= + + + + //========================================================================= + protected function destroy_token($tokenId) { + try { + $sql = "DELETE FROM ". $this->table ." WHERE auth_token_id=". $tokenId; + $deleteRes = $this->db->run_update($sql); + } + catch(exception $e) { + throw new exception(__METHOD__ .": failed to "); + } + + return($deleteRes); + }//end destroy_token() + //========================================================================= + + + + //========================================================================= + /** + * Determine if a token is authentic: the id is used to make the search as + * fast as possible, while the hash & checksum are given to compare against. + * Failure results in FALSE, while success returns the contact_id for the + * given token. + * + * NOTE: the calling program can leave it to this method to say if the + * token is authentic, or use a checksum which can in turn be used to get + * a specific contact_id; when they authenticate, the return of this + * method must then match the contact_id retrieved from the checksum... + * + * EXAMPLE: + * $tokenUid = cs_authToken::authenticate_token($tokenId, $hash, $checksum); + * $realUid = userClass::get_uid_from_email($checksum); + * if($tokenUid == $realUid) { + * //token is truly authentic + * } + */ + public function authenticate_token($tokenId, $checksum, $hash) { + + $authTokenRes = null; + + if(is_numeric($tokenId) && strlen($checksum) && strlen($hash) == 32) { + $sql = "SELECT * FROM ". $this->table ." WHERE auth_token_id=". $tokenId + ." AND (creation + duration)::date >= CURRENT_DATE"; + + try { + $data = $this->db->run_query($sql, 'auth_token_id'); + + if(count($data) == 1 && isset($data[$tokenId]) && is_array($data[$tokenId])) { + $data = $data[$tokenId]; + + if($data['token'] == $hash && $data['checksum'] == $checksum) { + + $methodCall = 'update_token_uses'; + if(is_numeric($data['max_uses'])) { + $authTokenRes = null; + if($data['max_uses'] == $data['total_uses']) { + //reached max uses already... (maybe this should throw an exception?) + $methodCall = 'destroy_token'; + } + elseif($data['total_uses'] < $data['max_uses']) { + $authTokenRes = $data['uid']; + if(($data['total_uses'] +1) == $data['max_uses']) { + //this is the last use: just destroy it. + $methodCall = 'destroy_token'; + } + } + else { + throw new exception(__METHOD__ .": token (". $tokenId .") used more than max allowed uses [total=". $data['total_uses'] .", max=". $data['max_uses'] ."]"); + } + } + else { + $authTokenRes = $data['uid']; + } + $this->$methodCall($tokenId); + } + } + elseif($data === false) { + $authTokenRes = null; + } + else { + throw new exception(__METHOD__ .": invalid data returned:: ". $this->gfObj->debug_var_dump($data,0)); + } + } + catch(exception $e) { + throw new exception(__METHOD__ .": failed to authenticate token::: ". $e->getMessage()); + } + } + + return($authTokenRes); + }//end authenticate_token() + //========================================================================= + + + //========================================================================= + protected function get_token_data($tokenId) { + try { + $data = $this->db->run_query("SELECT * FROM ". $this->table ." WHERE auth_token_id=". $tokenId); + } + catch(exception $e) { + throw new exception(__METHOD__ .": failed to retrieve tokenId (". $tokenId .")::: ". $e->getMessage()); + } + return($data); + }//end get_token_data(); + //========================================================================= + } ?> Modified: trunk/0.3/setup/authtoken_schema.pgsql.sql =================================================================== --- trunk/0.3/setup/authtoken_schema.pgsql.sql 2009-08-19 17:44:04 UTC (rev 111) +++ trunk/0.3/setup/authtoken_schema.pgsql.sql 2009-08-19 19:01:21 UTC (rev 112) @@ -13,7 +13,7 @@ uid integer NOT NULL DEFAULT 0, checksum text NOT NULL, token text NOT NULL, - use_limit integer DEFAULT NULL, + max_uses integer DEFAULT NULL, total_uses integer NOT NULL DEFAULT 0, creation date NOT NULL DEFAULT NOW(), duration interval NOT NULL DEFAULT '1 day'::interval Modified: trunk/0.3/tests/testOfAuthToken.php =================================================================== --- trunk/0.3/tests/testOfAuthToken.php 2009-08-19 17:44:04 UTC (rev 111) +++ trunk/0.3/tests/testOfAuthToken.php 2009-08-19 19:01:21 UTC (rev 112) @@ -69,19 +69,62 @@ //-------------------------------------------------------------------------- function test_basics() { $db = $this->create_db(); - $tok = new cs_authToken($db); + $tok = new authTokenTester($db); //Generic test to ensure we get the appropriate data back. - $tokenData = $tok->create_token(0, 'test', 'abc123'); + $tokenData = $tok->create_token(1, 'test', 'abc123'); $this->assertTrue(is_array($tokenData)); $this->assertTrue((count($tokenData) == 2)); $this->assertTrue(isset($tokenData['id'])); $this->assertTrue(isset($tokenData['hash'])); $this->assertTrue(($tokenData['id'] > 0)); $this->assertTrue((strlen($tokenData['hash']) == 32)); + + $this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1); + + + //now create a token with a maximum lifetime... + { + //Generic test to ensure we get the appropriate data back. + $tokenData = $tok->create_token(1, 'test', 'abc123', '2 years'); + $this->assertTrue(is_array($tokenData)); + $this->assertTrue((count($tokenData) == 2)); + $this->assertTrue(isset($tokenData['id'])); + $this->assertTrue(isset($tokenData['hash'])); + $this->assertTrue(($tokenData['id'] > 0)); + $this->assertTrue((strlen($tokenData['hash']) == 32)); + + $this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1); + } + + //create a token with only 1 available use and try to authenticate it twice. + { + //Generic test to ensure we get the appropriate data back. + $tokenData = $tok->create_token(1, 'test', 'abc123', null, 1); + $this->assertTrue(is_array($tokenData)); + $this->assertTrue((count($tokenData) == 2)); + $this->assertTrue(isset($tokenData['id'])); + $this->assertTrue(isset($tokenData['hash'])); + $this->assertTrue(($tokenData['id'] > 0)); + $this->assertTrue((strlen($tokenData['hash']) == 32)); + + if(!$this->assertEqual($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']), 1)) { + $this->gfObj->debug_print($tok->tokenData($tokenData['id']),1); + } + if(!$this->assertTrue(($tok->authenticate_token($tokenData['id'], 'test', $tokenData['hash']) === null), "Able to authenticate twice on a token with only 1 use")) { + $this->gfObj->debug_print($tok->tokenData($tokenData['id'])); + } + } }//end test_basics() //-------------------------------------------------------------------------- } +class authTokenTester extends cs_authToken { + public $isTest=true; + + public function tokenData($id) { + return($this->get_token_data($id)); + } +} ?> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 17:44:19
|
Revision: 111 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=111&view=rev Author: crazedsanity Date: 2009-08-19 17:44:04 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Testing of cs_authToken & ability to create a token. Modified Paths: -------------- trunk/0.3/cs_authToken.class.php trunk/0.3/setup/authtoken_schema.pgsql.sql trunk/0.3/tests/testOfAuthToken.php Modified: trunk/0.3/cs_authToken.class.php =================================================================== --- trunk/0.3/cs_authToken.class.php 2009-08-19 17:14:22 UTC (rev 110) +++ trunk/0.3/cs_authToken.class.php 2009-08-19 17:44:04 UTC (rev 111) @@ -18,6 +18,15 @@ /** Database object. */ private $db; + /** Object that helps deal with strings. */ + private $gfObj; + + /** Name of the table */ + private $table = 'cswal_auth_token_table'; + + /** Sequence name for the given table (for PostgreSQL) */ + private $seq = 'cswal_auth_token_table_auth_token_id_seq'; + //========================================================================= public function __construct(cs_phpDB $db) { @@ -27,6 +36,7 @@ else { throw new exception(__METHOD__ .": database object not connected"); } + $this->gfObj = new cs_globalFunctions(); }//end __construct() //========================================================================= @@ -54,7 +64,46 @@ //========================================================================= + protected function create_hash_string($tokenId, $uid, $checksum, $stringToHash=NULL) { + return(md5($tokenId ."_". $uid ."_". $checksum ."_". $stringToHash)); + }//end create_hash_string() //========================================================================= + + + //========================================================================= + public function create_token($uid, $checksum, $stringToHash) { + + $this->db->beginTrans(); + + $insertData = array( + 'uid' => $uid, + 'checksum' => $checksum, + 'token' => '____INCOMPLETE____' + ); + try { + $sql = "INSERT INTO cswal_auth_token_table ". + $this->gfObj->string_from_array($insertData, 'insert', null, 'sql'); + $tokenId = $this->db->run_insert($sql, $this->seq); + + //now that we have the ID, let's create the real has string. + $finalHash = $this->create_hash_string($tokenId, $uid, $checksum, $stringToHash); + + $this->db->run_update("UPDATE ". $this->table ." SET token='". $finalHash ."' WHERE " . + "auth_token_id=". $tokenId); + + $tokenInfo = array( + 'id' => $tokenId, + 'hash' => $finalHash + ); + } + catch(exception $e) { + throw new exception(__METHOD__ .": failed to create token::: ". $e->getMessage()); + } + + return($tokenInfo); + }//end create_token() + //========================================================================= + } ?> Modified: trunk/0.3/setup/authtoken_schema.pgsql.sql =================================================================== --- trunk/0.3/setup/authtoken_schema.pgsql.sql 2009-08-19 17:14:22 UTC (rev 110) +++ trunk/0.3/setup/authtoken_schema.pgsql.sql 2009-08-19 17:44:04 UTC (rev 111) @@ -13,6 +13,8 @@ uid integer NOT NULL DEFAULT 0, checksum text NOT NULL, token text NOT NULL, + use_limit integer DEFAULT NULL, + total_uses integer NOT NULL DEFAULT 0, creation date NOT NULL DEFAULT NOW(), duration interval NOT NULL DEFAULT '1 day'::interval ); \ No newline at end of file Modified: trunk/0.3/tests/testOfAuthToken.php =================================================================== --- trunk/0.3/tests/testOfAuthToken.php 2009-08-19 17:14:22 UTC (rev 110) +++ trunk/0.3/tests/testOfAuthToken.php 2009-08-19 17:44:04 UTC (rev 111) @@ -71,7 +71,14 @@ $db = $this->create_db(); $tok = new cs_authToken($db); - + //Generic test to ensure we get the appropriate data back. + $tokenData = $tok->create_token(0, 'test', 'abc123'); + $this->assertTrue(is_array($tokenData)); + $this->assertTrue((count($tokenData) == 2)); + $this->assertTrue(isset($tokenData['id'])); + $this->assertTrue(isset($tokenData['hash'])); + $this->assertTrue(($tokenData['id'] > 0)); + $this->assertTrue((strlen($tokenData['hash']) == 32)); }//end test_basics() //-------------------------------------------------------------------------- } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 17:14:30
|
Revision: 110 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=110&view=rev Author: crazedsanity Date: 2009-08-19 17:14:22 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Beginnings of cs_authToken class, for storing of generic tokens to test against. Added Paths: ----------- trunk/0.3/cs_authToken.class.php trunk/0.3/setup/authtoken_schema.pgsql.sql trunk/0.3/tests/testOfAuthToken.php Added: trunk/0.3/cs_authToken.class.php =================================================================== --- trunk/0.3/cs_authToken.class.php (rev 0) +++ trunk/0.3/cs_authToken.class.php 2009-08-19 17:14:22 UTC (rev 110) @@ -0,0 +1,60 @@ +<?php +/* + * Created on Aug 19, 2009 + * + * SVN INFORMATION::: + * ------------------- + * Last Author::::::::: $Author$ + * Current Revision:::: $Revision$ + * Repository Location: $HeadURL$ + * Last Updated:::::::: $Date$ + */ + + +require_once(dirname(__FILE__) .'/cs_webapplibs.abstract.class.php'); + +class cs_authToken extends cs_webapplibsAbstract { + + /** Database object. */ + private $db; + + //========================================================================= + public function __construct(cs_phpDB $db) { + + if($db->is_connected()) { + $this->db = $db; + } + else { + throw new exception(__METHOD__ .": database object not connected"); + } + + }//end __construct() + //========================================================================= + + + + //========================================================================= + public function load_table() { + $file = dirname(__FILE__) .'/setup/authtoken_schema.'. $this->db->get_dbtype() .'.sql'; + + if(file_exists($file)) { + try { + $this->db->run_update(file_get_contents($file), true); + } + catch(exception $e) { + throw new exception(__METHOD__ .": error while trying to load table::: ". $e->getMessage()); + } + } + else { + throw new exception(__METHOD__ .": unsupported database type (". $this->db->get_dbtype() .")"); + } + }//end load_table() + //========================================================================= + + + + //========================================================================= + //========================================================================= + +} +?> Property changes on: trunk/0.3/cs_authToken.class.php ___________________________________________________________________ Added: svn:keywords + Id Author Revision HeadURL Date Added: trunk/0.3/setup/authtoken_schema.pgsql.sql =================================================================== --- trunk/0.3/setup/authtoken_schema.pgsql.sql (rev 0) +++ trunk/0.3/setup/authtoken_schema.pgsql.sql 2009-08-19 17:14:22 UTC (rev 110) @@ -0,0 +1,18 @@ +-- +-- SVN INFORMATION::: +-- --------------- +-- SVN Signature::::::: $Id$ +-- Last Author::::::::: $Author$ +-- Current Revision:::: $Revision$ +-- Repository Location: $HeadURL$ +-- Last Updated:::::::: $Date$ +-- + +CREATE TABLE cswal_auth_token_table ( + auth_token_id serial NOT NULL PRIMARY KEY, + uid integer NOT NULL DEFAULT 0, + checksum text NOT NULL, + token text NOT NULL, + creation date NOT NULL DEFAULT NOW(), + duration interval NOT NULL DEFAULT '1 day'::interval +); \ No newline at end of file Property changes on: trunk/0.3/setup/authtoken_schema.pgsql.sql ___________________________________________________________________ Added: svn:keywords + Id Author Revision HeadURL Date Copied: trunk/0.3/tests/testOfAuthToken.php (from rev 109, trunk/0.3/tests/testOfCSVersionParse.php) =================================================================== --- trunk/0.3/tests/testOfAuthToken.php (rev 0) +++ trunk/0.3/tests/testOfAuthToken.php 2009-08-19 17:14:22 UTC (rev 110) @@ -0,0 +1,80 @@ +<?php +/* + * Created on Jan 25, 2009 + * + * FILE INFORMATION: + * + * $HeadURL$ + * $Id$ + * $LastChangedDate$ + * $LastChangedBy$ + * $LastChangedRevision$ + */ + +require_once(dirname(__FILE__) .'/../cs_authToken.class.php'); + +class testOfCSAuthToken extends UnitTestCase { + + //-------------------------------------------------------------------------- + function __construct() { + $this->gfObj = new cs_globalFunctions; + $this->gfObj->debugPrintOpt=1; + }//end __construct() + //-------------------------------------------------------------------------- + + + + //-------------------------------------------------------------------------- + function setUp() { + $tok = new cs_authToken($this->create_db()); + try { + $tok->load_table(); + } + catch(exception $e) { + } + }//end setUp() + //-------------------------------------------------------------------------- + + + + //-------------------------------------------------------------------------- + function tearDown() { + $db = $this->create_db(); + try { + $db->run_update('DROP TABLE cswal_auth_token_table', true); + } + catch(exception $e) { + } + }//end + //-------------------------------------------------------------------------- + + + + //-------------------------------------------------------------------------- + private function create_db() { + $dbParams = array( + 'host' => constant('DB_PG_HOST'), + 'dbname' => constant('DB_PG_DBNAME'), + 'user' => constant('DB_PG_DBUSER'), + 'password' => constant('DB_PG_DBPASS'), + 'port' => constant('DB_PG_PORT') + ); + $db = new cs_phpDB(constant('DBTYPE')); + $db->connect($dbParams); + return($db); + }//end create_db() + //-------------------------------------------------------------------------- + + + //-------------------------------------------------------------------------- + function test_basics() { + $db = $this->create_db(); + $tok = new cs_authToken($db); + + + }//end test_basics() + //-------------------------------------------------------------------------- +} + + +?> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 16:13:28
|
Revision: 109 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=109&view=rev Author: crazedsanity Date: 2009-08-19 16:13:16 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Use a main abstract class which they all extend, fix require_once() paths. Modified Paths: -------------- trunk/0.3/cs_webdblogger.class.php trunk/0.3/cs_webdbupgrade.class.php Added Paths: ----------- trunk/0.3/cs_webapplibs.abstract.class.php Added: trunk/0.3/cs_webapplibs.abstract.class.php =================================================================== --- trunk/0.3/cs_webapplibs.abstract.class.php (rev 0) +++ trunk/0.3/cs_webapplibs.abstract.class.php 2009-08-19 16:13:16 UTC (rev 109) @@ -0,0 +1,20 @@ +<?php +/* + * Created on Aug 19, 2009 + * + * SVN INFORMATION::: + * ------------------- + * Last Author::::::::: $Author$ + * Current Revision:::: $Revision$ + * Repository Location: $HeadURL$ + * Last Updated:::::::: $Date$ + */ + +require_once(dirname(__FILE__) .'/cs_version.abstract.class.php'); + + +abstract class cs_webapplibsAbstract extends cs_versionAbstract { + +} + +?> Property changes on: trunk/0.3/cs_webapplibs.abstract.class.php ___________________________________________________________________ Added: svn:keywords + Id Author Revision HeadURL Date Modified: trunk/0.3/cs_webdblogger.class.php =================================================================== --- trunk/0.3/cs_webdblogger.class.php 2009-08-19 16:10:34 UTC (rev 108) +++ trunk/0.3/cs_webdblogger.class.php 2009-08-19 16:13:16 UTC (rev 109) @@ -27,9 +27,9 @@ //NOTE::: this class **REQUIRES** cs-content for its "cs_phpDB" class. -require_once(constant('LIBDIR') .'/cs-versionparse/cs_version.abstract.class.php'); +require_once(dirname(__FILE__) .'/cs_webapplibs.abstract.class.php'); -class cs_webdblogger extends cs_versionAbstract { +class cs_webdblogger extends cs_webapplibsAbstract { /** Database handle */ public $db; Modified: trunk/0.3/cs_webdbupgrade.class.php =================================================================== --- trunk/0.3/cs_webdbupgrade.class.php 2009-08-19 16:10:34 UTC (rev 108) +++ trunk/0.3/cs_webdbupgrade.class.php 2009-08-19 16:13:16 UTC (rev 109) @@ -12,10 +12,10 @@ * */ -require_once(constant('LIBDIR') .'/cs-versionparse/cs_version.abstract.class.php'); -require_once(constant('LIBDIR') .'/cs_debug.php'); +require_once(dirname(__FILE__) .'/cs_webapplibs.abstract.class.php'); + require_once(dirname(__FILE__) .'/cs_webdblogger.class.php'); -class cs_webdbupgrade extends cs_versionAbstract { +class cs_webdbupgrade extends cs_webapplibsAbstract { /** cs_fileSystem{} object: for filesystem read/write operations. */ private $fsObj; @@ -89,7 +89,6 @@ require_once(constant('LIBDIR') .'/cs-content/cs_globalFunctions.class.php'); require_once(constant('LIBDIR') .'/cs-content/cs_fileSystem.class.php'); require_once(constant('LIBDIR') .'/cs-content/cs_phpDB.class.php'); - require_once(constant('LIBDIR') .'/cs-webdblogger/cs_webdblogger.class.php'); require_once(constant('LIBDIR') .'/cs-phpxml/cs_phpxmlParser.class.php'); require_once(constant('LIBDIR') .'/cs-phpxml/cs_phpxmlCreator.class.php'); require_once(constant('LIBDIR') .'/cs-phpxml/cs_arrayToPath.class.php'); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 16:10:42
|
Revision: 108 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=108&view=rev Author: crazedsanity Date: 2009-08-19 16:10:34 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Copy tests folder for cs_versionAbstract. Added Paths: ----------- trunk/0.3/tests/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 15:47:19
|
Revision: 107 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=107&view=rev Author: crazedsanity Date: 2009-08-19 15:47:08 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Ignore Eclipse's ".project" file. Property Changed: ---------------- trunk/0.3/ Property changes on: trunk/0.3 ___________________________________________________________________ Added: svn:ignore + .project This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 15:44:59
|
Revision: 106 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=106&view=rev Author: crazedsanity Date: 2009-08-19 15:44:52 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Consolidate schema into setup files & documentation into "docs" folder. Modified Paths: -------------- trunk/0.3/docs/README.txt trunk/0.3/setup/schema.mysql.sql trunk/0.3/setup/schema.pgsql.sql Removed Paths: ------------- trunk/0.3/CREDITS trunk/0.3/LICENSE trunk/0.3/README.txt trunk/0.3/schema/ Deleted: trunk/0.3/CREDITS =================================================================== --- trunk/0.3/CREDITS 2009-08-19 15:35:35 UTC (rev 105) +++ trunk/0.3/CREDITS 2009-08-19 15:44:52 UTC (rev 106) @@ -1,3 +0,0 @@ - -Lead Developer: Dan Falconer (cra...@us...) - Deleted: trunk/0.3/LICENSE =================================================================== --- trunk/0.3/LICENSE 2009-08-19 15:35:35 UTC (rev 105) +++ trunk/0.3/LICENSE 2009-08-19 15:44:52 UTC (rev 106) @@ -1,291 +0,0 @@ -NOTE: a full HTML version of this license can be found at: -http://www.opensource.org/licenses/gpl-license.php - -It has been reproduced below without any HTML. -========================================================================== - -The GNU General Public License (GPL) - -Version 2, June 1991 - - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - -NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS Deleted: trunk/0.3/README.txt =================================================================== --- trunk/0.3/README.txt 2009-08-19 15:35:35 UTC (rev 105) +++ trunk/0.3/README.txt 2009-08-19 15:44:52 UTC (rev 106) @@ -1,30 +0,0 @@ - -=== CS Web DB Logger === -Once the appropriate schema has been built, code can be updated easily to start logging: - -//Create the class... -$this->log = new cs_webdblogger($dbObj, 'Generic Activity'); - -//Now call the logger. -$this->log->log_by_class('User viewed page', 'info', $this->userId); - - - -UNDERSTANDING THE DATABASE SCHEMA::: -I understand things best from real data, so here goes:::: - -live_cs_project=# select rca.name as category, rcl.name as class, le.description from log_event_table AS le INNER JOIN log_class_table AS rcl USING (log_class_id) INNER JOIN log_category_table AS rca USING (log_category_id) limit 5; - category | class | description -----------+--------+-------------------------- - Project | Create | Project: created record - Project | Delete | Project: deleted record - Project | Update | Project: updated record - Project | Error | Project: ERROR - Helpdesk | Create | Helpdesk: Created record -(5 rows) - -The category indicates what system it is attached to, and class is a more -generic way of indicating what type of action it is. - - -$Id$ \ No newline at end of file Modified: trunk/0.3/docs/README.txt =================================================================== --- trunk/0.3/docs/README.txt 2009-08-19 15:35:35 UTC (rev 105) +++ trunk/0.3/docs/README.txt 2009-08-19 15:44:52 UTC (rev 106) @@ -1,6 +1,39 @@ $Id$ +=== CS Web DB Logger === +Once the appropriate schema has been built, code can be updated easily to start logging: + +//Create the class... +$this->log = new cs_webdblogger($dbObj, 'Generic Activity'); + +//Now call the logger. +$this->log->log_by_class('User viewed page', 'info', $this->userId); + + + +UNDERSTANDING THE DATABASE SCHEMA::: +I understand things best from real data, so here goes:::: + +live_cs_project=# select rca.name as category, rcl.name as class, le.description from log_event_table AS le INNER JOIN log_class_table AS rcl USING (log_class_id) INNER JOIN log_category_table AS rca USING (log_category_id) limit 5; + category | class | description +----------+--------+-------------------------- + Project | Create | Project: created record + Project | Delete | Project: deleted record + Project | Update | Project: updated record + Project | Error | Project: ERROR + Helpdesk | Create | Helpdesk: Created record +(5 rows) + +The category indicates what system it is attached to, and class is a more +generic way of indicating what type of action it is. + + + + +=== CS Web DB Upgrade === + + This system is built to make upgrading a database-driven app seamless. No need to coordinate SQL or schema changes with the code updates: previously, one would have to take the entire website down, run the schema/SQL change, update the code, Modified: trunk/0.3/setup/schema.mysql.sql =================================================================== --- trunk/0.3/setup/schema.mysql.sql 2009-08-19 15:35:35 UTC (rev 105) +++ trunk/0.3/setup/schema.mysql.sql 2009-08-19 15:44:52 UTC (rev 106) @@ -92,3 +92,20 @@ -- ALTER TABLE `cswdbl_log_table` ADD CONSTRAINT `cswdbl_log_table_event_id_fkey` FOREIGN KEY (`event_id`) REFERENCES `cswdbl_event_table` (`event_id`); + + +-- This table create statement MUST work in PostgreSQL v8.2.x+ AND MySQL v5.0.x+: +-- otherwise separate schema files have to be created and the code will have to +-- do extra checking... +-- +-- The "{tableName}" portion will be replaced with the value of the configured +-- "DB_TABLE" setting. +CREATE TABLE cs_version_table ( + version_id int NOT NULL PRIMARY KEY, + project_name varchar(30) NOT NULL UNIQUE, + version_string varchar(50) NOT NULL, + version_major integer NOT NULL, + version_minor integer NOT NULL, + version_maintenance integer NOT NULL, + version_suffix varchar(20) NOT NULL +); Modified: trunk/0.3/setup/schema.pgsql.sql =================================================================== --- trunk/0.3/setup/schema.pgsql.sql 2009-08-19 15:35:35 UTC (rev 105) +++ trunk/0.3/setup/schema.pgsql.sql 2009-08-19 15:44:52 UTC (rev 106) @@ -63,3 +63,16 @@ details text NOT NULL ); +-- This table create statement MUST work in PostgreSQL v8.2.x+ AND MySQL v5.0.x+: +-- otherwise separate schema files have to be created and the code will have to +-- do extra checking... +CREATE TABLE cs_version_table ( + version_id serial NOT NULL PRIMARY KEY, + project_name varchar(30) NOT NULL UNIQUE, + version_string varchar(50) NOT NULL, + version_major integer NOT NULL, + version_minor integer NOT NULL, + version_maintenance integer NOT NULL, + version_suffix varchar(20) NOT NULL +); + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 15:35:48
|
Revision: 105 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=105&view=rev Author: crazedsanity Date: 2009-08-19 15:35:35 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Copied stuff from cs-webdbupgrade... Modified Paths: -------------- trunk/0.3/README.txt Added Paths: ----------- trunk/0.3/cs_webdbupgrade.class.php trunk/0.3/docs/ trunk/0.3/schema/ Modified: trunk/0.3/README.txt =================================================================== --- trunk/0.3/README.txt 2009-08-19 15:28:38 UTC (rev 104) +++ trunk/0.3/README.txt 2009-08-19 15:35:35 UTC (rev 105) @@ -1,4 +1,5 @@ +=== CS Web DB Logger === Once the appropriate schema has been built, code can be updated easily to start logging: //Create the class... Copied: trunk/0.3/cs_webdbupgrade.class.php (from rev 101, import/cs-webdbupgrade/trunk/0.2/cs_webdbupgrade.class.php) =================================================================== --- trunk/0.3/cs_webdbupgrade.class.php (rev 0) +++ trunk/0.3/cs_webdbupgrade.class.php 2009-08-19 15:35:35 UTC (rev 105) @@ -0,0 +1,1096 @@ +<?php +/* + * Created on Jul 2, 2007 + * + * SVN INFORMATION::: + * ------------------ + * SVN Signature::::::: $Id$ + * Last Author::::::::: $Author$ + * Current Revision:::: $Revision$ + * Repository Location: $HeadURL$ + * Last Updated:::::::: $Date$ + * + */ + +require_once(constant('LIBDIR') .'/cs-versionparse/cs_version.abstract.class.php'); +require_once(constant('LIBDIR') .'/cs_debug.php'); + +class cs_webdbupgrade extends cs_versionAbstract { + + /** cs_fileSystem{} object: for filesystem read/write operations. */ + private $fsObj; + + /** cs_globalFunctions{} object: debugging, array, and string operations. */ + protected $gfObj; + + /** Array of configuration parameters. */ + private $config = NULL; + + /** Name of primary key sequence of main table (for handling inserts with PostgreSQL) */ + private $sequenceName; + + /** Database object. */ + protected $db; + + /** Object used to log activity. */ + protected $logsObj; + + /** Name of the project as referenced in the database. */ + protected $projectName; + + /** Internal cache of the version string from the VERSION file. */ + private $versionFileVersion = NULL; + + /** Stored database version. */ + private $databaseVersion = NULL; + + /** Name (absolute location) of *.lock file that indicates an upgrade is running. */ + private $lockfile; + + /** Determines if an internal upgrade is happening (avoids some infinite loops) */ + private $internalUpgradeInProgress = false; + + /** */ + private $allowNoDBVersion=true; + + /** Log messages to store during an internal upgrade (to avoid problems) */ + private $storedLogs = array(); + private $debugLogs=array(); + + /** List of acceptable suffixes; example "1.0.0-BETA3" -- NOTE: these MUST be in + * an order that reflects newest -> oldest; "ALPHA happens before BETA, etc. */ + private $suffixList = array( + 'ALPHA', //very unstable + 'BETA', //kinda unstable, but probably useable + 'RC' //all known bugs fixed, searching for unknown ones + ); + + //========================================================================= + public function __construct($versionFileLocation, $upgradeConfigFile, $lockFile='upgrade.lock') { + + //setup configuration parameters for database connectivity. + $dbParams = array( + 'host' => constant(__CLASS__ .'-DB_CONNECT_HOST'), + 'port' => constant(__CLASS__ .'-DB_CONNECT_PORT'), + 'dbname' => constant(__CLASS__ .'-DB_CONNECT_DBNAME'), + 'user' => constant(__CLASS__ .'-DB_CONNECT_USER'), + 'password' => constant(__CLASS__ .'-DB_CONNECT_PASSWORD') + ); + $this->config['DBPARAMS'] = $dbParams; + //Check for some required constants. + $requisiteConstants = array('LIBDIR'); + if(!defined('LIBDIR')) { + throw new exception(__METHOD__ .": required constant 'LIBDIR' not set"); + } + if(!defined('SITE_ROOT')) { + throw new exception(__METHOD__ .": required constant 'SITE_ROOT' not set"); + } + + require_once(constant('LIBDIR') .'/cs-content/cs_globalFunctions.class.php'); + require_once(constant('LIBDIR') .'/cs-content/cs_fileSystem.class.php'); + require_once(constant('LIBDIR') .'/cs-content/cs_phpDB.class.php'); + require_once(constant('LIBDIR') .'/cs-webdblogger/cs_webdblogger.class.php'); + require_once(constant('LIBDIR') .'/cs-phpxml/cs_phpxmlParser.class.php'); + require_once(constant('LIBDIR') .'/cs-phpxml/cs_phpxmlCreator.class.php'); + require_once(constant('LIBDIR') .'/cs-phpxml/cs_arrayToPath.class.php'); + + $this->fsObj = new cs_fileSystem(constant('SITE_ROOT')); + $this->gfObj = new cs_globalFunctions; + if(defined('DEBUGPRINTOPT')) { + $this->gfObj->debugPrintOpt = constant('DEBUGPRINTOPT'); + } + + if(!defined(__CLASS__ .'-DB_PRIMARYKEY') || !defined(__CLASS__ .'-DB_TABLE')) { + throw new exception(__METHOD__ .": no setting for DB_TABLE or DB_PRIMARYKEY, cannot continue"); + } + else { + $this->config['DB_TABLE'] = constant(__CLASS__ .'-DB_TABLE'); + $this->config['DB_PRIMARYKEY'] = constant(__CLASS__ .'-DB_PRIMARYKEY'); + } + $this->sequenceName = $this->config['DB_TABLE'] .'_'. $this->config['DB_PRIMARYKEY'] .'_seq'; + + if(!defined('DBTYPE')) { + throw new exception(__METHOD__ .": required constant 'DBTYPE' not set"); + } + + if(!file_exists($upgradeConfigFile) || !is_readable($upgradeConfigFile)) { + throw new exception(__METHOD__ .": required upgrade config file location (". $upgradeConfigFile .") not set or unreadable"); + } + else { + $this->config['UPGRADE_CONFIG_FILE'] = $upgradeConfigFile; + } + if(!strlen($versionFileLocation) || !file_exists($versionFileLocation)) { + throw new exception(__METHOD__ .": unable to locate version file (". $versionFileLocation .")"); + } + $this->set_version_file_location($versionFileLocation); + + if(!defined(__CLASS__ .'-RWDIR') || !is_dir(constant(__CLASS__ .'-RWDIR')) || !is_readable(constant(__CLASS__ .'-RWDIR')) || !is_writable(constant(__CLASS__ .'-RWDIR'))) { + throw new exception(__METHOD__ .": missing RWDIR (". constant(__CLASS__ .'-RWDIR') .") or isn't readable/writable"); + } + else { + $this->config['RWDIR'] = constant(__CLASS__ .'-RWDIR'); + } + if(is_null($lockFile) || !strlen($lockFile)) { + $lockFile = 'upgrade.lock'; + } + $this->lockfile = $this->config['RWDIR'] .'/'. $lockFile; + + $this->db = new cs_phpDB(constant('DBTYPE')); + try { + $this->db->connect($this->config['DBPARAMS']); + } + catch(exception $e) { + throw new exception(__METHOD__ .": failed to connect to database or logger error: ". $e->getMessage()); + } + + if($this->check_lockfile()) { + //there is an existing lockfile... + throw new exception(__METHOD__ .": upgrade in progress: ". $this->fsObj->read($this->lockfile)); + } + + $this->check_internal_upgrades(); + + try { + $loggerDb = new cs_phpDB(constant('DBTYPE')); + $loggerDb->connect($this->config['DBPARAMS'], true); + $this->logsObj = new cs_webdblogger($loggerDb, "Upgrade ". $this->projectName, false); + } + catch(exception $e) { + throw new exception(__METHOD__ .": failed to create logger::: ". $e->getMessage()); + } + + $this->check_versions(false); + }//end __construct() + //========================================================================= + + + + //========================================================================= + /** + * Determine if there are any upgrades that need to be performed... + */ + private function check_internal_upgrades() { + $oldVersionFileLocation = $this->versionFileLocation; + $oldUpgradeConfigFile = $this->config['UPGRADE_CONFIG_FILE']; + $this->config['UPGRADE_CONFIG_FILE'] = dirname(__FILE__) .'/upgrades/upgrade.xml'; + + + //set a status flag so we can store log messages (for now). + $this->internalUpgradeInProgress = true; + + + //do stuff here... + $this->set_version_file_location(dirname(__FILE__) .'/VERSION'); + $this->read_version_file(); + + //if there is an error, then... uh... yeah. + try { + $this->get_database_version(); + } + catch(exception $e) { + throw new exception(__METHOD__ .": error while retrieving database version: ". $e->getMessage()); + + //try creating the version. + $this->load_initial_version(); + } + + //do upgrades here... + $this->check_versions(true); + $this->internalUpgradeInProgress = false; + + + + + //reset internal vars. + $this->set_version_file_location($oldVersionFileLocation); + $this->config['UPGRADE_CONFIG_FILE'] = $oldUpgradeConfigFile; + $this->read_version_file(); + + }//end check_internal_upgrades() + //========================================================================= + + + + //========================================================================= + /** + * Where everything begins: checks if the version held in config.xml lines-up + * with the one in the VERSION file; if it does, then it checks the version + * listed in the database. + */ + public function check_versions($performUpgrade=TRUE) { + if(!is_bool($performUpgrade) || is_null($performUpgrade)) { + $performUpgrade = true; + } + + //first, check that all files exist. + $retval = NULL; + + //check to see if the lock files for upgrading exist. + if($this->upgrade_in_progress()) { + $this->do_log("Upgrade in progress", 'notice'); + throw new exception(__METHOD__ .": upgrade in progress"); + } + else { + //okay, all files present: check the version in the VERSION file. + $versionFileVersion = $this->read_version_file(); + $dbVersion = $this->get_database_version(); + if(!is_array($dbVersion)) { + $this->load_initial_version(); + } + + $versionsDiffer = TRUE; + $retval = FALSE; + + if($this->check_for_version_conflict() == false) { + $versionsDiffer = false; + $performUpgrade = false; + } + else { + $versionsDiffer = true; + } + + if($versionsDiffer == TRUE && $performUpgrade === TRUE) { + //reset the return value, so it'll default to failure until we say otherwise. + $retval = NULL; + + //Perform the upgrade! + $this->perform_upgrade(); + } + } + + return($retval); + }//end check_versions() + //========================================================================= + + + + //========================================================================= + protected function read_version_file() { + $retval = NULL; + + //okay, all files present: check the version in the VERSION file. + $versionFileContents = $this->fsObj->read($this->versionFileLocation); + + + $versionMatches = array(); + preg_match_all('/\nVERSION: (.*)\n/', $versionFileContents, $versionMatches); + if(count($versionMatches) == 2 && count($versionMatches[1]) == 1) { + $retval = trim($versionMatches[1][0]); + $this->versionFileVersion = $this->get_full_version_string($retval); + + //now retrieve the PROJECT name. + $projectMatches = array(); + preg_match_all('/\nPROJECT: (.*)\n/', $versionFileContents, $projectMatches); + if(count($projectMatches) == 2 && count($projectMatches[1]) == 1) { + $this->projectName = trim($projectMatches[1][0]); + } + else { + $this->error_handler(__METHOD__ .": failed to find PROJECT name"); + } + } + else { + $this->error_handler(__METHOD__ .": could not find VERSION data"); + } + + return($retval); + }//end read_version_file() + //========================================================================= + + + + //========================================================================= + /** + * Read information from our config file, so we know what to expect. + */ + private function read_upgrade_config_file() { + try { + $xmlString = $this->fsObj->read($this->config['UPGRADE_CONFIG_FILE']); + } + catch(exception $e) { + throw new exception(__METHOD__ .": failed to read upgrade config file::: ". $e->getMessage()); + } + + //parse the file. + $xmlParser = new cs_phpxmlParser($xmlString); + + $config = $xmlParser->get_tree(TRUE); + + if(is_array($config['UPGRADE']) && count($config['UPGRADE'])) { + $this->config['UPGRADELIST'] = $config['UPGRADE']; + } + else { + $this->error_handler(__METHOD__ .": failed to retrieve 'UPGRADE' section; " . + "make sure upgrade.xml's ROOT element is 'UPGRADE'"); + } + }//end read_upgrade_config_file() + //========================================================================= + + + + //========================================================================= + private function perform_upgrade() { + $this->logsObj->suspendLogging=true; + //make sure there's not already a lockfile. + if($this->upgrade_in_progress()) { + //ew. Can't upgrade. + $this->error_handler(__METHOD__ .": upgrade already in progress...????"); + } + else { + $lockConfig = $this->upgrade_in_progress(TRUE); + $this->fsObj->cd("/"); + + $this->do_log("Starting upgrade process...", 'begin'); + + //TODO: not only should the "create_file()" method be run, but also do a sanity check by calling lock_file_exists(). + if($lockConfig === 0) { + //can't create the lockfile. Die. + $this->error_handler(__METHOD__ .": failed to set 'upgrade in progress'"); + } + else { + $this->do_log(__METHOD__ .": result of creating lockfile: (". $lockConfig .")", 'debug'); + + //push data into our internal "config" array. + $this->read_upgrade_config_file(); + $this->get_database_version(); + + //check for version conflicts. + $versionConflictInfo = $this->check_for_version_conflict(); + + + if($versionConflictInfo !== false) { + $this->do_log("Upgrading ". $versionConflictInfo ." versions, from " . + "(". $this->databaseVersion .") to (". $this->versionFileVersion .")", 'info'); + } + + $upgradeList = $this->get_upgrade_list(); + try { + $i=0; + $this->do_log(__METHOD__ .": starting to run through the upgrade list, starting at (". $this->databaseVersion ."), " . + "total number of upgrades to perform: ". count($upgradeList), 'debug'); + $this->db->beginTrans(__METHOD__); + foreach($upgradeList as $fromVersion=>$toVersion) { + + $details = __METHOD__ .": upgrading from ". $fromVersion ." to ". $toVersion ."... "; + $this->do_log($details, 'system'); + $this->do_single_upgrade($fromVersion, $toVersion); + $this->get_database_version(); + $i++; + + $details = __METHOD__ .": finished upgrade #". $i .", now at version (". $this->databaseVersion .")"; + $this->do_log($details, 'system'); + } + + if($i < count($upgradeList)) { + $this->do_log(__METHOD__ .": completed upgrade ". $i ." of ". count($upgradeList), 'debug'); + } + else { + if($this->databaseVersion == $this->versionFileVersion) { + $this->do_log(__METHOD__ .": finished upgrading after performing (". $i .") upgrades", 'debug'); + $this->newVersion = $this->databaseVersion; + } + else { + $this->do_log(__METHOD__ .": upgradeList::: ". $this->gfObj->debug_print($upgradeList,0), 'debug'); + $this->error_handler(__METHOD__ .": finished upgrade, but version wasn't updated (expecting '". $this->versionFileVersion ."', got '". $this->databaseVersion ."')!!!"); + } + } + $this->remove_lockfile(); + + $this->db->commitTrans(); + } + catch(exception $e) { + $transactionStatus = $this->db->get_transaction_status(false); + $this->error_handler(__METHOD__ .": transaction status=(". $transactionStatus ."), upgrade aborted:::". $e->getMessage()); + $this->db->rollbackTrans(); + } + $this->logsObj->suspendLogging=false; + $this->do_log("Upgrade process complete", 'end'); + } + } + $this->logsObj->suspendLogging=false; + $logsHandled = $this->logsObj->handle_suspended_logs(); + }//end perform_upgrade() + //========================================================================= + + + + //========================================================================= + public function upgrade_in_progress($makeItSo=FALSE) { + if($makeItSo === TRUE) { + if(strlen($this->databaseVersion)) { + $details = $this->projectName .': Upgrade from '. $this->databaseVersion .' started at '. date('Y-m-d H:i:s'); + $this->create_lockfile($details); + $retval = TRUE; + } + else { + $this->error_handler(__METHOD__ .": missing internal databaseVersion (". $this->databaseVersion .")"); + } + } + $retval = $this->check_lockfile(); + + return($retval); + }//end upgrade_in_progress() + //========================================================================= + + + + //========================================================================= + public function parse_version_string($versionString) { + if(is_null($versionString) || !strlen($versionString)) { + $this->error_handler(__METHOD__ .": invalid version string ($versionString)"); + } + + $suffix = ""; + $explodeThis = $versionString; + if(preg_match('/-[A-Z]{2,5}[0-9]{1,}/', $versionString)) { + $bits = explode('-', $versionString); + $suffix = $bits[1]; + $explodeThis = $bits[0]; + } + $tmp = explode('.', $explodeThis); + + + if(is_numeric($tmp[0]) && is_numeric($tmp[1])) { + $retval = array( + 'version_string' => $versionString, + 'version_major' => $tmp[0], + 'version_minor' => $tmp[1], + ); + if(isset($tmp[2])) { + $retval['version_maintenance'] = $tmp[2]; + } + else { + $retval['version_maintenance'] = 0; + } + + $retval['version_suffix'] = $suffix; + } + else { + $this->error_handler(__METHOD__ .": invalid version string format, requires MAJOR.MINOR syntax (". $versionString .")"); + } + + return($retval); + }//end parse_version_string() + //========================================================================= + + + + //========================================================================= + /** + * Checks for issues with versions. + * 0 == No problems. + * (string) == upgrade applicable (indicates "major"/"minor"/"maintenance"). + * NULL == encountered error + */ + private function check_for_version_conflict() { + //set a default return... + $retval = NULL; + + $this->read_version_file(); + + //parse the version strings. + $dbVersion = $this->get_database_version(); + $versionFileData = $this->parse_version_string($this->versionFileVersion); + + if($versionFileData['version_string'] == $dbVersion['version_string']) { + //good to go: no upgrade needed. + $retval = false; + } + else { + //NOTE: this seems very convoluted, but it works. + if($versionFileData['version_major'] == $dbVersion['version_major']) { + if($versionFileData['version_minor'] == $dbVersion['version_minor']) { + if($versionFileData['version_maintenance'] == $dbVersion['version_maintenance']) { + if($versionFileData['version_suffix'] == $dbVersion['version_suffix']) { + $this->error_handler(__METHOD__ .": no version upgrade detected, but version strings don't match (versionFile=". $versionFileData['version_string'] .", dbVersion=". $dbVersion['version_string'] .")"); + } + else { + $retval = "suffix"; + } + } + elseif($versionFileData['version_maintenance'] > $dbVersion['version_maintenance']) { + $retval = "maintenance"; + } + else { + $this->error_handler(__METHOD__ .": downgrading from maintenance versions is unsupported"); + } + } + elseif($versionFileData['version_minor'] > $dbVersion['version_minor']) { + $retval = "minor"; + } + else { + $this->error_handler(__METHOD__ .": downgrading minor versions is unsupported"); + } + } + elseif($versionFileData['version_major'] > $dbVersion['version_major']) { + $retval = "major"; + } + else { + $this->error_handler(__METHOD__ .": downgrading major versions is unsupported"); + } + } + + return($retval); + }//end check_for_version_conflict() + //========================================================================= + + + + //========================================================================= + private function get_database_version() { + $this->gfObj->debugPrintOpt=1; + //create a database object & attempt to read the database version. + + $sql = "SELECT * FROM ". $this->config['DB_TABLE'] ." WHERE project_name='" . + $this->gfObj->cleanString($this->projectName, 'sql') ."'"; + + $numrows = $this->db->exec($sql); + $dberror = $this->db->errorMsg(); + + if(strlen($dberror) || $numrows != 1) { + // + if(preg_match('/doesn\'t exist/', $dberror) || preg_match('/does not exist/', $dberror)) { + //add the table... + $loadTableResult = $this->load_table(); + if($loadTableResult === TRUE) { + //now try the SQL... + $numrows = $this->db->exec($sql); + $dberror = $this->db->errorMsg(); + } + else { + $this->error_handler(__METHOD__ .": no table in database, failed to create one... ORIGINAL " . + "ERROR: ". $dberror .", SCHEMA LOAD ERROR::: ". $loadTableResult); + } + } + elseif(!strlen($dberror) && $numrows == 0) { + if($this->allowNoDBVersion) { + $retval = false; + } + else { + $this->error_handler(__METHOD__ .": no version data found for (". $this->projectName .")"); + } + } + else { + $this->error_handler(__METHOD__ .": failed to retrieve version... numrows=(". $numrows ."), DBERROR::: ". $dberror); + } + } + else { + $data = $this->db->farray_fieldnames(); + $this->databaseVersion = $data['version_string']; + $retval = $this->parse_version_string($data['version_string']); + } + + return($retval); + }//end get_database_version() + //========================================================================= + + + + //========================================================================= + private function do_single_upgrade($fromVersion, $toVersion=null) { + //Use the "matching_syntax" data in the upgrade.xml file to determine the filename. + $versionIndex = "V". $this->get_full_version_string($fromVersion); + if(!isset($this->config['UPGRADELIST']['MATCHING'][$versionIndex])) { + //version-only upgrade. + $this->newVersion = $toVersion; + $this->update_database_version($toVersion); + } + else { + //scripted upgrade... + $scriptIndex = $versionIndex; + + $upgradeData = $this->config['UPGRADELIST']['MATCHING'][$versionIndex]; + + if(isset($upgradeData['TARGET_VERSION']) && count($upgradeData) > 1) { + $this->newVersion = $upgradeData['TARGET_VERSION']; + if(isset($upgradeData['SCRIPT_NAME']) && isset($upgradeData['CLASS_NAME']) && isset($upgradeData['CALL_METHOD'])) { + //good to go; it's a scripted upgrade. + $this->do_scripted_upgrade($upgradeData); + $this->update_database_version($upgradeData['TARGET_VERSION']); + } + else { + $this->error_handler(__METHOD__ .": not enough information to run scripted upgrade for ". $versionIndex); + } + } + else { + $this->error_handler(__METHOD__ .": target version not specified, unable to proceed with upgrade for ". $versionIndex); + } + } + $this->do_log("Finished upgrade to ". $this->newVersion, 'system'); + }//end do_single_upgrade() + //========================================================================= + + + + //========================================================================= + /** + * Updates information that's stored in the database, internal to cs-project, + * so the version there is consistent with all the others. + */ + protected function update_database_version($newVersionString) { + $versionInfo = $this->parse_version_string($newVersionString); + + $sql = "UPDATE ". $this->config['DB_TABLE'] ." SET version_string='". + $this->gfObj->cleanString($versionInfo['version_string'], 'sql') + ."' WHERE project_name='". + $this->gfObj->cleanString($this->projectName, 'sql') ."'"; + + + $updateRes = $this->db->run_update($sql,false); + if($updateRes == 1) { + $retval = $updateRes; + } + else { + $this->error_handler(__METHOD__ .": invalid result (". $updateRes .") "); + } + + //okay, now check that the version string matches the updated bits. + if(!$this->check_database_version($this->newVersion)) { + $this->error_handler(__METHOD__ .": database version information is invalid: (". $this->newVersion .")"); + } + + return($retval); + + }//end update_database_version() + //========================================================================= + + + + //========================================================================= + /** + * Checks consistency of version information in the database, and optionally + * against a given version string. + */ + private function check_database_version() { + //retrieve the internal version information. + if(!is_null($this->newVersion)) { + $data = $this->get_database_version(); + $versionString = $data['version_string']; + + if($versionString == $this->newVersion) { + $retval = TRUE; + } + else { + $retval = FALSE; + } + + if(!$retval) { + $this->do_log("Version check failed, versionString=(". $versionString ."), checkVersion=(". $this->newVersion .")", 'FATAL'); + } + + } + else { + $this->error_handler(__METHOD__ .": no version string given (". $this->newVersion .")"); + } + + return($retval); + }//end check_database_version() + //========================================================================= + + + + //========================================================================= + private function do_scripted_upgrade(array $upgradeData) { + $myConfigFile = $upgradeData['SCRIPT_NAME']; + + $this->do_log("Preparing to run script '". $myConfigFile ."'", 'debug'); + + //we've got the filename, see if it exists. + + $scriptsDir = dirname($this->config['UPGRADE_CONFIG_FILE']); + $fileName = $scriptsDir .'/'. $myConfigFile; + + if(file_exists($fileName)) { + + $this->do_log("(". __CLASS__ .") Performing scripted upgrade (". $myConfigFile .") from file '". $fileName ."'", 'DEBUG'); + $createClassName = $upgradeData['CLASS_NAME']; + $classUpgradeMethod = $upgradeData['CALL_METHOD']; + require_once($fileName); + + //now check to see that the class we need actually exists. + if(class_exists($createClassName)) { + $upgradeObj = new $createClassName($this->db); + if(method_exists($upgradeObj, $classUpgradeMethod)) { + $upgradeResult = $upgradeObj->$classUpgradeMethod(); + + if($upgradeResult === true) { + //yay, it worked! + $this->do_log("Upgrade succeeded (". $upgradeResult .")", 'success'); + } + else { + $this->error_handler(__METHOD__ .": upgrade failed (". $upgradeResult .")"); + } + $this->do_log("Finished running ". $createClassName ."::". $classUpgradeMethod ."(), result was (". $upgradeResult .")", 'debug'); + } + else { + $this->error_handler(__METHOD__ .": upgrade method doesn't exist (". $createClassName ."::". $classUpgradeMethod + ."), unable to perform upgrade "); + } + } + else { + $this->error_handler(__METHOD__ .": unable to locate upgrade class name (". $createClassName .")"); + } + } + else { + $this->error_handler(__METHOD__ .": upgrade filename (". $fileName .") does not exist"); + } + }//end do_scripted_upgrade() + //========================================================================= + + + + //========================================================================= + public function is_higher_version($version, $checkIfHigher) { + try { + $retval = parent::is_higher_version($version, $checkIfHigher); + } + catch(exception $e) { + $this->error_handler($e->getMessage()); + } + + return($retval); + + }//end is_higher_version() + //========================================================================= + + + + //========================================================================= + /** + * Determines list of upgrades to perform. + * + * If the current version is 1.0.1, the version file is 1.0.5, and there's a + * scripted upgrade at 1.0.4, this will update the database version to 1.0.3, + * run the scripted upgrade at 1.0.4, then update the database version to + * 1.0.5 (keeps from skipping the upgrade at 1.0.4) + */ + private function get_upgrade_list() { + $this->get_database_version(); + $dbVersion = $this->databaseVersion; + $newVersion = $this->versionFileVersion; + + $retval = array(); + if(!$this->is_higher_version($dbVersion, $newVersion)) { + $this->error_handler(__METHOD__ .": version (". $newVersion .") isn't higher than (". $dbVersion .")... something is broken"); + } + elseif(is_array($this->config['UPGRADELIST']['MATCHING'])) { + $lastVersion = $dbVersion; + foreach($this->config['UPGRADELIST']['MATCHING'] as $matchVersion=>$data) { + + $matchVersion = preg_replace('/^V/', '', $matchVersion); + if($matchVersion == $data['TARGET_VERSION']) { + $this->error_handler(__METHOD__ .": detected invalid TARGET_VERSION in (". $matchVersion ."): make sure TARGET_VERSION is higher than matching!"); + } + elseif($this->databaseVersion == $matchVersion || $this->is_higher_version($this->databaseVersion, $matchVersion)) { + //the version in MATCHING is equal to or HIGHER than our database version... make sure it is NOT + // higher than the version in our versionFile. + if(!$this->is_higher_version($this->versionFileVersion, $matchVersion)) { + if(!count($retval) && $matchVersion != $this->databaseVersion) { + $retval[$this->databaseVersion] = $matchVersion; + } + //the MATCHING version is NOT higher than the version file's version, looks ok. + $lastVersion = $data['TARGET_VERSION']; + $retval[$matchVersion] = $data['TARGET_VERSION']; + } + else { + $this->do_log(__METHOD__ .": entry in upgrade.xml (". $matchVersion .") is higher than the VERSION file (". $this->versionFileVersion .")", 'warning'); + } + } + else { + $this->do_log(__METHOD__ .": SKIPPING (". $matchVersion .")", 'debug'); + } + } + + if($lastVersion !== $newVersion && (!isset($retval[$lastVersion]) || $retval[$lastVersion] != $newVersion)) { + $retval[$lastVersion] = $newVersion; + } + } + else { + //no intermediary upgrades: just pass back the latest version. + $this->do_log(__METHOD__ .": no intermediary upgrades", 'debug'); + $retval[$dbVersion] = $this->versionFileVersion; + } + + return($retval); + + }//end get_upgrade_list() + //========================================================================= + + + + //========================================================================= + protected function parse_suffix($suffix) { + $retval = NULL; + if(strlen($suffix)) { + //determine what kind it is. + foreach($this->suffixList as $type) { + if(preg_match('/^'. $type .'/', $suffix)) { + $checkThis = preg_replace('/^'. $type .'/', '', $suffix); + if(strlen($checkThis) && is_numeric($checkThis)) { + //oooh... it's something like "BETA3" + $retval = array( + 'type' => $type, + 'number' => $checkThis + ); + } + else { + $this->error_handler(__METHOD__ .": invalid suffix (". $suffix .")"); + } + break; + } + } + } + else { + $this->error_handler(__METHOD__ .": invalid suffix (". $suffix .")"); + } + + return($retval); + }//end parse_suffix() + //========================================================================= + + + + //========================================================================= + private function fix_xml_config($config, $path=null) { + $this->xmlLoops++; + if($this->xmlLoops > 1000) { + $this->error_handler(__METHOD__ .": infinite loop detected..."); + } + + try { + $a2p = new cs_arrayToPath($config); + } + catch(exception $e) { + $this->do_log(__METHOD__ .': encountered exception: '. $e->getMessage()); + $this->error_handler($e->getMessage()); + } + if(!is_array($this->tempXmlConfig)) { + $this->tempXmlConfig = array(); + } + try { + $myA2p = new cs_arrayToPath(&$this->tempXmlConfig); + } + catch(exception $e) { + $this->do_log(__METHOD__ .': encountered exception: '. $e->getMessage()); + $this->error_handler($e->getMessage()); + } + + $myData = $a2p->get_data($path); + + if(is_array($myData)) { + if(isset($myData['type']) && $myData['type'] != 'open') { + if($myData['type'] == 'complete') { + $val = null; + if(isset($myData['value'])) { + $val = $myData['value']; + } + $oldData = $myA2p->get_data(); + $myA2p->set_data($path, $val); + $this->tempXmlConfig = $myA2p->get_data(); + } + else { + $this->error_handler(__METHOD__ .": invalid type (". $myData['type'] .")"); + } + } + else { + foreach($myData as $i=>$d) { + if(!in_array($i, array('type', 'attributes', 'value'))) { + $this->fix_xml_config($config, $path .'/'. $i); + } + } + } + } + else { + $this->error_handler(__METHOD__ .": unable to fix data on path=(". $path .")::: ". $this->gfObj->debug_print($myData,0)); + } + }//end fix_xml_config() + //========================================================================= + + + + //========================================================================= + public function load_table() { + $schemaFileLocation = dirname(__FILE__) .'/schema/schema.sql'; + $schema = file_get_contents($schemaFileLocation); + $schema = str_replace('{tableName}', $this->config['DB_TABLE'], $schema); + $schema = str_replace('{primaryKey}', $this->config['DB_PRIMARYKEY'], $schema); + $this->db->exec($schema); + + $loadTableResult = $this->db->errorMsg(); + if(!strlen($loadTableResult)) { + $loadTableResult = true; + $logRes = 'Successfully loaded'; + $logType = 'initialize'; + + //now set the initial version information... + if(strlen($this->projectName) && strlen($this->versionFileVersion)) { + $this->load_initial_version(); + } + else { + throw new exception(__METHOD__ .": missing projectName (". $this->projectName .") " . + "or versionFileVersion (". $this->versionFileVersion ."), cannot load data"); + } + } + else { + $logRes = 'Failed to load'; + $logType = 'error'; + } + $this->do_log($logRes .' table ('. $this->config['DB_TABLE'] .') into ' . + 'database::: '. $loadTableResult, $logType); + + return($loadTableResult); + }//end load_table() + //========================================================================= + + + + //========================================================================= + public function check_lockfile() { + $status = false; + if(file_exists($this->lockfile)) { + $status = true; + } + + return($status); + }//end check_lockfile() + //========================================================================= + + + + //========================================================================= + /** + * Create a *.lock file that indicates the system is in the process of + * performing an upgrade (safer than always updating the site's configuration + * file). + */ + public function create_lockfile($contents) { + if(!$this->check_lockfile()) { + if($this->fsObj->create_file($this->lockfile)) { + if(!preg_match('/\n$/', $contents)) { + $contents .= "\n"; + } + $writeRes = $this->fsObj->write($contents); + if(is_numeric($writeRes) && $writeRes > 0) { + $this->fsObj->closeFile(); + } + else { + $this->error_handler(__METHOD__ .": failed to write contents (". $contents .") to lockfile"); + } + } + else { + $this->error_handler(__METHOD__ .": failed to create lockfile (". $this->lockfile .")"); + } + } + else { + $this->error_handler(__METHOD__ .": failed to create lockfile, one already exists (". $this->lockfile .")"); + } + }//end create_lockfile() + //========================================================================= + + + + //========================================================================= + /** + * Destroy the *.lock file that indicates an upgrade is underway. + */ + private function remove_lockfile() { + if($this->check_lockfile()) { + if(!$this->fsObj->rm($this->lockfile)) { + $this->error_handler(__METHOD__ .": failed to remove lockfile (". $this->lockfile .")"); + } + } + else { + $this->error_handler(__METHOD__ .": no lockfile (". $this->lockfile .")"); + } + }//end remove_lockfile() + //========================================================================= + + + + //========================================================================= + private function get_full_version_string($versionString) { + if(strlen($versionString)) { + $bits = $this->parse_version_string($versionString); + + $fullVersion = $bits['version_major'] .'.'. $bits['version_minor'] .'.'. + $bits['version_maintenance']; + if(strlen($bits['version_suffix'])) { + $fullVersion .= '-'. $bits['version_suffix']; + } + } + else { + $this->error_handler(__METHOD__ .": no version string given"); + } + + return($fullVersion); + }//end get_full_version_string() + //========================================================================= + + + + //========================================================================= + public function error_handler($details) { + //log the error. + if(!is_object($this->logsObj)) { + throw new exception(__METHOD__ .": error while running an internal upgrade::: ". $details); + } + if($this->internalUpgradeInProgress === false) { + $this->do_log($details, 'exception in code'); + } + + //now throw an exception so other code can catch it. + throw new exception($details); + }//end error_handler() + //========================================================================= + + + + //========================================================================= + public function load_initial_version() { + //if there's an INITIAL_VERSION in the upgrade config file, use that. + $this->read_upgrade_config_file(); + $insertData = array(); + if(isset($this->config['UPGRADELIST']['INITIALVERSION'])) { + $parseThis = $this->config['UPGRADELIST']['INITIALVERSION']; + } + else { + $parseThis = $this->versionFileVersion; + } + $versionInfo = $this->parse_version_string($parseThis); + $insertData = array( + 'project_name' => $this->projectName, + 'version_string' => $versionInfo['version_string'] + ); + + $sql = 'INSERT INTO '. $this->config['DB_TABLE'] . $this->gfObj->string_from_array($insertData, 'insert'); + + if($this->db->run_insert($sql, $this->sequenceName)) { + $loadRes = true; + $this->do_log("Created data for '". $this->projectName ."' with version '". $insertData['version_string'] ."'", 'initialize'); + } + else { + $this->error_handler(__METHOD__ .": failed to load initial version::: ". $e->getMessage()); + } + + return($loadRes); + }//end load_initial_version() + //========================================================================= + + + + //========================================================================= + protected function do_log($message, $type) { + $this->debugLogs[] = array('project'=>$this->projectName,'upgradeFile'=>$this->config['UPGRADE_CONFIG_FILE'],'message'=>$message,'type'=>$type); + if($this->internalUpgradeInProgress === true) { + $this->storedLogs[] = func_get_args(); + } + else { + $this->logsObj->log_by_class($message, $type); + } + }//end do_log() + //========================================================================= + + +}//end upgrade{} + + +?> \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 15:28:47
|
Revision: 104 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=104&view=rev Author: crazedsanity Date: 2009-08-19 15:28:38 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Copied folders from cs-webdblogger... Added Paths: ----------- trunk/0.3/README.txt trunk/0.3/cs_webdblogger.class.php trunk/0.3/setup/ trunk/0.3/upgrades/ Copied: trunk/0.3/README.txt (from rev 101, import/cs-webdblogger/trunk/0.2/README.txt) =================================================================== --- trunk/0.3/README.txt (rev 0) +++ trunk/0.3/README.txt 2009-08-19 15:28:38 UTC (rev 104) @@ -0,0 +1,29 @@ + +Once the appropriate schema has been built, code can be updated easily to start logging: + +//Create the class... +$this->log = new cs_webdblogger($dbObj, 'Generic Activity'); + +//Now call the logger. +$this->log->log_by_class('User viewed page', 'info', $this->userId); + + + +UNDERSTANDING THE DATABASE SCHEMA::: +I understand things best from real data, so here goes:::: + +live_cs_project=# select rca.name as category, rcl.name as class, le.description from log_event_table AS le INNER JOIN log_class_table AS rcl USING (log_class_id) INNER JOIN log_category_table AS rca USING (log_category_id) limit 5; + category | class | description +----------+--------+-------------------------- + Project | Create | Project: created record + Project | Delete | Project: deleted record + Project | Update | Project: updated record + Project | Error | Project: ERROR + Helpdesk | Create | Helpdesk: Created record +(5 rows) + +The category indicates what system it is attached to, and class is a more +generic way of indicating what type of action it is. + + +$Id$ \ No newline at end of file Copied: trunk/0.3/cs_webdblogger.class.php (from rev 101, import/cs-webdblogger/trunk/0.2/cs_webdblogger.class.php) =================================================================== --- trunk/0.3/cs_webdblogger.class.php (rev 0) +++ trunk/0.3/cs_webdblogger.class.php 2009-08-19 15:28:38 UTC (rev 104) @@ -0,0 +1,864 @@ +<?php +/* + * Created on Mar 8, 2007 + * + * NOTICE::: this class was derived from the logsClass.php found in cs-projet v1.2, found + * at URL: https://cs-project.svn.sourceforge.net/svnroot/cs-project/trunk/1.2/lib/logsClass.php + * Last SVN Signature (from cs-project v1.2): "logsClass.php 819 2008-02-09 10:01:10Z crazedsanity" + * + * SVN INFORMATION::: + * ------------------ + * SVN Signature::::::: $Id$ + * Last Author::::::::: $Author$ + * Current Revision:::: $Revision$ + * Repository Location: $HeadURL$ + * Last Updated:::::::: $Date$ + * + * + * Each class that's trying to log should have an internal var statically set to indicates what category + * it is: this allows them to call a method within this and tell it ONLY what "class" the log should be + * under, so this class can determine the appropriate log_event_id. This avoids having to hard-code + * too many id's that might need to be changed later. Yay, dynamic code! + * + * QUERY TO GET LAST COUPLE OF LOGS:::: + SELECT l.log_id as id, l.creation, l.event_id as lid, le.description AS event, l.details + FROM cswdbl_log_table AS l INNER JOIN cswdbl_event_table AS le USING (event_id) ORDER BY log_id DESC LIMIT 25; + */ + +//NOTE::: this class **REQUIRES** cs-content for its "cs_phpDB" class. + +require_once(constant('LIBDIR') .'/cs-versionparse/cs_version.abstract.class.php'); + +class cs_webdblogger extends cs_versionAbstract { + /** Database handle */ + public $db; + + /** Cache of all records in the class table */ + private $logClassCache = array(); + + /** Cache of all records in the attribute table */ + private $attributeCache=array(); + + /** The category_id value to use, set on class creation. */ + private $logCategoryId = null; + + /** Default uid (users.id) to log under when no uid is available */ + private $defaultUid = 0; + + /** Category to use when logging a database error */ + //TODO: make SURE this category is correct... + private $databaseCategory = 1; + + /** Check to see if setup has been performed (avoids running it multiple times) **/ + private $setupComplete=false; + + /** Last SQL file handled */ + protected $lastSQLFile=null; + + /** Global functions class from cs-content */ + protected $gfObj; + + protected $pendingLogs; + private $suspendLogging=false; + + /** List of tables keyed off an internal reference name. */ + protected $tables = array( + 'category' => 'cswdbl_category_table', + 'class' => 'cswdbl_class_table', + 'event' => 'cswdbl_event_table', + 'log' => 'cswdbl_log_table', + 'attrib' => 'cswdbl_attribute_table', + 'logAttrib' => 'cswdbl_log_attribute_table' + ); + + /** List of sequences keyed off an internal reference name (MUST match references above) */ + protected $seqs = array( + 'category' => "cswdbl_category_table_category_id_seq", + 'class' => "cswdbl_class_table_class_id_seq", + 'event' => "cswdbl_event_table_event_id_seq", + 'log' => "cswdbl_log_table_log_id_seq", + 'attrib' => "cswdbl_attribute_table_attribute_id_seq", + 'logAttrib' => "cswdbl_log_attribute_table_log_attribute_id_seq" + ); + + //========================================================================= + /** + * The constructor. + */ + public function __construct(cs_phpDB &$db, $logCategory=null, $checkForUpgrades=true) { + //assign the database object. + $this->db = $db; + + $this->set_version_file_location(dirname(__FILE__) . '/VERSION'); + + //Make sure the version of cs_phpDB is HIGHER THAN (not equal to) 1.0.0-ALPHA8, + // which added some methods that are required. + $mustBeHigherThan = '1.2-ALPHA8'; + if(!$this->is_higher_version($mustBeHigherThan, $this->db->get_version())) { + throw new exception(__METHOD__ .": requires cs_phpDB of higher than v". $mustBeHigherThan,1); + } + + $this->gfObj = new cs_globalFunctions; + + //see if there's an upgrade to perform... + if($checkForUpgrades === true) { + $this->suspendLogging = true; + $upgObj = new cs_webdbupgrade(dirname(__FILE__) . '/VERSION', dirname(__FILE__) .'/upgrades/upgrade.xml'); + $upgObj->check_versions(true); + $this->suspendLogging = false; + $this->handle_suspended_logs(); + } + + //assign the category_id. + if(strlen($logCategory)) { + if(!is_numeric($logCategory)) { + //attempt to retreive the logCategoryId (assuming they passed a name) + $this->logCategoryId = $this->get_category_id($logCategory); + } + else { + //it was numeric: set it! + $this->logCategoryId = $logCategory; + } + } + + //check for a uid in the session. + $this->defaultUid = $this->get_uid(); + + + //build our cache. + $this->build_cache(); + }//end __construct() + //========================================================================= + + + + //========================================================================= + /** + * Execute the entire contents of the given file (with absolute path) as SQL. + */ + final public function run_sql_file($filename) { + if(!is_object($this->fsObj)) { + if(class_exists('cs_fileSystem')) { + $fsObj = new cs_fileSystem; + } + else { + throw new exception(__METHOD__ .": required library (cs_fileSystem) not found"); + } + } + + $this->lastSQLFile = $filename; + + $fileContents = $fsObj->read($filename); + try { + $this->db->run_update($fileContents, true); + $this->build_cache(); + $retval = TRUE; + } + catch(exception $e) { + $retval = FALSE; + } + + return($retval); + }//end run_sql_file() + //========================================================================= + + + + //========================================================================= + /** + * Build internal cache to avoid extra queries. + */ + private function build_cache() { + //build query, run it, check for errors. + $sql = "SELECT class_id, lower(class_name) as name FROM ". $this->tables['class']; + + try { + $data = $this->db->run_query($sql, 'name', 'class_id'); + + if(is_array($data)) { + $this->logClassCache = $data; + } + elseif($data == false) { + $this->logClassCache = array(); + } + else { + throw new exception(__METHOD__ .": unknown data returned: ". $this->gfObj->debug_var_dump($data,0)); + } + } + catch(exception $e) { + throw new exception(__METHOD__ .": failed to build internal class cache::: ". $e->getMessage()); + } + + //now build cache for attributes. + $sql = "SELECT attribute_id, lower(attribute_name) AS attribute_name FROM ". $this->tables['attrib']; + + try { + $data = $this->db->run_query($sql, 'attribute_name', 'attribute_id'); + + if(is_array($data)) { + $this->attributeCache = $data; + } + elseif($data == false) { + $this->attributeCache = array(); + } + else { + throw new exception(__METHOD__ .": unknown data returned: ". $this->gfObj->debug_var_dump($data,0)); + } + } + catch(exception $e) { + throw new exception(__METHOD__ .": error occurred while retrieving attribute cache::: ". $e->getMessage()); + } + }//end build_cache() + //========================================================================= + + + + //========================================================================= + /** + * Retrieve log_class_id value from the given name, or insert a new one. + */ + private function get_class_id($name) { + $name = strtolower($name); + + //get the id. + if(isset($this->logClassCache[$name])) { + //set the id. + $retval = $this->logClassCache[$name]; + } + else { + //create the class & then rebuild cache. + $retval = $this->create_class($name); + $this->build_cache(); + } + + return($retval); + }//end get_class_id() + //========================================================================= + + + + //========================================================================= + /** + * Retrieve log_event_id based on the given class name & the internal + * logCategoryId value. + */ + function get_event_id($logClassName) { + $sqlArr = array( + 'class_id' => $this->get_class_id($logClassName), + 'category_id' => $this->logCategoryId + ); + $sql = "SELECT event_id FROM ". $this->tables['event'] ." WHERE " . + $this->gfObj->string_from_array($sqlArr, 'select', NULL, 'numeric'); + + try { + $data = $this->db->run_query($sql); + + + if($data === false) { + //no records & no error: create one. + $retval = $this->auto_insert_record($sqlArr['class_id']); + } + elseif(is_array($data) && isset($data['event_id'])) { + $retval = $data['event_id']; + } + else { + throw new exception(__METHOD__ .": invalid data returned::: ". $this->gfObj->debug_var_dump($data,0)); + } + } + catch(exception $e) { + throw new exception(__METHOD__ .": failed to retrieve event_id::: ". $e->getMessage()); + } + + return($retval); + }//end get_event_id() + //========================================================================= + + + + //========================================================================= + /** + * The primary means of building log entries: use log_dberror() to log an + * error with a bit more capabilities; throws the details of the error as + * an exception. + */ + public function log_by_class($details, $className="error", $uid=NULL, array $logAttribs=NULL) { + + if($this->suspendLogging === true) { + $this->pendingLogs[] = func_get_args(); + $retval = count($this->pendingLogs) -1; + } + else { + if(count($this->pendingLogs)) { + $this->handle_suspended_logs(); + } + + //make sure there's a valid class name. + if(!strlen($className) || is_null($className)) { + $className = 'error'; + } + + //make sure we've got a uid to log under. + if(is_null($uid) || !is_numeric($uid)) { + //set it. + $uid = $this->defaultUid; + } + + //determine the log_event_id. + try { + $logEventId = $this->get_event_id($className); + } + catch(Exception $e) { + throw new exception(__METHOD__ .": while attempting to retrieve logEventId, encountered an " . + "exception:::\n". $e->getMessage() ."\n\nCLASS: $className\nDETAILS: $details"); + } + + //check to see what uid to use. + $myUid = $this->get_uid(); + + //okay, setup an array of all the data we need. + $cleanStringArr = array( + 'event_id' => 'numeric', + 'uid' => 'numeric', + 'affected_uid' => 'numeric', + 'details' => 'sql' + ); + $sqlArr = array ( + 'event_id' => $this->gfObj->cleanString($logEventId, 'numeric'), + 'uid' => $myUid, + 'affected_uid' => $uid, + 'details' => $details + ); + + //build, run, error-checking. + $sql = "INSERT INTO ". $this->tables['log'] ." ". $this->gfObj->string_from_array($sqlArr, 'insert', NULL, $cleanStringArr, TRUE); + + try { + $newId = $this->db->run_insert($sql, $this->seqs['log']); + + if(is_numeric($newId) && $newId > 0) { + $retval = $newId; + + if(is_array($logAttribs) && count($logAttribs)) { + $this->create_log_attributes($newId, $logAttribs); + } + } + else { + throw new exception(__METHOD__ .": failed to insert id or invalid return (". $this->gfObj->debug_var_dump($newId,0) .")"); + } + } + catch(exception $e) { + throw new exception(__METHOD__ .": error while creating log::: ". $e->getMessage()); + } + } + + return($retval); + }//end log_by_class() + //========================================================================= + + + + //========================================================================= + /** + * Logs an error like log_by_class(), but also throws an exception. + */ + public function log_dberror($details, $uid=NULL, $skipCurrentCatLog=FALSE) { + //set the error for the current category. + if(!$skipCurrentCatLog && ($this->logCategoryId !== $this->databaseCategory)) { + //yep, log it! + $this->log_by_class($details, 'error', $uid); + } + + //now log the database error. + $originalCategoryId = $this->logCategoryId; + $this->logCategoryId = $this->databaseCategory; + $retval = $this->log_by_class($details, 'error', $uid); + $this->logCategoryId = $originalCategoryId; + + throw new exception(__METHOD__ .": encountered error::: $details"); + }//end log_dberror() + //========================================================================= + + + + //========================================================================= + /** + * Attempts to auto-recover if a class was requested that doesn't exist. + */ + private function auto_insert_record($logClassId) { + //generate a default name + + $className = $this->get_class_name($logClassId); + $categoryName = $this->get_category_name($this->logCategoryId); + + $details = ucwords($categoryName) .": ". ucwords($className); + + if(strlen($details) <= 4) { + //something bad happened (i.e. details="0: 0") + throw new exception(__METHOD__ .": failed to recover with class_id=(". $logClassId .") " . + "AND category_id=(". $this->logCategoryId ."), details=(". $details .")"); + } + else { + //create the sql array. + $sqlArr = array ( + 'class_id' => $logClassId, + 'category_id' => $this->logCategoryId, + 'description' => "'". $this->gfObj->cleanString($details, 'sql') ."'" + ); + + //now run the insert. + $sql = 'INSERT INTO '. $this->tables['event'] .' '. $this->gfObj->string_from_array($sqlArr, 'insert'); + + try { + $newId = $this->db->run_insert($sql, $this->seqs['event']); + + if(is_numeric($newId) && $newId > 0) { + $retval = $newId; + } + else { + throw new exception(__METHOD__ .": unable to insert id or bad return::: ". $this->gfObj->debug_var_dump($newId,0)); + } + } + catch(exception $e) { + throw new exception(__METHOD__ .": failed to create record::: ". $e->getMessage()); + } + } + + return($retval); + }//end auto_insert_record() + //========================================================================= + + + + //========================================================================= + /** + * Retrieves logs with the given criteria. + */ + public function get_logs(array $criteria, array $orderBy=NULL, $limit=20) { + //set a default for the limit. + if(!is_numeric($limit) || $limit < 1) { + //set it again. + $limit = 20; + } + + if(is_null($orderBy) || count($orderBy) < 1) { + //set it. + $orderBy = array( + 'log_id DESC' + ); + } + + //set the fields that can be used, along with what alias for the table & cleaning type to use on the data. + $allowedCritFields = array( + 'class_id' => array('cl', 'numeric'), + 'category_id' => array('ca', 'numeric'), + 'uid' => array('l', 'numeric'), + 'affected_uid' => array('l', 'numeric'), + 'creation' => array('l', 'sql') + ); + + //loop through the data to create our cleaned, prefixed array of criteria. + $sqlArr = array(); + foreach($criteria AS $field => $value) { + //is this field in the allowed list? + if(isset($allowedCritFields[$field])) { + //grab data for this field. + $myFieldData = $allowedCritFields[$field]; + $cleanStringArg = $myFieldData[1]; + + //clean the data. + if($field == 'creation' && is_numeric($value)) { + $value = $this->gfObj->cleanString($value, 'numeric'); + $cleanedData = ">= (NOW() - interval '". $value ." hours')"; + } + else { + $cleanedData = $this->gfObj->cleanString($value, $cleanStringArg); + } + + //set the prefixed column name. + $prefixedName = $myFieldData[0] .'.'. $field; + + //now add it to our array. + $sqlArr[$prefixedName] = $cleanedData; + } + } + + + //build the criteria. + $sqlArr['ca.category_id'] = '>0'; + $critString = $this->gfObj->string_from_array($sqlArr, 'select'); + + //check if "timeperiod" is in there (it's special) + if(isset($criteria['timeperiod']) && isset($criteria['timeperiod']['start']) && isset($criteria['timeperiod']['end'])) { + //add it in! + $myTime = $criteria['timeperiod']; + $addThis = "(l.creation >= '". $myTime['start'] ."'::date AND l.creation <= '". $myTime['end'] ."'::date + interval '1 day')"; + $critString = create_list($critString, $addThis, ' AND '); + } + + $orderString = $this->gfObj->string_from_array($orderBy, 'limit'); + $sql = "select " . + "l.creation, " . + "l.log_id, " . + "l.uid, " . + "cl.class_name, " . + "ca.category_name, " . + "ev.description, " . + "l.details " . + "FROM ". $this->tables['log'] ." AS l " . + "INNER JOIN ". $this->tables['event'] ." AS ev ON (l.event_id=ev.event_id) " . + "INNER JOIN ". $this->tables['class'] ." AS cl ON (cl.class_id=ev.class_id) " . + "INNER JOIN ". $this->tables['category'] ." AS ca ON (ca.category_id=ev.category_id) " . + "WHERE " . $critString . " " . + "ORDER BY " . + "log_id DESC " . + "LIMIT ". $limit; + + try { + //run it. + $data = $this->db->run_query($sql, 'log_id'); + + $retval = array(); + if(is_array($data)) { + $retval = $data; + } + } + catch(exception $e) { + throw new exception(__METHOD__ .": failed to retrieve logs::: ". $e->getMessage()); + } + + return($retval); + }//end get_logs() + //========================================================================= + + + + //========================================================================= + /** + * Uses arbitrary criteria to retrieve the last X log entries. + */ + public function get_recent_logs($numEntries=null) { + if(!is_numeric($numEntries) || $numEntries < 1) { + $numEntries = 20; + } + + //set the criteria so we only get the last few entries. + $retval = $this->get_logs(array(), NULL, $numEntries); + return($retval); + }//end get_recent_logs() + //========================================================================= + + + + //========================================================================= + /** + * Retrieve category_id from the given name. + */ + private function get_category_id($catName) { + if(strlen($catName) && is_string($catName)) { + $catName = trim($catName); + $sql = "SELECT category_id FROM ". $this->tables['category'] ." WHERE lower(category_name) = '". strtolower($catName) ."'"; + + try { + + $data = $this->db->run_query($sql); + + $numrows = $this->db->numRows(); + if($numrows == 1 && is_array($data) && isset($data['category_id']) && is_numeric($data['category_id'])) { + $retval = $data['category_id']; + } + elseif($data === false) { + $retval = $this->create_log_category($catName); + } + elseif($numrows > 1) { + throw new exception(__METHOD__ .": found too many records (". $numrows .")"); + } + else { + throw new exception(__METHOD__ .": unknown error (bad data in array?)"); + } + } + catch(exception $e) { + if($this->setupComplete === true) { + throw new exception(__METHOD__ .": encountered error::: ". $e->getMessage()); + } + else { + $mySchemaFile = dirname(__FILE__) .'/setup/schema.'. $this->db->get_dbtype() .'.sql'; + if(file_exists($mySchemaFile)) { + $this->setupComplete = true; + $this->run_sql_file($mySchemaFile); + + //Create the default category. + $this->create_log_category('Database'); + + $retval = $this->create_log_category($catName); + } + else { + throw new exception(__METHOD__ .": missing schema file (". $mySchemaFile ."), can't run setup"); + } + } + } + } + else { + throw new exception(__METHOD__ .": category name (". $catName .") is invalid"); + } + + return($retval); + }//end get_category_id() + //========================================================================= + + + + //========================================================================= + /** + * Create a category_id based on the given name. + */ + private function create_log_category($catName) { + $sql = "INSERT INTO ". $this->tables['category'] ." (category_name) VALUES ('". + $this->gfObj->cleanString($catName, 'sql') ."')"; + + try { + $newId = $this->db->run_insert($sql, $this->seqs['category']); + + if(is_numeric($newId) && $newId > 0) { + $retval = $newId; + } + else { + throw new exception(__METHOD__ .": invalid data returned for " . + "category::: ". $this->gfObj->debug_var_dump($newId,0)); + } + } + catch(exception $e) { + throw new exception(__METHOD__ .": error encountered while trying to " . + "create category::: ". $e->getMessage()); + } + + return($retval); + }//end create_log_category() + //========================================================================= + + + + //========================================================================= + /** + * Create a log_class_id based on the given name. + */ + private function create_class($className) { + $sql = "INSERT INTO ". $this->tables['class'] ." (class_name) VALUES ('". + $this->gfObj->cleanString($className, 'sql') ."')"; + + + try { + $newId = $this->db->run_insert($sql, $this->seqs['class']); + + if(is_numeric($newId) && $newId > 0) { + $retval = $newId; + } + else { + throw new exception(__METHOD__ .": failed to insert class or invalid " . + "id::: ". $this->gfObj->debug_var_dump($newId,0)); + } + } + catch(exception $e) { + throw new exception(__METHOD__ .": error encountered while creating log " . + "class::: ". $e->getMessage()); + } + + return($retval); + }//end create_class() + //========================================================================= + + + + //========================================================================= + /** + * Retrieve class name from the given id. + */ + private function get_class_name($classId) { + if(is_numeric($classId)) { + $sql = "SELECT class_name FROM ". $this->tables['class'] ." WHERE class_id=". $classId; + + try { + $data = $this->db->run_query($sql); + + if(is_array($data) && isset($data['class_name']) && $this->db->numRows() == 1) { + $className = $data['class_name']; + } + else { + throw new exception(__METHOD__ .": failed to retrieve class " . + "name, or invalid return data::: ". $this->gfObj->debug_print($data,0)); + } + } + catch(exception $e) { + throw new exception(__METHOD__ .": error encountered while " . + "retrieving class name::: ". $e->getMessage()); + } + + } + else { + throw new exception(__METHOD__ .": invalid class ID (". $classId .")"); + } + + return($className); + }//end get_class_name() + //========================================================================= + + + + //========================================================================= + /** + * Retrieve category name from the given ID. + */ + private function get_category_name($categoryId) { + if(is_numeric($categoryId)) { + $sql = "SELECT category_name FROM ". $this->tables['category'] ." WHERE category_id=". $categoryId; + + try { + $data = $this->db->run_query($sql); + + if(is_array($data) && isset($data['category_name']) && $this->db->numRows() == 1) { + $categoryName = $data['category_name']; + } + else { + throw new exception(__METHOD__ .": failed to retrieve " . + "category name::: ". $this->gfObj->debug_var_dump($data,0)); + } + } + catch(exception $e) { + throw new exception(__METHOD__ .": error encountered while " . + "retrieving category name::: ". $e->getMessage()); + } + } + else { + throw new exception(__METHOD__ .": invalid category ID (". $categoryId .")"); + } + + return($categoryName); + }//end get_category_name() + //========================================================================= + + + + //========================================================================= + public function __get($var) { + return($this->$var); + }//end __get() + //========================================================================= + + + + //========================================================================= + public function __set($var, $newVal) { + $res = false; + switch($var) { + case 'suspendLogging': + $this->$var = $newVal; + if($newVal === false) { + #$this->handle_suspended_logs(); + } + $res = true; + break; + + case 'logCategory': + case 'logCategoryId': + $this->logCategoryId = $this->get_category_id($newVal); + $res = true; + break; + } + return($res); + }//end __set() + //========================================================================= + + + + //========================================================================= + public function handle_suspended_logs() { + $retval = 0; + $debugThis = array(); + if($this->suspendLogging === false && count($this->pendingLogs)) { + $myLogs = $this->pendingLogs; + $this->build_cache(); + $this->pendingLogs = array(); + foreach($myLogs as $i=>$args) { + //this is potentially deadly: call self recursively to log the items prevously suspended. + $newId = call_user_func_array(array($this, 'log_by_class'), $args); + + $debugThis[$newId] = $args; + $retval++; + } + } + return($retval); + }//end handle_suspended_logs() + //========================================================================= + + + + //========================================================================= + public function get_uid() { + $myUid = $this->defaultUid; + //check for a uid in the session. + if(is_array($_SESSION) && isset($_SESSION['uid']) && is_numeric($_SESSION['uid'])) { + //got an ID in the session. + $myUid = $_SESSION['uid']; + } + return($myUid); + }//end get_uid() + //========================================================================= + + + + //========================================================================= + private function create_attribute($attribName, $buildCache=true) { + + $myId = null; + if(isset($this->attributeCache[strtolower($attribName)])) { + $myId = $this->attributeCache[strtolower($attribName)]; + } + else { + $sql = "INSERT INTO ". $this->tables['attrib'] ." (attribute_name) " . + "VALUES ('". $this->gfObj->cleanString($attribName, 'sql_insert') ."')"; + + try { + $myId = $this->db->run_insert($sql, $this->seqs['attrib']); + } + catch(exception $e) { + throw new exception(__METHOD__ .": fatal error while creating attribute (". $attribName .")::: ". $e->getMessage()); + } + } + + if($buildCache) { + $this->build_cache(); + } + + return($myId); + }//end create_attribute() + //========================================================================= + + + + //========================================================================= + private function create_log_attributes($logId, array $attribs) { + $myIds = array(); + foreach($attribs as $name=>$val) { + $insertData = array( + 'log_id' => $logId, + 'attribute_id' => $this->create_attribute($name, false), + 'value_text' => $val + ); + $sql = "INSERT INTO ". $this->tables['logAttrib'] ." ". + $this->gfObj->string_from_array($insertData, 'insert'); + + try { + $myIds[$name][] = $this->db->run_insert($sql, $this->seqs['logAttrib']); + } + catch(exception $e) { + throw new exception(__METHOD__ .": fatal error while creating log attribute " . + "(". $name .")::: ". $e->getMessage()); + } + } + $this->build_cache(); + + }//end create_log_attributes() + //========================================================================= + + +}//end logsClass{} +?> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 15:27:47
|
Revision: 103 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=103&view=rev Author: crazedsanity Date: 2009-08-19 15:27:38 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Import of cs-versionparse. Added Paths: ----------- trunk/0.3/CREDITS trunk/0.3/LICENSE trunk/0.3/VERSION trunk/0.3/cs_version.abstract.class.php Copied: trunk/0.3/CREDITS (from rev 101, import/cs-versionparse/trunk/0.1/CREDITS) =================================================================== --- trunk/0.3/CREDITS (rev 0) +++ trunk/0.3/CREDITS 2009-08-19 15:27:38 UTC (rev 103) @@ -0,0 +1,3 @@ + +Lead Developer: Dan Falconer (cra...@us...) + Copied: trunk/0.3/LICENSE (from rev 101, import/cs-versionparse/trunk/0.1/LICENSE) =================================================================== --- trunk/0.3/LICENSE (rev 0) +++ trunk/0.3/LICENSE 2009-08-19 15:27:38 UTC (rev 103) @@ -0,0 +1,291 @@ +NOTE: a full HTML version of this license can be found at: +http://www.opensource.org/licenses/gpl-license.php + +It has been reproduced below without any HTML. +========================================================================== + +The GNU General Public License (GPL) + +Version 2, June 1991 + + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + +NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS Copied: trunk/0.3/VERSION (from rev 101, import/cs-versionparse/trunk/0.1/VERSION) =================================================================== --- trunk/0.3/VERSION (rev 0) +++ trunk/0.3/VERSION 2009-08-19 15:27:38 UTC (rev 103) @@ -0,0 +1,6 @@ +## Stores the current version of the cs-versionparse system, and it's source. +## Please do NOT modify this file. + +VERSION: 0.3.0 +PROJECT: cs-webapplibs +$HeadURL$ \ No newline at end of file Copied: trunk/0.3/cs_version.abstract.class.php (from rev 101, import/cs-versionparse/trunk/0.1/cs_version.abstract.class.php) =================================================================== --- trunk/0.3/cs_version.abstract.class.php (rev 0) +++ trunk/0.3/cs_version.abstract.class.php 2009-08-19 15:27:38 UTC (rev 103) @@ -0,0 +1,398 @@ +<?php +/* + * Created on January 01, 2009 by Dan Falconer + * + * SVN INFORMATION::: + * ------------------- + * Last Author::::::::: $Author$ + * Current Revision:::: $Revision$ + * Repository Location: $HeadURL$ + * Last Updated:::::::: $Date$ + */ + +abstract class cs_versionAbstract { + + public $isTest = FALSE; + + + + private $versionFileLocation=null; + private $fullVersionString; + private $suffixList = array( + 'ALPHA', //very unstable + 'BETA', //kinda unstable, but probably useable + 'RC' //all known bugs fixed, searching for unknown ones + ); + + + + abstract public function __construct(); + + + + //========================================================================= + /** + * Retrieve our version string from the VERSION file. + */ + final public function get_version($asArray=false) { + $retval = NULL; + + $this->auto_set_version_file(); + + if(file_exists($this->versionFileLocation)) { + $myMatches = array(); + $findIt = preg_match('/VERSION: (.+)/', file_get_contents($this->versionFileLocation), $matches); + + if($findIt == 1 && count($matches) == 2) { + $fullVersionString = $matches[1]; + $versionInfo = $this->parse_version_string($fullVersionString); + $this->fullVersionString = $this->build_full_version_string($versionInfo); + + + if($asArray) { + $retval = $versionInfo; + $retval['version_string'] = $this->fullVersionString; + } + else { + $retval = $this->build_full_version_string($versionInfo); + } + } + else { + throw new exception(__METHOD__ .": failed to retrieve version string in file " . + "(". $this->versionFileLocation .")"); + } + } + else { + throw new exception(__METHOD__ .": failed to retrieve version information, file " . + "(". $this->versionFileLocation .") does not exist or was not set"); + } + + return($retval); + }//end get_version() + //========================================================================= + + + + //========================================================================= + public function __get($var) { + return($this->$var); + }//end __get() + //========================================================================= + + + + //========================================================================= + final public function get_project() { + $retval = NULL; + $this->auto_set_version_file(); + if(file_exists($this->versionFileLocation)) { + $myMatches = array(); + $findIt = preg_match('/PROJECT: (.+)/', file_get_contents($this->versionFileLocation), $matches); + + if($findIt == 1 && count($matches) == 2 && strlen($matches[1])) { + $retval = $matches[1]; + } + else { + throw new exception(__METHOD__ .": failed to retrieve project string"); + } + } + else { + throw new exception(__METHOD__ .": failed to retrieve project information"); + } + + return($retval); + }//end get_project() + //========================================================================= + + + + //========================================================================= + public function set_version_file_location($location) { + if(file_exists($location)) { + $this->versionFileLocation = $location; + } + else { + throw new exception(__METHOD__ .": invalid location of VERSION file (". $location .")"); + } + }//end set_version_file_location() + //========================================================================= + + + + //========================================================================= + protected function auto_set_version_file() { + if(!strlen($this->versionFileLocation)) { + $bt = debug_backtrace(); + foreach($bt as $callNum=>$data) { + if(strlen($data['class'])) { + if($data['class'] != __CLASS__) { + $dir = dirname($data['file']); + if(preg_match('/tests$/', $dir)) { + $dir = preg_replace('/\/tests$/', '', $dir); + } + elseif(preg_match('/test$/', $dir)) { + $dir = preg_replace('/\/test$/', '', $dir); + } + break; + } + } + else { + throw new exception(__METHOD__ .": failed to locate the calling class in backtrace"); + } + } + + if(file_exists($dir .'/VERSION')) { + $this->set_version_file_location($dir .'/VERSION'); + } + else { + throw new exception(__METHOD__ .": failed to automatically set version file (tried ". $dir ."/VERSION)"); + } + } + }//end auto_set_version_file() + //========================================================================= + + + + //========================================================================= + /** + * + * TODO: add logic to split apart the suffix (i.e. "-ALPHA5" broken into "ALPHA" and "5"). + */ + public function parse_version_string($version) { + if(is_string($version) && strlen($version) && preg_match('/\./', $version)) { + $version = preg_replace('/ /', '', $version); + + $pieces = explode('.', $version); + $retval = array( + 'version_major' => $pieces[0], + 'version_minor' => $pieces[1] + ); + if(isset($pieces[2]) && strlen($pieces[2])) { + $retval['version_maintenance'] = $pieces[2]; + } + else { + $retval['version_maintenance'] = 0; + } + + if(preg_match('/-/', $retval['version_maintenance'])) { + $bits = explode('-', $retval['version_maintenance']); + $retval['version_maintenance'] = $bits[0]; + $suffix = $bits[1]; + } + elseif(preg_match('/-/', $retval['version_minor'])) { + $bits = explode('-', $retval['version_minor']); + $retval['version_minor'] = $bits[0]; + $suffix = $bits[1]; + } + else { + $suffix = ""; + } + $retval['version_suffix'] = $suffix; + } + else { + throw new exception(__METHOD__ .": invalid version string passed (". $version .")"); + } + + return($retval); + }//end parse_version_string() + //========================================================================= + + + + //========================================================================= + public function build_full_version_string(array $versionInfo) { + $requiredIndexes = array( + 'version_major', 'version_minor', 'version_maintenance', 'version_suffix' + ); + + $missing=""; + $count=0; + foreach($requiredIndexes as $indexName) { + if(isset($versionInfo[$indexName])) { + $count++; + } + else { + if(strlen($missing)) { + $missing .= ", ". $indexName; + } + else { + $missing = $indexName; + } + } + } + + if($count == count($requiredIndexes) && !strlen($missing)) { + $suffix = $versionInfo['version_suffix']; + unset($versionInfo['version_suffix']); + + $retval = ""; + foreach($versionInfo as $name=>$value) { + if(strlen($retval)) { + $retval .= ".". $value; + } + else { + $retval = $value; + } + } + if(strlen($suffix)) { + $retval .= "-". $suffix; + } + } + else { + throw new exception(__METHOD__ .": missing indexes in given array (". $missing .")"); + } + + return($retval); + + }//end build_full_version_string() + //========================================================================= + + + + //========================================================================= + public function is_higher_version($version, $checkIfHigher) { + $retval = FALSE; + $this->gfObj = new cs_globalFunctions; + if(!is_string($version) || !is_string($checkIfHigher)) { + throw new exception(__METHOD__ .": no valid version strings, version=(". $version ."), checkIfHigher=(". $checkIfHigher .")"); + } + elseif($version == $checkIfHigher) { + $retval = FALSE; + } + else { + $curVersionArr = $this->parse_version_string($version); + $checkVersionArr = $this->parse_version_string($checkIfHigher); + + unset($curVersionArr['version_string'], $checkVersionArr['version_string']); + + + $curVersionSuffix = $curVersionArr['version_suffix']; + $checkVersionSuffix = $checkVersionArr['version_suffix']; + + + unset($curVersionArr['version_suffix']); + + foreach($curVersionArr as $index=>$versionNumber) { + $checkThis = $checkVersionArr[$index]; + + if(is_numeric($checkThis) && is_numeric($versionNumber)) { + //set them as integers. + settype($versionNumber, 'int'); + settype($checkThis, 'int'); + + if($checkThis > $versionNumber) { + $retval = TRUE; + break; + } + elseif($checkThis == $versionNumber) { + //they're equal... + } + else { + //TODO: should there maybe be an option to throw an exception (freak out) here? + } + } + else { + throw new exception(__METHOD__ .": ". $index ." is not numeric in one of the strings " . + "(versionNumber=". $versionNumber .", checkThis=". $checkThis .")"); + } + } + + //now deal with those damnable suffixes, but only if the versions are so far identical: if + // the "$checkIfHigher" is actually higher, don't bother (i.e. suffixes don't matter when + // we already know there's a major, minor, or maintenance version that's also higher. + if($retval === FALSE) { + //EXAMPLE: $version="1.0.0-BETA3", $checkIfHigher="1.1.0" + // Moving from a non-suffixed version to a suffixed version isn't supported, but the inverse is: + // i.e. (1.0.0-BETA3 to 1.0.0) is okay, but (1.0.0 to 1.0.0-BETA3) is NOT. + // Also: (1.0.0-BETA3 to 1.0.0-BETA4) is okay, but (1.0.0-BETA4 to 1.0.0-BETA3) is NOT. + if(strlen($curVersionSuffix) && strlen($checkVersionSuffix) && $curVersionSuffix == $checkVersionSuffix) { + //matching suffixes. + } + elseif(strlen($curVersionSuffix) || strlen($checkVersionSuffix)) { + //we know the suffixes are there and DO match. + if(strlen($curVersionSuffix) && strlen($checkVersionSuffix)) { + //okay, here's where we do some crazy things... + $curVersionData = $this->parse_suffix($curVersionSuffix); + $checkVersionData = $this->parse_suffix($checkVersionSuffix); + + if($curVersionData['type'] == $checkVersionData['type']) { + //got the same suffix type (like "BETA"), check the number. + if($checkVersionData['number'] > $curVersionData['number']) { + //new version's suffix number higher than current... + $retval = TRUE; + } + elseif($checkVersionData['number'] == $curVersionData['number']) { + //new version's suffix number is EQUAL TO current... + $retval = FALSE; + } + else { + //new version's suffix number is LESS THAN current... + $retval = FALSE; + } + } + else { + //not the same suffix... see if the new one is higher. + $suffixValues = array_flip($this->suffixList); + if($suffixValues[$checkVersionData['type']] > $suffixValues[$curVersionData['type']]) { + $retval = TRUE; + } + else { + //current suffix type is higher... + } + } + + } + elseif(strlen($curVersionSuffix) && !strlen($checkVersionSuffix)) { + //i.e. "1.0.0-BETA1" to "1.0.0" --->>> OKAY! + $retval = TRUE; + } + elseif(!strlen($curVersionSuffix) && strlen($checkVersionSuffix)) { + //i.e. "1.0.0" to "1.0.0-BETA1" --->>> NOT ACCEPTABLE! + } + } + else { + //no suffix to care about + } + } + } + + return($retval); + + }//end is_higher_version() + //========================================================================= + + + + //========================================================================= + protected function parse_suffix($suffix) { + $retval = NULL; + if(strlen($suffix)) { + //determine what kind it is. + foreach($this->suffixList as $type) { + if(preg_match('/^'. $type .'/', $suffix)) { + $checkThis = preg_replace('/^'. $type .'/', '', $suffix); + if(strlen($checkThis) && is_numeric($checkThis)) { + //oooh... it's something like "BETA3" + $retval = array( + 'type' => $type, + 'number' => $checkThis + ); + } + else { + throw new exception(__METHOD__ .": invalid suffix (". $suffix .")"); + } + break; + } + } + } + else { + throw new exception(__METHOD__ .": invalid suffix (". $suffix .")"); + } + + return($retval); + }//end parse_suffix() + //========================================================================= + + +} +?> \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 15:25:44
|
Revision: 102 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=102&view=rev Author: crazedsanity Date: 2009-08-19 15:25:32 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Trunk + 0.3 folder, for bleeding-edge development. NOTE::: starting @ 0.3 instead of 0.1 to avoid overlap from the 3 existing libs, which were at max of 0.2.x... Added Paths: ----------- trunk/ trunk/0.3/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 15:18:52
|
Revision: 2 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=2&view=rev Author: crazedsanity Date: 2009-08-19 15:18:36 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Initial layout for importing the other libraries. Added Paths: ----------- import/cs-versionparse/ import/cs-webdblogger/ import/cs-webdbupgrade/ Property Changed: ---------------- import/ Property changes on: import ___________________________________________________________________ Added: svn:ignore + .project This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cra...@us...> - 2009-08-19 15:08:57
|
Revision: 1 http://cs-webapplibs.svn.sourceforge.net/cs-webapplibs/?rev=1&view=rev Author: crazedsanity Date: 2009-08-19 15:08:50 +0000 (Wed, 19 Aug 2009) Log Message: ----------- Added Paths: ----------- import/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |