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> | 
