diff --git a/include/layout.inc b/include/layout.inc index eeedd43872..d0ad760564 100644 --- a/include/layout.inc +++ b/include/layout.inc @@ -139,21 +139,6 @@ function make_link(string $url, string $linktext = ''): string return sprintf("%s", $url, $linktext ?: $url); } -// make_popup_link() -// return a hyperlink to something, within the site, that pops up a new window -// -function make_popup_link($url, $linktext = false, $target = false, $windowprops = "", $extras = false) { - return sprintf("%s", - htmlspecialchars($url, ENT_QUOTES | ENT_IGNORE), - ($target ?: "_new"), - htmlspecialchars($url, ENT_QUOTES | ENT_IGNORE), - ($target ?: "_new"), - $windowprops, - ($extras ? ' ' . $extras : ''), - ($linktext ?: $url), - ); -} - // Print a link for a downloadable file (including filesize) function download_link($file, $title): void { @@ -195,20 +180,6 @@ function clean($var) { return htmlspecialchars($var, ENT_QUOTES); } -// Clean out the content of one user note for printing to HTML -function clean_note($text) -{ - // Highlight PHP source - $text = highlight_php(trim($text), true); - - // Turn urls into links - return preg_replace( - '!((mailto:|(https?|ftp|nntp|news)://).*?)(\s|<|\)|"|\\\\|\'|$)!', - '\1\4', - $text, - ); -} - function display_errors($errors): void { echo '
'; diff --git a/include/shared-manual.inc b/include/shared-manual.inc index a686b15cef..9128905f0a 100644 --- a/include/shared-manual.inc +++ b/include/shared-manual.inc @@ -24,178 +24,7 @@ $PGI = []; $SIDEBAR_DATA = ''; require_once __DIR__ . '/../src/autoload.php'; -use phpweb\UserNotes\Sorter; -use phpweb\UserNotes\UserNote; - -/** - * Print out all user notes for this manual page - * - * @param array $notes - */ -function manual_notes($notes):void { - // Get needed values - list($filename) = $GLOBALS['PGI']['this']; - - // Drop file extension from the name - if (substr($filename, -4) == '.php') { - $filename = substr($filename, 0, -4); - } - - $sorter = new Sorter(); - $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", - ); - - $num_notes = count($notes); - $noteCountHtml = ''; - if ($num_notes) { - $noteCountHtml = "$num_notes note" . ($num_notes == 1 ? '' : 's') . ""; - } - - echo << -
- {$addnotesnippet} -

User Contributed Notes {$noteCountHtml}

