diff options
Diffstat (limited to 'src/SemanticScuttle')
27 files changed, 8727 insertions, 0 deletions
diff --git a/src/SemanticScuttle/Service/bookmark2tagservice.php b/src/SemanticScuttle/Service/bookmark2tagservice.php new file mode 100644 index 0000000..918fb5b --- /dev/null +++ b/src/SemanticScuttle/Service/bookmark2tagservice.php @@ -0,0 +1,478 @@ +<?php +class Bookmark2TagService { + var $db; + var $tablename; + + function &getInstance(&$db) { + static $instance; + if (!isset($instance)) + $instance =& new Bookmark2TagService($db); + return $instance; + } + + function Bookmark2TagService(&$db) { + $this->db =& $db; + $this->tablename = $GLOBALS['tableprefix'] .'bookmarks2tags'; + } + + function isNotSystemTag($var) { + if (utf8_substr($var, 0, 7) == 'system:') + return false; + else + return true; + } + + function attachTags($bookmarkid, $tags, $fromApi = false, $extension = NULL, $replace = true, $fromImport = false) { + // Make sure that categories is an array of trimmed strings, and that if the categories are + // coming in from an API call to add a bookmark, that underscores are converted into strings. + + if (!is_array($tags)) { + $tags = trim($tags); + if ($tags != '') { + if (substr($tags, -1) == ',') { + $tags = substr($tags, 0, -1); + } + if ($fromApi) { + $tags = explode(' ', $tags); + } else { + $tags = explode(',', $tags); + } + } else { + $tags = null; + } + } + + $tagservice =& ServiceFactory::getServiceInstance('TagService'); + $tags = $tagservice->normalize($tags); + + + $tags_count = is_array($tags)?count($tags):0; + + for ($i = 0; $i < $tags_count; $i++) { + $tags[$i] = trim(strtolower($tags[$i])); + if ($fromApi) { + include_once(dirname(__FILE__) .'/../functions.inc.php'); + $tags[$i] = convertTag($tags[$i], 'in'); + } + } + + if ($tags_count > 0) { + // Remove system tags + $tags = array_filter($tags, array($this, "isNotSystemTag")); + + // Eliminate any duplicate categories + $temp = array_unique($tags); + $tags = array_values($temp); + } else { + // Unfiled + $tags[] = 'system:unfiled'; + } + + // Media and file types + if (!is_null($extension)) { + include_once(dirname(__FILE__) .'/../functions.inc.php'); + + if ($keys = multi_array_search($extension, $GLOBALS['filetypes'])) { + $tags[] = 'system:filetype:'. $extension; + $tags[] = 'system:media:'. array_shift($keys); + } + } + + // Imported + if ($fromImport) { + $tags[] = 'system:imported'; + } + + $this->db->sql_transaction('begin'); + + if ($replace) { + if (!$this->deleteTagsForBookmark($bookmarkid)){ + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not attach tags (deleting old ones failed)', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + } + + $bs =& ServiceFactory::getServiceInstance('BookmarkService'); + $tts =& ServiceFactory::getServiceInstance('Tag2TagService'); + + // Create links between tags + foreach($tags as $key => $tag) { + if(strpos($tag, '=')) { + // case "=" + $pieces = explode('=', $tag); + $nbPieces = count($pieces); + if($nbPieces > 1) { + for($i = 0; $i < $nbPieces-1; $i++) { + $bookmark = $bs->getBookmark($bookmarkid); + $uId = $bookmark['uId']; + $tts->addLinkedTags($pieces[$i], $pieces[$i+1], '=', $uId); + } + $tags[$key] = $pieces[0]; // Attach just the last tag to the bookmark + } + } else { + // case ">" + $pieces = explode('>', $tag); + $nbPieces = count($pieces); + if($nbPieces > 1) { + for($i = 0; $i < $nbPieces-1; $i++) { + $bookmark = $bs->getBookmark($bookmarkid); + $uId = $bookmark['uId']; + $tts->addLinkedTags($pieces[$i], $pieces[$i+1], '>', $uId); + } + $tags[$key] = $pieces[$nbPieces-1]; // Attach just the last tag to the bookmark + } + } + + + } + + // Add the categories to the DB. + for ($i = 0; $i < count($tags); $i++) { + if ($tags[$i] != '') { + $values = array( + 'bId' => intval($bookmarkid), + 'tag' => $tags[$i] + ); + + if (!$this->hasTag($bookmarkid, $tags[$i])) { + $sql = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values); + if (!($dbresult =& $this->db->sql_query($sql))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not attach tags', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + } + } + } + $this->db->sql_transaction('commit'); + return true; + } + + function deleteTag($uId, $tag) { + $bs =& ServiceFactory::getServiceInstance('BookmarkService'); + + $query = 'DELETE FROM '. $this->getTableName(); + $query.= ' USING '. $this->getTableName() .', '. $bs->getTableName(); + $query.= ' WHERE '. $this->getTableName() .'.bId = '. $bs->getTableName() .'.bId'; + $query.= ' AND '. $bs->getTableName() .'.uId = '. $uId; + $query.= ' AND '. $this->getTableName() .'.tag = "'. $this->db->sql_escape($tag) .'"'; + + if (!($dbresult =& $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not delete tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + return true; + } + + function deleteTagsForBookmark($bookmarkid) { + if (!is_int($bookmarkid)) { + message_die(GENERAL_ERROR, 'Could not delete tags (invalid bookmarkid)', '', __LINE__, __FILE__, $query); + return false; + } + + $query = 'DELETE FROM '. $this->getTableName() .' WHERE bId = '. intval($bookmarkid); + + if (!($dbresult =& $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not delete tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + return true; + } + + /* Allow deletion in admin page */ + function deleteTagsForUser($uId) {
+ $qmask = 'DELETE FROM %s USING %s, %s WHERE %s.bId = %s.bId AND %s.uId = %d';
+ $query = sprintf($qmask,
+ $this->getTableName(),
+ $this->getTableName(),
+ $GLOBALS['tableprefix'].'bookmarks',
+ $this->getTableName(),
+ $GLOBALS['tableprefix'].'bookmarks',
+ $GLOBALS['tableprefix'].'bookmarks',
+ $uId);
+
+ if (!($dbresult =& $this->db->sql_query($query))) {
+ message_die(GENERAL_ERROR, 'Could not delete tags', '', __LINE__, __FILE__, $query, $this->db);
+ return false;
+ }
+
+ return true;
+ } + + function &getTagsForBookmark($bookmarkid) { + if (!is_numeric($bookmarkid)) { + message_die(GENERAL_ERROR, 'Could not get tags (invalid bookmarkid)', '', __LINE__, __FILE__, $query); + return false; + } + + $query = 'SELECT tag FROM '. $this->getTableName() .' WHERE bId = '. intval($bookmarkid) .' AND LEFT(tag, 7) <> "system:" ORDER BY id ASC'; + + if (!($dbresult =& $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not get tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $tags = array(); + while ($row =& $this->db->sql_fetchrow($dbresult)) { + $tags[] = $row['tag']; + } + $this->db->sql_freeresult($dbresult); + return $tags; + } + + function &getTags($userid = NULL) { + $userservice =& ServiceFactory::getServiceInstance('UserService'); + $logged_on_user = $userservice->getCurrentUserId(); + + $query = 'SELECT T.tag, COUNT(B.bId) AS bCount FROM '. $GLOBALS['tableprefix'] .'bookmarks AS B INNER JOIN '. $userservice->getTableName() .' AS U ON B.uId = U.'. $userservice->getFieldName('primary') .' INNER JOIN '. $GLOBALS['tableprefix'] .'bookmarks2tags AS T ON B.bId = T.bId'; + + $conditions = array(); + if (!is_null($userid)) { + $conditions['U.'. $userservice->getFieldName('primary')] = intval($userid); + if ($logged_on_user != $userid) + $conditions['B.bStatus'] = 0; + } else { + $conditions['B.bStatus'] = 0; + } + + $query .= ' WHERE '. $this->db->sql_build_array('SELECT', $conditions) .' AND LEFT(T.tag, 7) <> "system:" GROUP BY T.tag ORDER BY bCount DESC, tag'; + + if (!($dbresult =& $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not get tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $output = $this->db->sql_fetchrowset($dbresult); + $this->db->sql_freeresult($dbresult); + return $output; + } + + + // Returns the tags related to the specified tags; i.e. attached to the same bookmarks + function &getRelatedTags($tags, $for_user = NULL, $logged_on_user = NULL, $limit = 10) { + $conditions = array(); + // Only count the tags that are visible to the current user. + if ($for_user != $logged_on_user || is_null($for_user)) + $conditions['B.bStatus'] = 0; + + if (!is_null($for_user)) + $conditions['B.uId'] = $for_user; + + // Set up the tags, if need be. + if (is_numeric($tags)) + $tags = NULL; + if (!is_array($tags) and !is_null($tags)) + $tags = explode('+', trim($tags)); + + $tagcount = count($tags); + for ($i = 0; $i < $tagcount; $i++) { + $tags[$i] = trim($tags[$i]); + } + + // Set up the SQL query. + $query_1 = 'SELECT DISTINCTROW T0.tag, COUNT(B.bId) AS bCount FROM '. $GLOBALS['tableprefix'] .'bookmarks AS B, '. $this->getTableName() .' AS T0'; + $query_2 = ''; + $query_3 = ' WHERE B.bId = T0.bId '; + if (count($conditions) > 0) + $query_4 = ' AND '. $this->db->sql_build_array('SELECT', $conditions); + else + $query_4 = ''; + // Handle the parts of the query that depend on any tags that are present. + for ($i = 1; $i <= $tagcount; $i++) { + $query_2 .= ', '. $this->getTableName() .' AS T'. $i; + $query_4 .= ' AND T'. $i .'.bId = B.bId AND T'. $i .'.tag = "'. $this->db->sql_escape($tags[$i - 1]) .'" AND T0.tag <> "'. $this->db->sql_escape($tags[$i - 1]) .'"'; + } + $query_5 = ' AND LEFT(T0.tag, 7) <> "system:" GROUP BY T0.tag ORDER BY bCount DESC, T0.tag'; + $query = $query_1 . $query_2 . $query_3 . $query_4 . $query_5; + + if (! ($dbresult =& $this->db->sql_query_limit($query, $limit)) ){ + message_die(GENERAL_ERROR, 'Could not get related tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + $output = $this->db->sql_fetchrowset($dbresult); + $this->db->sql_freeresult($dbresult); + return $output; + } + + // Returns the most popular tags used for a particular bookmark hash + function &getRelatedTagsByHash($hash, $limit = 20) { + $userservice = & ServiceFactory :: getServiceInstance('UserService'); + $sId = $userservice->getCurrentUserId(); + // Logged in + if ($userservice->isLoggedOn()) { + $arrWatch = $userservice->getWatchList($sId); + // From public bookmarks or user's own + $privacy = ' AND ((B.bStatus = 0) OR (B.uId = '. $sId .')'; + // From shared bookmarks in watchlist + foreach ($arrWatch as $w) { + $privacy .= ' OR (B.uId = '. $w .' AND B.bStatus = 1)'; + } + $privacy .= ') '; + // Not logged in + } else { + $privacy = ' AND B.bStatus = 0 '; + } + + $query = 'SELECT T.tag, COUNT(T.tag) AS bCount FROM '.$GLOBALS['tableprefix'].'bookmarks AS B LEFT JOIN '.$GLOBALS['tableprefix'].'bookmarks2tags AS T ON B.bId = T.bId WHERE B.bHash = "'. $hash .'" '. $privacy .'AND LEFT(T.tag, 7) <> "system:" GROUP BY T.tag ORDER BY bCount DESC'; + + if (!($dbresult =& $this->db->sql_query_limit($query, $limit))) { + message_die(GENERAL_ERROR, 'Could not get related tags for this hash', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + $output = $this->db->sql_fetchrowset($dbresult); + $this->db->sql_freeresult($dbresult); + return $output; + } + + function &getAdminTags($limit = 30, $logged_on_user = NULL, $days = NULL) { + // look for admin ids + $userservice = & ServiceFactory :: getServiceInstance('UserService'); + $adminIds = $userservice->getAdminIds(); + + // ask for their tags + return $this->getPopularTags($adminIds, $limit, $logged_on_user, $days); + } + + function &getContactTags($user, $limit = 30, $logged_on_user = NULL, $days = NULL) { + // look for contact ids + $userservice = & ServiceFactory :: getServiceInstance('UserService'); + $contacts = $userservice->getWatchlist($user); + + // add the user (to show him/her also his/her tags) + if(!is_null($logged_on_user)) { + $contacts[] = $logged_on_user; + } + + // ask for their tags + return $this->getPopularTags($contacts, $limit, $logged_on_user, $days); + } + + // $users can be {NULL, an id, an array of id} + function &getPopularTags($user = NULL, $limit = 30, $logged_on_user = NULL, $days = NULL) { + // Only count the tags that are visible to the current user. + if (($user != $logged_on_user) || is_null($user) || ($user === false)) + $privacy = ' AND B.bStatus = 0'; + else + $privacy = ''; + + if (is_null($days) || !is_int($days)) + $span = ''; + else + $span = ' AND B.bDatetime > "'. date('Y-m-d H:i:s', time() - (86400 * $days)) .'"'; + + $query = 'SELECT T.tag, COUNT(T.bId) AS bCount FROM '. $this->getTableName() .' AS T, '. $GLOBALS['tableprefix'] .'bookmarks AS B WHERE '; + if (is_null($user) || ($user === false)) { + $query .= 'B.bId = T.bId AND B.bStatus = 0'; + } elseif(is_array($user)) { + $query .= ' (1 = 0'; //tricks + foreach($user as $u) { + $query .= ' OR B.uId = '. $this->db->sql_escape($u) .' AND B.bId = T.bId'; + } + $query .= ' )'; + } else { + $query .= 'B.uId = '. $this->db->sql_escape($user) .' AND B.bId = T.bId'. $privacy; + } + $query .= $span .' AND LEFT(T.tag, 7) <> "system:" GROUP BY T.tag ORDER BY bCount DESC, tag'; + + if (!($dbresult =& $this->db->sql_query_limit($query, $limit))) { + message_die(GENERAL_ERROR, 'Could not get popular tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $output = $this->db->sql_fetchrowset($dbresult); + $this->db->sql_freeresult($dbresult); + return $output; + } + + function hasTag($bookmarkid, $tag) { + $query = 'SELECT COUNT(*) AS tCount FROM '. $this->getTableName() .' WHERE bId = '. intval($bookmarkid) .' AND tag ="'. $this->db->sql_escape($tag) .'"'; + + if (! ($dbresult =& $this->db->sql_query($query)) ) { + message_die(GENERAL_ERROR, 'Could not find tag', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + if ($row =& $this->db->sql_fetchrow($dbresult)) { + if ($row['tCount'] > 0) { + $output = true; + } + } + $output = false; + $this->db->sql_freeresult($dbresult); + return $output; + } + + function renameTag($userid, $old, $new, $fromApi = false) { + $bookmarkservice =& ServiceFactory::getServiceInstance('BookmarkService'); + $tagservice =& ServiceFactory::getServiceInstance('TagService'); + + if (is_null($userid) || is_null($old) || is_null($new)) + return false; + + // Find bookmarks with old tag + $bookmarksInfo =& $bookmarkservice->getBookmarks(0, NULL, $userid, $old); + $bookmarks =& $bookmarksInfo['bookmarks']; + + // Delete old tag + $this->deleteTag($userid, $old); + + // Attach new tags + $new = $tagservice->normalize($new); + + foreach(array_keys($bookmarks) as $key) { + $row =& $bookmarks[$key]; + $this->attachTags($row['bId'], $new, $fromApi, NULL, false); + } + + return true; + } + + function &tagCloud($tags = NULL, $steps = 5, $sizemin = 90, $sizemax = 225, $sortOrder = NULL) { + + if (is_null($tags) || count($tags) < 1) { + $output = false; + return $output; + } + + $min = $tags[count($tags) - 1]['bCount']; + $max = $tags[0]['bCount']; + + for ($i = 1; $i <= $steps; $i++) { + $delta = ($max - $min) / (2 * $steps - $i); + $limit[$i] = $i * $delta + $min; + } + $sizestep = ($sizemax - $sizemin) / $steps; + foreach ($tags as $row) { + $next = false; + for ($i = 1; $i <= $steps; $i++) { + if (!$next && $row['bCount'] <= $limit[$i]) { + $size = $sizestep * ($i - 1) + $sizemin; + $next = true; + } + } + $tempArray = array('size' => $size .'%'); + $row = array_merge($row, $tempArray); + $output[] = $row; + } + + if ($sortOrder == 'alphabet_asc') { + usort($output, create_function('$a,$b','return strcasecmp(utf8_deaccent($a["tag"]), utf8_deaccent($b["tag"]));')); + } + + return $output; + } + + function deleteAll() { + $query = 'TRUNCATE TABLE `'. $this->getTableName() .'`'; + $this->db->sql_query($query); + } + + + // Properties + function getTableName() { return $this->tablename; } + function setTableName($value) { $this->tablename = $value; } +} +?> diff --git a/src/SemanticScuttle/Service/bookmarkservice.php b/src/SemanticScuttle/Service/bookmarkservice.php new file mode 100644 index 0000000..f119593 --- /dev/null +++ b/src/SemanticScuttle/Service/bookmarkservice.php @@ -0,0 +1,552 @@ +<?php +class BookmarkService { + var $db; + var $tablename; + + function & getInstance(& $db) { + static $instance; + if (!isset ($instance)) + $instance = & new BookmarkService($db); + return $instance; + } + + function BookmarkService(& $db) { + $this->db = & $db; + $this->tablename = $GLOBALS['tableprefix'] .'bookmarks'; + } + + function _getbookmark($fieldname, $value, $all = false) { + if (!$all) { + $userservice = & ServiceFactory :: getServiceInstance('UserService'); + $sId = $userservice->getCurrentUserId(); + $range = ' AND uId = '. $sId; + } else { + $range = ''; + } + + $query = 'SELECT * FROM '. $this->getTableName() .' WHERE '. $fieldname .' = "'. $this->db->sql_escape($value) .'"'. $range; + + if (!($dbresult = & $this->db->sql_query_limit($query, 1, 0))) { + message_die(GENERAL_ERROR, 'Could not get bookmark', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + if ($row =& $this->db->sql_fetchrow($dbresult)) { + $output = $row; + } else { + $output = false; + } + $this->db->sql_freeresult($dbresult); + return $output; + } + + function & getBookmark($bid, $include_tags = false) { + if (!is_numeric($bid)) + return; + + $sql = 'SELECT * FROM '. $this->getTableName() .' WHERE bId = '. $this->db->sql_escape($bid); + + if (!($dbresult = & $this->db->sql_query($sql))) + message_die(GENERAL_ERROR, 'Could not get vars', '', __LINE__, __FILE__, $sql, $this->db); + + if ($row = & $this->db->sql_fetchrow($dbresult)) { + if ($include_tags) { + $b2tservice = & ServiceFactory :: getServiceInstance('Bookmark2TagService'); + $row['tags'] = $b2tservice->getTagsForBookmark($bid); + } + $output = $row; + } else { + $output = false; + } + $this->db->sql_freeresult($dbresult); + return $output; + } + + function getBookmarkByAddress($address) { + $hash = md5($address); + return $this->getBookmarkByHash($hash); + } + + function getBookmarkByHash($hash) { + return $this->_getbookmark('bHash', $hash, true); + } + + /* Counts bookmarks for a user. $range = {'public', 'shared', 'private', 'all'}*/ + function countBookmarks($uId, $range = 'public') { + $sql = 'SELECT COUNT(*) FROM '. $GLOBALS['tableprefix'] .'bookmarks'; + $sql.= ' WHERE uId = '.$uId; + switch ($range) { + case 'all': + //no constraints + break; + case 'private': + $sql.= ' AND bStatus = 2'; + break; + case 'shared': + $sql.= ' AND bStatus = 1'; + break; + case 'public': + default: + $sql.= ' AND bStatus = 0'; + break; + } + + if (!($dbresult = & $this->db->sql_query($sql))) { + message_die(GENERAL_ERROR, 'Could not get vars', '', __LINE__, __FILE__, $sql, $this->db); + } + return $this->db->sql_fetchfield(0, 0); + } + + /** + * Check if a bookmark may be edited by the current user + * + * @param integer|array $bookmark Bookmark uId or bookmark array + * + * @return boolean True if allowed + */ + function editAllowed($bookmark) + { + if (!is_numeric($bookmark) && (!is_array($bookmark) + || !is_numeric($bookmark['bId'])) + ) { + return false; + } + + if (!is_array($bookmark) + && !($bookmark = $this->getBookmark($bookmark)) + ) { + return false; + } + + $userservice = & ServiceFactory::getServiceInstance('UserService'); + $user = $userservice->getCurrentUser(); + + //user has to be either admin, or owner + if ($GLOBALS['adminsCanModifyBookmarksFromOtherUsers'] + && $userservice->isAdmin($user) + ) { + return true; + } else { + return ($bookmark['uId'] == $user['uId']); + } + } + + function bookmarkExists($address = false, $uid = NULL) { + if (!$address) { + return; + } + + $address = $this->normalize($address); + + $crit = array ('bHash' => md5($address)); + if (isset ($uid)) { + $crit['uId'] = $uid; + } + + $sql = 'SELECT COUNT(*) FROM '. $GLOBALS['tableprefix'] .'bookmarks WHERE '. $this->db->sql_build_array('SELECT', $crit); + if (!($dbresult = & $this->db->sql_query($sql))) { + message_die(GENERAL_ERROR, 'Could not get vars', '', __LINE__, __FILE__, $sql, $this->db); + } + if($this->db->sql_fetchfield(0, 0) > 0) { + $output = true; + } else { + $output = false; + } + $this->db->sql_freeresult($dbresult); + return $output; + } + + // Adds a bookmark to the database. + // Note that date is expected to be a string that's interpretable by strtotime(). + function addBookmark($address, $title, $description, $privateNote, $status, $categories, $date = NULL, $fromApi = false, $fromImport = false, $sId = -1) { + if($sId == -1) { + $userservice = & ServiceFactory :: getServiceInstance('UserService'); + $sId = $userservice->getCurrentUserId(); + } + + $address = $this->normalize($address); + + // Get the client's IP address and the date; note that the date is in GMT. + if (getenv('HTTP_CLIENT_IP')) + $ip = getenv('HTTP_CLIENT_IP'); + else + if (getenv('REMOTE_ADDR')) + $ip = getenv('REMOTE_ADDR'); + else + $ip = getenv('HTTP_X_FORWARDED_FOR'); + + // Note that if date is NULL, then it's added with a date and time of now, and if it's present, + // it's expected to be a string that's interpretable by strtotime(). + if (is_null($date) || $date == '') + $time = time(); + else + $time = strtotime($date); + $datetime = gmdate('Y-m-d H:i:s', $time); + + // Set up the SQL insert statement and execute it. + $values = array('uId' => intval($sId), 'bIp' => $ip, 'bDatetime' => $datetime, 'bModified' => $datetime, 'bTitle' => $title, 'bAddress' => $address, 'bDescription' => $description, 'bPrivateNote' => $privateNote, 'bStatus' => intval($status), 'bHash' => md5($address)); + $sql = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values); + $this->db->sql_transaction('begin'); + if (!($dbresult = & $this->db->sql_query($sql))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not insert bookmark', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + // Get the resultant row ID for the bookmark. + $bId = $this->db->sql_nextid($dbresult); + if (!isset($bId) || !is_int($bId)) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not insert bookmark', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + + $uriparts = explode('.', $address); + $extension = end($uriparts); + unset($uriparts); + + $b2tservice = & ServiceFactory :: getServiceInstance('Bookmark2TagService'); + if (!$b2tservice->attachTags($bId, $categories, $fromApi, $extension, false, $fromImport)) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not insert bookmark', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + $this->db->sql_transaction('commit'); + // Everything worked out, so return the new bookmark's bId. + return $bId; + } + + function updateBookmark($bId, $address, $title, $description, $privateNote, $status, $categories, $date = NULL, $fromApi = false) { + if (!is_numeric($bId)) + return false; + + // Get the client's IP address and the date; note that the date is in GMT. + if (getenv('HTTP_CLIENT_IP')) + $ip = getenv('HTTP_CLIENT_IP'); + else + if (getenv('REMOTE_ADDR')) + $ip = getenv('REMOTE_ADDR'); + else + $ip = getenv('HTTP_X_FORWARDED_FOR'); + + $moddatetime = gmdate('Y-m-d H:i:s', time()); + + $address = $this->normalize($address); + + //check if a new address ($address) doesn't already exist for another bookmark from the same user + $bookmark = $this->getBookmark($bId); + if($bookmark['bAddress'] != $address && $this->bookmarkExists($address, $bookmark['uId'])) { + message_die(GENERAL_ERROR, 'Could not update bookmark (URL already existing = '.$address.')', '', __LINE__, __FILE__); + return false; + } + + // Set up the SQL update statement and execute it. + $updates = array('bModified' => $moddatetime, 'bTitle' => $title, 'bAddress' => $address, 'bDescription' => $description, 'bPrivateNote' => $privateNote, 'bStatus' => $status, 'bHash' => md5($address)); + + if (!is_null($date)) { + $datetime = gmdate('Y-m-d H:i:s', strtotime($date)); + $updates[] = array('bDateTime' => $datetime); + } + + $sql = 'UPDATE '. $GLOBALS['tableprefix'] .'bookmarks SET '. $this->db->sql_build_array('UPDATE', $updates) .' WHERE bId = '. intval($bId); + $this->db->sql_transaction('begin'); + + if (!($dbresult = & $this->db->sql_query($sql))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not update bookmark', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + + $uriparts = explode('.', $address); + $extension = end($uriparts); + unset($uriparts); + + $b2tservice = & ServiceFactory :: getServiceInstance('Bookmark2TagService'); + if (!$b2tservice->attachTags($bId, $categories, $fromApi, $extension)) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not update bookmark', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + + $this->db->sql_transaction('commit'); + // Everything worked out, so return true. + return true; + } + + function & getBookmarks($start = 0, $perpage = NULL, $user = NULL, $tags = NULL, $terms = NULL, $sortOrder = NULL, $watched = NULL, $startdate = NULL, $enddate = NULL, $hash = NULL) { + // Only get the bookmarks that are visible to the current user. Our rules: + // - if the $user is NULL, that means get bookmarks from ALL users, so we need to make + // sure to check the logged-in user's watchlist and get the contacts-only bookmarks from + // those users. If the user isn't logged-in, just get the public bookmarks. + // - if the $user is set and isn't the logged-in user, then get that user's bookmarks, and + // if that user is on the logged-in user's watchlist, get the public AND contacts-only + // bookmarks; otherwise, just get the public bookmarks. + // - if the $user is set and IS the logged-in user, then get all bookmarks. + + $userservice =& ServiceFactory::getServiceInstance('UserService'); + $b2tservice =& ServiceFactory::getServiceInstance('Bookmark2TagService'); + $tag2tagservice =& ServiceFactory::getServiceInstance('Tag2TagService'); + $sId = $userservice->getCurrentUserId(); + + if ($userservice->isLoggedOn()) { + // All public bookmarks, user's own bookmarks and any shared with user + $privacy = ' AND ((B.bStatus = 0) OR (B.uId = '. $sId .')'; + $watchnames = $userservice->getWatchNames($sId, true); + foreach($watchnames as $watchuser) { + $privacy .= ' OR (U.username = "'. $watchuser .'" AND B.bStatus = 1)'; + } + $privacy .= ')'; + } else { + // Just public bookmarks + $privacy = ' AND B.bStatus = 0'; + } + + // Set up the tags, if need be. + if (!is_array($tags) && !is_null($tags)) { + $tags = explode('+', trim($tags)); + } + + $tagcount = count($tags); + for ($i = 0; $i < $tagcount; $i ++) { + $tags[$i] = trim($tags[$i]); + } + + // Set up the SQL query. + $query_1 = 'SELECT DISTINCT '; + if (SQL_LAYER == 'mysql4') { + $query_1 .= 'SQL_CALC_FOUND_ROWS '; + } + $query_1 .= 'B.*, U.'. $userservice->getFieldName('username'); + + $query_2 = ' FROM '. $userservice->getTableName() .' AS U, '. $this->getTableName() .' AS B'; + + $query_3 = ' WHERE B.uId = U.'. $userservice->getFieldName('primary') . $privacy; + if (is_null($watched)) { + if (!is_null($user)) { + $query_3 .= ' AND B.uId = '. $user; + } + } else { + $arrWatch = $userservice->getWatchlist($user); + if (count($arrWatch) > 0) { + $query_3_1 = ''; + foreach($arrWatch as $row) { + $query_3_1 .= 'B.uId = '. intval($row) .' OR '; + } + $query_3_1 = substr($query_3_1, 0, -3); + } else { + $query_3_1 = 'B.uId = -1'; + } + $query_3 .= ' AND ('. $query_3_1 .') AND B.bStatus IN (0, 1)'; + } + + $query_5 = ''; + if($hash == null) { + $query_5.= ' GROUP BY B.bHash'; + } + + switch($sortOrder) { + case 'date_asc': + $query_5.= ' ORDER BY B.bModified ASC '; + break; + case 'title_desc': + $query_5.= ' ORDER BY B.bTitle DESC '; + break; + case 'title_asc': + $query_5.= ' ORDER BY B.bTitle ASC '; + break; + case 'url_desc': + $query_5.= ' ORDER BY B.bAddress DESC '; + break; + case 'url_asc': + $query_5.= ' ORDER BY B.bAddress ASC '; + break; + default: + $query_5.= ' ORDER BY B.bModified DESC '; + } + + // Handle the parts of the query that depend on any tags that are present. + $query_4 = ''; + for ($i = 0; $i < $tagcount; $i ++) { + $query_2 .= ', '. $b2tservice->getTableName() .' AS T'. $i; + $query_4 .= ' AND ('; + + $allLinkedTags = $tag2tagservice->getAllLinkedTags($this->db->sql_escape($tags[$i]), '>', $user); + + while (is_array($allLinkedTags) && count($allLinkedTags)>0) { + $query_4 .= ' T'. $i .'.tag = "'. array_pop($allLinkedTags) .'"'; + $query_4 .= ' OR'; + } + + $query_4 .= ' T'. $i .'.tag = "'. $this->db->sql_escape($tags[$i]) .'"'; + + $query_4 .= ') AND T'. $i .'.bId = B.bId'; + //die($query_4); + } + + // Search terms + if ($terms) { + // Multiple search terms okay + $aTerms = explode(' ', $terms); + $aTerms = array_map('trim', $aTerms); + + // Search terms in tags as well when none given + if (!count($tags)) { + $query_2 .= ' LEFT JOIN '. $b2tservice->getTableName() .' AS T ON B.bId = T.bId'; + $dotags = true; + } else { + $dotags = false; + } + + $query_4 = ''; + for ($i = 0; $i < count($aTerms); $i++) { + $query_4 .= ' AND (B.bTitle LIKE "%'. $this->db->sql_escape($aTerms[$i]) .'%"'; + $query_4 .= ' OR B.bDescription LIKE "%'. $this->db->sql_escape($aTerms[$i]) .'%"'; + $query_4 .= ' OR B.bPrivateNote LIKE "'. $this->db->sql_escape($aTerms[$i]) .'%"'; //warning : search in private notes of everybody but private notes won't appear if not allowed. + $query_4 .= ' OR U.username = "'. $this->db->sql_escape($aTerms[$i]) .'"'; //exact match for username + if ($dotags) { + $query_4 .= ' OR T.tag LIKE "'. $this->db->sql_escape($aTerms[$i]) .'%"'; + } + $query_4 .= ')'; + } + } + + // Start and end dates + if ($startdate) { + $query_4 .= ' AND B.bDatetime > "'. $startdate .'"'; + } + if ($enddate) { + $query_4 .= ' AND B.bDatetime < "'. $enddate .'"'; + } + + // Hash + if ($hash) { + $query_4 .= ' AND B.bHash = "'. $hash .'"'; + } + $query = $query_1 . $query_2 . $query_3 . $query_4 . $query_5; + + if (!($dbresult = & $this->db->sql_query_limit($query, intval($perpage), intval($start)))) { + message_die(GENERAL_ERROR, 'Could not get bookmarks', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + if (SQL_LAYER == 'mysql4') { + $totalquery = 'SELECT FOUND_ROWS() AS total'; + } else { + if ($hash) { + $totalquery = 'SELECT COUNT(*) AS total'. $query_2 . $query_3 . $query_4; + } else { + $totalquery = 'SELECT COUNT(DISTINCT bAddress) AS total'. $query_2 . $query_3 . $query_4; + } + } + + if (!($totalresult = & $this->db->sql_query($totalquery)) || (!($row = & $this->db->sql_fetchrow($totalresult)))) { + message_die(GENERAL_ERROR, 'Could not get total bookmarks', '', __LINE__, __FILE__, $totalquery, $this->db); + return false; + } + + $total = $row['total']; + $this->db->sql_freeresult($totalresult); + + $bookmarks = array(); + while ($row = & $this->db->sql_fetchrow($dbresult)) { + $row['tags'] = $b2tservice->getTagsForBookmark(intval($row['bId'])); + $bookmarks[] = $row; + } + + $this->db->sql_freeresult($dbresult); + $output = array ('bookmarks' => $bookmarks, 'total' => $total); + return $output; + } + + function deleteBookmark($bookmarkid) { + $query = 'DELETE FROM '. $GLOBALS['tableprefix'] .'bookmarks WHERE bId = '. intval($bookmarkid); + $this->db->sql_transaction('begin'); + if (!($dbresult = & $this->db->sql_query($query))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not delete bookmarks', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + + + $query = 'DELETE FROM '. $GLOBALS['tableprefix'] .'bookmarks2tags WHERE bId = '. intval($bookmarkid); + $this->db->sql_transaction('begin'); + if (!($dbresult = & $this->db->sql_query($query))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not delete bookmarks', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $this->db->sql_transaction('commit'); + return true; + } + + function deleteBookmarksForUser($uId) {
+ $query = 'DELETE FROM '. $GLOBALS['tableprefix'] .'bookmarks WHERE uId = '. intval($uId);
+
+ if (!($dbresult = & $this->db->sql_query($query))) {
+ message_die(GENERAL_ERROR, 'Could not delete bookmarks', '', __LINE__, __FILE__, $query, $this->db);
+ return false;
+ }
+
+ return true;
+ } + + function countOthers($address) { + if (!$address) { + return false; + } + + $userservice = & ServiceFactory :: getServiceInstance('UserService'); + $sId = $userservice->getCurrentUserId(); + + if ($userservice->isLoggedOn()) { + // All public bookmarks, user's own bookmarks and any shared with user + $privacy = ' AND ((B.bStatus = 0) OR (B.uId = '. $sId .')'; + $watchnames = $userservice->getWatchNames($sId, true); + foreach($watchnames as $watchuser) { + $privacy .= ' OR (U.username = "'. $watchuser .'" AND B.bStatus = 1)'; + } + $privacy .= ')'; + } else { + // Just public bookmarks + $privacy = ' AND B.bStatus = 0'; + } + + $sql = 'SELECT COUNT(*) FROM '. $userservice->getTableName() .' AS U, '. $GLOBALS['tableprefix'] .'bookmarks AS B WHERE U.'. $userservice->getFieldName('primary') .' = B.uId AND B.bHash = "'. md5($address) .'"'. $privacy; + if (!($dbresult = & $this->db->sql_query($sql))) { + message_die(GENERAL_ERROR, 'Could not get vars', '', __LINE__, __FILE__, $sql, $this->db); + } + + $output = $this->db->sql_fetchfield(0, 0) - 1; + $this->db->sql_freeresult($dbresult); + return $output; + } + + function normalize($address) { + // If bookmark address doesn't contain ":", add "http://" to the start as a default protocol + if (strpos($address, ':') === false) { + $address = 'http://'. $address; + } + + // Delete final / + if (substr($address, -1) == '/') { + $address = substr($address, 0, count($address)-2); + } + + return $address; + } + + function deleteAll() { + $query = 'TRUNCATE TABLE `'. $this->getTableName() .'`'; + $this->db->sql_query($query); + } + + // Properties + function getTableName() { return $this->tablename; } + function setTableName($value) { $this->tablename = $value; } + +} + + + +?> diff --git a/src/SemanticScuttle/Service/cacheservice.php b/src/SemanticScuttle/Service/cacheservice.php new file mode 100644 index 0000000..fe66d38 --- /dev/null +++ b/src/SemanticScuttle/Service/cacheservice.php @@ -0,0 +1,38 @@ +<?php +class CacheService { + var $basedir; + var $fileextension = '.cache'; + + function &getInstance() { + static $instance; + + if (!isset($instance)) + $instance =& new CacheService(); + + return $instance; + } + + function CacheService() { + $this->basedir = $GLOBALS['dir_cache']; + } + + function Start($hash, $time = 300) { + $cachefile = $this->basedir .'/'. $hash . $this->fileextension; + if (file_exists($cachefile) && time() < filemtime($cachefile) + $time) { + @readfile($cachefile); + echo "\n<!-- Cached: ". date('r', filemtime($cachefile)) ." -->\n"; + unset($cachefile); + exit; + } + ob_start("ob_gzhandler"); + } + + function End($hash) { + $cachefile = $this->basedir .'/'. $hash . $this->fileextension; + $handle = fopen($cachefile, 'w'); + fwrite($handle, ob_get_contents()); + fclose($handle); + ob_flush(); + } +} +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/Service/commondescriptionservice.php b/src/SemanticScuttle/Service/commondescriptionservice.php new file mode 100644 index 0000000..86e0c0f --- /dev/null +++ b/src/SemanticScuttle/Service/commondescriptionservice.php @@ -0,0 +1,167 @@ +<?php +class CommonDescriptionService { + var $db; + var $tablename; + + function &getInstance(&$db) { + static $instance; + if (!isset($instance)) + $instance =& new CommonDescriptionService($db); + return $instance; + } + + function CommonDescriptionService(&$db) { + $this->db =& $db; + $this->tablename = $GLOBALS['tableprefix'] .'commondescription'; + } + + function addTagDescription($tag, $desc, $uId, $time) { + // Check if no modification + $lastDesc = $this->getLastTagDescription($tag); + if($lastDesc['cdDescription'] == $desc) { + return true; + } + + // If modification + $datetime = gmdate('Y-m-d H:i:s', $time); + $values = array('tag'=>$tag, 'cdDescription'=>$desc, 'uId'=>$uId, 'cdDatetime'=>$datetime); + $sql = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values); + + if (!($dbresult =& $this->db->sql_query($sql))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not add tag description', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + + return true; + } + + function getLastTagDescription($tag) { + $query = "SELECT *"; + $query.= " FROM `". $this->getTableName() ."`"; + $query.= " WHERE tag='".$tag."'"; + $query.= " ORDER BY cdDatetime DESC"; + + if (!($dbresult = & $this->db->sql_query_limit($query, 1, 0))) { + message_die(GENERAL_ERROR, 'Could not get tag description', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + if ($row =& $this->db->sql_fetchrow($dbresult)) { + return $row; + } else { + return false; + } + } + + function getAllTagsDescription($tag) { + $query = "SELECT *"; + $query.= " FROM `". $this->getTableName() ."`"; + $query.= " WHERE tag='".$tag."'"; + $query.= " ORDER BY cdDatetime DESC"; + + if (!($dbresult = & $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not get tag descriptions', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + return $this->db->sql_fetchrowset($dbresult); + + } + + function getDescriptionById($cdId) { + $query = "SELECT *"; + $query.= " FROM `". $this->getTableName() ."`"; + $query.= " WHERE cdId='".$cdId."'"; + + if (!($dbresult = & $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not get tag descriptions', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + if ($row =& $this->db->sql_fetchrow($dbresult)) { + return $row; + } else { + return false; + } + + } + + function addBookmarkDescription($bHash, $title, $desc, $uId, $time) { + // Check if no modification + $lastDesc = $this->getLastBookmarkDescription($bHash); + if($lastDesc['cdTitle'] == $title && $lastDesc['cdDescription'] == $desc) { + return true; + } + + // If modification + $datetime = gmdate('Y-m-d H:i:s', $time); + $values = array('bHash'=>$bHash, 'cdTitle'=>$title, 'cdDescription'=>$desc, 'uId'=>$uId, 'cdDatetime'=>$datetime); + $sql = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values); + + if (!($dbresult =& $this->db->sql_query($sql))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not add bookmark description', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + return true; + } + + function getLastBookmarkDescription($bHash) { + $query = "SELECT *"; + $query.= " FROM `". $this->getTableName() ."`"; + $query.= " WHERE bHash='".$bHash."'"; + $query.= " ORDER BY cdDatetime DESC"; + + if (!($dbresult = & $this->db->sql_query_limit($query, 1, 0))) { + message_die(GENERAL_ERROR, 'Could not get bookmark description', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + if ($row =& $this->db->sql_fetchrow($dbresult)) { + return $row; + } else { + return false; + } + } + + function getAllBookmarksDescription($bHash) { + $query = "SELECT *"; + $query.= " FROM `". $this->getTableName() ."`"; + $query.= " WHERE bHash='".$bHash."'"; + $query.= " ORDER BY cdDatetime DESC"; + + if (!($dbresult = & $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not get bookmark descriptions', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + return $this->db->sql_fetchrowset($dbresult); + + } + + function deleteDescriptionsForUser($uId){ + $query = 'DELETE FROM '. $this->getTableName() . ' WHERE uId = '. intval($uId); + + $this->db->sql_transaction('begin'); + if (!($dbresult = & $this->db->sql_query($query))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not delete user descriptions', '', + __LINE__, __FILE__, $query, $this->db); + return false; + } + + return true; + } + + + function deleteAll() { + $query = 'TRUNCATE TABLE `'. $this->getTableName() .'`'; + $this->db->sql_query($query); + } + + // Properties + function getTableName() { return $this->tablename; } + function setTableName($value) { $this->tablename = $value; } +} +?> diff --git a/src/SemanticScuttle/Service/searchhistoryservice.php b/src/SemanticScuttle/Service/searchhistoryservice.php new file mode 100644 index 0000000..91457e8 --- /dev/null +++ b/src/SemanticScuttle/Service/searchhistoryservice.php @@ -0,0 +1,124 @@ +<?php +class SearchHistoryService { + var $db; + var $tablename; + var $sizeSearchHistory; + + function &getInstance(&$db) { + static $instance; + if (!isset($instance)) + $instance =& new SearchHistoryService($db); + return $instance; + } + + function SearchHistoryService(& $db) { + $this->db =& $db; + $this->tablename = $GLOBALS['tableprefix'] .'searchhistory'; + if(isset($GLOBALS['sizeSearchHistory'])) { + $this->sizeSearchHistory = $GLOBALS['sizeSearchHistory']; + } else { + $this->sizeSearchHistory = 10; + } + } + + function addSearch($terms, $range, $nbResults, $uId=0) { + if(strlen($terms) == 0) { + return false; + } + $datetime = gmdate('Y-m-d H:i:s', time()); + + //Insert values + $values = array('shTerms'=>$terms, 'shRange'=>$range, 'shDatetime'=>$datetime, 'shNbResults'=>$nbResults, 'uId'=>$uId); + $sql = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values); + $this->db->sql_transaction('begin'); + if (!($dbresult = & $this->db->sql_query($sql))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not insert search history', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + + if($this->sizeSearchHistory != -1 && + $this->countSearches() > $this->sizeSearchHistory) { + $this->deleteOldestSearch(); + } + } + + function getAllSearches($range = NULL, $uId = NULL, $nb = NULL, $start = NULL, $distinct = false, $withResults = false) { + $sql = 'SELECT DISTINCT(shTerms), shId, shRange, shNbResults, shDatetime, uId'; + $sql.= ' FROM '. $this->getTableName(); + $sql.= ' WHERE 1=1'; + if($range != NULL) { + $sql.= ' AND shRange = "'.$range.'"'; + } else { + $sql.= ' AND shRange = "all"'; + } + if($uId != NULL) { + $sql.= ' AND uId = '.$uId; + } + if($withResults = true) { + $sql.= ' AND shNbResults > 0'; + } + if($distinct) { + $sql.= ' GROUP BY shTerms'; + } + $sql.= ' ORDER BY shId DESC'; + + if (!($dbresult = & $this->db->sql_query_limit($sql, $nb, $start))) { + message_die(GENERAL_ERROR, 'Could not get searches', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + + $searches = array(); + while ($row = & $this->db->sql_fetchrow($dbresult)) { + $searches[] = $row; + } + $this->db->sql_freeresult($dbresult); + return $searches; + } + + function countSearches() { + $sql = 'SELECT COUNT(*) AS `total` FROM '. $this->getTableName(); + if (!($dbresult = & $this->db->sql_query($sql)) || (!($row = & $this->db->sql_fetchrow($dbresult)))) { + message_die(GENERAL_ERROR, 'Could not get total searches', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + $this->db->sql_freeresult($dbresult); + return $row['total']; + } + + /* This function allows to limit the number of saved searches + by deleting the oldest one */ + function deleteOldestSearch() { + $sql = 'DELETE FROM '.$this->getTableName(); + $sql.= ' ORDER BY shId ASC LIMIT 1'; // warning: here the limit is important + + $this->db->sql_transaction('begin'); + if (!($dbresult = & $this->db->sql_query($sql))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not delete bookmarks', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + } + + function deleteSearchHistoryForUser($uId) { + $query = 'DELETE FROM '. $this->getTableName() .' WHERE uId = '. intval($uId); + + if (!($dbresult = & $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not delete search history', '', + __LINE__, __FILE__, $query, $this->db); + return false; + } + + return true; + } + + function deleteAll() { + $query = 'TRUNCATE TABLE `'. $this->getTableName() .'`'; + $this->db->sql_query($query); + } + + // Properties + function getTableName() { return $this->tablename; } + function setTableName($value) { $this->tablename = $value; } +} +?> diff --git a/src/SemanticScuttle/Service/servicefactory.php b/src/SemanticScuttle/Service/servicefactory.php new file mode 100644 index 0000000..b5215e3 --- /dev/null +++ b/src/SemanticScuttle/Service/servicefactory.php @@ -0,0 +1,38 @@ +<?php +/* Connect to the database and build services */ + +class ServiceFactory { + function ServiceFactory(&$db, $serviceoverrules = array()) { + } + + function &getServiceInstance($name, $servicedir = NULL) { + global $dbhost, $dbuser, $dbpass, $dbname, $dbport, $dbpersist, $dbtype; + static $instances = array(); + static $db; + if (!isset($db)) { + require_once(dirname(__FILE__) .'/../includes/db/'. $dbtype .'.php'); + $db = new sql_db(); + $db->sql_connect($dbhost, $dbuser, $dbpass, $dbname, $dbport, $dbpersist); + if(!$db->db_connect_id) { + message_die(CRITICAL_ERROR, "Could not connect to the database", $db); + } + $db->sql_query("SET NAMES UTF8"); + } + + if (!isset($instances[$name])) { + if (isset($serviceoverrules[$name])) { + $name = $serviceoverrules[$name]; + } + if (!class_exists($name)) { + if (!isset($servicedir)) { + $servicedir = dirname(__FILE__) .'/'; + } + + require_once($servicedir . strtolower($name) . '.php'); + } + $instances[$name] = call_user_func(array($name, 'getInstance'), $db); + } + return $instances[$name]; + } +} +?> diff --git a/src/SemanticScuttle/Service/tag2tagservice.php b/src/SemanticScuttle/Service/tag2tagservice.php new file mode 100644 index 0000000..956fd49 --- /dev/null +++ b/src/SemanticScuttle/Service/tag2tagservice.php @@ -0,0 +1,377 @@ +<?php +class Tag2TagService { + var $db; + var $tablename; + + function &getInstance(&$db) { + static $instance; + if (!isset($instance)) + $instance =& new Tag2TagService($db); + return $instance; + } + + function Tag2TagService(&$db) { + $this->db =& $db; + $this->tablename = $GLOBALS['tableprefix'] .'tags2tags'; + } + + function addLinkedTags($tag1, $tag2, $relationType, $uId) { + $tagservice =& ServiceFactory::getServiceInstance('TagService'); + $tag1 = $tagservice->normalize($tag1); + $tag2 = $tagservice->normalize($tag2); + + if($tag1 == $tag2 || strlen($tag1) == 0 || strlen($tag2) == 0 + || ($relationType != ">" && $relationType != "=") + || !is_numeric($uId) || $uId<=0 + || ($this->existsLinkedTags($tag1, $tag2, $relationType, $uId))) { + return false; + } + + $values = array('tag1' => $tag1, 'tag2' => $tag2, 'relationType'=> $relationType, 'uId'=> $uId); + $query = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values); + //die($query); + if (!($dbresult =& $this->db->sql_query($query))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not attach tag to tag', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + $this->db->sql_transaction('commit'); + + // Update stats and cache + $this->update($tag1, $tag2, $relationType, $uId); + + return true; + } + + // Return linked tags just for admin users + function getAdminLinkedTags($tag, $relationType, $inverseRelation = false, $stopList = array()) { + // look for admin ids + $userservice = & ServiceFactory :: getServiceInstance('UserService'); + $adminIds = $userservice->getAdminIds(); + + //ask for their linked tags + return $this->getLinkedTags($tag, $relationType, $adminIds, $inverseRelation, $stopList); + } + + // Return the target linked tags. If inverseRelation is true, return the source linked tags. + function getLinkedTags($tag, $relationType, $uId = null, $inverseRelation = false, $stopList = array()) { + // Set up the SQL query. + if($inverseRelation) { + $queriedTag = "tag1"; + $givenTag = "tag2"; + } else { + $queriedTag = "tag2"; + $givenTag = "tag1"; + } + + $query = "SELECT DISTINCT ". $queriedTag ." as 'tag'"; + $query.= " FROM `". $this->getTableName() ."`"; + $query.= " WHERE 1=1"; + if($tag !=null) { + $query.= " AND ". $givenTag ." = '". $tag ."'"; + } + if($relationType) { + $query.= " AND relationType = '". $relationType ."'"; + } + if(is_array($uId)) { + $query.= " AND ( 1=0 "; //tricks always false + foreach($uId as $u) { + $query.= " OR uId = '".$u."'"; + } + $query.= " ) "; + } elseif($uId != null) { + $query.= " AND uId = '".$uId."'"; + } + //die($query); + if (! ($dbresult =& $this->db->sql_query($query)) ){ + message_die(GENERAL_ERROR, 'Could not get related tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $rowset = $this->db->sql_fetchrowset($dbresult); + $output = array(); + foreach($rowset as $row) { + if(!in_array($row['tag'], $stopList)) { + $output[] = $row['tag']; + } + } + + //bijective case for '=' + if($relationType == '=' && $inverseRelation == false) { + //$stopList[] = $tag; + $bijectiveOutput = $this->getLinkedTags($tag, $relationType, $uId, true, $stopList); + $output = array_merge($output, $bijectiveOutput); + //$output = array_unique($output); // remove duplication + } + + $this->db->sql_freeresult($dbresult); + return $output; + } + + /* + * Returns all linked tags (all descendants if relation is >, + * all synonyms if relation is = ) + * $stopList allows to avoid cycle (a > b > a) between tags + */ + function getAllLinkedTags($tag1, $relationType, $uId, $stopList=array()) { + if(in_array($tag1, $stopList) || $tag1 == '') { + return array(); + } + + // try to find data in cache + $tcs = & ServiceFactory::getServiceInstance('TagCacheService'); + if(count($stopList) == 0) { + $activatedCache = true; + } else { + $activatedCache = false; + } + + // look for existing links + $stopList[] = $tag1; + $linkedTags = $this->getLinkedTags($tag1, $relationType, $uId, false, $stopList); + if($relationType != '=') { + $linkedTags = array_merge($linkedTags, $this->getLinkedTags($tag1, '=', $uId, false, $stopList)); + } + + if(count($linkedTags) == 0) { + return array(); + + } else { + // use cache if possible + if($activatedCache) { + if($relationType == '>') { + $output = $tcs->getChildren($tag1, $uId); + } elseif($relationType == '=') { + $output = $tcs->getSynonyms($tag1, $uId); + } + if(count($output)>0) { + return $output; + } + } + + // else compute the links + $output = array(); + + foreach($linkedTags as $linkedTag) { + $allLinkedTags = $this->getAllLinkedTags($linkedTag, $relationType, $uId, $stopList); + $output[] = $linkedTag; + if(is_array($allLinkedTags)) { + $output = array_merge($output, $allLinkedTags); + } else { + $output[] = $allLinkedTags; + } + } + + // and save in cache + if($activatedCache == true && $uId>0) { + $tcs->updateTag($tag1, $relationType, $output, $uId); + } + + //$output = array_unique($output); // remove duplication + return $output; + + } + } + + function getOrphewTags($relationType, $uId = 0, $limit = null, $orderBy = null) { + $query = "SELECT DISTINCT tts.tag1 as tag"; + $query.= " FROM `". $this->getTableName() ."` tts"; + if($orderBy != null) { + $tsts =& ServiceFactory::getServiceInstance('TagStatService'); + $query.= ", ".$tsts->getTableName() ." tsts"; + } + $query.= " WHERE tts.tag1 <> ALL"; + $query.= " (SELECT DISTINCT tag2 FROM `". $this->getTableName() ."`"; + $query.= " WHERE relationType = '".$relationType."'"; + if($uId > 0) { + $query.= " AND uId = '".$uId."'"; + } + $query.= ")"; + if($uId > 0) { + $query.= " AND tts.uId = '".$uId."'"; + } + + switch($orderBy) { + case "nb": + $query.= " AND tts.tag1 = tsts.tag1"; + $query.= " AND tsts.relationType = '".$relationType."'"; + if($uId > 0) { + $query.= " AND tsts.uId = ".$uId; + } + $query.= " ORDER BY tsts.nb DESC"; + break; + case "depth": // by nb of descendants + $query.= " AND tts.tag1 = tsts.tag1"; + $query.= " AND tsts.relationType = '".$relationType."'"; + if($uId > 0) { + $query.= " AND tsts.uId = ".$uId; + } + $query.= " ORDER BY tsts.depth DESC"; + break; + case "nbupdate": + $query.= " AND tts.tag1 = tsts.tag1"; + $query.= " AND tsts.relationType = '".$relationType."'"; + if($uId > 0) { + $query.= " AND tsts.uId = ".$uId; + } + $query.= " ORDER BY tsts.nbupdate DESC"; + break; + } + + if($limit != null) { + $query.= " LIMIT 0,".$limit; + } + + if (! ($dbresult =& $this->db->sql_query($query)) ){ + message_die(GENERAL_ERROR, 'Could not get linked tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + $output = $this->db->sql_fetchrowset($dbresult); + $this->db->sql_freeresult($dbresult); + return $output; + } + + function getMenuTags($uId) { + if(strlen($GLOBALS['menuTag']) < 1) { + return array(); + } else { + // we don't use the getAllLinkedTags function in order to improve performance + $query = "SELECT tag2 as 'tag', COUNT(tag2) as 'count'"; + $query.= " FROM `". $this->getTableName() ."`"; + $query.= " WHERE tag1 = '".$GLOBALS['menuTag']."'"; + $query.= " AND relationType = '>'"; + if($uId > 0) { + $query.= " AND uId = '".$uId."'"; + } + $query.= " GROUP BY tag2"; + $query.= " ORDER BY count DESC"; + $query.= " LIMIT 0, ".$GLOBALS['maxSizeMenuBlock']; + + if (! ($dbresult =& $this->db->sql_query($query)) ){ + message_die(GENERAL_ERROR, 'Could not get linked tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + $output = $this->db->sql_fetchrowset($dbresult); + $this->db->sql_freeresult($dbresult); + return $output; + } + } + + + function existsLinkedTags($tag1, $tag2, $relationType, $uId) { + + //$tag1 = mysql_real_escape_string($tag1); + //$tag2 = mysql_real_escape_string($tag2); + + $query = "SELECT tag1, tag2, relationType, uId FROM `". $this->getTableName() ."`"; + $query.= " WHERE tag1 = '" .$tag1 ."'"; + $query.= " AND tag2 = '".$tag2."'"; + $query.= " AND relationType = '". $relationType ."'"; + $query.= " AND uId = '".$uId."'"; + + //echo($query."<br>\n"); + + return $this->db->sql_numrows($this->db->sql_query($query)) > 0; + } + + function getLinks($uId) { + $query = "SELECT tag1, tag2, relationType, uId FROM `". $this->getTableName() ."`"; + $query.= " WHERE 1=1"; + if($uId > 0) { + $query.= " AND uId = '".$uId."'"; + } + + return $this->db->sql_fetchrowset($this->db->sql_query($query)); + } + + function removeLinkedTags($tag1, $tag2, $relationType, $uId) { + if(($tag1 != '' && $tag1 == $tag2) || + ($relationType != ">" && $relationType != "=" && $relationType != "") || + ($tag1 == '' && $tag2 == '')) { + return false; + } + $query = 'DELETE FROM '. $this->getTableName(); + $query.= ' WHERE 1=1'; + $query.= strlen($tag1)>0 ? ' AND tag1 = "'. $tag1 .'"' : ''; + $query.= strlen($tag2)>0 ? ' AND tag2 = "'. $tag2 .'"' : ''; + $query.= strlen($relationType)>0 ? ' AND relationType = "'. $relationType .'"' : ''; + $query.= strlen($uId)>0 ? ' AND uId = "'. $uId .'"' : ''; + + if (!($dbresult =& $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not remove tag relation', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + + // Update stats and cache + $this->update($tag1, $tag2, $relationType, $uId); + + $this->db->sql_freeresult($dbresult); + return true; + } + + function removeLinkedTagsForUser($uId) { + $query = 'DELETE FROM '. $this->getTableName(); + $query.= ' WHERE uId = "'. $uId .'"'; + + if (!($dbresult =& $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not remove tag relation', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + + // Update stats and cache + $this->update('', '', '', $uId); + + $this->db->sql_freeresult($dbresult); + return true; + } + + function renameTag($uId, $oldName, $newName) { + $tagservice =& ServiceFactory::getServiceInstance('TagService'); + $newName = $tagservice->normalize($newName); + + $query = 'UPDATE `'. $this->getTableName() .'`'; + $query.= ' SET tag1="'.$newName.'"'; + $query.= ' WHERE tag1="'.$oldName.'"'; + $query.= ' AND uId="'.$uId.'"'; + $this->db->sql_query($query); + + $query = 'UPDATE `'. $this->getTableName() .'`'; + $query.= ' SET tag2="'.$newName.'"'; + $query.= ' WHERE tag2="'.$oldName.'"'; + $query.= ' AND uId="'.$uId.'"'; + $this->db->sql_query($query); + + + // Update stats and cache + $this->update($oldName, NULL, '=', $uId); + $this->update($oldName, NULL, '>', $uId); + $this->update($newName, NULL, '=', $uId); + $this->update($newName, NULL, '>', $uId); + + return true; + + } + + function update($tag1, $tag2, $relationType, $uId) { + $tsts =& ServiceFactory::getServiceInstance('TagStatService'); + $tsts->updateStat($tag1, $relationType, $uId); + + $tcs = & ServiceFactory::getServiceInstance('TagCacheService'); + $tcs->deleteByUser($uId); + } + + function deleteAll() { + $query = 'TRUNCATE TABLE `'. $this->getTableName() .'`'; + $this->db->sql_query($query); + + $tsts =& ServiceFactory::getServiceInstance('TagStatService'); + $tsts->deleteAll(); + } + + // Properties + function getTableName() { return $this->tablename; } + function setTableName($value) { $this->tablename = $value; } +} +?> diff --git a/src/SemanticScuttle/Service/tagcacheservice.php b/src/SemanticScuttle/Service/tagcacheservice.php new file mode 100644 index 0000000..ed2eefc --- /dev/null +++ b/src/SemanticScuttle/Service/tagcacheservice.php @@ -0,0 +1,349 @@ +<?php + +/* + * This class infers on relation between tags by storing all the including tags or synonymous tag. + * For example, if the user creates: tag1>tag2>tag3, the system can infer that tag is included into tag1. + * Instead of computing this relation several times, it is saved into this current table. + * For synonymy, this table stores also the group of synonymous tags. + * The table must be updated for each modification of the relations between tags. + */ + +class TagCacheService { + var $db; + var $tablename; + + function &getInstance(&$db) { + static $instance; + if (!isset($instance)) + $instance =& new TagCacheService($db); + return $instance; + } + + function TagCacheService(&$db) { + $this->db =& $db; + $this->tablename = $GLOBALS['tableprefix'] .'tagscache'; + } + + function getChildren($tag1, $uId) { + $tagservice =& ServiceFactory::getServiceInstance('TagService'); + $tag1 = $tagservice->normalize($tag1); + + if($tag1 == '') return false; + + $query = "SELECT DISTINCT tag2 as 'tag'"; + $query.= " FROM `". $this->getTableName() ."`"; + $query.= " WHERE relationType = '>'"; + $query.= " AND tag1 = '".$tag1."'"; + $query.= " AND uId = '".$uId."'"; + + //die($query); + if (! ($dbresult =& $this->db->sql_query($query)) ){ + message_die(GENERAL_ERROR, 'Could not get related tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + + $rowset = $this->db->sql_fetchrowset($dbresult); + $output = array(); + foreach($rowset as $row) { + $output[] = $row['tag']; + } + + $this->db->sql_freeresult($dbresult); + return $output; + } + + function addChild($tag1, $tag2, $uId) { + $tagservice =& ServiceFactory::getServiceInstance('TagService'); + $tag1 = $tagservice->normalize($tag1); + $tag2 = $tagservice->normalize($tag2); + + if($tag1 == $tag2 || strlen($tag1) == 0 || strlen($tag2) == 0 + || ($this->existsChild($tag1, $tag2, $uId))) { + return false; + } + + $values = array('tag1' => $tag1, 'tag2' => $tag2, 'relationType'=> '>', 'uId'=> $uId); + $query = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values); + //die($query); + if (!($dbresult =& $this->db->sql_query($query))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not add tag cache inference', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + $this->db->sql_transaction('commit'); + } + + function removeChild($tag1, $tag2, $uId) { + if(($tag1 != '' && $tag1 == $tag2) || + ($tag1 == '' && $tag2 == '' && $uId == '')) { + return false; + } + + $query = 'DELETE FROM '. $this->getTableName(); + $query.= ' WHERE 1=1'; + $query.= strlen($tag1)>0 ? ' AND tag1 = "'. $tag1 .'"' : ''; + $query.= strlen($tag2)>0 ? ' AND tag2 = "'. $tag2 .'"' : ''; + $query.= ' AND relationType = ">"'; + $query.= strlen($uId)>0 ? ' AND uId = "'. $uId .'"' : ''; + + if (!($dbresult =& $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not remove tag cache inference', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + } + + function removeChildren($tag1, $uId) { + $this->removeChild($tag1, NULL, $uId); + } + + function existsChild($tag1, $tag2, $uId) { + $tagservice =& ServiceFactory::getServiceInstance('TagService'); + $tag1 = $tagservice->normalize($tag1); + $tag2 = $tagservice->normalize($tag2); + + $query = "SELECT tag1, tag2, relationType, uId FROM `". $this->getTableName() ."`"; + $query.= " WHERE tag1 = '" .$tag1 ."'"; + $query.= " AND tag2 = '".$tag2."'"; + $query.= " AND relationType = '>'"; + $query.= " AND uId = '".$uId."'"; + + //echo($query."<br>\n"); + + return $this->db->sql_numrows($this->db->sql_query($query)) > 0; + + } + + /* + * Synonyms of a same concept are a group. A group has one main synonym called key + * and a list of synonyms called values. + */ + function addSynonym($tag1, $tag2, $uId) { + + if($tag1 == $tag2 || strlen($tag1) == 0 || strlen($tag2) == 0 + || ($this->existsSynonym($tag1, $tag2, $uId))) { + return false; + } + + $case1 = '0'; // not in DB + if($this->_isSynonymKey($tag1, $uId)) { + $case1 = 'key'; + } elseif($this->_isSynonymValue($tag1, $uId)) { + $case1 = 'value'; + } + + $case2 = '0'; // not in DB + if($this->_isSynonymKey($tag2, $uId)) { + $case2 = 'key'; + } elseif($this->_isSynonymValue($tag2, $uId)) { + $case2 = 'value'; + } + $case = $case1.$case2; + + // all the possible cases + switch ($case) { + case 'keykey': + $values = $this->_getSynonymValues($tag2, $uId); + $this->removeSynonymGroup($tag2, $uId); + foreach($values as $value) { + $this->addSynonym($tag1, $value['tag'], $uId); + } + $this->addSynonym($tag1, $tag2, $uId); + break; + + case 'valuekey': + $key = $this->_getSynonymKey($tag1, $uId); + $this->addSynonym($key, $tag2, $uId); + break; + + case 'keyvalue': + $this->addSynonym($tag2, $tag1, $uId); + break; + case 'valuevalue': + $key1 = $this->_getSynonymKey($tag1, $uId); + $key2 = $this->_getSynonymKey($tag2, $uId); + $this->addSynonym($key1, $key2, $uId); + break; + case '0value': + $key = $this->_getSynonymKey($tag2, $uId); + $this->addSynonym($key, $tag1, $uId); + break; + case 'value0': + $this->addSynonym($tag2, $tag1, $uId); + break; + case '0key': + $this->addSynonym($tag2, $tag1, $uId); + break; + default: + $values = array('tag1' => $tag1, 'tag2' => $tag2, 'relationType'=> '=', 'uId'=> $uId); + $query = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values); + //die($query); + if (!($dbresult =& $this->db->sql_query($query))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not add tag cache synonymy', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + $this->db->sql_transaction('commit'); + break; + } + } + + function removeSynonymGroup($tag1, $uId) { + $query = 'DELETE FROM '. $this->getTableName(); + $query.= ' WHERE 1=1'; + $query.= ' AND tag1 = "'. $tag1 .'"'; + $query.= ' AND relationType = "="'; + $query.= ' AND uId = "'. $uId .'"'; + + if (!($dbresult =& $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not remove tag cache inference', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + } + + function _isSynonymKey($tag1, $uId) { + $tagservice =& ServiceFactory::getServiceInstance('TagService'); + $tag1 = $tagservice->normalize($tag1); + + $query = "SELECT tag1 FROM `". $this->getTableName() ."`"; + $query.= " WHERE tag1 = '" .$tag1 ."'"; + $query.= " AND relationType = '='"; + $query.= " AND uId = '".$uId."'"; + + return $this->db->sql_numrows($this->db->sql_query($query)) > 0; + } + + function _isSynonymValue($tag2, $uId) { + $tagservice =& ServiceFactory::getServiceInstance('TagService'); + $tag2 = $tagservice->normalize($tag2); + + $query = "SELECT tag2 FROM `". $this->getTableName() ."`"; + $query.= " WHERE tag2 = '" .$tag2 ."'"; + $query.= " AND relationType = '='"; + $query.= " AND uId = '".$uId."'"; + + return $this->db->sql_numrows($this->db->sql_query($query)) > 0; + } + + function getSynonyms($tag1, $uId) { + $values = array(); + if($this->_isSynonymKey($tag1, $uId)) { + $values = $this->_getSynonymValues($tag1, $uId); + } elseif($this->_isSynonymValue($tag1, $uId)) { + $key = $this->_getSynonymKey($tag1, $uId); + $values = $this->_getSynonymValues($key, $uId, $tag1); + $values[] = $key; + } + return $values; + } + + function _getSynonymKey($tag2, $uId) { + $tagservice =& ServiceFactory::getServiceInstance('TagService'); + $tag2 = $tagservice->normalize($tag2); + + if($this->_isSynonymKey($tag2)) return $tag2; + + if($tag2 == '') return false; + + $query = "SELECT DISTINCT tag1 as 'tag'"; + $query.= " FROM `". $this->getTableName() ."`"; + $query.= " WHERE relationType = '='"; + $query.= " AND tag2 = '".$tag2."'"; + $query.= " AND uId = '".$uId."'"; + + //die($query); + if (! ($dbresult =& $this->db->sql_query($query)) ){ + message_die(GENERAL_ERROR, 'Could not get related tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $row = $this->db->sql_fetchrow($dbresult); + $this->db->sql_freeresult($dbresult); + return $row['tag']; + } + + /* + * Return values associated with a key. + * $tagExcepted allows to hide a value. + */ + function _getSynonymValues($tag1, $uId, $tagExcepted = NULL) { + $tagservice =& ServiceFactory::getServiceInstance('TagService'); + $tag1 = $tagservice->normalize($tag1); + $tagExcepted = $tagservice->normalize($tagExcepted); + + if($tag1 == '') return false; + + $query = "SELECT DISTINCT tag2 as 'tag'"; + $query.= " FROM `". $this->getTableName() ."`"; + $query.= " WHERE relationType = '='"; + $query.= " AND tag1 = '".$tag1."'"; + $query.= " AND uId = '".$uId."'"; + $query.= $tagExcepted!=''?" AND tag2!='".$tagExcepted."'":""; + + if (! ($dbresult =& $this->db->sql_query($query)) ){ + message_die(GENERAL_ERROR, 'Could not get related tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $rowset = $this->db->sql_fetchrowset($dbresult); + + $output = array(); + foreach($rowset as $row) { + $output[] = $row['tag']; + } + + $this->db->sql_freeresult($dbresult); + return $output; + } + + function existsSynonym($tag1, $tag2, $uId) { + if($this->_getSynonymKey($tag1, $uId) == $tag2 || $this->_getSynonymKey($tag2, $uId) == $tag1) { + return true; + } else { + return false; + } + } + + + function updateTag($tag1, $relationType, $otherTags, $uId) { + if($relationType == '=') { + if($this->getSynonyms($tag1, $uId)) { // remove previous data avoiding unconstistency + $this->removeSynonymGroup($tag1, $uId); + } + + foreach($otherTags as $tag2) { + $this->addSynonym($tag1, $tag2, $uId); + } + } elseif($relationType == '>') { + if(count($this->getChildren($tag1, $uId))>0) { // remove previous data avoiding unconstistency + $this->removeChildren($tag1); + } + + foreach($otherTags as $tag2) { + $this->addChild($tag1, $tag2, $uId); + } + } + } + + function deleteByUser($uId) { + $query = 'DELETE FROM '. $this->getTableName() .' WHERE uId = '. intval($uId); + + if (!($dbresult = & $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not delete user tags cache', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + return true; + + } + + function deleteAll() { + $query = 'TRUNCATE TABLE `'. $this->getTableName() .'`'; + $this->db->sql_query($query); + } + + // Properties + function getTableName() { return $this->tablename; } + function setTableName($value) { $this->tablename = $value; } +} +?> diff --git a/src/SemanticScuttle/Service/tagservice.php b/src/SemanticScuttle/Service/tagservice.php new file mode 100644 index 0000000..fc44a99 --- /dev/null +++ b/src/SemanticScuttle/Service/tagservice.php @@ -0,0 +1,123 @@ +<?php +class TagService { + var $db; + var $tablename; + + function &getInstance(&$db) { + static $instance; + if (!isset($instance)) + $instance =& new TagService($db); + return $instance; + } + + function TagService(&$db) { + $this->db =& $db; + $this->tablename = $GLOBALS['tableprefix'] .'tags'; + } + + function getDescription($tag, $uId) { + $query = 'SELECT tag, uId, tDescription'; + $query.= ' FROM '.$this->getTableName(); + $query.= ' WHERE tag = "'.$tag.'"'; + $query.= ' AND uId = "'.$uId.'"'; + + if (!($dbresult = & $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not get tag description', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + if ($row =& $this->db->sql_fetchrow($dbresult)) { + return $row; + } else { + return array('tDescription'=>''); + } + } + + function existsDescription($tag, $uId) { + $query = 'SELECT tag, uId, tDescription'; + $query.= ' FROM '.$this->getTableName(); + $query.= ' WHERE tag = "'.$tag.'"'; + $query.= ' AND uId = "'.$uId.'"'; + + if (!($dbresult = & $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not get tag description', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + if ($row =& $this->db->sql_fetchrow($dbresult)) { + return true; + } else { + return false; + } + } + + function getAllDescriptions($tag) { + $query = 'SELECT tag, uId, tDescription'; + $query.= ' FROM '.$this->getTableName(); + $query.= ' WHERE tag = "'.$tag.'"'; + + if (!($dbresult = & $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not get tag description', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + return $this->db->sql_fetchrowset($dbresult); + } + + function updateDescription($tag, $uId, $desc) { + if($this->existsDescription($tag, $uId)) { + $query = 'UPDATE '.$this->getTableName(); + $query.= ' SET tDescription="'.$this->db->sql_escape($desc).'"'; + $query.= ' WHERE tag="'.$tag.'" AND uId="'.$uId.'"'; + } else { + $values = array('tag'=>$tag, 'uId'=>$uId, 'tDescription'=>$desc); + $query = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values); + } + + $this->db->sql_transaction('begin'); + if (!($dbresult = & $this->db->sql_query($query))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not delete bookmarks', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + $this->db->sql_transaction('commit'); + return true; + } + + function renameTag($uId, $oldName, $newName) { + $newname = $this->normalize($newname); + + $query = 'UPDATE `'. $this->getTableName() .'`'; + $query.= ' SET tag="'.$newName.'"'; + $query.= ' WHERE tag="'.$oldName.'"'; + $query.= ' AND uId="'.$uId.'"'; + $this->db->sql_query($query); + return true; + } + + /* normalize the input tags which could be a string or an array*/ + function normalize($tags) { + //clean tags from strange characters + $tags = str_replace(array('"', '\'', '/'), "_", $tags); + + //normalize + if(!is_array($tags)) { + $tags = strtolower(trim($tags)); + } else { + for($i=0; $i<count($tags); $i++) { + $tags[$i] = strtolower(trim($tags[$i])); + } + } + return $tags; + } + + function deleteAll() { + $query = 'TRUNCATE TABLE `'. $this->getTableName() .'`'; + $this->db->sql_query($query); + } + + // Properties + function getTableName() { return $this->tablename; } + function setTableName($value) { $this->tablename = $value; } +} +?> diff --git a/src/SemanticScuttle/Service/tagstatservice.php b/src/SemanticScuttle/Service/tagstatservice.php new file mode 100644 index 0000000..9d3ca5d --- /dev/null +++ b/src/SemanticScuttle/Service/tagstatservice.php @@ -0,0 +1,193 @@ +<?php +class TagStatService { + var $db; + var $tablename; + + function &getInstance(&$db) { + static $instance; + if (!isset($instance)) + $instance =& new TagStatService($db); + return $instance; + } + + function TagStatService(&$db) { + $this->db =& $db; + $this->tablename = $GLOBALS['tableprefix'] .'tagsstats'; + } + + function getNbChildren($tag1, $relationType, $uId) { + $tts =& ServiceFactory::getServiceInstance('Tag2TagService'); + $query = "SELECT tag1, relationType, uId FROM `". $tts->getTableName() ."`"; + $query.= " WHERE tag1 = '" .$tag1 ."'"; + $query.= " AND relationType = '". $relationType ."'"; + $query.= " AND uId = '".$uId."'"; + + return $this->db->sql_numrows($this->db->sql_query($query)); + } + + function getNbDescendants($tag1, $relationType, $uId) { + $query = "SELECT nb FROM `". $this->getTableName() ."`"; + $query.= " WHERE tag1 = '" .$tag1 ."'"; + $query.= " AND relationType = '". $relationType ."'"; + $query.= " AND uId = '".$uId."'"; + + $dbresults =& $this->db->sql_query($query); + $row = $this->db->sql_fetchrow($dbresults); + if($row['nb'] == null) { + return 0; + } else { + return (int) $row['nb']; + } + } + + function getMaxDepth($tag1, $relationType, $uId) { + $query = "SELECT depth FROM `". $this->getTableName() ."`"; + $query.= " WHERE tag1 = '" .$tag1 ."'"; + $query.= " AND relationType = '". $relationType ."'"; + $query.= " AND uId = '".$uId."'"; + + $dbresults =& $this->db->sql_query($query); + $row = $this->db->sql_fetchrow($dbresults); + if($row['depth'] == null) { + return 0; + } else { + return (int) $row['depth']; + }; + } + + function getNbUpdates($tag1, $relationType, $uId) { + $query = "SELECT nbupdate FROM `". $this->getTableName() ."`"; + $query.= " WHERE tag1 = '" .$tag1 ."'"; + $query.= " AND relationType = '". $relationType ."'"; + $query.= " AND uId = '".$uId."'"; + + $dbresults =& $this->db->sql_query($query); + $row = $this->db->sql_fetchrow($dbresults); + if($row['nbupdate'] == null) { + return 0; + } else { + return (int) $row['nbupdate']; + } + } + + function existStat($tag1, $relationType, $uId) { + $query = "SELECT tag1, relationType, uId FROM `". $this->getTableName() ."`"; + $query.= " WHERE tag1 = '" .$tag1 ."'"; + $query.= " AND relationType = '". $relationType ."'"; + $query.= " AND uId = '".$uId."'"; + + return $this->db->sql_numrows($this->db->sql_query($query))>0; + } + + function createStat($tag1, $relationType, $uId) { + $query = "INSERT INTO `". $this->getTableName() ."`"; + $query.= "(tag1, relationType, uId)"; + $query.= " VALUES ('".$tag1."','".$relationType."','".$uId."')"; + $this->db->sql_query($query); + } + + function updateStat($tag1, $relationType, $uId=null, $stoplist=array()) { + if(in_array($tag1, $stoplist)) { + return false; + } + + $tts =& ServiceFactory::getServiceInstance('Tag2TagService'); + $linkedTags = $tts->getLinkedTags($tag1, $relationType, $uId); + $nbDescendants = 0; + $maxDepth = 0; + foreach($linkedTags as $linkedTag) { + $nbDescendants+= 1 + $this->getNbDescendants($linkedTag, $relationType, $uId); + $maxDepth = max($maxDepth, 1 + $this->getMaxDepth($linkedTag, $relationType, $uId)); + } + $this->setNbDescendants($tag1, $relationType, $uId, $nbDescendants); + $this->setMaxDepth($tag1, $relationType, $uId, $maxDepth); + $this->increaseNbUpdate($tag1, $relationType, $uId); + + // propagation to the precedent tags + $linkedTags = $tts->getLinkedTags($tag1, $relationType, $uId, true); + $stoplist[] = $tag1; + foreach($linkedTags as $linkedTag) { + $this->updateStat($linkedTag, $relationType, $uId, $stoplist); + } + } + + function updateAllStat() { + $tts =& ServiceFactory::getServiceInstance('Tag2TagService'); + + $query = "SELECT tag1, uId FROM `". $tts->getTableName() ."`"; + $query.= " WHERE relationType = '>'"; + + //die($query); + + if (! ($dbresult =& $this->db->sql_query($query)) ){ + message_die(GENERAL_ERROR, 'Could not update stats', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $rowset = $this->db->sql_fetchrowset($dbresult); + foreach($rowset as $row) { + $this->updateStat($row['tag1'], '>', $row['uId']); + } + } + + function setNbDescendants($tag1, $relationType, $uId, $nb) { + if(!$this->existStat($tag1, $relationType, $uId)) { + $this->createStat($tag1, $relationType, $uId); + } + $query = "UPDATE `". $this->getTableName() ."`"; + $query.= " SET nb = ". $nb; + $query.= " WHERE tag1 = '" .$tag1 ."'"; + $query.= " AND relationType = '". $relationType ."'"; + $query.= " AND uId = '".$uId."'"; + $this->db->sql_query($query); + } + + function setMaxDepth($tag1, $relationType, $uId, $depth) { + if(!$this->existStat($tag1, $relationType, $uId)) { + $this->createStat($tag1, $relationType, $uId); + } + $query = "UPDATE `". $this->getTableName() ."`"; + $query.= " SET depth = ". $depth; + $query.= " WHERE tag1 = '" .$tag1 ."'"; + $query.= " AND relationType = '". $relationType ."'"; + $query.= " AND uId = '".$uId."'"; + $this->db->sql_query($query); + } + + function increaseNbUpdate($tag1, $relationType, $uId) { + if(!$this->existStat($tag1, $relationType, $uId)) { + $this->createStat($tag1, $relationType, $uId); + } + $query = "UPDATE `". $this->getTableName() ."`"; + $query.= " SET nbupdate = nbupdate + 1"; + $query.= " WHERE tag1 = '" .$tag1 ."'"; + $query.= " AND relationType = '". $relationType ."'"; + $query.= " AND uId = '".$uId."'"; + + //die($query); + + $this->db->sql_query($query); + } + + function deleteTagStatForUser($uId) { + $query = 'DELETE FROM '. $this->getTableName() .' WHERE uId = '. intval($uId); + + if (!($dbresult = & $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not delete tag stats', '', __LINE__, + __FILE__, $query, $this->db); + return false; + } + + return true; + } + + function deleteAll() { + $query = 'TRUNCATE TABLE `'. $this->getTableName() .'`'; + $this->db->sql_query($query); + } + + // Properties + function getTableName() { return $this->tablename; } + function setTableName($value) { $this->tablename = $value; } +} +?> diff --git a/src/SemanticScuttle/Service/templateservice.php b/src/SemanticScuttle/Service/templateservice.php new file mode 100644 index 0000000..05e494c --- /dev/null +++ b/src/SemanticScuttle/Service/templateservice.php @@ -0,0 +1,46 @@ +<?php +class TemplateService { + var $basedir; + + function &getInstance() { + static $instance; + if (!isset($instance)) + $instance =& new TemplateService(); + return $instance; + } + + function TemplateService() { + $this->basedir = $GLOBALS['TEMPLATES_DIR']; + } + + function loadTemplate($template, $vars = NULL) { + if (substr($template, -4) != '.php') + $template .= '.php'; + $tpl =& new Template($this->basedir .'/'. $template, $vars, $this); + $tpl->parse(); + return $tpl; + } +} + +class Template { + var $vars = array(); + var $file = ''; + var $templateservice; + + function Template($file, $vars = NULL, &$templateservice) { + $this->vars = $vars; + $this->file = $file; + $this->templateservice = $templateservice; + } + + function parse() { + if (isset($this->vars)) + extract($this->vars); + include($this->file); + } + + function includeTemplate($name) { + return $this->templateservice->loadTemplate($name, $this->vars); + } +} +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/Service/userservice.php b/src/SemanticScuttle/Service/userservice.php new file mode 100644 index 0000000..407632b --- /dev/null +++ b/src/SemanticScuttle/Service/userservice.php @@ -0,0 +1,665 @@ +<?php +class UserService { + var $db; + var $fields = array( + 'primary' => 'uId', + 'username' => 'username', + 'password' => 'password'); + var $profileurl; + var $tablename; + var $sessionkey; + var $cookiekey; + var $cookietime = 1209600; // 2 weeks + + function &getInstance(&$db) { + static $instance; + if (!isset($instance)) + $instance =& new UserService($db); + return $instance; + } + + function UserService(& $db) { + $this->db =& $db; + $this->tablename = $GLOBALS['tableprefix'] .'users'; + $this->sessionkey = INSTALLATION_ID.'-currentuserid'; + $this->cookiekey = INSTALLATION_ID.'-login'; + $this->profileurl = createURL('profile', '%2$s'); + $this->updateSessionStability(); + } + + function _checkdns($host) { + if (function_exists('checkdnsrr')) { + return checkdnsrr($host); + } else { + return $this->_checkdnsrr($host); + } + } + + function _checkdnsrr($host, $type = "MX") { + if(!empty($host)) { + @exec("nslookup -type=$type $host", $output); + while(list($k, $line) = each($output)) { + if(eregi("^$host", $line)) { + return true; + } + } + return false; + } + } + + function _getuser($fieldname, $value) { + $query = 'SELECT * FROM '. $this->getTableName() .' WHERE '. $fieldname .' = "'. $this->db->sql_escape($value) .'"'; + + if (! ($dbresult =& $this->db->sql_query($query)) ) { + message_die(GENERAL_ERROR, 'Could not get user', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $row =& $this->db->sql_fetchrow($dbresult); + $this->db->sql_freeresult($dbresult); + if ($row) { + return $row; + } else { + return false; + } + } + + function & getUsers($nb=0) { + $query = 'SELECT * FROM '. $this->getTableName() .' ORDER BY `uId` DESC'; + if($nb>0) { + $query .= ' LIMIT 0, '.$nb; + } + if (! ($dbresult =& $this->db->sql_query($query)) ) { + message_die(GENERAL_ERROR, 'Could not get user', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + while ($row = & $this->db->sql_fetchrow($dbresult)) { + $users[] = $row; + } + $this->db->sql_freeresult($dbresult); + return $users; + } + + function & getObjectUsers($nb=0) { + $query = 'SELECT * FROM '. $this->getTableName() .' ORDER BY `uId` DESC'; + if($nb>0) { + $query .= ' LIMIT 0, '.$nb; + } + if (! ($dbresult =& $this->db->sql_query($query)) ) { + message_die(GENERAL_ERROR, 'Could not get user', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + while ($row = & $this->db->sql_fetchrow($dbresult)) { + $users[] = new User($row[$this->getFieldName('primary')], $row[$this->getFieldName('username')]); + } + $this->db->sql_freeresult($dbresult); + return $users; + } + + function _randompassword() { + $seed = (integer) md5(microtime()); + mt_srand($seed); + $password = mt_rand(1, 99999999); + $password = substr(md5($password), mt_rand(0, 19), mt_rand(6, 12)); + return $password; + } + + function _updateuser($uId, $fieldname, $value) { + $updates = array ($fieldname => $value); + $sql = 'UPDATE '. $this->getTableName() .' SET '. $this->db->sql_build_array('UPDATE', $updates) .' WHERE '. $this->getFieldName('primary') .'='. intval($uId); + + // Execute the statement. + $this->db->sql_transaction('begin'); + if (!($dbresult = & $this->db->sql_query($sql))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not update user', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + $this->db->sql_transaction('commit'); + + // Everything worked out, so return true. + return true; + } + + function getProfileUrl($id, $username) { + return sprintf($this->profileurl, urlencode($id), urlencode($username)); + } + + function getUserByUsername($username) { + return $this->_getuser($this->getFieldName('username'), $username); + } + + function getObjectUserByUsername($username) { + $user = $this->_getuser($this->getFieldName('username'), $username); + if($user != false) { + return new User($user[$this->getFieldName('primary')], $username); + } else { + return NULL; + } + } + + /* Takes an numerical "id" or a string "username" + and returns the numerical "id" if the user exists else returns NULL */ + function getIdFromUser($user) { + if (is_int($user)) { + return intval($user); + } else { + $objectUser = $this->getObjectUserByUsername($user); + if($objectUser != NULL) { + return $objectUser->getId(); + } + } + return NULL; + } + + function getUser($id) { + return $this->_getuser($this->getFieldName('primary'), $id); + } + + // Momentary useful in order to go to object code + function getObjectUser($id) { + $user = $this->_getuser($this->getFieldName('primary'), $id); + return new User($id, $user[$this->getFieldName('username')]); + } + + function isLoggedOn() { + return ($this->getCurrentUserId() !== false); + } + + function &getCurrentUser($refresh = FALSE, $newval = NULL) { + static $currentuser; + if (!is_null($newval)) { //internal use only: reset currentuser + $currentuser = $newval; + } else if ($refresh || !isset($currentuser)) { + if ($id = $this->getCurrentUserId()) { + $currentuser = $this->getUser($id); + } else { + $currentuser = null; + } + } + return $currentuser; + } + + // Momentary useful in order to go to object code + function getCurrentObjectUser($refresh = FALSE, $newval = NULL) { + static $currentObjectUser; + if (!is_null($newval)) { //internal use only: reset currentuser + $currentObjectUser = $newval; + } else if ($refresh || !isset($currentObjectUser)) { + if ($id = $this->getCurrentUserId()) { + $currentObjectUser = $this->getObjectUser($id); + } else { + $currentObjectUser = null; + } + } + return $currentObjectUser; + } + + function existsUserWithUsername($username) { + if($this->getUserByUsername($username) != '') { + return true; + } else { + return false; + } + } + + function existsUser($id) { + if($this->getUser($id) != '') { + return true; + } else { + return false; + } + } + + /** + * Checks if the given user is an administrator. + * Uses global admin_users property containing admin + * user names + * + * @param integer|array $user User ID or user row from DB + * + * @return boolean True if the user is admin + */ + function isAdmin($user) + { + if (is_numeric($user)) { + $user = $this->getUser($user); + } + + if (isset($GLOBALS['admin_users']) + && in_array($user['username'], $GLOBALS['admin_users']) + ) { + return true; + } else { + return false; + } + } + + /* return current user id based on session or cookie */ + function getCurrentUserId() { + if (isset($_SESSION[$this->getSessionKey()])) { + return $_SESSION[$this->getSessionKey()]; + } else if (isset($_COOKIE[$this->getCookieKey()])) { + $cook = split(':', $_COOKIE[$this->getCookieKey()]); + //cookie looks like this: 'id:md5(username+password)' + $query = 'SELECT * FROM '. $this->getTableName() . + ' WHERE MD5(CONCAT('.$this->getFieldName('username') . + ', '.$this->getFieldName('password') . + ')) = \''.$this->db->sql_escape($cook[1]).'\' AND '. + $this->getFieldName('primary'). ' = '. $this->db->sql_escape($cook[0]); + + if (! ($dbresult =& $this->db->sql_query($query)) ) { + message_die(GENERAL_ERROR, 'Could not get user', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + if ($row = $this->db->sql_fetchrow($dbresult)) { + $_SESSION[$this->getSessionKey()] = $row[$this->getFieldName('primary')]; + $this->db->sql_freeresult($dbresult); + return $_SESSION[$this->getSessionKey()]; + } + } + return false; + } + + function login($username, $password, $remember = FALSE) { + $password = $this->sanitisePassword($password); + $query = 'SELECT '. $this->getFieldName('primary') .' FROM '. $this->getTableName() .' WHERE '. $this->getFieldName('username') .' = "'. $this->db->sql_escape($username) .'" AND '. $this->getFieldName('password') .' = "'. $this->db->sql_escape($password) .'"'; + + if (! ($dbresult =& $this->db->sql_query($query)) ) { + message_die(GENERAL_ERROR, 'Could not get user', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + if ($row =& $this->db->sql_fetchrow($dbresult)) { + $id = $_SESSION[$this->getSessionKey()] = $row[$this->getFieldName('primary')]; + if ($remember) { + $cookie = $id .':'. md5($username.$password); + setcookie($this->cookiekey, $cookie, time() + $this->cookietime, '/'); + } + $this->db->sql_freeresult($dbresult); + return true; + } else { + return false; + } + } + + function logout() { + @setcookie($this->getCookiekey(), '', time() - 1, '/'); + unset($_COOKIE[$this->getCookiekey()]); + session_unset(); + $this->getCurrentUser(TRUE, false); + } + + function getWatchlist($uId) { + // Gets the list of user IDs being watched by the given user. + $query = 'SELECT watched FROM '. $GLOBALS['tableprefix'] .'watched WHERE uId = '. intval($uId); + + if (! ($dbresult =& $this->db->sql_query($query)) ) { + message_die(GENERAL_ERROR, 'Could not get watchlist', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $arrWatch = array(); + if ($this->db->sql_numrows($dbresult) == 0) { + $this->db->sql_freeresult($dbresult); + return $arrWatch; + } + while ($row =& $this->db->sql_fetchrow($dbresult)) { + $arrWatch[] = $row['watched']; + } + $this->db->sql_freeresult($dbresult); + return $arrWatch; + } + + function getWatchNames($uId, $watchedby = false) { + // Gets the list of user names being watched by the given user. + // - If $watchedby is false get the list of users that $uId watches + // - If $watchedby is true get the list of users that watch $uId + if ($watchedby) { + $table1 = 'b'; + $table2 = 'a'; + } else { + $table1 = 'a'; + $table2 = 'b'; + } + $query = 'SELECT '. $table1 .'.'. $this->getFieldName('username') .' FROM '. $GLOBALS['tableprefix'] .'watched AS W, '. $this->getTableName() .' AS a, '. $this->getTableName() .' AS b WHERE W.watched = a.'. $this->getFieldName('primary') .' AND W.uId = b.'. $this->getFieldName('primary') .' AND '. $table2 .'.'. $this->getFieldName('primary') .' = '. intval($uId) .' ORDER BY '. $table1 .'.'. $this->getFieldName('username'); + + if (!($dbresult =& $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not get watchlist', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $arrWatch = array(); + if ($this->db->sql_numrows($dbresult) == 0) { + $this->db->sql_freeresult($dbresult); + return $arrWatch; + } + while ($row =& $this->db->sql_fetchrow($dbresult)) { + $arrWatch[] = $row[$this->getFieldName('username')]; + } + $this->db->sql_freeresult($dbresult); + return $arrWatch; + } + + function getWatchStatus($watcheduser, $currentuser) { + // Returns true if the current user is watching the given user, and false otherwise. + $query = 'SELECT watched FROM '. $GLOBALS['tableprefix'] .'watched AS W INNER JOIN '. $this->getTableName() .' AS U ON U.'. $this->getFieldName('primary') .' = W.watched WHERE U.'. $this->getFieldName('primary') .' = '. intval($watcheduser) .' AND W.uId = '. intval($currentuser); + + if (! ($dbresult =& $this->db->sql_query($query)) ) { + message_die(GENERAL_ERROR, 'Could not get watchstatus', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $arrWatch = array(); + if ($this->db->sql_numrows($dbresult) == 0) + return false; + else + return true; + } + + function setWatchStatus($subjectUserID) { + if (!is_numeric($subjectUserID)) + return false; + + $currentUserID = $this->getCurrentUserId(); + $watched = $this->getWatchStatus($subjectUserID, $currentUserID); + + if ($watched) { + $sql = 'DELETE FROM '. $GLOBALS['tableprefix'] .'watched WHERE uId = '. intval($currentUserID) .' AND watched = '. intval($subjectUserID); + if (!($dbresult =& $this->db->sql_query($sql))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not add user to watch list', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + } else { + $values = array( + 'uId' => intval($currentUserID), + 'watched' => intval($subjectUserID) + ); + $sql = 'INSERT INTO '. $GLOBALS['tableprefix'] .'watched '. $this->db->sql_build_array('INSERT', $values); + if (!($dbresult =& $this->db->sql_query($sql))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not add user to watch list', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + } + + $this->db->sql_transaction('commit'); + return true; + } + + function addUser($username, $password, $email) { + // Set up the SQL UPDATE statement. + $datetime = gmdate('Y-m-d H:i:s', time()); + $password = $this->sanitisePassword($password); + $values = array('username' => $username, 'password' => $password, 'email' => $email, 'uDatetime' => $datetime, 'uModified' => $datetime); + $sql = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values); + + // Execute the statement. + $this->db->sql_transaction('begin'); + if (!($dbresult = & $this->db->sql_query($sql))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not insert user', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + $this->db->sql_transaction('commit'); + + // Everything worked out, so return true. + return true; + } + + function updateUser($uId, $password, $name, $email, $homepage, $uContent) { + if (!is_numeric($uId)) + return false; + + // Set up the SQL UPDATE statement. + $moddatetime = gmdate('Y-m-d H:i:s', time()); + if ($password == '') + $updates = array ('uModified' => $moddatetime, 'name' => $name, 'email' => $email, 'homepage' => $homepage, 'uContent' => $uContent); + else + $updates = array ('uModified' => $moddatetime, 'password' => $this->sanitisePassword($password), 'name' => $name, 'email' => $email, 'homepage' => $homepage, 'uContent' => $uContent); + $sql = 'UPDATE '. $this->getTableName() .' SET '. $this->db->sql_build_array('UPDATE', $updates) .' WHERE '. $this->getFieldName('primary') .'='. intval($uId); + + // Execute the statement. + $this->db->sql_transaction('begin'); + if (!($dbresult = & $this->db->sql_query($sql))) { + $this->db->sql_transaction('rollback'); + message_die(GENERAL_ERROR, 'Could not update user', '', __LINE__, __FILE__, $sql, $this->db); + return false; + } + $this->db->sql_transaction('commit'); + + // Everything worked out, so return true. + return true; + } + + function getAllUsers ( ) {
+ $query = 'SELECT * FROM '. $this->getTableName();
+
+ if (! ($dbresult =& $this->db->sql_query($query)) ) {
+ message_die(GENERAL_ERROR, 'Could not get users', '', __LINE__, __FILE__, $query, $this->db);
+ return false;
+ }
+
+ $rows = array();
+
+ while ( $row = $this->db->sql_fetchrow($dbresult) ) {
+ $rows[] = $row;
+ }
+ $this->db->sql_freeresult($dbresult);
+ return $rows;
+ } + + // Returns an array with admin uIds + function getAdminIds() { + $admins = array(); + foreach($GLOBALS['admin_users'] as $adminName) { + if($this->getIdFromUser($adminName) != NULL) + $admins[] = $this->getIdFromUser($adminName); + } + return $admins; + }
+
+ function deleteUser($uId) {
+ $query = 'DELETE FROM '. $this->getTableName() .' WHERE uId = '. intval($uId);
+
+ if (!($dbresult = & $this->db->sql_query($query))) {
+ message_die(GENERAL_ERROR, 'Could not delete user', '', __LINE__, __FILE__, $query, $this->db);
+ return false;
+ }
+
+ return true;
+ }
+ + + function sanitisePassword($password) { + return sha1(trim($password)); + } + + function generatePassword($uId) { + if (!is_numeric($uId)) + return false; + + $password = $this->_randompassword(); + + if ($this->_updateuser($uId, $this->getFieldName('password'), $this->sanitisePassword($password))) + return $password; + else + return false; + } + + function isReserved($username) { + if (in_array($username, $GLOBALS['reservedusers'])) { + return true; + } else { + return false; + } + } + + function isValidUsername($username) { + if (strlen($username) < 4) { + return false; + }elseif (strlen($username) > 24) { + // too long usernames are cut by database and may cause bugs when compared + return false; + } elseif (preg_match('/(\W)/', $username) > 0) { + // forbidden non-alphanumeric characters + return false; + } + return true; + } + + + + function isValidEmail($email) { + if (eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,6})$", $email)) { + list($emailUser, $emailDomain) = split("@", $email); + + // Check if the email domain has a DNS record + //if ($this->_checkdns($emailDomain)) { + return true; + //} + } + return false; + } + + /** + * Sets a session variable. + * Updates it when it is already set. + * This is used to detect if cookies work. + * + * @return void + * + * @see isSessionStable() + */ + function updateSessionStability() { + //find out if we have cookies enabled + if (!isset($_SESSION['sessionStable'])) { + $_SESSION['sessionStable'] = 0; + } else { + $_SESSION['sessionStable'] = 1; + } + } + + /** + * Tells you if the session is fresh or old. + * If the session is fresh, it's the first page + * call with that session id. If the session is old, + * we know that cookies (or session persistance) works + * + * @return boolean True if the + * + * @see updateSessionStability() + */ + function isSessionStable() { + return $_SESSION['sessionStable'] == 1; + } + + // Properties + function getTableName() { return $this->tablename; } + function setTableName($value) { $this->tablename = $value; } + + function getFieldName($field) { return $this->fields[$field]; } + function setFieldName($field, $value) { $this->fields[$field] = $value; } + + function getSessionKey() { return $this->sessionkey; } + function setSessionKey($value) { $this->sessionkey = $value; } + + function getCookieKey() { return $this->cookiekey; } + function setCookieKey($value) { $this->cookiekey = $value; } +} + + +/* Defines a user. Rare fields are filled if required. */ +class User { + + var $id; + var $username; + var $name; + var $email; + var $homepage; + var $content; + var $datetime; + var $isAdmin; + + function User($id, $username) { + $this->id = $id; + $this->username = $username; + } + + function getId() { + return $this->id; + } + + function getUsername() { + return $this->username; + } + + function getName() { + // Look for value only if not already set + if(!isset($this->name)) { + $userservice =& ServiceFactory::getServiceInstance('UserService'); + $user = $userservice->getUser($this->id); + $this->name = $user['name']; + } + return $this->name; + } + + function getEmail() { + // Look for value only if not already set + if(!isset($this->email)) { + $userservice =& ServiceFactory::getServiceInstance('UserService'); + $user = $userservice->getUser($this->id); + $this->email = $user['email']; + } + return $this->email; + } + + function getHomepage() { + // Look for value only if not already set + if(!isset($this->homepage)) { + $userservice =& ServiceFactory::getServiceInstance('UserService'); + $user = $userservice->getUser($this->id); + $this->homepage = $user['homepage']; + } + return $this->homepage; + } + + function getContent() { + // Look for value only if not already set + if(!isset($this->content)) { + $userservice =& ServiceFactory::getServiceInstance('UserService'); + $user = $userservice->getUser($this->id); + $this->content = $user['uContent']; + } + return $this->content; + } + + function getDatetime() { + // Look for value only if not already set + if(!isset($this->content)) { + $userservice =& ServiceFactory::getServiceInstance('UserService'); + $user = $userservice->getUser($this->id); + $this->datetime = $user['uDatetime']; + } + return $this->datetime; + } + + function isAdmin() { + // Look for value only if not already set + if(!isset($this->isAdmin)) { + $userservice =& ServiceFactory::getServiceInstance('UserService'); + $this->isAdmin = $userservice->isAdmin($this->id); + } + return $this->isAdmin; + } + + function getNbBookmarks($range = 'public') { + $bookmarkservice =& ServiceFactory::getServiceInstance('BookmarkService'); + return $bookmarkservice->countBookmarks($this->getId(), $range); + } +} +?> diff --git a/src/SemanticScuttle/constants.php b/src/SemanticScuttle/constants.php new file mode 100644 index 0000000..4940af8 --- /dev/null +++ b/src/SemanticScuttle/constants.php @@ -0,0 +1,62 @@ +<?php +/* + * Define constants used in all the application. + * Some constants are based on variables from configuration file. + */ + +// Debug managament +if(isset($GLOBALS['debugMode'])) { + define('DEBUG_MODE', $GLOBALS['debugMode']); + define('DEBUG_EXTRA', $GLOBALS['debugMode']); // Constant used exclusively into db/ directory +} + +// Determine the base URL as ROOT +if (!isset($GLOBALS['root'])) { + $pieces = explode('/', $_SERVER['SCRIPT_NAME']); + + $rootTmp = '/'; + foreach($pieces as $piece) { + //we eliminate possible sscuttle subfolders (like gsearch for example) + if ($piece != '' && !strstr($piece, '.php') && $piece != 'gsearch') { + $rootTmp .= $piece .'/'; + } + } + if (($rootTmp != '/') && (substr($rootTmp, -1, 1) != '/')) { + $rootTmp .= '/'; + } + + define('ROOT', 'http://'. $_SERVER['HTTP_HOST'] . $rootTmp); +} else { + define('ROOT', $GLOBALS['root']); +} + +// Error codes +define('GENERAL_MESSAGE', 200); +define('GENERAL_ERROR', 202); +define('CRITICAL_MESSAGE', 203); +define('CRITICAL_ERROR', 204); + +// Page name +define('PAGE_INDEX', "index"); +define('PAGE_BOOKMARKS', "bookmarks"); +define('PAGE_WATCHLIST', "watchlist"); + + +// Miscellanous + +// INSTALLATION_ID is based on directory DB and used as prefix (in session and cookie) to prevent mutual login for different installations on the same host server +define('INSTALLATION_ID', md5($GLOBALS['dbname'].$GLOBALS['tableprefix'])); + +// Correct bugs with PATH_INFO (maybe for Apache 1 or CGI) -- for 1&1 host... +if (isset($_SERVER['PATH_INFO']) && isset($_SERVER['ORIG_PATH_INFO'])) { + if(strlen($_SERVER["PATH_INFO"])<strlen($_SERVER["ORIG_PATH_INFO"])) { + $_SERVER["PATH_INFO"] = $_SERVER["ORIG_PATH_INFO"]; + } + if(strcasecmp($_SERVER["PATH_INFO"], $_SERVER["SCRIPT_NAME "]) == 0) { + unset($_SERVER["PATH_INFO"]); + } + if(strpos($_SERVER["PATH_INFO"], '.php') !== false) { + unset($_SERVER["PATH_INFO"]); + } +} +?> diff --git a/src/SemanticScuttle/db/db2.php b/src/SemanticScuttle/db/db2.php new file mode 100644 index 0000000..b1abf1a --- /dev/null +++ b/src/SemanticScuttle/db/db2.php @@ -0,0 +1,417 @@ +<?php +/** +* +* @package dbal_db2 +* @version $Id: db2.php,v 1.2 2005/06/10 08:52:03 devalley Exp $ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if(!defined("SQL_LAYER")) +{ + +define("SQL_LAYER","db2"); + +/** +* @package dbal_db2 +* DB2 Database Abstraction Layer +*/ +class sql_db +{ + + var $db_connect_id; + var $query_result; + var $query_resultset; + var $query_numrows; + var $next_id; + var $row = array(); + var $rowset = array(); + var $row_index; + var $num_queries = 0; + + // + // Constructor + // + function sql_db($sqlserver, $sqluser, $sqlpassword, $database, $persistency = true) + { + $this->persistency = $persistency; + $this->user = $sqluser; + $this->password = $sqlpassword; + $this->dbname = $database; + + $this->server = $sqlserver; + + if($this->persistency) + { + $this->db_connect_id = odbc_pconnect($this->server, "", ""); + } + else + { + $this->db_connect_id = odbc_connect($this->server, "", ""); + } + + if($this->db_connect_id) + { + @odbc_autocommit($this->db_connect_id, off); + + return $this->db_connect_id; + } + else + { + return false; + } + } + // + // Other base methods + // + function sql_close() + { + if($this->db_connect_id) + { + if($this->query_result) + { + @odbc_free_result($this->query_result); + } + $result = @odbc_close($this->db_connect_id); + return $result; + } + else + { + return false; + } + } + + + // + // Query method + // + function sql_query($query = "", $transaction = FALSE) + { + // + // Remove any pre-existing queries + // + unset($this->query_result); + unset($this->row); + if($query != "") + { + $this->num_queries++; + + if(!eregi("^INSERT ",$query)) + { + if(eregi("LIMIT", $query)) + { + preg_match("/^(.*)LIMIT ([0-9]+)[, ]*([0-9]+)*/s", $query, $limits); + + $query = $limits[1]; + if($limits[3]) + { + $row_offset = $limits[2]; + $num_rows = $limits[3]; + } + else + { + $row_offset = 0; + $num_rows = $limits[2]; + } + + $query .= " FETCH FIRST ".($row_offset+$num_rows)." ROWS ONLY OPTIMIZE FOR ".($row_offset+$num_rows)." ROWS"; + + $this->query_result = odbc_exec($this->db_connect_id, $query); + + $query_limit_offset = $row_offset; + $this->result_numrows[$this->query_result] = $num_rows; + } + else + { + $this->query_result = odbc_exec($this->db_connect_id, $query); + + $row_offset = 0; + $this->result_numrows[$this->query_result] = 5E6; + } + + $result_id = $this->query_result; + if($this->query_result && eregi("^SELECT", $query)) + { + + for($i = 1; $i < odbc_num_fields($result_id)+1; $i++) + { + $this->result_field_names[$result_id][] = odbc_field_name($result_id, $i); + } + + $i = $row_offset + 1; + $k = 0; + while(odbc_fetch_row($result_id, $i) && $k < $this->result_numrows[$result_id]) + { + + for($j = 1; $j < count($this->result_field_names[$result_id])+1; $j++) + { + $this->result_rowset[$result_id][$k][$this->result_field_names[$result_id][$j-1]] = odbc_result($result_id, $j); + } + $i++; + $k++; + } + + $this->result_numrows[$result_id] = $k; + $this->row_index[$result_id] = 0; + } + else + { + $this->result_numrows[$result_id] = @odbc_num_rows($result_id); + $this->row_index[$result_id] = 0; + } + } + else + { + if(eregi("^(INSERT|UPDATE) ", $query)) + { + $query = preg_replace("/\\\'/s", "''", $query); + } + + $this->query_result = odbc_exec($this->db_connect_id, $query); + + if($this->query_result) + { + $sql_id = "VALUES(IDENTITY_VAL_LOCAL())"; + + $id_result = odbc_exec($this->db_connect_id, $sql_id); + if($id_result) + { + $row_result = odbc_fetch_row($id_result); + if($row_result) + { + $this->next_id[$this->query_result] = odbc_result($id_result, 1); + } + } + } + + odbc_commit($this->db_connect_id); + + $this->query_limit_offset[$this->query_result] = 0; + $this->result_numrows[$this->query_result] = 0; + } + + return $this->query_result; + } + else + { + return false; + } + } + + // + // Other query methods + // + function sql_numrows($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + return $this->result_numrows[$query_id]; + } + else + { + return false; + } + } + function sql_affectedrows($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + return $this->result_numrows[$query_id]; + } + else + { + return false; + } + } + function sql_numfields($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $result = count($this->result_field_names[$query_id]); + return $result; + } + else + { + return false; + } + } + function sql_fieldname($offset, $query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $result = $this->result_field_names[$query_id][$offset]; + return $result; + } + else + { + return false; + } + } + function sql_fieldtype($offset, $query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $result = @odbc_field_type($query_id, $offset); + return $result; + } + else + { + return false; + } + } + function sql_fetchrow($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + if($this->row_index[$query_id] < $this->result_numrows[$query_id]) + { + $result = $this->result_rowset[$query_id][$this->row_index[$query_id]]; + $this->row_index[$query_id]++; + return $result; + } + else + { + return false; + } + } + else + { + return false; + } + } + function sql_fetchrowset($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $this->row_index[$query_id] = $this->result_numrows[$query_id]; + return $this->result_rowset[$query_id]; + } + else + { + return false; + } + } + function sql_fetchfield($field, $row = -1, $query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + if($row < $this->result_numrows[$query_id]) + { + if($row == -1) + { + $getrow = $this->row_index[$query_id]-1; + } + else + { + $getrow = $row; + } + + return $this->result_rowset[$query_id][$getrow][$this->result_field_names[$query_id][$field]]; + + } + else + { + return false; + } + } + else + { + return false; + } + } + function sql_rowseek($offset, $query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $this->row_index[$query_id] = 0; + return true; + } + else + { + return false; + } + } + function sql_nextid($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + return $this->next_id[$query_id]; + } + else + { + return false; + } + } + function sql_freeresult($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $result = @odbc_free_result($query_id); + return $result; + } + else + { + return false; + } + } + function sql_error($query_id = 0) + { +// $result['code'] = @odbc_error($this->db_connect_id); +// $result['message'] = @odbc_errormsg($this->db_connect_id); + + return ""; + } + +} // class sql_db + +} // if ... define + +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/db/firebird.php b/src/SemanticScuttle/db/firebird.php new file mode 100644 index 0000000..58a7d07 --- /dev/null +++ b/src/SemanticScuttle/db/firebird.php @@ -0,0 +1,527 @@ +<?php +/** +* +* @package dbal_firebird +* @version $Id: firebird.php,v 1.2 2005/06/10 08:52:03 devalley Exp $ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('SQL_LAYER')) +{ + +define('SQL_LAYER', 'firebird'); + +/** +* @package dbal_firebird +* Firebird/Interbase Database Abstraction Layer +* Minimum Requirement is Firebird 1.5+/Interbase 7.1+ +*/ +class sql_db +{ + var $db_connect_id; + var $query_result; + var $return_on_error = false; + var $transaction = false; + var $sql_time = 0; + var $num_queries = 0; + var $open_queries = array(); + + var $last_query_text = ''; + + function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false) + { + $this->persistency = $persistency; + $this->user = $sqluser; + $this->server = $sqlserver . (($port) ? ':' . $port : ''); + $this->dbname = $database; + + $this->db_connect_id = ($this->persistency) ? @ibase_pconnect($this->server . ':' . $this->dbname, $this->user, $sqlpassword, false, false, 3) : @ibase_connect($this->server . ':' . $this->dbname, $this->user, $sqlpassword, false, false, 3); + + return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); + } + + // + // Other base methods + // + function sql_close() + { + if (!$this->db_connect_id) + { + return false; + } + + if ($this->transaction) + { + @ibase_commit($this->db_connect_id); + } + + if (sizeof($this->open_queries)) + { + foreach ($this->open_queries as $i_query_id => $query_id) + { + @ibase_free_query($query_id); + } + } + + return @ibase_close($this->db_connect_id); + } + + function sql_return_on_error($fail = false) + { + $this->return_on_error = $fail; + } + + function sql_num_queries() + { + return $this->num_queries; + } + + function sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + $this->transaction = true; + break; + + case 'commit': + $result = @ibase_commit(); + $this->transaction = false; + + if (!$result) + { + @ibase_rollback(); + } + break; + + case 'rollback': + $result = @ibase_rollback(); + $this->transaction = false; + break; + + default: + $result = true; + } + + return $result; + } + + // Base query method + function sql_query($query = '', $cache_ttl = 0) + { + if ($query != '') + { + global $cache; + + $this->last_query_text = $query; + $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + + if (!$this->query_result) + { + $this->num_queries++; + + if (($this->query_result = @ibase_query($this->db_connect_id, $query)) === false) + { + $this->sql_error($query); + } + + // TODO: have to debug the commit states in firebird + if (!$this->transaction) + { + @ibase_commit_ret(); + } + + if ($cache_ttl && method_exists($cache, 'sql_save')) + { + $cache->sql_save($query, $this->query_result, $cache_ttl); + } + } + } + else + { + return false; + } + + return ($this->query_result) ? $this->query_result : false; + } + + function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) + { + if ($query != '') + { + $this->query_result = false; + + $query = 'SELECT FIRST ' . $total . ((!empty($offset)) ? ' SKIP ' . $offset : '') . substr($query, 6); + + return $this->sql_query($query, $cache_ttl); + } + else + { + return false; + } + } + + // Idea for this from Ikonboard + function sql_build_array($query, $assoc_ary = false) + { + if (!is_array($assoc_ary)) + { + return false; + } + + $fields = array(); + $values = array(); + if ($query == 'INSERT') + { + foreach ($assoc_ary as $key => $var) + { + $fields[] = $key; + + if (is_null($var)) + { + $values[] = 'NULL'; + } + elseif (is_string($var)) + { + $values[] = "'" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? intval($var) : $var; + } + } + + $query = ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')'; + } + else if ($query == 'UPDATE' || $query == 'SELECT') + { + $values = array(); + foreach ($assoc_ary as $key => $var) + { + if (is_null($var)) + { + $values[] = "$key = NULL"; + } + elseif (is_string($var)) + { + $values[] = "$key = '" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? "$key = " . intval($var) : "$key = $var"; + } + } + $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); + } + + return $query; + } + + // Other query methods + // + // NOTE :: Want to remove _ALL_ reliance on sql_numrows from core code ... + // don't want this here by a middle Milestone + function sql_numrows($query_id = false) + { + return FALSE; + } + + function sql_affectedrows() + { + // TODO: hmm, maybe doing something similar as in mssql-odbc.php? + return ($this->query_result) ? true : false; + } + + function sql_fetchrow($query_id = false) + { + global $cache; + + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_fetchrow($query_id); + } + + $row = array(); + $cur_row = @ibase_fetch_object($query_id, IBASE_TEXT); + + if (!$cur_row) + { + return false; + } + + foreach (get_object_vars($cur_row) as $key => $value) + { + $row[strtolower($key)] = trim(str_replace("\\0", "\0", str_replace("\\n", "\n", $value))); + } + return ($query_id) ? $row : false; + } + + function sql_fetchrowset($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + unset($this->rowset[$query_id]); + unset($this->row[$query_id]); + + $result = array(); + while ($this->rowset[$query_id] = get_object_vars(@ibase_fetch_object($query_id, IBASE_TEXT))) + { + $result[] = $this->rowset[$query_id]; + } + + return $result; + } + else + { + return false; + } + } + + function sql_fetchfield($field, $rownum = -1, $query_id = 0) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + if ($rownum > -1) + { + // erm... ok, my bad, we always use zero. :/ + for ($i = 0; $i <= $rownum; $i++) + { + $row = $this->sql_fetchrow($query_id); + } + + return $row[$field]; + } + else + { + if (empty($this->row[$query_id]) && empty($this->rowset[$query_id])) + { + if ($this->sql_fetchrow($query_id)) + { + $result = $this->row[$query_id][$field]; + } + } + else + { + if ($this->rowset[$query_id]) + { + $result = $this->rowset[$query_id][$field]; + } + else if ($this->row[$query_id]) + { + $result = $this->row[$query_id][$field]; + } + } + } + return $result; + } + else + { + return false; + } + } + + function sql_rowseek($rownum, $query_id = 0) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + for($i = 1; $i < $rownum; $i++) + { + if (!$this->sql_fetchrow($query_id)) + { + return false; + } + } + + return true; + } + + function sql_nextid() + { + if ($this->query_result && preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename)) + { + $query = "SELECT GEN_ID('" . $tablename[1] . "_gen', 0) AS new_id + FROM RDB\$DATABASE"; + if (!($temp_q_id = @ibase_query($this->db_connect_id, $query))) + { + return false; + } + + $temp_result = @ibase_fetch_object($temp_q_id); + $this->sql_freeresult($temp_q_id); + + return ($temp_result) ? $temp_result->last_value : false; + } + } + + function sql_freeresult($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (!$this->transaction && $query_id) + { + @ibase_commit(); + } + + return ($query_id) ? @ibase_free_result($query_id) : false; + } + + function sql_escape($msg) + { + return (@ini_get('magic_quotes_sybase') || strtolower(@ini_get('magic_quotes_sybase')) == 'on') ? str_replace('\\\'', '\'', addslashes($msg)) : str_replace('\'', '\'\'', stripslashes($msg)); + } + + function sql_error($sql = '') + { + if (!$this->return_on_error) + { + $this_page =(!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF']; + $this_page .= '&' .((!empty($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : $_ENV['QUERY_STRING']); + + $message = '<u>SQL ERROR</u> [ ' . SQL_LAYER . ' ]<br /><br />' . @ibase_errmsg() . '<br /><br /><u>CALLING PAGE</u><br /><br />' . $this_page .(($sql != '') ? '<br /><br /><u>SQL</u><br /><br />' . $sql : '') . '<br />'; + + if ($this->transaction) + { + $this->sql_transaction('rollback'); + } + + trigger_error($message, E_USER_ERROR); + } + + $result['message'] = @ibase_errmsg(); + $result['code'] = ''; + + return $result; + } + + function sql_report($mode, $query = '') + { + if (empty($_GET['explain'])) + { + return; + } + + global $cache, $starttime, $phpbb_root_path; + static $curtime, $query_hold, $html_hold; + static $sql_report = ''; + static $cache_num_queries = 0; + + if (!$query && !empty($query_hold)) + { + $query = $query_hold; + } + + switch ($mode) + { + case 'display': + if (!empty($cache)) + { + $cache->unload(); + } + $this->sql_close(); + + $mtime = explode(' ', microtime()); + $totaltime = $mtime[0] + $mtime[1] - $starttime; + + echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8869-1"><meta http-equiv="Content-Style-Type" content="text/css"><link rel="stylesheet" href="' . $phpbb_root_path . 'adm/subSilver.css" type="text/css"><style type="text/css">' . "\n"; + echo 'th { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic3.gif\') }' . "\n"; + echo 'td.cat { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic1.gif\') }' . "\n"; + echo '</style><title>' . $msg_title . '</title></head><body>'; + echo '<table width="100%" cellspacing="0" cellpadding="0" border="0"><tr><td><a href="' . htmlspecialchars(preg_replace('/&explain=([^&]*)/', '', $_SERVER['REQUEST_URI'])) . '"><img src="' . $phpbb_root_path . 'adm/images/header_left.jpg" width="200" height="60" alt="phpBB Logo" title="phpBB Logo" border="0"/></a></td><td width="100%" background="' . $phpbb_root_path . 'adm/images/header_bg.jpg" height="60" align="right" nowrap="nowrap"><span class="maintitle">SQL Report</span> </td></tr></table><br clear="all"/><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td height="40" align="center" valign="middle"><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries} queries" . (($cache_num_queries) ? " + $cache_num_queries " . (($cache_num_queries == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></td></tr><tr><td align="center" nowrap="nowrap">Time spent on MySQL queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></td></tr></table><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td>'; + echo $sql_report; + echo '</td></tr></table><br /></body></html>'; + exit; + break; + + case 'start': + $query_hold = $query; + $html_hold = ''; + + $curtime = explode(' ', microtime()); + $curtime = $curtime[0] + $curtime[1]; + break; + + case 'fromcache': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $result = @ibase_query($this->db_connect_id, $query); + while ($void = @ibase_fetch_object($result, IBASE_TEXT)) + { + // Take the time spent on parsing rows into account + } + $splittime = explode(' ', microtime()); + $splittime = $splittime[0] + $splittime[1]; + + $time_cache = $endtime - $curtime; + $time_db = $splittime - $endtime; + $color = ($time_db > $time_cache) ? 'green' : 'red'; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query results obtained from the cache</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table><p align="center">'; + + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p>'; + + // Pad the start time to not interfere with page timing + $starttime += $time_db; + + @ibase_freeresult($result); + $cache_num_queries++; + break; + + case 'stop': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query #' . $this->num_queries . '</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table> ' . $html_hold . '<p align="center">'; + + if ($this->query_result) + { + if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) + { + $sql_report .= "Affected rows: <b>" . $this->sql_affectedrows($this->query_result) . '</b> | '; + } + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $curtime) . 's</b>'; + } + else + { + $error = $this->sql_error(); + $sql_report .= '<b style="color: red">FAILED</b> - ' . SQL_LAYER . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); + } + + $sql_report .= '</p>'; + + $this->sql_time += $endtime - $curtime; + break; + } + } + +} // class sql_db + +} // if ... define + +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/db/index.htm b/src/SemanticScuttle/db/index.htm new file mode 100644 index 0000000..ee1f723 --- /dev/null +++ b/src/SemanticScuttle/db/index.htm @@ -0,0 +1,10 @@ +<html> +<head> +<title></title> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +</head> + +<body bgcolor="#FFFFFF" text="#000000"> + +</body> +</html> diff --git a/src/SemanticScuttle/db/mssql-odbc.php b/src/SemanticScuttle/db/mssql-odbc.php new file mode 100644 index 0000000..a2d3d02 --- /dev/null +++ b/src/SemanticScuttle/db/mssql-odbc.php @@ -0,0 +1,576 @@ +<?php +/** +* +* @package dbal_odbc_mssql +* @version $Id: mssql-odbc.php,v 1.2 2005/06/10 08:52:03 devalley Exp $ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('SQL_LAYER')) +{ + +define('SQL_LAYER', 'mssql-odbc'); + +/** +* @package dbal_odbc_mssql +* MSSQL ODBC Database Abstraction Layer for MSSQL +* Minimum Requirement is Version 2000+ +*/ +class sql_db +{ + var $db_connect_id; + var $query_result; + var $return_on_error = false; + var $transaction = false; + var $sql_time = 0; + var $num_queries = 0; + var $open_queries = array(); + + var $result_rowset = array(); + var $field_names = array(); + var $field_types = array(); + var $num_rows = array(); + var $current_row = array(); + + function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false) + { + $this->persistency = $persistency; + $this->user = $sqluser; + $this->server = $sqlserver . (($port) ? ':' . $port : ''); + $this->dbname = $database; + + $this->db_connect_id = ($this->persistency) ? @odbc_pconnect($this->server, $this->user, $sqlpassword) : @odbc_connect($this->server, $this->user, $sqlpassword); + + return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); + } + + // + // Other base methods + // + function sql_close() + { + if (!$this->db_connect_id) + { + return false; + } + + if ($this->transaction) + { + @odbc_commit($this->db_connect_id); + } + + if (sizeof($this->result_rowset)) + { + unset($this->result_rowset); + unset($this->field_names); + unset($this->field_types); + unset($this->num_rows); + unset($this->current_row); + } + + if (sizeof($this->open_queries)) + { + foreach ($this->open_queries as $i_query_id => $query_id) + { + @odbc_free_result($query_id); + } + } + + return @odbc_close($this->db_connect_id); + } + + function sql_return_on_error($fail = false) + { + $this->return_on_error = $fail; + } + + function sql_num_queries() + { + return $this->num_queries; + } + + function sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + $result = @odbc_autocommit($this->db_connect_id, false); + $this->transaction = true; + break; + + case 'commit': + $result = @odbc_commit($this->db_connect_id); + @odbc_autocommit($this->db_connect_id, true); + $this->transaction = false; + + if (!$result) + { + @odbc_rollback($this->db_connect_id); + @odbc_autocommit($this->db_connect_id, true); + } + break; + + case 'rollback': + $result = @odbc_rollback($this->db_connect_id); + @odbc_autocommit($this->db_connect_id, true); + $this->transaction = false; + break; + + default: + $result = true; + } + + return $result; + } + + // Base query method + function sql_query($query = '', $cache_ttl = 0) + { + if ($query != '') + { + global $cache; + + // EXPLAIN only in extra debug mode + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('start', $query); + } + + $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + + if (!$this->query_result) + { + $this->num_queries++; + + if (($this->query_result = $this->_odbc_execute_query($query)) === false) + { + $this->sql_error($query); + } + + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('stop', $query); + } + + if ($cache_ttl && method_exists($cache, 'sql_save')) + { + $this->open_queries[(int) $this->query_result] = $this->query_result; + $cache->sql_save($query, $this->query_result, $cache_ttl); + // odbc_free_result called within sql_save() + } + else if (strpos($query, 'SELECT') !== false && $this->query_result) + { + $this->open_queries[(int) $this->query_result] = $this->query_result; + } + } + else if (defined('DEBUG_EXTRA')) + { + $this->sql_report('fromcache', $query); + } + } + else + { + return false; + } + + return ($this->query_result) ? $this->query_result : false; + } + + function _odbc_execute_query($query) + { + $result = false; + + if (eregi("^SELECT ", $query)) + { + $result = @odbc_exec($this->db_connect_id, $query); + + if ($result) + { + if (empty($this->field_names[$result])) + { + for ($i = 1, $j = @odbc_num_fields($result) + 1; $i < $j; $i++) + { + $this->field_names[$result][] = @odbc_field_name($result, $i); + $this->field_types[$result][] = @odbc_field_type($result, $i); + } + } + + $this->current_row[$result] = 0; + $this->result_rowset[$result] = array(); + + $row_outer = (isset($row_offset)) ? $row_offset + 1 : 1; + $row_outer_max = (isset($num_rows)) ? $row_offset + $num_rows + 1 : 1E9; + $row_inner = 0; + + while (@odbc_fetch_row($result, $row_outer) && $row_outer < $row_outer_max) + { + for ($i = 0, $j = sizeof($this->field_names[$result]); $i < $j; $i++) + { + $this->result_rowset[$result][$row_inner][$this->field_names[$result][$i]] = stripslashes(@odbc_result($result, $i + 1)); + } + + $row_outer++; + $row_inner++; + } + + $this->num_rows[$result] = sizeof($this->result_rowset[$result]); + } + } + else if (eregi("^INSERT ", $query)) + { + $result = @odbc_exec($this->db_connect_id, $query); + + if ($result) + { + $result_id = @odbc_exec($this->db_connect_id, 'SELECT @@IDENTITY'); + if ($result_id) + { + if (@odbc_fetch_row($result_id)) + { + $this->next_id[$this->db_connect_id] = @odbc_result($result_id, 1); + $this->affected_rows[$this->db_connect_id] = @odbc_num_rows($result); + } + } + } + } + else + { + $result = @odbc_exec($this->db_connect_id, $query); + + if ($result) + { + $this->affected_rows[$this->db_connect_id] = @odbc_num_rows($result); + } + } + + return $result; + } + + function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) + { + if ($query != '') + { + $this->query_result = false; + + // if $total is set to 0 we do not want to limit the number of rows + if ($total == 0) + { + $total = -1; + } + + $row_offset = ($total) ? $offset : ''; + $num_rows = ($total) ? $total : $offset; + + $query = 'SELECT TOP ' . ($row_offset + $num_rows) . ' ' . substr($query, 6); + + return $this->sql_query($query, $cache_ttl); + } + else + { + return false; + } + } + + // Idea for this from Ikonboard + function sql_build_array($query, $assoc_ary = false) + { + if (!is_array($assoc_ary)) + { + return false; + } + + $fields = array(); + $values = array(); + if ($query == 'INSERT') + { + foreach ($assoc_ary as $key => $var) + { + $fields[] = $key; + + if (is_null($var)) + { + $values[] = 'NULL'; + } + elseif (is_string($var)) + { + $values[] = "'" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? intval($var) : $var; + } + } + + $query = ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')'; + } + else if ($query == 'UPDATE' || $query == 'SELECT') + { + $values = array(); + foreach ($assoc_ary as $key => $var) + { + if (is_null($var)) + { + $values[] = "$key = NULL"; + } + elseif (is_string($var)) + { + $values[] = "$key = '" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? "$key = " . intval($var) : "$key = $var"; + } + } + $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); + } + + return $query; + } + + // Other query methods + // + // NOTE :: Want to remove _ALL_ reliance on sql_numrows from core code ... + // don't want this here by a middle Milestone + function sql_numrows($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return ($query_id) ? @$this->num_rows($query_id) : false; + } + + function sql_affectedrows() + { + return ($this->affected_rows[$this->db_connect_id]) ? $this->affected_rows[$this->db_connect_id] : false; + } + + function sql_fetchrow($query_id = false) + { + global $cache; + + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_fetchrow($query_id); + } + + return ($this->num_rows[$query_id] && $this->current_row[$query_id] < $this->num_rows[$query_id]) ? $this->result_rowset[$query_id][$this->current_row[$query_id]++] : false; + } + + function sql_fetchrowset($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return ($this->num_rows[$query_id]) ? $this->result_rowset[$query_id] : false; + } + + function sql_fetchfield($field, $rownum = -1, $query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + if ($rownum < $this->num_rows[$query_id]) + { + $getrow = ($rownum == -1) ? $this->current_row[$query_id] - 1 : $rownum; + + return $this->result_rowset[$query_id][$getrow][$this->field_names[$query_id][$field]]; + } + } + + return false; + } + + function sql_rowseek($rownum, $query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (isset($this->current_row[$query_id])) + { + $this->current_row[$query_id] = $rownum; + return true; + } + + return false; + } + + function sql_nextid() + { + return ($this->next_id[$this->db_connect_id]) ? $this->next_id[$this->db_connect_id] : false; + } + + function sql_freeresult($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (isset($this->open_queries[(int) $query_id])) + { + unset($this->open_queries[(int) $query_id]); + unset($this->num_rows[$query_id]); + unset($this->current_row[$query_id]); + unset($this->result_rowset[$query_id]); + unset($this->field_names[$query_id]); + unset($this->field_types[$query_id]); + + return @odbc_free_result($query_id); + } + + return false; + } + + function sql_escape($msg) + { + return str_replace("'", "''", str_replace('\\', '\\\\', $msg)); + } + + function sql_error($sql = '') + { + if (!$this->return_on_error) + { + $this_page = (isset($_SERVER['PHP_SELF']) && !empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF']; + $this_page .= '&' . ((isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : (isset($_ENV['QUERY_STRING']) ? $_ENV['QUERY_STRING'] : '')); + + $message = '<u>SQL ERROR</u> [ ' . SQL_LAYER . ' ]<br /><br />' . @odbc_errormsg() . '<br /><br /><u>CALLING PAGE</u><br /><br />' . htmlspecialchars($this_page) . (($sql != '') ? '<br /><br /><u>SQL</u><br /><br />' . $sql : '') . '<br />'; + + if ($this->transaction) + { + $this->sql_transaction('rollback'); + } + + trigger_error($message, E_USER_ERROR); + } + + $result = array( + 'message' => @odbc_errormsg(), + 'code' => @odbc_error() + ); + + return $result; + } + + function sql_report($mode, $query = '') + { + if (empty($_GET['explain'])) + { + return; + } + + global $cache, $starttime, $phpbb_root_path; + static $curtime, $query_hold, $html_hold; + static $sql_report = ''; + static $cache_num_queries = 0; + + if (!$query && !empty($query_hold)) + { + $query = $query_hold; + } + + switch ($mode) + { + case 'display': + if (!empty($cache)) + { + $cache->unload(); + } + $this->sql_close(); + + $mtime = explode(' ', microtime()); + $totaltime = $mtime[0] + $mtime[1] - $starttime; + + echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8869-1"><meta http-equiv="Content-Style-Type" content="text/css"><link rel="stylesheet" href="' . $phpbb_root_path . 'adm/subSilver.css" type="text/css"><style type="text/css">' . "\n"; + echo 'th { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic3.gif\') }' . "\n"; + echo 'td.cat { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic1.gif\') }' . "\n"; + echo '</style><title>' . $msg_title . '</title></head><body>'; + echo '<table width="100%" cellspacing="0" cellpadding="0" border="0"><tr><td><a href="' . htmlspecialchars(preg_replace('/&explain=([^&]*)/', '', $_SERVER['REQUEST_URI'])) . '"><img src="' . $phpbb_root_path . 'adm/images/header_left.jpg" width="200" height="60" alt="phpBB Logo" title="phpBB Logo" border="0"/></a></td><td width="100%" background="' . $phpbb_root_path . 'adm/images/header_bg.jpg" height="60" align="right" nowrap="nowrap"><span class="maintitle">SQL Report</span> </td></tr></table><br clear="all"/><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td height="40" align="center" valign="middle"><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries} queries" . (($cache_num_queries) ? " + $cache_num_queries " . (($cache_num_queries == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></td></tr><tr><td align="center" nowrap="nowrap">Time spent on MySQL queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></td></tr></table><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td>'; + echo $sql_report; + echo '</td></tr></table><br /></body></html>'; + exit; + break; + + case 'start': + $query_hold = $query; + $html_hold = ''; + + $curtime = explode(' ', microtime()); + $curtime = $curtime[0] + $curtime[1]; + break; + + case 'fromcache': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $result = $this->_odbc_execute_query($query); + + $splittime = explode(' ', microtime()); + $splittime = $splittime[0] + $splittime[1]; + + $time_cache = $endtime - $curtime; + $time_db = $splittime - $endtime; + $color = ($time_db > $time_cache) ? 'green' : 'red'; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query results obtained from the cache</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table><p align="center">'; + + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p>'; + + // Pad the start time to not interfere with page timing + $starttime += $time_db; + + @odbc_free_result($result); + $cache_num_queries++; + break; + + case 'stop': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query #' . $this->num_queries . '</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table> ' . $html_hold . '<p align="center">'; + + if ($this->query_result) + { + if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) + { + $sql_report .= "Affected rows: <b>" . $this->sql_affectedrows($this->query_result) . '</b> | '; + } + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $curtime) . 's</b>'; + } + else + { + $error = $this->sql_error(); + $sql_report .= '<b style="color: red">FAILED</b> - ' . SQL_LAYER . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); + } + + $sql_report .= '</p>'; + + $this->sql_time += $endtime - $curtime; + break; + } + } + +} // class sql_db + +} // if ... define + +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/db/mssql.php b/src/SemanticScuttle/db/mssql.php new file mode 100644 index 0000000..2b17b9e --- /dev/null +++ b/src/SemanticScuttle/db/mssql.php @@ -0,0 +1,551 @@ +<?php +/** +* +* @package dbal_mssql +* @version $Id: mssql.php,v 1.2 2005/06/10 08:52:03 devalley Exp $ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('SQL_LAYER')) +{ + +define('SQL_LAYER', 'mssql'); + +/** +* @package dbal_mssql +* MSSQL Database Abstraction Layer +* Minimum Requirement is MSSQL 2000+ +*/ +class sql_db +{ + var $db_connect_id; + var $query_result; + var $return_on_error = false; + var $transaction = false; + var $sql_time = 0; + var $num_queries = 0; + var $open_queries = array(); + + function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false) + { + $this->persistency = $persistency; + $this->user = $sqluser; + $this->server = $sqlserver . (($port) ? ':' . $port : ''); + $this->dbname = $database; + + $this->db_connect_id = ($this->persistency) ? @mssql_pconnect($this->server, $this->user, $sqlpassword) : @mssql_connect($this->server, $this->user, $sqlpassword); + + if ($this->db_connect_id && $this->dbname != '') + { + if (!@mssql_select_db($this->dbname, $this->db_connect_id)) + { + @mssql_close($this->db_connect_id); + return false; + } + } + + return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); + } + + function sql_close() + { + if (!$this->db_connect_id) + { + return false; + } + + if ($this->transaction) + { + @mssql_query('COMMIT', $this->db_connect_id); + } + + if (sizeof($this->open_queries)) + { + foreach ($this->open_queries as $i_query_id => $query_id) + { + @mssql_free_result($query_id); + } + } + + return @mssql_close($this->db_connect_id); + } + + function sql_return_on_error($fail = false) + { + $this->return_on_error = $fail; + } + + function sql_num_queries() + { + return $this->num_queries; + } + + function sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + $result = @mssql_query('BEGIN TRANSACTION', $this->db_connect_id); + $this->transaction = true; + break; + + case 'commit': + $result = @mssql_query('commit', $this->db_connect_id); + $this->transaction = false; + + if (!$result) + { + @mssql_query('ROLLBACK', $this->db_connect_id); + } + break; + + case 'rollback': + $result = @mssql_query('ROLLBACK', $this->db_connect_id); + $this->transaction = false; + break; + + default: + $result = true; + } + + return $result; + } + + // Base query method + function sql_query($query = '', $cache_ttl = 0) + { + if ($query != '') + { + global $cache; + + // EXPLAIN only in extra debug mode + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('start', $query); + } + + $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + + if (!$this->query_result) + { + $this->num_queries++; + + if (($this->query_result = @mssql_query($query, $this->db_connect_id)) === false) + { + $this->sql_error($query); + } + + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('stop', $query); + } + + if ($cache_ttl && method_exists($cache, 'sql_save')) + { + $this->open_queries[(int) $this->query_result] = $this->query_result; + $cache->sql_save($query, $this->query_result, $cache_ttl); + // sql_freeresult called within sql_save() + } + else if (strpos($query, 'SELECT') !== false && $this->query_result) + { + $this->open_queries[(int) $this->query_result] = $this->query_result; + } + } + else if (defined('DEBUG_EXTRA')) + { + $this->sql_report('fromcache', $query); + } + } + else + { + return false; + } + + return ($this->query_result) ? $this->query_result : false; + } + + function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) + { + if ($query != '') + { + $this->query_result = false; + + // if $total is set to 0 we do not want to limit the number of rows + if ($total == 0) + { + $total = -1; + } + + $row_offset = ($total) ? $offset : ''; + $num_rows = ($total) ? $total : $offset; + + $query = 'SELECT TOP ' . ($row_offset + $num_rows) . ' ' . substr($query, 6); + + return $this->sql_query($query, $cache_ttl); + } + else + { + return false; + } + } + + // Idea for this from Ikonboard + function sql_build_array($query, $assoc_ary = false) + { + if (!is_array($assoc_ary)) + { + return false; + } + + $fields = array(); + $values = array(); + if ($query == 'INSERT') + { + foreach ($assoc_ary as $key => $var) + { + $fields[] = $key; + + if (is_null($var)) + { + $values[] = 'NULL'; + } + elseif (is_string($var)) + { + $values[] = "'" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? intval($var) : $var; + } + } + + $query = ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')'; + } + else if ($query == 'UPDATE' || $query == 'SELECT') + { + $values = array(); + foreach ($assoc_ary as $key => $var) + { + if (is_null($var)) + { + $values[] = "$key = NULL"; + } + elseif (is_string($var)) + { + $values[] = "$key = '" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? "$key = " . intval($var) : "$key = $var"; + } + } + $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); + } + + return $query; + } + + // Other query methods + // + // NOTE :: Want to remove _ALL_ reliance on sql_numrows from core code ... + // don't want this here by a middle Milestone + function sql_numrows($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + +// return (isset($this->limit_offset[$query_id])) ? @mssql_num_rows($query_id) - $this->limit_offset[$query_id] : @mssql_num_rows($query_id); + return ($query_id) ? @mssql_num_rows($query_id) : false; + } + + function sql_affectedrows() + { + return ($this->db_connect_id) ? @mssql_rows_affected($this->db_connect_id) : false; + } + + function sql_fetchrow($query_id = false) + { + global $cache; + + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_fetchrow($query_id); + } + + $row = @mssql_fetch_array($query_id, MSSQL_ASSOC); + + if ($row) + { + foreach ($row as $key => $value) + { + $row[$key] = ($value === ' ') ? trim($value) : $value; + } + } + + return $row; + } + + function sql_fetchrowset($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + unset($this->rowset[$query_id]); + unset($this->row[$query_id]); + + $result = array(); + while ($this->rowset[$query_id] = $this->sql_fetchrow($query_id)) + { + $result[] = $this->rowset[$query_id]; + } + return $result; + } + + return false; + } + + function sql_fetchfield($field, $rownum = -1, $query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + if ($rownum > -1) + { +// (!empty($this->limit_offset[$query_id])) ? @mssql_data_seek($query_id, ($this->limit_offset[$query_id] + $rownum)) : @mssql_data_seek($query_id, $rownum); + @mssql_data_seek($query_id, $rownum); + $row = @mssql_fetch_array($query_id, MSSQL_ASSOC); + $result = isset($row[$field]) ? $row[$field] : false; + } + else + { + if (empty($this->row[$query_id]) && empty($this->rowset[$query_id])) + { + if ($this->sql_fetchrow($query_id)) + { + $result = $this->row[$query_id][$field]; + } + } + else + { + if ($this->rowset[$query_id]) + { + $result = $this->rowset[$query_id][$field]; + } + elseif ($this->row[$query_id]) + { + $result = $this->row[$query_id][$field]; + } + } + } + + return $result; + } + + return false; + } + + function sql_rowseek($rownum, $query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (isset($this->current_row[$query_id])) + { +// (!empty($this->limit_offset[$query_id])) ? @mssql_data_seek($query_id, ($this->limit_offset[$query_id] + $rownum)) : @mssql_data_seek($query_id, $rownum); + @mssql_data_seek($query_id, $rownum); + return true; + } + + return false; + } + + function sql_nextid() + { + $result_id = @mssql_query('SELECT @@IDENTITY', $this->db_connect_id); + if ($result_id) + { + if (@mssql_fetch_array($result_id, MSSQL_ASSOC)) + { + return @mssql_result($result_id, 1); + } + } + + return false; + } + + function sql_freeresult($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (isset($this->open_queries[$query_id])) + { + unset($this->open_queries[$query_id]); + unset($this->result_rowset[$query_id]); + + return @mssql_free_result($query_id); + } + + return false; + } + + function sql_escape($msg) + { + return str_replace("'", "''", str_replace('\\', '\\\\', $msg)); + } + + function sql_error($sql = '') + { + if (!$this->return_on_error) + { + $this_page = (isset($_SERVER['PHP_SELF']) && !empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF']; + $this_page .= '&' . ((isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : (isset($_ENV['QUERY_STRING']) ? $_ENV['QUERY_STRING'] : '')); + + $message = '<u>SQL ERROR</u> [ ' . SQL_LAYER . ' ]<br /><br />' . @mssql_get_last_message() . '<br /><br /><u>CALLING PAGE</u><br /><br />' . htmlspecialchars($this_page) . (($sql != '') ? '<br /><br /><u>SQL</u><br /><br />' . $sql : '') . '<br />'; + + if ($this->transaction) + { + $this->sql_transaction('rollback'); + } + + trigger_error($message, E_USER_ERROR); + } + + $result = array( + 'message' => @mssql_get_last_message($this->db_connect_id), + 'code' => '' + ); + + return $result; + } + + function sql_report($mode, $query = '') + { + if (empty($_GET['explain'])) + { + return; + } + + global $cache, $starttime, $phpbb_root_path; + static $curtime, $query_hold, $html_hold; + static $sql_report = ''; + static $cache_num_queries = 0; + + if (!$query && !empty($query_hold)) + { + $query = $query_hold; + } + + switch ($mode) + { + case 'display': + if (!empty($cache)) + { + $cache->unload(); + } + $this->sql_close(); + + $mtime = explode(' ', microtime()); + $totaltime = $mtime[0] + $mtime[1] - $starttime; + + echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8869-1"><meta http-equiv="Content-Style-Type" content="text/css"><link rel="stylesheet" href="' . $phpbb_root_path . 'adm/subSilver.css" type="text/css"><style type="text/css">' . "\n"; + echo 'th { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic3.gif\') }' . "\n"; + echo 'td.cat { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic1.gif\') }' . "\n"; + echo '</style><title>' . $msg_title . '</title></head><body>'; + echo '<table width="100%" cellspacing="0" cellpadding="0" border="0"><tr><td><a href="' . htmlspecialchars(preg_replace('/&explain=([^&]*)/', '', $_SERVER['REQUEST_URI'])) . '"><img src="' . $phpbb_root_path . 'adm/images/header_left.jpg" width="200" height="60" alt="phpBB Logo" title="phpBB Logo" border="0"/></a></td><td width="100%" background="' . $phpbb_root_path . 'adm/images/header_bg.jpg" height="60" align="right" nowrap="nowrap"><span class="maintitle">SQL Report</span> </td></tr></table><br clear="all"/><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td height="40" align="center" valign="middle"><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries} queries" . (($cache_num_queries) ? " + $cache_num_queries " . (($cache_num_queries == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></td></tr><tr><td align="center" nowrap="nowrap">Time spent on MySQL queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></td></tr></table><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td>'; + echo $sql_report; + echo '</td></tr></table><br /></body></html>'; + exit; + break; + + case 'start': + $query_hold = $query; + $html_hold = ''; + + $curtime = explode(' ', microtime()); + $curtime = $curtime[0] + $curtime[1]; + break; + + case 'fromcache': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $result = @mssql_query($query, $this->db_connect_id); + while ($void = @mssql_fetch_array($result, MSSQL_ASSOC)) + { + // Take the time spent on parsing rows into account + } + $splittime = explode(' ', microtime()); + $splittime = $splittime[0] + $splittime[1]; + + $time_cache = $endtime - $curtime; + $time_db = $splittime - $endtime; + $color = ($time_db > $time_cache) ? 'green' : 'red'; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query results obtained from the cache</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table><p align="center">'; + + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p>'; + + // Pad the start time to not interfere with page timing + $starttime += $time_db; + + @mssql_free_result($result); + $cache_num_queries++; + break; + + case 'stop': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query #' . $this->num_queries . '</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table> ' . $html_hold . '<p align="center">'; + + if ($this->query_result) + { + if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) + { + $sql_report .= "Affected rows: <b>" . $this->sql_affectedrows($this->query_result) . '</b> | '; + } + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $curtime) . 's</b>'; + } + else + { + $error = $this->sql_error(); + $sql_report .= '<b style="color: red">FAILED</b> - ' . SQL_LAYER . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); + } + + $sql_report .= '</p>'; + + $this->sql_time += $endtime - $curtime; + break; + } + } + +} // class sql_db + +} // if ... define + +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/db/mysql.php b/src/SemanticScuttle/db/mysql.php new file mode 100644 index 0000000..a646e0d --- /dev/null +++ b/src/SemanticScuttle/db/mysql.php @@ -0,0 +1,552 @@ +<?php +/** +* +* @package dbal_mysql +* @version $Id: mysql.php,v 1.5 2006/02/10 01:30:19 scronide Exp $ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('SQL_LAYER')) +{ + +define('SQL_LAYER', 'mysql'); + +/** +* @package dbal_mysql +* MySQL Database Abstraction Layer +* Minimum Requirement is 3.23+/4.0+/4.1+ +*/ +class sql_db +{ + var $db_connect_id; + var $query_result; + var $return_on_error = false; + var $transaction = false; + var $sql_time = 0; + var $num_queries = 0; + var $open_queries = array(); + + function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false) + { + $this->persistency = $persistency; + $this->user = $sqluser; + $this->server = $sqlserver . (($port) ? ':' . $port : ''); + $this->dbname = $database; + + $this->db_connect_id = ($this->persistency) ? @mysql_pconnect($this->server, $this->user, $sqlpassword) : @mysql_connect($this->server, $this->user, $sqlpassword); + + if ($this->db_connect_id && $this->dbname != '') + { + if (@mysql_select_db($this->dbname)) + { + return $this->db_connect_id; + } + } + + return $this->sql_error(''); + } + + // + // Other base methods + // + function sql_close() + { + if (!$this->db_connect_id) + { + return false; + } + + if (sizeof($this->open_queries)) + { + foreach ($this->open_queries as $i_query_id => $query_id) + { + @mysql_free_result($query_id); + } + } + + return @mysql_close($this->db_connect_id); + } + + function sql_return_on_error($fail = false) + { + $this->return_on_error = $fail; + } + + function sql_num_queries() + { + return $this->num_queries; + } + + function sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + $result = @mysql_query('BEGIN', $this->db_connect_id); + $this->transaction = true; + break; + + case 'commit': + $result = @mysql_query('COMMIT', $this->db_connect_id); + $this->transaction = false; + + if (!$result) + { + @mysql_query('ROLLBACK', $this->db_connect_id); + } + break; + + case 'rollback': + $result = @mysql_query('ROLLBACK', $this->db_connect_id); + $this->transaction = false; + break; + + default: + $result = true; + } + + return $result; + } + + // Base query method + function sql_query($query = '', $cache_ttl = 0) + { + if ($query != '') + { + global $cache; + + // EXPLAIN only in extra debug mode + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('start', $query); + } + + $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + + if (!$this->query_result) + { + $this->num_queries++; + + if (($this->query_result = @mysql_query($query, $this->db_connect_id)) === false) + { + $this->sql_error($query); + } + + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('stop', $query); + } + + if ($cache_ttl && method_exists($cache, 'sql_save')) + { + $this->open_queries[(int) $this->query_result] = $this->query_result; + $cache->sql_save($query, $this->query_result, $cache_ttl); + // mysql_free_result called within sql_save() + } + else if (strpos($query, 'SELECT') !== false && $this->query_result) + { + $this->open_queries[(int) $this->query_result] = $this->query_result; + } + } + else if (defined('DEBUG_EXTRA')) + { + $this->sql_report('fromcache', $query); + } + } + else + { + return false; + } + + return ($this->query_result) ? $this->query_result : false; + } + + function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { + if ($query != '') { + $this->query_result = false; + + // only limit the number of rows if $total is greater than 0 + if ($total > 0) + $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); + + return $this->sql_query($query, $cache_ttl); + } else { + return false; + } + } + + // Idea for this from Ikonboard + function sql_build_array($query, $assoc_ary = false) + { + if (!is_array($assoc_ary)) + { + return false; + } + + $fields = array(); + $values = array(); + if ($query == 'INSERT') + { + foreach ($assoc_ary as $key => $var) + { + $fields[] = $key; + + if (is_null($var)) + { + $values[] = 'NULL'; + } + elseif (is_string($var)) + { + $values[] = "'" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? intval($var) : $var; + } + } + + $query = ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')'; + } + else if ($query == 'UPDATE' || $query == 'SELECT') + { + $values = array(); + foreach ($assoc_ary as $key => $var) + { + if (is_null($var)) + { + $values[] = "$key = NULL"; + } + elseif (is_string($var)) + { + $values[] = "$key = '" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? "$key = " . intval($var) : "$key = $var"; + } + } + $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); + } + + return $query; + } + + // Other query methods + // + // NOTE :: Want to remove _ALL_ reliance on sql_numrows from core code ... + // don't want this here by a middle Milestone + function sql_numrows($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return ($query_id) ? @mysql_num_rows($query_id) : false; + } + + function sql_affectedrows() + { + return ($this->db_connect_id) ? @mysql_affected_rows($this->db_connect_id) : false; + } + + function sql_fetchrow($query_id = false) + { + global $cache; + + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_fetchrow($query_id); + } + + return ($query_id) ? @mysql_fetch_assoc($query_id) : false; + } + + function sql_fetchrowset($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + unset($this->rowset[$query_id]); + unset($this->row[$query_id]); + + $result = array(); + while ($this->rowset[$query_id] = $this->sql_fetchrow($query_id)) + { + $result[] = $this->rowset[$query_id]; + } + return $result; + } + + return false; + } + + function sql_fetchfield($field, $rownum = -1, $query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + if ($rownum > -1) + { + $result = @mysql_result($query_id, $rownum, $field); + } + else + { + if (empty($this->row[$query_id]) && empty($this->rowset[$query_id])) + { + if ($this->sql_fetchrow($query_id)) + { + $result = $this->row[$query_id][$field]; + } + } + else + { + if ($this->rowset[$query_id]) + { + $result = $this->rowset[$query_id][$field]; + } + elseif ($this->row[$query_id]) + { + $result = $this->row[$query_id][$field]; + } + } + } + return $result; + } + return false; + } + + function sql_rowseek($rownum, $query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return ($query_id) ? @mysql_data_seek($query_id, $rownum) : false; + } + + function sql_nextid() + { + return ($this->db_connect_id) ? @mysql_insert_id($this->db_connect_id) : false; + } + + function sql_freeresult($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (isset($this->open_queries[(int) $query_id])) + { + unset($this->open_queries[(int) $query_id]); + return @mysql_free_result($query_id); + } + + return false; + } + + function sql_escape($msg) { + if (function_exists('mysql_real_escape_string')) { + return @mysql_real_escape_string($msg, $this->db_connect_id); + } else { + return mysql_escape_string($msg); + } + } + + function sql_error($sql = '') + { + if (!$this->return_on_error) + { + $this_page = (isset($_SERVER['PHP_SELF']) && !empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF']; + $this_page .= '&' . ((isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : (isset($_ENV['QUERY_STRING']) ? $_ENV['QUERY_STRING'] : '')); + + $message = '<u>SQL ERROR</u> [ ' . SQL_LAYER . ' ]<br /><br />' . @mysql_error() . '<br /><br /><u>CALLING PAGE</u><br /><br />' . htmlspecialchars($this_page) . (($sql != '') ? '<br /><br /><u>SQL</u><br /><br />' . $sql : '') . '<br />'; + + if ($this->transaction) + { + $this->sql_transaction('rollback'); + } + + trigger_error($message, E_USER_ERROR); + } + + $result = array( + 'message' => @mysql_error(), + 'code' => @mysql_errno() + ); + + return $result; + } + + function sql_report($mode, $query = '') + { + if (empty($_GET['explain'])) + { + return; + } + + global $db, $cache, $starttime, $phpbb_root_path; + static $curtime, $query_hold, $html_hold; + static $sql_report = ''; + static $cache_num_queries = 0; + + if (!$query && !empty($query_hold)) + { + $query = $query_hold; + } + + switch ($mode) + { + case 'display': + if (!empty($cache)) + { + $cache->unload(); + } + $db->sql_close(); + + $mtime = explode(' ', microtime()); + $totaltime = $mtime[0] + $mtime[1] - $starttime; + + echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8869-1"><meta http-equiv="Content-Style-Type" content="text/css"><link rel="stylesheet" href="' . $phpbb_root_path . 'adm/subSilver.css" type="text/css"><style type="text/css">' . "\n"; + echo 'th { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic3.gif\') }' . "\n"; + echo 'td.cat { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic1.gif\') }' . "\n"; + echo '</style><title>' . $msg_title . '</title></head><body>'; + echo '<table width="100%" cellspacing="0" cellpadding="0" border="0"><tr><td><a href="' . htmlspecialchars(preg_replace('/&explain=([^&]*)/', '', $_SERVER['REQUEST_URI'])) . '"><img src="' . $phpbb_root_path . 'adm/images/header_left.jpg" width="200" height="60" alt="phpBB Logo" title="phpBB Logo" border="0"/></a></td><td width="100%" background="' . $phpbb_root_path . 'adm/images/header_bg.jpg" height="60" align="right" nowrap="nowrap"><span class="maintitle">SQL Report</span> </td></tr></table><br clear="all"/><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td height="40" align="center" valign="middle"><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries} queries" . (($cache_num_queries) ? " + $cache_num_queries " . (($cache_num_queries == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></td></tr><tr><td align="center" nowrap="nowrap">Time spent on MySQL queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></td></tr></table><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td>'; + echo $sql_report; + echo '</td></tr></table><br /></body></html>'; + exit; + break; + + case 'start': + $query_hold = $query; + $html_hold = ''; + + $explain_query = $query; + if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) + { + $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; + } + elseif (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) + { + $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; + } + + if (preg_match('/^SELECT/', $explain_query)) + { + $html_table = FALSE; + + if ($result = mysql_query("EXPLAIN $explain_query", $this->db_connect_id)) + { + while ($row = mysql_fetch_assoc($result)) + { + if (!$html_table && sizeof($row)) + { + $html_table = TRUE; + $html_hold .= '<table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0" align="center"><tr>'; + + foreach (array_keys($row) as $val) + { + $html_hold .= '<th nowrap="nowrap">' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '</th>'; + } + $html_hold .= '</tr>'; + } + $html_hold .= '<tr>'; + + $class = 'row1'; + foreach (array_values($row) as $val) + { + $class = ($class == 'row1') ? 'row2' : 'row1'; + $html_hold .= '<td class="' . $class . '">' . (($val) ? $val : ' ') . '</td>'; + } + $html_hold .= '</tr>'; + } + } + + if ($html_table) + { + $html_hold .= '</table>'; + } + } + + $curtime = explode(' ', microtime()); + $curtime = $curtime[0] + $curtime[1]; + break; + + case 'fromcache': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $result = mysql_query($query, $this->db_connect_id); + while ($void = mysql_fetch_assoc($result)) + { + // Take the time spent on parsing rows into account + } + $splittime = explode(' ', microtime()); + $splittime = $splittime[0] + $splittime[1]; + + $time_cache = $endtime - $curtime; + $time_db = $splittime - $endtime; + $color = ($time_db > $time_cache) ? 'green' : 'red'; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query results obtained from the cache</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table><p align="center">'; + + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p>'; + + // Pad the start time to not interfere with page timing + $starttime += $time_db; + + mysql_free_result($result); + $cache_num_queries++; + break; + + case 'stop': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query #' . $this->num_queries . '</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table> ' . $html_hold . '<p align="center">'; + + if ($this->query_result) + { + if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) + { + $sql_report .= "Affected rows: <b>" . $this->sql_affectedrows($this->query_result) . '</b> | '; + } + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $curtime) . 's</b>'; + } + else + { + $error = $this->sql_error(); + $sql_report .= '<b style="color: red">FAILED</b> - MySQL Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); + } + + $sql_report .= '</p>'; + + $this->sql_time += $endtime - $curtime; + break; + } + } +} // class sql_db + +} // if ... define + +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/db/mysql4.php b/src/SemanticScuttle/db/mysql4.php new file mode 100644 index 0000000..0639518 --- /dev/null +++ b/src/SemanticScuttle/db/mysql4.php @@ -0,0 +1,552 @@ +<?php +/** +* +* @package dbal_mysql4 +* @version $Id: mysql4.php,v 1.4 2006/02/10 01:30:19 scronide Exp $ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('SQL_LAYER')) +{ + +define('SQL_LAYER', 'mysql4'); + +/** +* @package dbal_mysql4 +* MySQL4 Database Abstraction Layer +* Minimum Requirement is 4.0+/4.1+ +*/ +class sql_db +{ + var $db_connect_id; + var $query_result; + var $return_on_error = false; + var $transaction = false; + var $sql_time = 0; + var $num_queries = 0; + var $open_queries = array(); + + function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false) + { + $this->persistency = $persistency; + $this->user = $sqluser; + $this->server = $sqlserver . (($port) ? ':' . $port : ''); + $this->dbname = $database; + + $this->db_connect_id = ($this->persistency) ? @mysql_pconnect($this->server, $this->user, $sqlpassword) : @mysql_connect($this->server, $this->user, $sqlpassword); + + if ($this->db_connect_id && $this->dbname != '') + { + if (@mysql_select_db($this->dbname)) + { + return $this->db_connect_id; + } + } + + return $this->sql_error(''); + } + + // + // Other base methods + // + function sql_close() + { + if (!$this->db_connect_id) + { + return false; + } + + if (sizeof($this->open_queries)) + { + foreach ($this->open_queries as $i_query_id => $query_id) + { + @mysql_free_result($query_id); + } + } + + return @mysql_close($this->db_connect_id); + } + + function sql_return_on_error($fail = false) + { + $this->return_on_error = $fail; + } + + function sql_num_queries() + { + return $this->num_queries; + } + + function sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + $result = @mysql_query('BEGIN', $this->db_connect_id); + $this->transaction = true; + break; + + case 'commit': + $result = @mysql_query('COMMIT', $this->db_connect_id); + $this->transaction = false; + + if (!$result) + { + @mysql_query('ROLLBACK', $this->db_connect_id); + } + break; + + case 'rollback': + $result = @mysql_query('ROLLBACK', $this->db_connect_id); + $this->transaction = false; + break; + + default: + $result = true; + } + + return $result; + } + + // Base query method + function sql_query($query = '', $cache_ttl = 0) + { + if ($query != '') + { + global $cache; + + // EXPLAIN only in extra debug mode + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('start', $query); + } + + $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + + if (!$this->query_result) + { + $this->num_queries++; + + if (($this->query_result = @mysql_query($query, $this->db_connect_id)) === false) + { + $this->sql_error($query); + } + + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('stop', $query); + } + + if ($cache_ttl && method_exists($cache, 'sql_save')) + { + $this->open_queries[(int) $this->query_result] = $this->query_result; + $cache->sql_save($query, $this->query_result, $cache_ttl); + // mysql_free_result called within sql_save() + } + else if (strpos($query, 'SELECT') !== false && $this->query_result) + { + $this->open_queries[(int) $this->query_result] = $this->query_result; + } + } + else if (defined('DEBUG_EXTRA')) + { + $this->sql_report('fromcache', $query); + } + } + else + { + return false; + } + + return ($this->query_result) ? $this->query_result : false; + } + + function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { + if ($query != '') { + $this->query_result = false; + + // only limit the number of rows if $total is greater than 0 + if ($total > 0) + $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); + + return $this->sql_query($query, $cache_ttl); + } else { + return false; + } + } + + // Idea for this from Ikonboard + function sql_build_array($query, $assoc_ary = false) + { + if (!is_array($assoc_ary)) + { + return false; + } + + $fields = array(); + $values = array(); + if ($query == 'INSERT') + { + foreach ($assoc_ary as $key => $var) + { + $fields[] = $key; + + if (is_null($var)) + { + $values[] = 'NULL'; + } + elseif (is_string($var)) + { + $values[] = "'" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? intval($var) : $var; + } + } + + $query = ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')'; + } + else if ($query == 'UPDATE' || $query == 'SELECT') + { + $values = array(); + foreach ($assoc_ary as $key => $var) + { + if (is_null($var)) + { + $values[] = "$key = NULL"; + } + elseif (is_string($var)) + { + $values[] = "$key = '" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? "$key = " . intval($var) : "$key = $var"; + } + } + $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); + } + + return $query; + } + + // Other query methods + // + // NOTE :: Want to remove _ALL_ reliance on sql_numrows from core code ... + // don't want this here by a middle Milestone + function sql_numrows($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return ($query_id) ? @mysql_num_rows($query_id) : false; + } + + function sql_affectedrows() + { + return ($this->db_connect_id) ? @mysql_affected_rows($this->db_connect_id) : false; + } + + function sql_fetchrow($query_id = false) + { + global $cache; + + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_fetchrow($query_id); + } + + return ($query_id) ? @mysql_fetch_assoc($query_id) : false; + } + + function sql_fetchrowset($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + unset($this->rowset[$query_id]); + unset($this->row[$query_id]); + + $result = array(); + while ($this->rowset[$query_id] = $this->sql_fetchrow($query_id)) + { + $result[] = $this->rowset[$query_id]; + } + return $result; + } + + return false; + } + + function sql_fetchfield($field, $rownum = -1, $query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + if ($rownum > -1) + { + $result = @mysql_result($query_id, $rownum, $field); + } + else + { + if (empty($this->row[$query_id]) && empty($this->rowset[$query_id])) + { + if ($this->sql_fetchrow($query_id)) + { + $result = $this->row[$query_id][$field]; + } + } + else + { + if ($this->rowset[$query_id]) + { + $result = $this->rowset[$query_id][$field]; + } + elseif ($this->row[$query_id]) + { + $result = $this->row[$query_id][$field]; + } + } + } + return $result; + } + return false; + } + + function sql_rowseek($rownum, $query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return ($query_id) ? @mysql_data_seek($query_id, $rownum) : false; + } + + function sql_nextid() + { + return ($this->db_connect_id) ? @mysql_insert_id($this->db_connect_id) : false; + } + + function sql_freeresult($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (isset($this->open_queries[(int) $query_id])) + { + unset($this->open_queries[(int) $query_id]); + return @mysql_free_result($query_id); + } + + return false; + } + + function sql_escape($msg) { + if (function_exists('mysql_real_escape_string')) { + return @mysql_real_escape_string($msg, $this->db_connect_id); + } else { + return mysql_escape_string($msg); + } + } + + function sql_error($sql = '') + { + if (!$this->return_on_error) + { + $this_page = (isset($_SERVER['PHP_SELF']) && !empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF']; + $this_page .= '&' . ((isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : (isset($_ENV['QUERY_STRING']) ? $_ENV['QUERY_STRING'] : '')); + + $message = '<u>SQL ERROR</u> [ ' . SQL_LAYER . ' ]<br /><br />' . @mysql_error() . '<br /><br /><u>CALLING PAGE</u><br /><br />' . htmlspecialchars($this_page) . (($sql != '') ? '<br /><br /><u>SQL</u><br /><br />' . $sql : '') . '<br />'; + + if ($this->transaction) + { + $this->sql_transaction('rollback'); + } + + trigger_error($message, E_USER_ERROR); + } + + $result = array( + 'message' => @mysql_error(), + 'code' => @mysql_errno() + ); + + return $result; + } + + function sql_report($mode, $query = '') + { + if (empty($_GET['explain'])) + { + return; + } + + global $db, $cache, $starttime, $phpbb_root_path; + static $curtime, $query_hold, $html_hold; + static $sql_report = ''; + static $cache_num_queries = 0; + + if (!$query && !empty($query_hold)) + { + $query = $query_hold; + } + + switch ($mode) + { + case 'display': + if (!empty($cache)) + { + $cache->unload(); + } + $db->sql_close(); + + $mtime = explode(' ', microtime()); + $totaltime = $mtime[0] + $mtime[1] - $starttime; + + echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8869-1"><meta http-equiv="Content-Style-Type" content="text/css"><link rel="stylesheet" href="' . $phpbb_root_path . 'adm/subSilver.css" type="text/css"><style type="text/css">' . "\n"; + echo 'th { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic3.gif\') }' . "\n"; + echo 'td.cat { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic1.gif\') }' . "\n"; + echo '</style><title>' . $msg_title . '</title></head><body>'; + echo '<table width="100%" cellspacing="0" cellpadding="0" border="0"><tr><td><a href="' . htmlspecialchars(preg_replace('/&explain=([^&]*)/', '', $_SERVER['REQUEST_URI'])) . '"><img src="' . $phpbb_root_path . 'adm/images/header_left.jpg" width="200" height="60" alt="phpBB Logo" title="phpBB Logo" border="0"/></a></td><td width="100%" background="' . $phpbb_root_path . 'adm/images/header_bg.jpg" height="60" align="right" nowrap="nowrap"><span class="maintitle">SQL Report</span> </td></tr></table><br clear="all"/><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td height="40" align="center" valign="middle"><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries} queries" . (($cache_num_queries) ? " + $cache_num_queries " . (($cache_num_queries == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></td></tr><tr><td align="center" nowrap="nowrap">Time spent on MySQL queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></td></tr></table><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td>'; + echo $sql_report; + echo '</td></tr></table><br /></body></html>'; + exit; + break; + + case 'start': + $query_hold = $query; + $html_hold = ''; + + $explain_query = $query; + if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) + { + $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; + } + elseif (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) + { + $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; + } + + if (preg_match('/^SELECT/', $explain_query)) + { + $html_table = FALSE; + + if ($result = mysql_query("EXPLAIN $explain_query", $this->db_connect_id)) + { + while ($row = mysql_fetch_assoc($result)) + { + if (!$html_table && sizeof($row)) + { + $html_table = TRUE; + $html_hold .= '<table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0" align="center"><tr>'; + + foreach (array_keys($row) as $val) + { + $html_hold .= '<th nowrap="nowrap">' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '</th>'; + } + $html_hold .= '</tr>'; + } + $html_hold .= '<tr>'; + + $class = 'row1'; + foreach (array_values($row) as $val) + { + $class = ($class == 'row1') ? 'row2' : 'row1'; + $html_hold .= '<td class="' . $class . '">' . (($val) ? $val : ' ') . '</td>'; + } + $html_hold .= '</tr>'; + } + } + + if ($html_table) + { + $html_hold .= '</table>'; + } + } + + $curtime = explode(' ', microtime()); + $curtime = $curtime[0] + $curtime[1]; + break; + + case 'fromcache': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $result = mysql_query($query, $this->db_connect_id); + while ($void = mysql_fetch_assoc($result)) + { + // Take the time spent on parsing rows into account + } + $splittime = explode(' ', microtime()); + $splittime = $splittime[0] + $splittime[1]; + + $time_cache = $endtime - $curtime; + $time_db = $splittime - $endtime; + $color = ($time_db > $time_cache) ? 'green' : 'red'; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query results obtained from the cache</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table><p align="center">'; + + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p>'; + + // Pad the start time to not interfere with page timing + $starttime += $time_db; + + mysql_free_result($result); + $cache_num_queries++; + break; + + case 'stop': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query #' . $this->num_queries . '</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table> ' . $html_hold . '<p align="center">'; + + if ($this->query_result) + { + if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) + { + $sql_report .= "Affected rows: <b>" . $this->sql_affectedrows($this->query_result) . '</b> | '; + } + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $curtime) . 's</b>'; + } + else + { + $error = $this->sql_error(); + $sql_report .= '<b style="color: red">FAILED</b> - MySQL Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); + } + + $sql_report .= '</p>'; + + $this->sql_time += $endtime - $curtime; + break; + } + } +} // class sql_db + +} // if ... define + +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/db/mysqli.php b/src/SemanticScuttle/db/mysqli.php new file mode 100644 index 0000000..27814a7 --- /dev/null +++ b/src/SemanticScuttle/db/mysqli.php @@ -0,0 +1,562 @@ +<?php +/** +* +* @package dbal_mysqli +* @version $Id: mysqli.php,v 1.4 2006/02/10 01:30:19 scronide Exp $ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('SQL_LAYER')) +{ + +define('SQL_LAYER', 'mysqli'); + +/** +* @package dbal_mysqli +* MySQLi Database Abstraction Layer +* Minimum Requirement is MySQL 4.1+ and the mysqli-extension +*/ +class sql_db +{ + var $db_connect_id; + var $query_result; + var $return_on_error = false; + var $transaction = false; + var $sql_time = 0; + var $num_queries = 0; + var $open_queries = array(); + + var $indexed = 0; + + function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false) + { + $this->persistency = $persistency; + $this->user = $sqluser; + $this->server = $sqlserver . (($port) ? ':' . $port : ''); + $this->dbname = $database; + + $this->db_connect_id = ($this->persistency) ? @mysqli_pconnect($this->server, $this->user, $sqlpassword) : @mysqli_connect($this->server, $this->user, $sqlpassword); + + if ($this->db_connect_id && $this->dbname != '') + { + if (@mysqli_select_db($this->db_connect_id, $this->dbname)) + { + return $this->db_connect_id; + } + } + + return $this->sql_error(''); + } + + // + // Other base methods + // + function sql_close() + { + if (!$this->db_connect_id) + { + return false; + } + + if ($this->transaction) + { + @mysqli_commit($this->db_connect_id); + } + + return @mysqli_close($this->db_connect_id); + } + + function sql_return_on_error($fail = false) + { + $this->return_on_error = $fail; + } + + function sql_num_queries() + { + return $this->num_queries; + } + + function sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + $result = @mysqli_autocommit($this->db_connect_id, false); + $this->transaction = true; + break; + + case 'commit': + $result = @mysqli_commit($this->db_connect_id); + @mysqli_autocommit($this->db_connect_id, true); + $this->transaction = false; + + if (!$result) + { + @mysqli_rollback($this->db_connect_id); + @mysqli_autocommit($this->db_connect_id, true); + } + break; + + case 'rollback': + $result = @mysqli_rollback($this->db_connect_id); + @mysqli_autocommit($this->db_connect_id, true); + $this->transaction = false; + break; + + default: + $result = true; + } + + return $result; + } + + // Base query method + function sql_query($query = '', $cache_ttl = 0) + { + if ($query != '') + { + global $cache; + + // EXPLAIN only in extra debug mode + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('start', $query); + } + + $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + + if (!$this->query_result) + { + $this->num_queries++; + + if (($this->query_result = @mysqli_query($this->db_connect_id, $query)) === false) + { + $this->sql_error($query); + } + + if (is_object($this->query_result)) + { + $this->query_result->cur_index = $this->indexed++; + } + + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('stop', $query); + } + + if ($cache_ttl && method_exists($cache, 'sql_save')) + { + $cache->sql_save($query, $this->query_result, $cache_ttl); + } + } + else if (defined('DEBUG_EXTRA')) + { + $this->sql_report('fromcache', $query); + } + } + else + { + return false; + } + + return ($this->query_result) ? $this->query_result : false; + } + + function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) { + if ($query != '') { + $this->query_result = false; + + // only limit the number of rows if $total is greater than 0 + if ($total > 0) + $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); + + return $this->sql_query($query, $cache_ttl); + } else { + return false; + } + } + + // Idea for this from Ikonboard + function sql_build_array($query, $assoc_ary = false) + { + if (!is_array($assoc_ary)) + { + return false; + } + + $fields = array(); + $values = array(); + if ($query == 'INSERT') + { + foreach ($assoc_ary as $key => $var) + { + $fields[] = $key; + + if (is_null($var)) + { + $values[] = 'NULL'; + } + elseif (is_string($var)) + { + $values[] = "'" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? intval($var) : $var; + } + } + + $query = ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')'; + } + else if ($query == 'UPDATE' || $query == 'SELECT') + { + $values = array(); + foreach ($assoc_ary as $key => $var) + { + if (is_null($var)) + { + $values[] = "$key = NULL"; + } + elseif (is_string($var)) + { + $values[] = "$key = '" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? "$key = " . intval($var) : "$key = $var"; + } + } + $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); + } + + return $query; + } + + // Other query methods + // + // NOTE :: Want to remove _ALL_ reliance on sql_numrows from core code ... + // don't want this here by a middle Milestone + function sql_numrows($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return ($query_id) ? @mysqli_num_rows($query_id) : false; + } + + function sql_affectedrows() + { + return ($this->db_connect_id) ? @mysqli_affected_rows($this->db_connect_id) : false; + } + + function sql_fetchrow($query_id = false) + { + global $cache; + + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_fetchrow($query_id); + } + + return ($query_id) ? @mysqli_fetch_assoc($query_id) : false; + } + + function sql_fetchrowset($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + $cur_index = (is_object($query_id)) ? $query_id->cur_index : $query_id; + + unset($this->rowset[$cur_index]); + unset($this->row[$cur_index]); + + $result = array(); + while ($this->rowset[$cur_index] = $this->sql_fetchrow($query_id)) + { + $result[] = $this->rowset[$cur_index]; + } + return $result; + } + + return false; + } + + function sql_fetchfield($field, $rownum = -1, $query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + if ($rownum > -1) + { + @mysqli_data_seek($query_id, $rownum); + $row = @mysqli_fetch_assoc($query_id); + $result = isset($row[$field]) ? $row[$field] : false; + } + else + { + $cur_index = (is_object($query_id)) ? $query_id->cur_index : $query_id; + + if (empty($this->row[$cur_index]) && empty($this->rowset[$cur_index])) + { + if ($this->row[$cur_index] = $this->sql_fetchrow($query_id)) + { + $result = $this->row[$cur_index][$field]; + } + } + else + { + if ($this->rowset[$cur_index]) + { + $result = $this->rowset[$cur_index][$field]; + } + elseif ($this->row[$cur_index]) + { + $result = $this->row[$cur_index][$field]; + } + } + } + return $result; + } + return false; + } + + function sql_rowseek($rownum, $query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return ($query_id) ? @mysqli_data_seek($query_id, $rownum) : false; + } + + function sql_nextid() + { + return ($this->db_connect_id) ? @mysqli_insert_id($this->db_connect_id) : false; + } + + function sql_freeresult($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + $cur_index = (is_object($query_id)) ? $query_id->cur_index : $query_id; + + unset($this->rowset[$cur_index]); + unset($this->row[$cur_index]); + + if (is_object($query_id)) + { + $this->indexed--; + return @mysqli_free_result($query_id); + } + else + { + return false; + } + } + + function sql_escape($msg) { + return mysqli_real_escape_string($this->db_connect_id, $msg); + } + + function sql_error($sql = '') + { + if (!$this->return_on_error) + { + $this_page = (isset($_SERVER['PHP_SELF']) && !empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF']; + $this_page .= '&' . ((isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : (isset($_ENV['QUERY_STRING']) ? $_ENV['QUERY_STRING'] : '')); + + $message = '<u>SQL ERROR</u> [ ' . SQL_LAYER . ' ]<br /><br />' . @mysqli_error($this->db_connect_id) . '<br /><br /><u>CALLING PAGE</u><br /><br />' . htmlspecialchars($this_page) . (($sql != '') ? '<br /><br /><u>SQL</u><br /><br />' . $sql : '') . '<br />'; + + if ($this->transaction) + { + $this->sql_transaction('rollback'); + } + + trigger_error($message, E_USER_ERROR); + } + + $result = array( + 'message' => @mysqli_error($this->db_connect_id), + 'code' => @mysqli_errno($this->db_connect_id) + ); + + return $result; + } + + function sql_report($mode, $query = '') + { + if (empty($_GET['explain'])) + { + return; + } + + global $db, $cache, $starttime, $phpbb_root_path; + static $curtime, $query_hold, $html_hold; + static $sql_report = ''; + static $cache_num_queries = 0; + + if (!$query && !empty($query_hold)) + { + $query = $query_hold; + } + + switch ($mode) + { + case 'display': + if (!empty($cache)) + { + $cache->unload(); + } + $db->sql_close(); + + $mtime = explode(' ', microtime()); + $totaltime = $mtime[0] + $mtime[1] - $starttime; + + echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8869-1"><meta http-equiv="Content-Style-Type" content="text/css"><link rel="stylesheet" href="' . $phpbb_root_path . 'adm/subSilver.css" type="text/css"><style type="text/css">' . "\n"; + echo 'th { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic3.gif\') }' . "\n"; + echo 'td.cat { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic1.gif\') }' . "\n"; + echo '</style><title>' . $msg_title . '</title></head><body>'; + echo '<table width="100%" cellspacing="0" cellpadding="0" border="0"><tr><td><a href="' . htmlspecialchars(preg_replace('/&explain=([^&]*)/', '', $_SERVER['REQUEST_URI'])) . '"><img src="' . $phpbb_root_path . 'adm/images/header_left.jpg" width="200" height="60" alt="phpBB Logo" title="phpBB Logo" border="0"/></a></td><td width="100%" background="' . $phpbb_root_path . 'adm/images/header_bg.jpg" height="60" align="right" nowrap="nowrap"><span class="maintitle">SQL Report</span> </td></tr></table><br clear="all"/><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td height="40" align="center" valign="middle"><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries} queries" . (($cache_num_queries) ? " + $cache_num_queries " . (($cache_num_queries == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></td></tr><tr><td align="center" nowrap="nowrap">Time spent on MySQL queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></td></tr></table><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td>'; + echo $sql_report; + echo '</td></tr></table><br /></body></html>'; + exit; + break; + + case 'start': + $query_hold = $query; + $html_hold = ''; + + $explain_query = $query; + if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) + { + $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; + } + elseif (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) + { + $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; + } + + if (preg_match('/^SELECT/', $explain_query)) + { + $html_table = FALSE; + + if ($result = @mysqli_query($this->db_connect_id, "EXPLAIN $explain_query")) + { + while ($row = @mysqli_fetch_assoc($result)) + { + if (!$html_table && sizeof($row)) + { + $html_table = TRUE; + $html_hold .= '<table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0" align="center"><tr>'; + + foreach (array_keys($row) as $val) + { + $html_hold .= '<th nowrap="nowrap">' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '</th>'; + } + $html_hold .= '</tr>'; + } + $html_hold .= '<tr>'; + + $class = 'row1'; + foreach (array_values($row) as $val) + { + $class = ($class == 'row1') ? 'row2' : 'row1'; + $html_hold .= '<td class="' . $class . '">' . (($val) ? $val : ' ') . '</td>'; + } + $html_hold .= '</tr>'; + } + } + + if ($html_table) + { + $html_hold .= '</table>'; + } + } + + $curtime = explode(' ', microtime()); + $curtime = $curtime[0] + $curtime[1]; + break; + + case 'fromcache': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $result = @mysqli_query($this->db_connect_id, $query); + while ($void = @mysqli_fetch_assoc($result)) + { + // Take the time spent on parsing rows into account + } + $splittime = explode(' ', microtime()); + $splittime = $splittime[0] + $splittime[1]; + + $time_cache = $endtime - $curtime; + $time_db = $splittime - $endtime; + $color = ($time_db > $time_cache) ? 'green' : 'red'; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query results obtained from the cache</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table><p align="center">'; + + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p>'; + + // Pad the start time to not interfere with page timing + $starttime += $time_db; + + @mysqli_free_result($result); + $cache_num_queries++; + break; + + case 'stop': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query #' . $this->num_queries . '</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table> ' . $html_hold . '<p align="center">'; + + if ($this->query_result) + { + if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) + { + $sql_report .= "Affected rows: <b>" . $this->sql_affectedrows($this->query_result) . '</b> | '; + } + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $curtime) . 's</b>'; + } + else + { + $error = $this->sql_error(); + $sql_report .= '<b style="color: red">FAILED</b> - MySQL Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); + } + + $sql_report .= '</p>'; + + $this->sql_time += $endtime - $curtime; + break; + } + } +} // class sql_db + +} // if ... define + +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/db/oracle.php b/src/SemanticScuttle/db/oracle.php new file mode 100644 index 0000000..7ef10e5 --- /dev/null +++ b/src/SemanticScuttle/db/oracle.php @@ -0,0 +1,468 @@ +<?php +/** +* +* @package dbal_oracle +* @version $Id: oracle.php,v 1.2 2005/06/10 08:52:03 devalley Exp $ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if(!defined("SQL_LAYER")) +{ + +define("SQL_LAYER","oracle"); + +/** +* @package dbal_oracle +* Oracle Database Abstraction Layer +*/ +class sql_db +{ + + var $db_connect_id; + var $query_result; + var $in_transaction = 0; + var $row = array(); + var $rowset = array(); + var $num_queries = 0; + var $last_query_text = ""; + + // + // Constructor + // + function sql_db($sqlserver, $sqluser, $sqlpassword, $database="", $persistency = true) + { + $this->persistency = $persistency; + $this->user = $sqluser; + $this->password = $sqlpassword; + $this->server = $sqlserver; + $this->dbname = $database; + + if($this->persistency) + { + $this->db_connect_id = @OCIPLogon($this->user, $this->password, $this->server); + } + else + { + $this->db_connect_id = @OCINLogon($this->user, $this->password, $this->server); + } + if($this->db_connect_id) + { + return $this->db_connect_id; + } + else + { + return false; + } + } + + // + // Other base methods + // + function sql_close() + { + if($this->db_connect_id) + { + // Commit outstanding transactions + if($this->in_transaction) + { + OCICommit($this->db_connect_id); + } + + if($this->query_result) + { + @OCIFreeStatement($this->query_result); + } + $result = @OCILogoff($this->db_connect_id); + return $result; + } + else + { + return false; + } + } + + // + // Base query method + // + function sql_query($query = "", $transaction = FALSE) + { + // Remove any pre-existing queries + unset($this->query_result); + + // Put us in transaction mode because with Oracle as soon as you make a query you're in a transaction + $this->in_transaction = TRUE; + + if($query != "") + { + $this->last_query = $query; + $this->num_queries++; + + if(eregi("LIMIT", $query)) + { + preg_match("/^(.*)LIMIT ([0-9]+)[, ]*([0-9]+)*/s", $query, $limits); + + $query = $limits[1]; + if($limits[3]) + { + $row_offset = $limits[2]; + $num_rows = $limits[3]; + } + else + { + $row_offset = 0; + $num_rows = $limits[2]; + } + } + + if(eregi("^(INSERT|UPDATE) ", $query)) + { + $query = preg_replace("/\\\'/s", "''", $query); + } + + $this->query_result = @OCIParse($this->db_connect_id, $query); + $success = @OCIExecute($this->query_result, OCI_DEFAULT); + } + if($success) + { + if($transaction == END_TRANSACTION) + { + OCICommit($this->db_connect_id); + $this->in_transaction = FALSE; + } + + unset($this->row[$this->query_result]); + unset($this->rowset[$this->query_result]); + $this->last_query_text[$this->query_result] = $query; + + return $this->query_result; + } + else + { + if($this->in_transaction) + { + OCIRollback($this->db_connect_id); + } + return false; + } + } + + // + // Other query methods + // + function sql_numrows($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $result = @OCIFetchStatement($query_id, $this->rowset); + // OCIFetchStatment kills our query result so we have to execute the statment again + // if we ever want to use the query_id again. + @OCIExecute($query_id, OCI_DEFAULT); + return $result; + } + else + { + return false; + } + } + function sql_affectedrows($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $result = @OCIRowCount($query_id); + return $result; + } + else + { + return false; + } + } + function sql_numfields($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $result = @OCINumCols($query_id); + return $result; + } + else + { + return false; + } + } + function sql_fieldname($offset, $query_id = 0) + { + // OCIColumnName uses a 1 based array so we have to up the offset by 1 in here to maintain + // full abstraction compatibitly + $offset += 1; + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $result = strtolower(@OCIColumnName($query_id, $offset)); + return $result; + } + else + { + return false; + } + } + function sql_fieldtype($offset, $query_id = 0) + { + // This situation is the same as fieldname + $offset += 1; + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $result = @OCIColumnType($query_id, $offset); + return $result; + } + else + { + return false; + } + } + function sql_fetchrow($query_id = 0, $debug = FALSE) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $result_row = ""; + $result = @OCIFetchInto($query_id, $result_row, OCI_ASSOC+OCI_RETURN_NULLS); + if($debug) + { + echo "Query was: ".$this->last_query . "<br>"; + echo "Result: $result<br>"; + echo "Query ID: $query_id<br>"; + echo "<pre>"; + var_dump($result_row); + echo "</pre>"; + } + if($result_row == "") + { + return false; + } + + for($i = 0; $i < count($result_row); $i++) + { + list($key, $val) = each($result_row); + $return_arr[strtolower($key)] = $val; + } + $this->row[$query_id] = $return_arr; + + return $this->row[$query_id]; + } + else + { + return false; + } + } + // This function probably isn't as efficant is it could be but any other way I do it + // I end up losing 1 row... + function sql_fetchrowset($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $rows = @OCIFetchStatement($query_id, $results); + @OCIExecute($query_id, OCI_DEFAULT); + for($i = 0; $i <= $rows; $i++) + { + @OCIFetchInto($query_id, $tmp_result, OCI_ASSOC+OCI_RETURN_NULLS); + + for($j = 0; $j < count($tmp_result); $j++) + { + list($key, $val) = each($tmp_result); + $return_arr[strtolower($key)] = $val; + } + $result[] = $return_arr; + } + return $result; + } + else + { + return false; + } + } + function sql_fetchfield($field, $rownum = -1, $query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + if($rownum > -1) + { + // Reset the internal rownum pointer. + @OCIExecute($query_id, OCI_DEFAULT); + for($i = 0; $i < $rownum; $i++) + { + // Move the interal pointer to the row we want + @OCIFetch($query_id); + } + // Get the field data. + $result = @OCIResult($query_id, strtoupper($field)); + } + else + { + // The internal pointer should be where we want it + // so we just grab the field out of the current row. + $result = @OCIResult($query_id, strtoupper($field)); + } + return $result; + } + else + { + return false; + } + } + function sql_rowseek($rownum, $query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + @OCIExecute($query_id, OCI_DEFAULT); + for($i = 0; $i < $rownum; $i++) + { + @OCIFetch($query_id); + } + $result = @OCIFetch($query_id); + return $result; + } + else + { + return false; + } + } + function sql_nextid($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id && $this->last_query_text[$query_id] != "") + { + if( eregi("^(INSERT{1}|^INSERT INTO{1})[[:space:]][\"]?([a-zA-Z0-9\_\-]+)[\"]?", $this->last_query_text[$query_id], $tablename)) + { + $query = "SELECT ".$tablename[2]."_id_seq.currval FROM DUAL"; + $stmt = @OCIParse($this->db_connect_id, $query); + @OCIExecute($stmt,OCI_DEFAULT ); + $temp_result = @OCIFetchInto($stmt, $temp_result, OCI_ASSOC+OCI_RETURN_NULLS); + if($temp_result) + { + return $temp_result['CURRVAL']; + } + else + { + return false; + } + } + else + { + return false; + } + } + else + { + return false; + } + } + + function sql_nextid($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id && $this->last_query_text[$query_id] != "") + { + if( eregi("^(INSERT{1}|^INSERT INTO{1})[[:space:]][\"]?([a-zA-Z0-9\_\-]+)[\"]?", $this->last_query_text[$query_id], $tablename)) + { + $query = "SELECT ".$tablename[2]."_id_seq.CURRVAL FROM DUAL"; + $temp_q_id = @OCIParse($this->db_connect_id, $query); + @OCIExecute($temp_q_id, OCI_DEFAULT); + @OCIFetchInto($temp_q_id, $temp_result, OCI_ASSOC+OCI_RETURN_NULLS); + + if($temp_result) + { + return $temp_result['CURRVAL']; + } + else + { + return false; + } + } + else + { + return false; + } + } + else + { + return false; + } + } + + + + function sql_freeresult($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + $result = @OCIFreeStatement($query_id); + return $result; + } + else + { + return false; + } + } + function sql_error($query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + $result = @OCIError($query_id); + return $result; + } + +} // class sql_db + +} // if ... define + +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/db/postgres.php b/src/SemanticScuttle/db/postgres.php new file mode 100644 index 0000000..b5bad20 --- /dev/null +++ b/src/SemanticScuttle/db/postgres.php @@ -0,0 +1,597 @@ +<?php +/** +* +* @package dbal_postgres +* @version $Id: postgres.php,v 1.2 2005/06/10 08:52:03 devalley Exp $ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('SQL_LAYER')) +{ + +define('SQL_LAYER', 'postgresql'); + +/** +* @package dbal_postgres +* PostgreSQL Database Abstraction Layer +* Minimum Requirement is Version 7.3+ +*/ +class sql_db +{ + var $db_connect_id; + var $query_result; + var $return_on_error = false; + var $transaction = false; + var $sql_time = 0; + var $num_queries = 0; + var $open_queries = array(); + + function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false) + { + $this->connect_string = ''; + + if ($sqluser) + { + $this->connect_string .= "user=$sqluser "; + } + + if ($sqlpassword) + { + $this->connect_string .= "password=$sqlpassword "; + } + + if ($sqlserver) + { + if (ereg(":", $sqlserver)) + { + list($sqlserver, $sqlport) = split(":", $sqlserver); + $this->connect_string .= "host=$sqlserver port=$sqlport "; + } + else + { + if ($sqlserver != "localhost") + { + $this->connect_string .= "host=$sqlserver "; + } + + if ($port) + { + $this->connect_string .= "port=$port "; + } + } + } + + if ($database) + { + $this->dbname = $database; + $this->connect_string .= "dbname=$database"; + } + + $this->persistency = $persistency; + + $this->db_connect_id = ($this->persistency) ? @pg_pconnect($this->connect_string) : @pg_connect($this->connect_string); + + return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); + } + + // + // Other base methods + // + function sql_close() + { + if (!$this->db_connect_id) + { + return false; + } + + if ($this->transaction) + { + @pg_exec($this->db_connect_id, 'COMMIT'); + } + + return @pg_close($this->db_connect_id); + } + + function sql_return_on_error($fail = false) + { + $this->return_on_error = $fail; + } + + function sql_num_queries() + { + return $this->num_queries; + } + + function sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + $result = @pg_exec($this->db_connect_id, 'BEGIN'); + $this->transaction = true; + break; + + case 'commit': + $result = @pg_exec($this->db_connect_id, 'COMMIT'); + $this->transaction = false; + + if (!$result) + { + @pg_exec($this->db_connect_id, 'ROLLBACK'); + } + break; + + case 'rollback': + $result = @pg_exec($this->db_connect_id, 'ROLLBACK'); + $this->transaction = false; + break; + + default: + $result = true; + } + + return $result; + } + + // Base query method + function sql_query($query = '', $cache_ttl = 0) + { + if ($query != '') + { + global $cache; + + // EXPLAIN only in extra debug mode + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('start', $query); + } + + $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + + if (!$this->query_result) + { + $this->num_queries++; + $this->last_query_text = $query; + + if (($this->query_result = @pg_exec($this->db_connect_id, $query)) === false) + { + $this->sql_error($query); + } + + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('stop', $query); + } + + if ($cache_ttl && method_exists($cache, 'sql_save')) + { + $cache->sql_save($query, $this->query_result, $cache_ttl); + } + } + else if (defined('DEBUG_EXTRA')) + { + $this->sql_report('fromcache', $query); + } + } + else + { + return false; + } + + return ($this->query_result) ? $this->query_result : false; + } + + function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) + { + if ($query != '') + { + $this->query_result = false; + + // if $total is set to 0 we do not want to limit the number of rows + if ($total == 0) + { + $total = -1; + } + + $query .= "\n LIMIT $total OFFSET $offset"; + + return $this->sql_query($query, $cache_ttl); + } + else + { + return false; + } + } + + // Idea for this from Ikonboard + function sql_build_array($query, $assoc_ary = false) + { + if (!is_array($assoc_ary)) + { + return false; + } + + $fields = array(); + $values = array(); + if ($query == 'INSERT') + { + foreach ($assoc_ary as $key => $var) + { + $fields[] = $key; + + if (is_null($var)) + { + $values[] = 'NULL'; + } + elseif (is_string($var)) + { + $values[] = "'" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? intval($var) : $var; + } + } + + $query = ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')'; + } + else if ($query == 'UPDATE' || $query == 'SELECT') + { + $values = array(); + foreach ($assoc_ary as $key => $var) + { + if (is_null($var)) + { + $values[] = "$key = NULL"; + } + elseif (is_string($var)) + { + $values[] = "$key = '" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? "$key = " . intval($var) : "$key = $var"; + } + } + $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); + } + + return $query; + } + + // Other query methods + // + // NOTE :: Want to remove _ALL_ reliance on sql_numrows from core code ... + // don't want this here by a middle Milestone + function sql_numrows($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return ($query_id) ? @pg_numrows($query_id) : false; + } + + function sql_affectedrows($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return ($query_id) ? @pg_cmdtuples($query_id) : false; + } + + function sql_fetchrow($query_id = false) + { + global $cache; + + if (!$query_id) + { + $query_id = $this->query_result; + } + + if (!isset($this->rownum[$query_id])) + { + $this->rownum[$query_id] = 0; + } + + if (isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_fetchrow($query_id); + } + + $result = @pg_fetch_array($query_id, NULL, PGSQL_ASSOC); + + if ($result) + { + $this->rownum[$query_id]++; + } + + return $result; + } + + function sql_fetchrowset($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + $result = array(); + + if ($query_id) + { + unset($this->rowset[$query_id]); + unset($this->row[$query_id]); + + $result = array(); + while ($this->rowset[$query_id] = $this->sql_fetchrow($query_id)) + { + $result[] = $this->rowset[$query_id]; + } + return $result; + } + + return false; + } + + function sql_fetchfield($field, $rownum = -1, $query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + if ($rownum > -1) + { + if (@function_exists('pg_result_seek')) + { + @pg_result_seek($query_id, $rownum); + $row = @pg_fetch_assoc($query_id); + $result = isset($row[$field]) ? $row[$field] : false; + } + else + { + $this->sql_rowseek($offset, $query_id); + $row = $this->sql_fetchrow($query_id); + $result = isset($row[$field]) ? $row[$field] : false; + } + } + else + { + if (empty($this->row[$query_id]) && empty($this->rowset[$query_id])) + { + if ($this->sql_fetchrow($query_id)) + { + $result = $this->row[$query_id][$field]; + } + } + else + { + if ($this->rowset[$query_id]) + { + $result = $this->rowset[$query_id][$field]; + } + elseif ($this->row[$query_id]) + { + $result = $this->row[$query_id][$field]; + } + } + } + return $result; + } + return false; + } + + function sql_rowseek($offset, $query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + if ($offset > -1) + { + if (@function_exists('pg_result_seek')) + { + @pg_result_seek($query_id, $rownum); + } + else + { + for ($i = $this->rownum[$query_id]; $i < $offset; $i++) + { + $this->sql_fetchrow($query_id); + } + } + return true; + } + else + { + return false; + } + } + + return false; + } + + function sql_nextid() + { + $query_id = $this->query_result; + + if ($query_id && $this->last_query_text != '') + { + if (preg_match("/^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)/is", $this->last_query_text, $tablename)) + { + $query = "SELECT currval('" . $tablename[1] . "_id_seq') AS last_value"; + $temp_q_id = @pg_exec($this->db_connect_id, $query); + if (!$temp_q_id) + { + return false; + } + + $temp_result = @pg_fetch_array($temp_q_id, NULL, PGSQL_ASSOC); + + return ($temp_result) ? $temp_result['last_value'] : false; + } + } + + return false; + } + + function sql_freeresult($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return (is_resource($query_id)) ? @pg_freeresult($query_id) : false; + } + + function sql_escape($msg) + { + return str_replace("'", "''", str_replace('\\', '\\\\', $msg)); + } + + function sql_error($sql = '') + { + if (!$this->return_on_error) + { + $this_page = (isset($_SERVER['PHP_SELF']) && !empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF']; + $this_page .= '&' . ((isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : (isset($_ENV['QUERY_STRING']) ? $_ENV['QUERY_STRING'] : '')); + + $message = '<u>SQL ERROR</u> [ ' . SQL_LAYER . ' ]<br /><br />' . @pg_errormessage() . '<br /><br /><u>CALLING PAGE</u><br /><br />' . htmlspecialchars($this_page) . (($sql != '') ? '<br /><br /><u>SQL</u><br /><br />' . $sql : '') . '<br />'; + + if ($this->transaction) + { + $this->sql_transaction('rollback'); + } + + trigger_error($message, E_USER_ERROR); + } + + $result = array( + 'message' => @pg_errormessage(), + 'code' => '' + ); + + return $result; + } + + function sql_report($mode, $query = '') + { + if (empty($_GET['explain'])) + { + return; + } + + global $cache, $starttime, $phpbb_root_path; + static $curtime, $query_hold, $html_hold; + static $sql_report = ''; + static $cache_num_queries = 0; + + if (!$query && !empty($query_hold)) + { + $query = $query_hold; + } + + switch ($mode) + { + case 'display': + if (!empty($cache)) + { + $cache->unload(); + } + $this->sql_close(); + + $mtime = explode(' ', microtime()); + $totaltime = $mtime[0] + $mtime[1] - $starttime; + + echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8869-1"><meta http-equiv="Content-Style-Type" content="text/css"><link rel="stylesheet" href="' . $phpbb_root_path . 'adm/subSilver.css" type="text/css"><style type="text/css">' . "\n"; + echo 'th { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic3.gif\') }' . "\n"; + echo 'td.cat { background-image: url(\'' . $phpbb_root_path . 'adm/images/cellpic1.gif\') }' . "\n"; + echo '</style><title>' . $msg_title . '</title></head><body>'; + echo '<table width="100%" cellspacing="0" cellpadding="0" border="0"><tr><td><a href="' . htmlspecialchars(preg_replace('/&explain=([^&]*)/', '', $_SERVER['REQUEST_URI'])) . '"><img src="' . $phpbb_root_path . 'adm/images/header_left.jpg" width="200" height="60" alt="phpBB Logo" title="phpBB Logo" border="0"/></a></td><td width="100%" background="' . $phpbb_root_path . 'adm/images/header_bg.jpg" height="60" align="right" nowrap="nowrap"><span class="maintitle">SQL Report</span> </td></tr></table><br clear="all"/><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td height="40" align="center" valign="middle"><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries} queries" . (($cache_num_queries) ? " + $cache_num_queries " . (($cache_num_queries == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></td></tr><tr><td align="center" nowrap="nowrap">Time spent on MySQL queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></td></tr></table><table width="95%" cellspacing="1" cellpadding="4" border="0" align="center"><tr><td>'; + echo $sql_report; + echo '</td></tr></table><br /></body></html>'; + exit; + break; + + case 'start': + $query_hold = $query; + $html_hold = ''; + + $curtime = explode(' ', microtime()); + $curtime = $curtime[0] + $curtime[1]; + break; + + case 'fromcache': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $result = @pg_exec($this->db_connect_id, $query); + while ($void = @pg_fetch_array($result, NULL, PGSQL_ASSOC)) + { + // Take the time spent on parsing rows into account + } + $splittime = explode(' ', microtime()); + $splittime = $splittime[0] + $splittime[1]; + + $time_cache = $endtime - $curtime; + $time_db = $splittime - $endtime; + $color = ($time_db > $time_cache) ? 'green' : 'red'; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query results obtained from the cache</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table><p align="center">'; + + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p>'; + + // Pad the start time to not interfere with page timing + $starttime += $time_db; + + @pg_freeresult($result); + $cache_num_queries++; + break; + + case 'stop': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $sql_report .= '<hr width="100%"/><br /><table class="bg" width="100%" cellspacing="1" cellpadding="4" border="0"><tr><th>Query #' . $this->num_queries . '</th></tr><tr><td class="row1"><textarea style="font-family:\'Courier New\',monospace;width:100%" rows="5">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></table> ' . $html_hold . '<p align="center">'; + + if ($this->query_result) + { + if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) + { + $sql_report .= "Affected rows: <b>" . $this->sql_affectedrows($this->query_result) . '</b> | '; + } + $sql_report .= 'Before: ' . sprintf('%.5f', $curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $curtime) . 's</b>'; + } + else + { + $error = $this->sql_error(); + $sql_report .= '<b style="color: red">FAILED</b> - ' . SQL_LAYER . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); + } + + $sql_report .= '</p>'; + + $this->sql_time += $endtime - $curtime; + break; + } + } + +} // class ... db_sql + +} // if ... defined + +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/db/sqlite.php b/src/SemanticScuttle/db/sqlite.php new file mode 100644 index 0000000..1591396 --- /dev/null +++ b/src/SemanticScuttle/db/sqlite.php @@ -0,0 +1,387 @@ +<?php +/** +* +* @package dbal_sqlite +* @version $Id: sqlite.php,v 1.2 2005/06/10 08:52:03 devalley Exp $ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined("SQL_LAYER")) +{ + +define("SQL_LAYER","sqlite"); + +/** +* @package dbal_sqlite +* Sqlite Database Abstraction Layer +*/ +class sql_db +{ + var $db_connect_id; + var $query_result; + var $return_on_error = false; + var $transaction = false; + var $sql_report = ''; + var $sql_time = 0; + var $num_queries = 0; + var $open_queries = array(); + + function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port, $persistency = false) + { + $this->persistency = $persistency; + $this->user = $sqluser; + $this->server = $sqlserver . (($port) ? ':' . $port : ''); + $this->dbname = $database; + + $this->db_connect_id = ($this->persistency) ? @sqlite_popen($this->server, 0, $error) : @sqlite_open($this->server, 0, $error); + + return ($this->db_connect_id) ? true : $error; + } + + // Other base methods + function sql_close() + { + if (!$this->db_connect_id) + { + return false; + } + + return @sqlite_close($this->db_connect_id); + } + + function sql_return_on_error($fail = false) + { + $this->return_on_error = $fail; + } + + function sql_num_queries() + { + return $this->num_queries; + } + + function sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + $this->transaction = true; + $result = @sqlite_query('BEGIN', $this->db_connect_id); + break; + + case 'commit': + $this->transaction = false; + $result = @sqlite_query('COMMIT', $this->db_connect_id); + break; + + case 'rollback': + $this->transaction = false; + $result = @sqlite_query('ROLLBACK', $this->db_connect_id); + break; + + default: + $result = true; + } + + return $result; + } + + // Base query method + function sql_query($query = '', $expire_time = 0) + { + if ($query != '') + { + global $cache; + + $query = preg_replace('#FROM \((.*?)\)(,|[\n\t ]+?WHERE) #s', 'FROM \1\2 ', $query); + + if (!$expire_time || !$cache->sql_load($query, $expire_time)) + { + if ($expire_time) + { + $cache_result = true; + } + + $this->query_result = false; + $this->num_queries++; + + if (!empty($_GET['explain'])) + { + global $starttime; + + $curtime = explode(' ', microtime()); + $curtime = $curtime[0] + $curtime[1] - $starttime; + } + + if (!($this->query_result = @sqlite_query($query, $this->db_connect_id))) + { + $this->sql_error($query); + } + + if (!empty($_GET['explain'])) + { + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1] - $starttime; + + $this->sql_report .= "<pre>Query:\t" . htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n\t", $query)) . "\n\n"; + + if ($this->query_result) + { + $this->sql_report .= "Time before: $curtime\nTime after: $endtime\nElapsed time: <b>" . ($endtime - $curtime) . "</b>\n</pre>"; + } + else + { + $error = $this->sql_error(); + $this->sql_report .= '<b>FAILED</b> - SQLite ' . $error['code'] . ': ' . htmlspecialchars($error['message']) . '<br><br><pre>'; + } + + $this->sql_time += $endtime - $curtime; + + if (preg_match('#^SELECT#', $query)) + { + $html_table = FALSE; + if ($result = @sqlite_query("EXPLAIN $query", $this->db_connect_id)) + { + while ($row = @sqlite_fetch_array($result, @sqlite_ASSOC)) + { + if (!$html_table && sizeof($row)) + { + $html_table = TRUE; + $this->sql_report .= "<table width=100% border=1 cellpadding=2 cellspacing=1>\n"; + $this->sql_report .= "<tr>\n<td><b>" . implode("</b></td>\n<td><b>", array_keys($row)) . "</b></td>\n</tr>\n"; + } + $this->sql_report .= "<tr>\n<td>" . implode(" </td>\n<td>", array_values($row)) . " </td>\n</tr>\n"; + } + } + + if ($html_table) + { + $this->sql_report .= '</table><br>'; + } + } + + $this->sql_report .= "<hr>\n"; + } + + if (preg_match('#^SELECT#', $query)) + { + $this->open_queries[] = $this->query_result; + } + } + + if (!empty($cache_result)) + { + $cache->sql_save($query, $this->query_result); + } + } + else + { + return false; + } + + return ($this->query_result) ? $this->query_result : false; + } + + function sql_query_limit($query, $total, $offset = 0, $expire_time = 0) + { + if ($query != '') + { + $this->query_result = false; + + $query .= ' LIMIT ' . ((!empty($offset)) ? $total . ' OFFSET ' . $offset : $total); + + return $this->sql_query($query, $expire_time); + } + else + { + return false; + } + } + + // Idea for this from Ikonboard + function sql_build_array($query, $assoc_ary = false) + { + if (!is_array($assoc_ary)) + { + return false; + } + + $fields = array(); + $values = array(); + if ($query == 'INSERT') + { + foreach ($assoc_ary as $key => $var) + { + $fields[] = $key; + + if (is_null($var)) + { + $values[] = 'NULL'; + } + elseif (is_string($var)) + { + $values[] = "'" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? intval($var) : $var; + } + } + + $query = ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')'; + } + else if ($query == 'UPDATE') + { + $values = array(); + foreach ($assoc_ary as $key => $var) + { + if (is_null($var)) + { + $values[] = "$key = NULL"; + } + elseif (is_string($var)) + { + $values[] = "$key = '" . $this->sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? "$key = " . intval($var) : "$key = $var"; + } + } + $query = implode(', ', $values); + } + + return $query; + } + + // Other query methods + // + // NOTE :: Want to remove _ALL_ reliance on sql_numrows from core code ... + // don't want this here by a middle Milestone + function sql_numrows($query_id = false) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return ($query_id) ? @sqlite_num_rows($query_id) : false; + } + + function sql_affectedrows() + { + return ($this->db_connect_id) ? @sqlite_changes($this->db_connect_id) : false; + } + + function sql_fetchrow($query_id = 0) + { + global $cache; + + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($cache->sql_exists($query_id)) + { + return $cache->sql_fetchrow($query_id); + } + + return ($query_id) ? @sqlite_fetch_array($query_id, @sqlite_ASSOC) : false; + } + + function sql_fetchrowset($query_id = 0) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + unset($this->rowset[$query_id]); + unset($this->row[$query_id]); + while ($this->rowset[$query_id] = @sqlite_fetch_array($query_id, @sqlite_ASSOC)) + { + $result[] = $this->rowset[$query_id]; + } + return $result; + } + else + { + return false; + } + } + + function sql_fetchfield($field, $rownum = -1, $query_id = 0) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + if ($query_id) + { + return ($rownum > -1) ? ((@sqlite_seek($query_id, $rownum)) ? @sqlite_column($query_id, $field) : false) : @sqlite_column($query_id, $field); + } + } + + function sql_rowseek($rownum, $query_id = 0) + { + if (!$query_id) + { + $query_id = $this->query_result; + } + + return ($query_id) ? @sqlite_seek($query_id, $rownum) : false; + } + + function sql_nextid() + { + return ($this->db_connect_id) ? @sqlite_last_insert_rowid($this->db_connect_id) : false; + } + + function sql_freeresult($query_id = false) + { + return true; + } + + function sql_escape($msg) + { + return @sqlite_escape_string(stripslashes($msg)); + } + + function sql_error($sql = '') + { + if (!$this->return_on_error) + { + $this_page = (!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF']; + $this_page .= '&' . ((!empty($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : $_ENV['QUERY_STRING']); + + $message = '<u>SQL ERROR</u> [ ' . SQL_LAYER . ' ]<br /><br />' . @sqlite_error_string(@sqlite_last_error($this->db_connect_id)) . '<br /><br /><u>CALLING PAGE</u><br /><br />' . htmlspecialchars($this_page) . (($sql != '') ? '<br /><br /><u>SQL</u><br /><br />' . $sql : '') . '<br />'; + + if ($this->transaction) + { + $this->sql_transaction('rollback'); + } + + trigger_error($message, E_USER_ERROR); + } + + $result = array( + 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), + 'code' => @sqlite_last_error($this->db_connect_id) + ); + + return $result; + } + +} // class sql_db + +} // if ... define + +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/functions.inc.php b/src/SemanticScuttle/functions.inc.php new file mode 100644 index 0000000..08d5f33 --- /dev/null +++ b/src/SemanticScuttle/functions.inc.php @@ -0,0 +1,207 @@ +<?php +/* Define functions used into the application */ + + +// Converts tags: +// - direction = out: convert spaces to underscores; +// - direction = in: convert underscores to spaces. +function convertTag($tag, $direction = 'out') { + if ($direction == 'out') { + $tag = str_replace(' ', '_', $tag); + } else { + $tag = str_replace('_', ' ', $tag); + } + return $tag; +} + +function filter($data, $type = NULL) { + if (is_string($data)) { + $data = trim($data); + $data = stripslashes($data); + switch ($type) { + case 'url': + $data = rawurlencode($data); + break; + default: + $data = htmlspecialchars($data); + break; + } + } else if (is_array($data)) { + foreach(array_keys($data) as $key) { + $row =& $data[$key]; + $row = filter($row, $type); + } + } + return $data; +} + +function getPerPageCount($userObject = null) { + global $defaultPerPage, $defaultPerPageForAdmins; + + if(isset($defaultPerPageForAdmins) && $userObject != null && $userObject->isAdmin()) { + return $defaultPerPageForAdmins; + } else { + return $defaultPerPage; + } +} + +function getSortOrder($override = NULL) { + global $defaultOrderBy; + + if (isset($_GET['sort'])) { + return $_GET['sort']; + } else if (isset($override)) { + return $override; + } else { + return $defaultOrderBy; + } +} + +function multi_array_search($needle, $haystack) { + if (is_array($haystack)) { + foreach(array_keys($haystack) as $key) { + $value =& $haystack[$key]; + $result = multi_array_search($needle, $value); + if (is_array($result)) { + $return = $result; + array_unshift($return, $key); + return $return; + } elseif ($result == true) { + $return[] = $key; + return $return; + } + } + return false; + } else { + if ($needle === $haystack) { + return true; + } else { + return false; + } + } +} + +function createURL($page = '', $ending = '') { + global $cleanurls; + if (!$cleanurls && $page != '') { + $page .= '.php'; + } + if(strlen($ending)>0) { + return ROOT . $page .'/'. $ending; + } else { + return ROOT . $page; + } +} + +/* Shorten a string like a URL for example by cutting the middle of it */ +function shortenString($string, $maxSize=75) { + $output = ''; + if(strlen($string) > $maxSize) { + $output = substr($string, 0, $maxSize/2).'...'.substr($string, -$maxSize/2); + } else { + $output = $string; + } + return $output; +} + +/* Check url format and check online if the url is a valid page (Not a 404 error for example) */ +function checkUrl($url, $checkOnline = true) { + //check format + if(!preg_match("#(ht|f)tp(s?)\://\S+\.\S+#i",$url)) { + return false; + } + + if($checkOnline) { + //look if the page doesn't return a void or 40X or 50X HTTP code error + $h = @get_headers($url); + if(is_array($h) && strpos($h[0], '40') === false && strpos($h[0], '50') === false) { + return true; + } else { + return false; + } + } else { + return true; + } +} + +/* Returns a concatenated String + * including all the tags from the array $arrayTags (excepted of the $exceptedTag) + * separated by the $separator. + * */ +function aggregateTags($arrayTags, $separator = ' + ', $exceptedTag = '') { + $output = ''; + + for($i = 0; $i<count($arrayTags); $i++) { + if($arrayTags[$i] != $exceptedTag) { + $output.= $arrayTags[$i] . $separator; + } + } + return substr($output, 0, strlen($output) - strlen($separator) ); +} + +function message_die($msg_code, $msg_text = '', $msg_title = '', $err_line = '', $err_file = '', $sql = '', $db = NULL) { + if(defined('HAS_DIED')) + die(T_('message_die() was called multiple times.')); + define('HAS_DIED', 1); + + $sql_store = $sql; + + // Get SQL error if we are debugging. Do this as soon as possible to prevent + // subsequent queries from overwriting the status of sql_error() + if (DEBUG_MODE && ($msg_code == GENERAL_ERROR || $msg_code == CRITICAL_ERROR)) { + $sql_error = is_null($db) ? '' : $db->sql_error(); + $debug_text = ''; + + if ($sql_error['message'] != '') + $debug_text .= '<br /><br />'. T_('SQL Error') .' : '. $sql_error['code'] .' '. $sql_error['message']; + + if ($sql_store != '') + $debug_text .= '<br /><br />'. $sql_store; + + if ($err_line != '' && $err_file != '') + $debug_text .= '</br /><br />'. T_('Line') .' : '. $err_line .'<br />'. T_('File') .' :'. $err_file; + } + + switch($msg_code) { + case GENERAL_MESSAGE: + if ($msg_title == '') + $msg_title = T_('Information'); + break; + + case CRITICAL_MESSAGE: + if ($msg_title == '') + $msg_title = T_('Critical Information'); + break; + + case GENERAL_ERROR: + if ($msg_text == '') + $msg_text = T_('An error occured'); + + if ($msg_title == '') + $msg_title = T_('General Error'); + break; + + case CRITICAL_ERROR: + // Critical errors mean we cannot rely on _ANY_ DB information being + // available so we're going to dump out a simple echo'd statement + + if ($msg_text == '') + $msg_text = T_('An critical error occured'); + + if ($msg_title == '') + $msg_title = T_('Critical Error'); + break; + } + + // Add on DEBUG_MODE info if we've enabled debug mode and this is an error. This + // prevents debug info being output for general messages should DEBUG_MODE be + // set TRUE by accident (preventing confusion for the end user!) + if (DEBUG_MODE && ($msg_code == GENERAL_ERROR || $msg_code == CRITICAL_ERROR)) { + if ($debug_text != '') + $msg_text = $msg_text . '<br /><br /><strong>'. T_('DEBUG MODE') .'</strong>'. $debug_text; + } + + echo "<html>\n<body>\n". $msg_title ."\n<br /><br />\n". $msg_text ."</body>\n</html>"; + exit; +} +?> diff --git a/src/SemanticScuttle/header.inc.php b/src/SemanticScuttle/header.inc.php new file mode 100644 index 0000000..024cb06 --- /dev/null +++ b/src/SemanticScuttle/header.inc.php @@ -0,0 +1,55 @@ +<?php +if(!file_exists(dirname(__FILE__) .'/config.inc.php')) { + die('Please copy "config.inc.php.dist" to "config.inc.php"'); +} + +// 1 // First requirements part (before debug management) +require_once(dirname(__FILE__) .'/config.default.inc.php'); +require_once(dirname(__FILE__) .'/config.inc.php'); +require_once(dirname(__FILE__) .'/constants.inc.php'); // some constants are based on variables from config file + + +// Debug Management using constants +if(DEBUG_MODE) { + ini_set('display_errors', '1'); + ini_set('mysql.trace_mode', '1'); + error_reporting(E_ALL); +} else { + ini_set('display_errors', '0'); + ini_set('mysql.trace_mode', '0'); + error_reporting(0); +} + +// 2 // Second requirements part which could display bugs (must come after debug management) +require_once(dirname(__FILE__) .'/services/servicefactory.php'); +require_once(dirname(__FILE__) .'/functions.inc.php'); + + +// 3 // Third requirements part which import functions from includes/ directory + +// UTF-8 functions +require_once(dirname(__FILE__) .'/includes/utf8.php'); + +// Translation +require_once(dirname(__FILE__) .'/includes/php-gettext/gettext.inc'); +$domain = 'messages'; +T_setlocale(LC_MESSAGES, $locale); +T_bindtextdomain($domain, dirname(__FILE__) .'/locales'); +T_bind_textdomain_codeset($domain, 'UTF-8'); +T_textdomain($domain); + +// 4 // Session +session_start(); + +// 5 // Create mandatory services and objects +$userservice =& ServiceFactory::getServiceInstance('UserService'); +$currentUser = $userservice->getCurrentObjectUser(); + +$templateservice =& ServiceFactory::getServiceInstance('TemplateService'); +$tplVars = array(); +$tplVars['currentUser'] = $currentUser; +$tplVars['userservice'] = $userservice; + +// 6 // Force UTF-8 behaviour for server (cannot be move into top.inc.php which is not included into every file) +header('Content-Type: text/html; charset=utf-8'); +?> diff --git a/src/SemanticScuttle/search.inc.php b/src/SemanticScuttle/search.inc.php new file mode 100644 index 0000000..ce57aea --- /dev/null +++ b/src/SemanticScuttle/search.inc.php @@ -0,0 +1,54 @@ +<?php + + +/* Managing all possible inputs */ +$select_watchlist = isset($select_watchlist)?$select_watchlist:''; +$select_all = isset($select_all)?$select_all:''; + +$selected = ' selected="selected"'; +?> + + +<form id="search" action="<?php echo createURL('search'); ?>" method="post"> + <table> + <tr> + <?php + $currentUser = $currentUsername = null; + if ($userservice->isLoggedOn()) { + $currentUser = $userservice->getCurrentObjectUser(); + $currentUsername = $currentUser->getUsername(); + } + if ($userservice->isLoggedOn() || isset($user)) { + ?> + + <td><input type="text" name="terms" size="30" value="<?php $terms=!isset($terms)?T_('Search...'):$terms; echo filter($terms); ?>" onfocus="if (this.value == '<?php echo T_('Search...') ?>') this.value = '';" onblur="if (this.value == '') this.value = '<?php echo T_('Search...') ?>';"/></td> + <td><?php echo T_('in') ?></td> + <td> + <select name="range"> + <?php + if ($range == 'user' && $user!=$currentUsername) { + ?> + <option value="<?php echo $user ?>"><?php echo T_("this user's bookmarks"); ?></option> + <?php + } + if ($userservice->isLoggedOn()) { + ?> + <option value="<?php echo $currentUsername; ?>"><?php echo T_('my bookmarks'); ?></option> + <option value="watchlist" <?php echo ($range == 'watchlist')?$selected:''?> ><?php echo T_('my watchlist'); ?></option> + <?php + } + ?> + <option value="all" <?php echo ($range == 'all' || $range == '')?$selected:'' ?> ><?php echo T_('all bookmarks'); ?></option> + </select> + </td> + <?php + } else { + ?> + <td><input type="hidden" name="range" value="all" /></td> + <?php + } + ?> + <td><input type="submit" value="<?php echo T_('Search' /* Submit button */); ?>" /></td> + </tr> + </table> +</form> |