[web-php] master: Revert "Create UserNoteService class"

From: Date: Wed, 21 Jan 2026 15:04:38 +0000
Subject: [web-php] master: Revert "Create UserNoteService class"
Groups: php.webmaster 
Request: Send a blank email to php-webmaster+get-33534@lists.php.net to get a copy of this message
Author: Derick Rethans (derickr) Date: 2026-01-21T15:02:14Z Commit: https://github.com/php/web-php/commit/7e2d16d545c612887bf18b33ce6e312ecf562baf Raw diff: https://github.com/php/web-php/commit/7e2d16d545c612887bf18b33ce6e312ecf562baf.diff Revert "Create UserNoteService class" This reverts commit b31ec1c7f1ad8901a2a27df56e766a1bf236cea5. Changed paths: D src/UserNotes/UserNoteService.php M include/layout.inc M include/shared-manual.inc M manual/add-note.php M manual/vote-note.php Diff: diff --git a/include/layout.inc b/include/layout.inc index 98d8c845c1..02b6f733ca 100644 --- a/include/layout.inc +++ b/include/layout.inc @@ -164,6 +164,21 @@ function make_link(string $url, string $linktext = ''): string return sprintf("<a href=\"%s\">%s</a>", $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("<a href=\"%s\" target=\"%s\" onclick=\"window.open('%s','%s','%s');return false;\"%s>%s</a>", + 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 { @@ -205,6 +220,20 @@ 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|<|\)|"|\\\\|\'|$)!', + '<a href="\1" rel="nofollow" target="_blank">\1</a>\4', + $text, + ); +} + function display_errors($errors): void { echo '<div class="errors">'; diff --git a/include/shared-manual.inc b/include/shared-manual.inc index 0a7c6e8ac7..821b2704ba 100644 --- a/include/shared-manual.inc +++ b/include/shared-manual.inc @@ -23,7 +23,185 @@ $PGI = []; $SIDEBAR_DATA = ''; // ============================================================================= use phpweb\I18n\Languages; -use phpweb\UserNotes\UserNoteService; +use phpweb\UserNotes\Sorter; +use phpweb\UserNotes\UserNote; + +/** + * Print out all user notes for this manual page + * + * @param array<string, UserNote> $notes + */ +function manual_notes($notes):void { + global $LANG; + + // 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); + + $repo = strtolower($LANG); + $addNote = autogen('add_a_note', $LANG); + // 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 . + '&amp;repo=' . $repo . + '&amp;redirect=' . $_SERVER['BASE_HREF']; + $addnotesnippet = make_link( + $addnotelink, + "+<small>$addNote</small>", + ); + + $num_notes = count($notes); + $noteCountHtml = ''; + if ($num_notes) { + $noteCountHtml = "<span class=\"count\">$num_notes note" . ($num_notes == 1 ? '' : 's') . "</span>"; + } + + $userContributedNotes = autogen('user_contributed_notes', $LANG); + echo <<<END_USERNOTE_HEADER +<section id="usernotes"> + <div class="head"> + <span class="action">{$addnotesnippet}</span> + <h3 class="title">$userContributedNotes {$noteCountHtml}</h3> + </div> +END_USERNOTE_HEADER; + + // If we have no notes, then inform the user + if ($num_notes === 0) { + $noUserContributedNotes = autogen('no_user_notes', $LANG); + echo "\n <div class=\"note\">$noUserContributedNotes</div>"; + } else { + // If we have notes, print them out + echo '<div id="allnotes">'; + foreach ($notes as $note) { + manual_note_display($note); + } + echo "</div>\n"; + echo "<div class=\"foot\">$addnotesnippet</div>\n"; + } + echo "</section>"; +} + +/** + * Get user notes from the appropriate text dump + * + * @return array<string, UserNote> + */ +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 <strong class=\"user\"><em>" . htmlspecialchars($note->user) . "</em></strong>"; + } else { + $name = "<strong class=\"user\"><em>Anonymous</em></strong>"; + } + $name = ($note->id ? "\n <a href=\"#{$note->id}\" class=\"name\">$name</a><a class=\"genanchor\" href=\"#{$note->id}\"> &para;</a>" : "\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 = <<<VOTEDIV + <div class="votes"> + <div id="Vu{$note->id}"> + <a href="/manual/vote-note.php?id={$note->id}&amp;page={$rredir_filename}&amp;vote=up" title="Vote up!" class="usernotes-voteu">up</a> + </div> + <div id="Vd{$note->id}"> + <a href="/manual/vote-note.php?id={$note->id}&amp;page={$rredir_filename}&amp;vote=down" title="Vote down!" class="usernotes-voted">down</a> + </div> + <div class="tally" id="V{$note->id}" title="{$rate}"> + {$vote} + </div> + </div> +VOTEDIV; + } else { + $votediv = null; + } + + // If the viewer is logged in, show admin options + if (isset($_COOKIE['IS_DEV']) && $note->id) { + + $admin = "\n <span class=\"admin\">\n " . + + make_popup_link( + 'https://main.php.net/manage/user-notes.php?action=edit+' . $note->id, + '<img src="/images/notes-edit@2x.png" height="12" width="12" alt="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, + '<img src="/images/notes-reject@2x.png" height="12" width="12" alt="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, + '<img src="/images/notes-delete@2x.png" height="12" width="12" alt="delete note">', + 'admin', + 'scrollbars=no,width=300,height=200', + ) . "\n </span>"; + + } else { + $admin = ''; + } + + echo <<<USER_NOTE_TEXT + + <div class="note" id="{$note->id}">{$votediv}{$name}{$admin}<div class="date" title="$fdatestr"><strong>{$datestr}</strong></div> + <div class="text" id="Hcom{$note->id}"> +{$text} + </div> + </div> +USER_NOTE_TEXT; + +} function manual_navigation_breadcrumbs(array $setup) { $menu = []; @@ -120,9 +298,7 @@ function manual_setup($setup): void { if (substr($filename, -4) == '.php') { $filename = substr($filename, 0, -4); } - - $userNoteService = new UserNoteService(); - $USERNOTES = $userNoteService->load($filename); + $USERNOTES = manual_notes_load($filename); if ($USERNOTES) { $note = current($USERNOTES); $timestamps[] = $note->ts; @@ -246,14 +422,35 @@ function manual_footer($setup): void { </div> CONTRIBUTE; - $userNoteService = new UserNoteService(); - $userNoteService->display($USERNOTES); + manual_notes($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; +} + function contributors($setup) { if (!isset($_GET["contributors"]) || !isset($setup["history"]["contributors"]) @@ -280,6 +477,7 @@ function autogen(string $text, string $lang) { static $translations = []; $lang = ($lang === "") ? "en" : $lang; + $lang = strtolower($lang); if (isset($translations[$lang])) { if (isset($translations[$lang][$text]) && $translations[$lang][$text] !== "") { return $translations[$lang][$text]; diff --git a/manual/add-note.php b/manual/add-note.php index 522c4b509e..4cb6651366 100644 --- a/manual/add-note.php +++ b/manual/add-note.php @@ -8,7 +8,6 @@ include __DIR__ . '/spam_challenge.php'; use phpweb\UserNotes\UserNote; -use phpweb\UserNotes\UserNoteService; site_header("Add Manual Note", ['css' => 'add-note.css']); @@ -147,10 +146,9 @@ if ($error) { echo "<p class=\"formerror\">$error</p>\n"; } // Print out preview of note - $userNoteService = new UserNoteService(); echo '<p>This is what your entry will look like, roughly:</p>'; echo '<div id="usernotes">'; - $userNoteService->displaySingle(new UserNote('', '', '', time(), $user, $note)); + manual_note_display(new UserNote('', '', '', time(), $user, $note)); echo '</div><br><br>'; } diff --git a/manual/vote-note.php b/manual/vote-note.php index 94b4f69e80..d07689e8ed 100644 --- a/manual/vote-note.php +++ b/manual/vote-note.php @@ -1,7 +1,4 @@ <?php - -use phpweb\UserNotes\UserNoteService; - $_SERVER['BASE_PAGE'] = 'manual/vote-note.php'; include_once __DIR__ . '/../include/prepend.inc'; include_once __DIR__ . '/../include/posttohost.inc'; @@ -16,10 +13,9 @@ $BACKid = htmlspecialchars($_REQUEST['id'] ?? ''); $link = "/{$BACKpage}#{$BACKid}"; $master_url = "https://main.php.net/entry/user-notes-vote.php"; -$notes = new UserNoteService(); if ($_SERVER['REQUEST_METHOD'] == 'POST') { - if (isset($_SERVER['HTTP_X_JSON']) && $_SERVER['HTTP_X_JSON'] == 'On' && !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 (isset($_SERVER['HTTP_X_JSON']) && $_SERVER['HTTP_X_JSON'] == 'On' && !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')) { $response = []; $hash = substr(md5($_REQUEST['page']), 0, 16); $notes_file = $_SERVER['DOCUMENT_ROOT'] . "/backend/notes/" . substr($hash, 0, 2) . "/$hash"; @@ -55,7 +51,7 @@ echo json_encode($response); exit; } - 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($_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($_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."; @@ -100,7 +96,7 @@ site_header("Vote On User Notes"); $headerset = true; - 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($_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')) { ?> <div class="container" id="notes-dialog" style="width: 100%; padding-bottom: 15px; margin: auto;"> <div style="width: 100%; margin: auto;"><h1>Voting</h1></div> @@ -122,7 +118,7 @@ <?php $backID = htmlspecialchars($_REQUEST['id']); $backPAGE = htmlspecialchars($_REQUEST['page']); - $notes->displaySingle($N[$_REQUEST['id']], false); + manual_note_display($N[$_REQUEST['id']], false); ?> </div> <div style="width: 90%; margin: auto;"><p><a href="<?php echo "/{$backPAGE}#{$backID}"; ?>">&lt;&lt; Back to user notes page</a></p></div> @@ -175,7 +171,7 @@ <?php $backID = htmlspecialchars($_REQUEST['id']); $backPAGE = htmlspecialchars($_REQUEST['page']); - $notes->displaySingle($N[$_REQUEST['id']], false); + manual_note_display($N[$_REQUEST['id']], false); ?> </div> <div style="width: 90%; margin: auto;"><p><a href="<?php echo "/{$backPAGE}#{$backID}"; ?>">&lt;&lt; Back to user notes page</a></p></div> diff --git a/src/UserNotes/UserNoteService.php b/src/UserNotes/UserNoteService.php deleted file mode 100644 index 5e49ad9b55..0000000000 --- a/src/UserNotes/UserNoteService.php +++ /dev/null @@ -1,237 +0,0 @@ -<?php - -namespace phpweb\UserNotes; - -final class UserNoteService -{ - /** - * Get user notes from the appropriate text dump - * - * @return array<string, UserNote> - */ - 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<string, UserNote> $notes - */ - public function display($notes):void { - global $LANG; - - // 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); - - $addNote = autogen('add_a_note', $LANG); - $repo = strtolower($LANG); - // 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 . - '&amp;repo=' . $repo . - '&amp;redirect=' . $_SERVER['BASE_HREF']; - $addnotesnippet = make_link( - $addnotelink, - "+<small>$addNote</small>", - ); - - $num_notes = count($notes); - $noteCountHtml = ''; - if ($num_notes) { - $noteCountHtml = "<span class=\"count\">$num_notes note" . ($num_notes == 1 ? '' : 's') . "</span>"; - } - - $userContributedNotes = autogen('user_contributed_notes', $LANG); - echo <<<END_USERNOTE_HEADER -<section id="usernotes"> - <div class="head"> - <span class="action">{$addnotesnippet}</span> - <h3 class="title">$userContributedNotes {$noteCountHtml}</h3> - </div> -END_USERNOTE_HEADER; - - // If we have no notes, then inform the user - if ($num_notes === 0) { - $noUserContributedNotes = autogen('no_user_notes', $LANG); - echo "\n <div class=\"note\">$noUserContributedNotes</div>"; - } else { - // If we have notes, print them out - echo '<div id="allnotes">'; - foreach ($notes as $note) { - $this->displaySingle($note); - } - echo "</div>\n"; - echo "<div class=\"foot\">$addnotesnippet</div>\n"; - } - echo "</section>"; - } - - /** - * Print out one user note entry - */ - public function displaySingle(UserNote $note, $voteOption = true): void - { - if ($note->user) { - $name = "\n <strong class=\"user\"><em>" . htmlspecialchars($note->user) . "</em></strong>"; - } else { - $name = "<strong class=\"user\"><em>Anonymous</em></strong>"; - } - $name = ($note->id ? "\n <a href=\"#{$note->id}\" class=\"name\">$name</a><a class=\"genanchor\" href=\"#{$note->id}\"> &para;</a>" : "\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 = <<<VOTEDIV - <div class="votes"> - <div id="Vu{$note->id}"> - <a href="/manual/vote-note.php?id={$note->id}&amp;page={$rredir_filename}&amp;vote=up" title="Vote up!" class="usernotes-voteu">up</a> - </div> - <div id="Vd{$note->id}"> - <a href="/manual/vote-note.php?id={$note->id}&amp;page={$rredir_filename}&amp;vote=down" title="Vote down!" class="usernotes-voted">down</a> - </div> - <div class="tally" id="V{$note->id}" title="{$rate}"> - {$vote} - </div> - </div> -VOTEDIV; - } else { - $votediv = null; - } - - // If the viewer is logged in, show admin options - if (isset($_COOKIE['IS_DEV']) && $note->id) { - - $admin = "\n <span class=\"admin\">\n " . - - $this->makePopupLink( - 'https://main.php.net/manage/user-notes.php?action=edit+' . $note->id, - '<img src="/images/notes-edit@2x.png" height="12" width="12" alt="edit note">', - 'admin', - 'scrollbars=yes,width=650,height=400', - ) . "\n " . - - $this->makePopupLink( - 'https://main.php.net/manage/user-notes.php?action=reject+' . $note->id, - '<img src="/images/notes-reject@2x.png" height="12" width="12" alt="reject note">', - 'admin', - 'scrollbars=no,width=300,height=200', - ) . "\n " . - - $this->makePopupLink( - 'https://main.php.net/manage/user-notes.php?action=delete+' . $note->id, - '<img src="/images/notes-delete@2x.png" height="12" width="12" alt="delete note">', - 'admin', - 'scrollbars=no,width=300,height=200', - ) . "\n </span>"; - - } else { - $admin = ''; - } - - echo <<<USER_NOTE_TEXT - - <div class="note" id="{$note->id}">{$votediv}{$name}{$admin}<div class="date" title="$fdatestr"><strong>{$datestr}</strong></div> - <div class="text" id="Hcom{$note->id}"> -{$text} - </div> - </div> -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|<|\)|"|\\\\|\'|$)!', - '<a href="\1" rel="nofollow" target="_blank">\1</a>\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("<a href=\"%s\" target=\"%s\" onclick=\"window.open('%s','%s','%s');return false;\"%s>%s</a>", - htmlspecialchars($url, ENT_QUOTES | ENT_IGNORE), - ($target ?: "_new"), - htmlspecialchars($url, ENT_QUOTES | ENT_IGNORE), - ($target ?: "_new"), - $windowprops, - ($linktext ?: $url), - ); - } -}

« previous php.webmaster (#33534) next »