require_once 'config.php'; require_once 'class.php'; $task = isset($_POST['task']) ? $_POST['task'] : ''; $ufrom = isset($_POST['ufrom']) ? (int) $_POST['ufrom'] : 72; $uto = isset($_POST['uto']) ? (int) $_POST['uto'] : 117; $db = new MySQLi(DB_HOST, DB_USER, DB_PASS, DB_NAME, 3306); if ($db->connect_error) { echo "Not connected, error: " . $db->connect_error; } else { switch ($task) { case 'generate': SixDegrees::prepareFriendList($db); echo "<div style='color:green;'>Done!</div>"; break; case 'build': $result = SixDegrees::buildConnection($ufrom, $uto, $db); if (!empty($result) && is_array($result) && is_array($result['path']) && count($result['path']) > 0) { echo "<h3>Generated chain:</h3>"; include 'html/result.tpl.php'; echo "<h3>Ready to build some more?</h3>"; } elseif (!$result['brokenLink']) { echo "<div style='color:red;'>Users are not connected</div>"; } else { echo "<div style='color:red;'>Could not generate the chain</div>"; } break; default: } echo "<h3>Six Degrees of Separation Algorithm Demo</h3>"; include 'html/main.tpl.php'; }
/** * Method to generate array of IDs of the users that are in a chain between the two given users $ufrom and $uto. * * @param MySQLi Database handler * @param object Table record for user $ufrom * @param object Table record for user $uto * @param integer Radius of the minimum intersection circle we want to find * @param array This is to be used internally only, should be left empty * @param array This is to be used internally only, should be left empty * * @return null */ private function _findIntersection($db, $ufrom, $uto, $level, $from = array(), $to = array()) { $t = "friends" . $level; //name of a table field where list of friends of $level are kept $from[$level] = explode(',', $ufrom->{$t}); $to[$level] = explode(',', $uto->{$t}); //the simplest case is when $ufrom and $uto are mutual friends if ($level == 1 && (in_array($ufrom->id_user, $to[$level]) || in_array($uto->id_user, $from[$level]))) { $this->_chainLength = 1; return array($ufrom->id_user, $uto->id_user); } //see if $ufrom's circle of radius $level intersects with any of the circles of $uto of smaller or equal radius for ($k = 1; $k <= $level; $k++) { $intersection = array_intersect($from[$level], $to[$k]); if (!empty($intersection) && is_array($intersection)) { reset($intersection); //set internal pointer to the first element of an array $this->_chainLength = $k + $level; //the length of the chain between $ufrom to $uto //if there's an intersection with $level equal 1, then there's just one person in between $ufrom and $uto if ($level == 1) { return array($ufrom->id_user, current($intersection), $uto->id_user); } //$ufrom and $uto may have several people in common in the circle of the same radius //So we just pick the first person in $intersection array $result = $db->query("SELECT * FROM friends WHERE id_user = '******'"); $ucommon = $result->fetch_object(); //convert available friend levels of $ucommon to array for ($i = 1; $i < self::_maximumCircleRadius + 1; $i++) { $common[$i] = explode(',', $ucommon->{"friends" . $i}); } $stack = array('to' => array(), 'from' => array()); SixDegrees::_reverseSearch($from, $common, $level, 1, $stack, 'from'); //build a chain from $ucommon to $ufrom SixDegrees::_reverseSearch($to, $common, $k, 1, $stack, 'to'); //build a chain from $ucommon to $uto //start: build the resulting array $result = array($ufrom->id_user); $j = count($stack['from']) - 1; while ($j >= 0 && isset($stack['from'][$j])) { //build a chain from $ufrom to $ucommon $result[] = $stack['from'][$j]; $j--; } $result[] = current($intersection); //add $ucommon himself to the chain for ($j = 0; $j < count($stack['to']); $j++) { //build a chain from $ucommon to $uto $result[] = $stack['to'][$j]; } $result[] = $uto->id_user; //end: build the resulting array return $result; } } if ($level < self::_maximumCircleRadius) { // we can continue until we reach _maximumCircleRadius return $this->_findIntersection($db, $ufrom, $uto, $level + 1, $from, $to); } else { return null; } }