findMinMaxValues($notes); $this->voteFactor = $this->maxVote - $this->minVote ? (1 - .3)/ ($this->maxVote - $this->minVote) : .5; $this->ageFactor = $this->maxAge - $this->minAge ? 1 / ($this->maxAge - $this->minAge) : .5; $this->ageFactor *= $this->ageWeight; // Second we loop through to calculate sort priority using the above numbers $this->calcSortPriority($notes); // Third we sort the data. uasort($notes, array($this, 'factorSort')); } private function calcVotePriority(array $note) { return ($note['score'] - $this->minVote) * $this->voteFactor + .3; } private function calcRatingPriority(array $note) { if ($note['total'] <= 2) { return 0.5; } else { return $note['rating']; } } private function calcSortPriority(array &$notes) { foreach ($notes as &$note) { $prio = array( 'vote' => $this->calcVotePriority($note) * $this->voteWeight, 'rating' => $this->calcRatingPriority($note) * $this->ratingWeight, 'age' => ($note['xwhen'] - $this->minAge) * $this->ageFactor ); $note['sort'] = $prio['value'] = array_sum($prio); } } /* * Not sure why, but using `$b['sort'] - $a['sort']` does not seem to * work properly. */ private function factorSort($a, $b) { if ($a['sort'] < $b['sort']) { return 1; } elseif ($a['sort'] == $b['sort']) { return 0; } else { return -1; } } private function findMinMaxValues(array &$notes) { $count = count($notes); if ($count <= 0) { return; } $note = array_shift($notes); $note['score'] = $net = ($note['votes']['up'] - $note['votes']['down']); $note['total'] = $totalVotes = ($note['votes']['up'] + $note['votes']['down']); $note['rating'] = $totalVotes > 0 ? $note['votes']['up'] / $totalVotes : .5; $this->minVote = $this->maxVote = $net; $this->minAge = $this->maxAge = $age = $note['xwhen']; $first = $note; foreach ($notes as &$note) { $note['score'] = $net = ($note['votes']['up'] - $note['votes']['down']); $note['total'] = $totalVotes = ($note['votes']['up'] + $note['votes']['down']); $note['rating'] = $totalVotes > 0 ? $note['votes']['up'] / $totalVotes : .5; $age = $note['xwhen']; $this->maxVote = max($this->maxVote, $net); $this->minVote = min($this->minVote, $net); $this->maxAge = max($this->maxAge, $age); $this->minAge = min($this->minAge, $age); } array_unshift($notes, $first); } } // Print out all user notes for this manual page function manual_notes($notes) { // Get needed values list($filename, $title) = $GLOBALS['PGI']['this']; // Drop file extension from the name if (substr($filename, -4) == '.php') { $filename = substr($filename, 0, -4); } $sorter = new ManualNotesSorter; $sorter->sort($notes); // Link target to add a note to the current manual page, // and it's extended form with a [+] image $addnotelink = '/manual/add-note.php?sect=' . $filename . '&redirect=' . $_SERVER['BASE_HREF']; $addnotesnippet = make_link( $addnotelink, "add a note add a note" ); $num_notes = count($notes); if ($num_notes) { $num_notes = "$num_notes note" . ($num_notes == 1 ? '' : 's') . ""; } else { $num_notes = null; } echo <<
{$addnotesnippet}

User Contributed Notes {$num_notes}