-
-END_USERNOTE_HEADER; - - // If we have no notes, then inform the user - if ($num_notes === 0) { - echo "\n
There are no user contributed notes for this page.
"; - } else { - // If we have notes, print them out - echo '
'; - foreach ($notes as $note) { - manual_note_display($note); - } - echo "
\n"; - echo "
$addnotesnippet
\n"; - } - echo ""; -} - -/** - * Get user notes from the appropriate text dump - * - * @return array - */ -function manual_notes_load(string $id): 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] = new UserNote($id, $sect, $rate, $ts, $user, base64_decode($note, true), (int) $up, (int) $down); - } - fclose($fp); - } - return $notes; -} - -// Print out one user note entry -function manual_note_display(UserNote $note, $voteOption = true): void -{ - if ($note->user) { - $name = "\n " . htmlspecialchars($note->user) . ""; - } else { - $name = "Anonymous"; - } - $name = ($note->id ? "\n id}\" class=\"name\">$nameid}\"> ¶" : "\n $name"); - - // New date style will be relative time - $date = new DateTime("@{$note->ts}"); - $datestr = relTime($date); - $fdatestr = $date->format("Y-m-d h:i"); - $text = clean_note($note->text); - - // Calculate note rating by up/down votes - $vote = $note->upvotes - $note->downvotes; - $p = floor(($note->upvotes / (($note->upvotes + $note->downvotes) ?: 1)) * 100); - $rate = !$p && !($note->upvotes + $note->downvotes) ? "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 -
-
- down -
-
- {$vote} -
-
-VOTEDIV; - } else { - $votediv = null; - } - - // If the viewer is logged in, show admin options - if (isset($_COOKIE['IS_DEV']) && $note->id) { - - $admin = "\n \n " . - - make_popup_link( - 'https://main.php.net/manage/user-notes.php?action=edit+' . $note->id, - 'edit note', - 'admin', - 'scrollbars=yes,width=650,height=400', - ) . "\n " . - - make_popup_link( - 'https://main.php.net/manage/user-notes.php?action=reject+' . $note->id, - 'reject note', - 'admin', - 'scrollbars=no,width=300,height=200', - ) . "\n " . - - make_popup_link( - 'https://main.php.net/manage/user-notes.php?action=delete+' . $note->id, - 'delete note', - 'admin', - 'scrollbars=no,width=300,height=200', - ) . "\n "; - - } else { - $admin = ''; - } - - echo <<{$votediv}{$name}{$admin}
{$datestr}
-
-{$text} -
- -USER_NOTE_TEXT; - -} +use phpweb\UserNotes\UserNoteService; function manual_navigation_breadcrumbs(array $setup) { $menu = []; @@ -293,7 +122,9 @@ function manual_setup($setup): void { if (substr($filename, -4) == '.php') { $filename = substr($filename, 0, -4); } - $USERNOTES = manual_notes_load($filename); + + $userNoteService = new UserNoteService(); + $USERNOTES = $userNoteService->load($filename); if ($USERNOTES) { $note = current($USERNOTES); $timestamps[] = $note->ts; @@ -384,31 +215,10 @@ CHANGE_LANG; function manual_footer(): void { global $USERNOTES, $__RELATED; - manual_notes($USERNOTES); + $userNoteService = new UserNoteService(); + $userNoteService->display($USERNOTES); site_footer([ 'related_menu' => $__RELATED['toc'], 'related_menu_deprecated' => $__RELATED['toc_deprecated'], ]); } - -// 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 = ["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; -} diff --git a/manual/add-note.php b/manual/add-note.php index 1398e5d006..1577ad5663 100644 --- a/manual/add-note.php +++ b/manual/add-note.php @@ -8,6 +8,7 @@ include __DIR__ . '/spam_challenge.php'; use phpweb\UserNotes\UserNote; +use phpweb\UserNotes\UserNoteService; site_header("Add Manual Note", ['css' => 'add-note.css']); @@ -139,9 +140,10 @@ if ($error) { echo "

$error

\n"; } // Print out preview of note + $userNoteService = new UserNoteService(); echo '

This is what your entry will look like, roughly:

'; echo '
'; - manual_note_display(new UserNote('', '', '', time(), $user, $note)); + $userNoteService->displaySingle(new UserNote('', '', '', time(), $user, $note)); echo '


'; } diff --git a/manual/vote-note.php b/manual/vote-note.php index fa8de7c7e2..2d59721855 100644 --- a/manual/vote-note.php +++ b/manual/vote-note.php @@ -1,4 +1,7 @@ load($_REQUEST['page'])) && array_key_exists($_REQUEST['id'], $N) && !empty($_REQUEST['vote']) && ($_REQUEST['vote'] === 'up' || $_REQUEST['vote'] === 'down')) { $response = []; $hash = substr(md5($_REQUEST['page']), 0, 16); $notes_file = $_SERVER['DOCUMENT_ROOT'] . "/backend/notes/" . substr($hash, 0, 2) . "/$hash"; @@ -51,7 +55,7 @@ echo json_encode($response); exit; } - if (!empty($_REQUEST['id']) && !empty($_REQUEST['page']) && ($N = manual_notes_load($_REQUEST['page'])) && array_key_exists($_REQUEST['id'], $N) && !empty($_REQUEST['vote']) && ($_REQUEST['vote'] === 'up' || $_REQUEST['vote'] === 'down')) { + if (!empty($_REQUEST['id']) && !empty($_REQUEST['page']) && ($N = $notes->load($_REQUEST['page'])) && array_key_exists($_REQUEST['id'], $N) && !empty($_REQUEST['vote']) && ($_REQUEST['vote'] === 'up' || $_REQUEST['vote'] === 'down')) { if (!empty($_POST['challenge']) && !empty($_POST['func']) || empty($_POST['arga']) || empty($_POST['argb'])) { if (!test_answer($_POST['func'], $_POST['arga'], $_POST['argb'], $_POST['challenge'])) { $error = "Incorrect answer! Please try again."; @@ -102,7 +106,7 @@ site_header("Vote On User Notes"); $headerset = true; - if (!empty($_REQUEST['id']) && !empty($_REQUEST['page']) && ($N = manual_notes_load($_REQUEST['page'])) && array_key_exists($_REQUEST['id'], $N) && !empty($_REQUEST['vote']) && ($_REQUEST['vote'] === 'up' || $_REQUEST['vote'] === 'down')) { + if (!empty($_REQUEST['id']) && !empty($_REQUEST['page']) && ($N = $notes->load($_REQUEST['page'])) && array_key_exists($_REQUEST['id'], $N) && !empty($_REQUEST['vote']) && ($_REQUEST['vote'] === 'up' || $_REQUEST['vote'] === 'down')) { ?>

Voting

@@ -124,7 +128,7 @@ displaySingle($N[$_REQUEST['id']], false); ?>

"><< Back to user notes page

@@ -177,7 +181,7 @@ displaySingle($N[$_REQUEST['id']], false); ?>

"><< Back to user notes page

diff --git a/src/UserNotes/UserNoteService.php b/src/UserNotes/UserNoteService.php new file mode 100644 index 0000000000..cc51636d0a --- /dev/null +++ b/src/UserNotes/UserNoteService.php @@ -0,0 +1,230 @@ + + */ + public function load(string $id): 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] = new UserNote($id, $sect, $rate, $ts, $user, base64_decode($note, true), (int) $up, (int) $down); + } + fclose($fp); + } + return $notes; + } + + /** + * Print out all user notes for this manual page + * + * @param array $notes + */ + public function display($notes):void + { + // Get needed values + list($filename) = $GLOBALS['PGI']['this']; + + // Drop file extension from the name + if (substr($filename, -4) == '.php') { + $filename = substr($filename, 0, -4); + } + + $sorter = new Sorter(); + $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", + ); + + $num_notes = count($notes); + $noteCountHtml = ''; + if ($num_notes) { + $noteCountHtml = "$num_notes note" . ($num_notes == 1 ? '' : 's') . ""; + } + + echo << +
+ {$addnotesnippet} +

User Contributed Notes {$noteCountHtml}

+
+END_USERNOTE_HEADER; + + // If we have no notes, then inform the user + if ($num_notes === 0) { + echo "\n
There are no user contributed notes for this page.
"; + } else { + // If we have notes, print them out + echo '
'; + foreach ($notes as $note) { + $this->displaySingle($note); + } + echo "
\n"; + echo "
$addnotesnippet
\n"; + } + echo ""; + } + + /** + * Print out one user note entry + */ + public function displaySingle(UserNote $note, $voteOption = true): void + { + if ($note->user) { + $name = "\n " . htmlspecialchars($note->user) . ""; + } else { + $name = "Anonymous"; + } + $name = ($note->id ? "\n id}\" class=\"name\">$nameid}\"> ¶" : "\n $name"); + + // New date style will be relative time + $date = new \DateTime("@{$note->ts}"); + $datestr = $this->relTime($date); + $fdatestr = $date->format("Y-m-d h:i"); + $text = $this->cleanContent($note->text); + + // Calculate note rating by up/down votes + $vote = $note->upvotes - $note->downvotes; + $p = floor(($note->upvotes / (($note->upvotes + $note->downvotes) ?: 1)) * 100); + $rate = !$p && !($note->upvotes + $note->downvotes) ? "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 +
+
+ down +
+
+ {$vote} +
+ +VOTEDIV; + } else { + $votediv = null; + } + + // If the viewer is logged in, show admin options + if (isset($_COOKIE['IS_DEV']) && $note->id) { + + $admin = "\n \n " . + + $this->makePopupLink( + 'https://main.php.net/manage/user-notes.php?action=edit+' . $note->id, + 'edit note', + 'admin', + 'scrollbars=yes,width=650,height=400', + ) . "\n " . + + $this->makePopupLink( + 'https://main.php.net/manage/user-notes.php?action=reject+' . $note->id, + 'reject note', + 'admin', + 'scrollbars=no,width=300,height=200', + ) . "\n " . + + $this->makePopupLink( + 'https://main.php.net/manage/user-notes.php?action=delete+' . $note->id, + 'delete note', + 'admin', + 'scrollbars=no,width=300,height=200', + ) . "\n "; + + } else { + $admin = ''; + } + + echo <<{$votediv}{$name}{$admin}
{$datestr}
+
+{$text} +
+ +USER_NOTE_TEXT; + } + + // Clean out the content of one user note for printing to HTML + private function cleanContent(string $text): string + { + // Highlight PHP source + $text = highlight_php(trim($text), true); + + // Turn urls into links + return preg_replace( + '!((mailto:|(https?|ftp|nntp|news)://).*?)(\s|<|\)|"|\\\\|\'|$)!', + '\1\4', + $text, + ); + } + + /** + * This function takes a DateTime object and returns a formated string of the time difference relative to now + */ + private function relTime(\DateTime $date): string + { + $current = new \DateTime(); + $diff = $current->diff($date); + $units = ["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; + } + + /** + * Return a hyperlink to something, within the site, that pops up a new window + */ + private function makePopupLink(string $url, string $linktext = '', string $target = '', string $windowprops = ''): string + { + return sprintf("%s", + htmlspecialchars($url, ENT_QUOTES | ENT_IGNORE), + ($target ?: "_new"), + htmlspecialchars($url, ENT_QUOTES | ENT_IGNORE), + ($target ?: "_new"), + $windowprops, + ($linktext ?: $url), + ); + } +}