END_USERNOTE_HEADER; // If we have no notes, then inform the user if (sizeof($notes) == 0) { echo "\n
There are no user contributed notes for this page.
"; } // If we have notes, print them out else { echo '
'; foreach($notes as $note) { manual_note_display( $note['xwhen'], $note['user'], $note['note'], $note['id'], $note['votes'] ); } echo "
\n"; echo "\n
$addnotesnippet
\n"; } // #usernotes gets closed by the footer } // Get user notes from the appropriate text dump function manual_notes_load($id) { // Initialize values $notes = array(); $hash = substr(md5($id), 0, 16); $notes_file = $_SERVER['DOCUMENT_ROOT'] . "/backend/notes/" . substr($hash, 0, 2) . "/$hash"; // Open the note file for reading and get the data (12KB) // ..if it exists if (!file_exists($notes_file)) { return $notes; } if ($fp = @fopen($notes_file, "r")) { while (!feof($fp)) { $line = chop(fgets($fp, 12288)); if ($line == "") { continue; } @list($id, $sect, $rate, $ts, $user, $note, $up, $down) = explode("|", $line); $notes[$id] = array( "id" => $id, "sect" => $sect, "rate" => $rate, "xwhen" => $ts, "user" => $user, "note" => base64_decode($note), "votes" => array("up"=> (int)$up, "down"=> (int)$down) ); } fclose($fp); } return $notes; } // Print out one user note entry function manual_note_display($date, $name, $text, $id, $votes = array('up'=>0,'down'=>0), $voteOption = true) { if ($name) { $name = "\n " . htmlspecialchars($name) . ""; } else { $name = "Anonymous"; } $name = ($id ? "\n $name" : "\n $name"); // New date style will be relative time $datestr = relTime(new DateTime("@{$date}")); $fdatestr = date("Y-m-d h:i", $date); $text = clean_note($text); // Calculate note rating by up/down votes $vote = $votes['up'] - $votes['down']; $p = floor(($votes['up'] / (($votes['up'] + $votes['down']) ? $votes['up'] + $votes['down'] : 1)) * 100); $rate = !$p && !($votes['up'] + $votes['down']) ? "no votes..." : "$p% like this..."; // Vote User Notes Div if ($voteOption) { list($redir_filename) = $GLOBALS['PGI']['this']; if (substr($redir_filename, -4) == '.php') { $redir_filename = substr($redir_filename, 0, -4); } $rredir_filename = urlencode($redir_filename); $votediv = <<
up
{$vote}
VOTEDIV; } else { $votediv = null; } // If the viewer is logged in, show admin options if (isset($_COOKIE['IS_DEV']) && $id) { $admin = "\n \n " . make_popup_link( 'https://master.php.net/manage/user-notes.php?action=edit+' . $id, 'edit note', 'admin', 'scrollbars=yes,width=650,height=400' ) . "\n " . make_popup_link( 'https://master.php.net/manage/user-notes.php?action=reject+' . $id, 'reject note', 'admin', 'scrollbars=no,width=300,height=200' ) . "\n " . make_popup_link( 'https://master.php.net/manage/user-notes.php?action=delete+' . $id, 'delete note', 'admin', 'scrollbars=no,width=300,height=200' ) . "\n "; } else { $admin = ''; } echo <<{$votediv}{$name}{$admin}
{$datestr}
{$text}
USER_NOTE_TEXT; } function manual_navigation_breadcrumbs(array $setup) { $menu = array(); foreach(array_reverse($setup["parents"]) as $parent) { $menu[] = array( "title" => $parent[1], "link" => $parent[0], ); } // The index manual page has no parent.. if ($setup["up"][0]) { $last_item = array( "title" => $setup["up"][1], "link" => $setup["up"][0], ); $menu[] = $last_item; } return $menu; } function manual_navigation_related(array $setup) { $siblings = array(); foreach($setup['toc'] as $entry) { $siblings[] = array( "title" => manual_navigation_methodname($entry[1]), "link" => $entry[0], "current" => $setup["this"][0] == $entry[0], ); } // The index manual page has no parent.. if ($setup["up"][0]) { $last_item = array( "title" => $setup["up"][1], "link" => $setup["up"][0], ); $siblings = array(array_merge($last_item, array("children" => $siblings))); } return $siblings; } function manual_navigation_deprecated(array $setup) { $methods = array(); foreach((array)$setup['toc_deprecated'] as $entry) { $methods[] = array( "title" => manual_navigation_methodname($entry[1]), "link" => $entry[0], "current" => $setup["this"][0] == $entry[0], ); } return $methods; } function manual_navigation_methodname($methodname) { // We strip out any class prefix here, we only want method names if (strpos($methodname, '::') !== false && strpos($methodname, ' ') === false) { $tmp = explode('::', $methodname); $methodname = $tmp[1]; } // Add zero-width spaces to allow line-breaks at various characters return str_replace(array('-','_'), array('-​','_​'), $methodname); } // Set up variables important for this page // including HTTP header information function manual_setup($setup) { global $PGI, $MYSITE, $USERNOTES; global $ACTIVE_ONLINE_LANGUAGES; //TODO: get rid of this hack to get the related items into manual_footer global $__RELATED; if (!isset($setup["toc_deprecated"])) { $setup["toc_deprecated"] = array(); } $PGI = $setup; // Set base href for this manual page $base = 'manual/' . language_convert($setup['head'][1]) . "/"; $_SERVER['BASE_PAGE'] = $base . $setup['this'][0]; $_SERVER['BASE_HREF'] = $MYSITE . $_SERVER['BASE_PAGE']; // Load user note for this page list($filename, $title) = $PGI['this']; // Drop file extension from the name if (substr($filename, -4) == '.php') { $filename = substr($filename, 0, -4); } $USERNOTES = manual_notes_load($filename); $note = current($USERNOTES); $lastusernote = $note["xwhen"]; $timestamps = array( filemtime($_SERVER["DOCUMENT_ROOT"] . "/" . $_SERVER["BASE_PAGE"]), filemtime($_SERVER["DOCUMENT_ROOT"] . "/include/prepend.inc"), filemtime($_SERVER["DOCUMENT_ROOT"] . "/styles/theme-base.css"), $lastusernote, ); $lastmod = max($timestamps); $breadcrumbs = manual_navigation_breadcrumbs($setup); $__RELATED['toc'] = manual_navigation_related($setup); $__RELATED['toc_deprecated'] = manual_navigation_deprecated($setup); $config = array( "current" => "docs", "breadcrumbs" => $breadcrumbs, "languages" => array_keys($ACTIVE_ONLINE_LANGUAGES), "meta-navigation" => array( "contents" => $base . $setup["home"][0], "index" => $base . $setup["up"][0], "prev" => $base . $setup["prev"][0], "next" => $base . $setup["next"][0], ), "lang" => $setup["head"][1], "thispage" => $setup["this"][0], "prev" => $setup["prev"], "next" => $setup["next"], "cache" => $lastmod, ); site_header($setup["this"][1] . " - Manual ", $config); $id = substr($setup['this'][0], 0, -4); $language_chooser = 'manual_language_chooser'; echo <<
{$language_chooser($config['lang'], $config['thispage'])}
PAGE_TOOLS; } function manual_language_chooser($currentlang, $currentpage) { global $ACTIVE_ONLINE_LANGUAGES; $links = array(); foreach ($ACTIVE_ONLINE_LANGUAGES as $lang => $name) { $links[] = array("$lang/$currentpage", $name, $lang); } // Print out the form with all the options $othersel = ' selected="selected"'; $format_options = function (array $links) use ($currentlang, &$othersel) { $out = ''; $tab = str_repeat(' ', 6); foreach ($links as $link) { list($value, $text, $lang) = $link; $selected = ''; if ($lang == $currentlang) { $selected = ' selected="selected"'; $othersel = ''; } $out .= "$tab\n"; } return trim($out); }; $r = <<
CHANGE_LANG; return trim($r); } function manual_header(){} function manual_footer() { global $USERNOTES, $__RELATED; manual_notes($USERNOTES); echo ""; $config = array( 'related_menu' => $__RELATED['toc'], 'related_menu_deprecated' => $__RELATED['toc_deprecated'] ); site_footer($config); } // This function takes a DateTime object and returns a formated string of the time difference relative to now function relTime(DateTime $date) { $current = new DateTime; $diff = $current->diff($date); $units = array("year" => $diff->format("%y"), "month" => $diff->format("%m"), "day" => $diff->format("%d"), "hour" => $diff->format("%h"), "minute" => $diff->format("%i"), "second" => $diff->format("%s"), ); $out = "just now..."; foreach ($units as $unit => $amount) { if (empty($amount)) { continue; } $out = $amount . " " . ($amount == 1 ? $unit : $unit . "s") . " ago"; break; } return $out; } /* vim: set et ts=4 sw=4: */