Commit: 8b0a4d377cec9551f3d0e9fce7a98fc0011bcb54
Author: Sherif Ramadan <[email protected]> Wed, 12 Dec 2012 08:48:48
-0500
Parents: 4c9cf5b3a960c47210408b60b4ba603aea7e1fc1
Branches: master
Link:
http://git.php.net/?p=web/master.git;a=commitdiff;h=8b0a4d377cec9551f3d0e9fce7a98fc0011bcb54
Log:
Added new user notes voting backend code.
This will update the notes files on master with information from the database
and provide the mirrors with an API to submit votes as well.
Changed paths:
A entry/user-notes-vote.php
M fetch/user-notes.php
diff --git a/entry/user-notes-vote.php b/entry/user-notes-vote.php
new file mode 100644
index 0000000..bac75d8
--- /dev/null
+++ b/entry/user-notes-vote.php
@@ -0,0 +1,168 @@
+<?php
+/*
+ This script acts as the backend communication API for the user notes vote
feature.
+ Requests come in here from the mirrors to update the database with new votes.
+ master.php.net should respond with a JSON object (with one required property
[status] and two optional properties
+ [votes] and [message]).
+ The JSON object [status] property contains a status returned by the server
for that request.
+ It's value may be either a boolean true or false. If the status is true the
mirror will know the vote went through successfully.
+ The optional [votes] property may then be supplied to update the mirror with
the new value of the votes for that note.
+ If the status is false the mirror will know the request for voting failed
and an optional [message] property may be
+ set to supply the mirror with a message string, explaining why the request
failed.
+
+ Example Success:
+
+ { "status": true, "votes": 1 }
+
+ Example Failed:
+
+ { "status": false, "message": "You have already voted
today!" }
+ { "status": false, "message": "Invalid request..." }
+*/
+
+
+// Validate that the request to vote on a user note is OK (ip limits, post
variables, and db info must pass validation)
+function vote_validate_request(PDO $dbh) {
+ // Initialize local variables
+ $ip = $hostip = $id = $vote = 0;
+ $ts = date("Y-m-d H:i:s");
+
+ // Validate POST variables
+ if (isset($_POST['ip']) &&
+ filter_var($_POST['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE |
+ FILTER_FLAG_NO_PRIV_RANGE |
+ FILTER_FLAG_IPV4))
+ {
+ $ip = sprintf("%u", ip2long($_POST['ip']));
+ } else {
+ return false;
+ }
+
+ if (isset($_SERVER['REMOTE_ADDR']) &&
+ filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP,
FILTER_FLAG_NO_RES_RANGE |
+
FILTER_FLAG_NO_PRIV_RANGE |
+
FILTER_FLAG_IPV4))
+ {
+ $hostip = sprintf("%u", ip2long($_SERVER['REMOTE_ADDR']));
+ } else {
+ return false;
+ }
+
+ if (!empty($_POST['noteid']) && filter_var($_POST['noteid'],
FILTER_VALIDATE_INT))
+ {
+ $id = filter_var($_POST['noteid'], FILTER_VALIDATE_INT);
+ } else {
+ return false;
+ }
+
+ if (!empty($_POST['vote']) && ($_POST['vote'] === 'up' || $_POST['vote'] ===
'down'))
+ {
+ $vote = $_POST['vote'] === 'up' ? 1 : 0;
+ }
+
+ if (empty($_POST['sect'])) {
+ return false;
+ }
+
+
+ // Validate the note exists and is in the requested section
+ $noteStmt = $dbh->prepare("SELECT COUNT(*) AS num, sect FROM note WHERE id =
:id");
+ if (!$noteStmt) {
+ return false;
+ }
+ if (!$noteStmt->execute(array('id' => $id))) {
+ return false;
+ }
+ if (false === $noteResult = $noteStmt->fetch(PDO::FETCH_ASSOC)) {
+ return false;
+ }
+ if ($noteResult['sect'] !== $_POST['sect']) {
+ return false;
+ }
+
+ // Validate remote IP has not exceeded voting limits
+ $remoteStmt = $dbh->prepare("SELECT COUNT(*) AS num FROM votes WHERE ip =
:ip AND ts >= (NOW() - INTERVAL 1 DAY) AND note_id = :id");
+ if (!$remoteStmt) {
+ return false;
+ }
+ if (!$remoteStmt->execute(array('ip' => $ip, 'id' => $id))) {
+ return false;
+ }
+ if (false === $remoteResult = $remoteStmt->fetch(PDO::FETCH_ASSOC)) {
+ return false;
+ }
+ if ($remoteResult['num'] >= 1) { // Limit of 1 vote, per note, per remote
IP, per day.
+ return false;
+ }
+
+ // Validate host IP has not exceeded voting limits
+ $hostStmt = $dbh->prepare("SELECT COUNT(*) AS num FROM votes WHERE hostip =
:ip AND ts >= (NOW() - INTERVAL 1 HOUR) AND note_id = :id");
+ if (!$hostStmt) {
+ return false;
+ }
+ if (!$hostStmt->execute(array('ip' => $ip, 'id' => $id))) {
+ return false;
+ }
+ if (false === $hostResult = $hostStmt->fetch(PDO::FETCH_ASSOC)) {
+ return false;
+ }
+ if ($hostResult['num'] >= 100) { // Limit of 100 votes, per note, per host
IP, per hour.
+ return false;
+ }
+
+ // Inser the new vote
+ $voteStmt = $dbh->prepare("INSERT INTO votes(note_id,ip,hostip,ts,vote)
VALUES(:id,:ip,:host,:ts,:vote)");
+ if (!$voteStmt) {
+ return false;
+ }
+ if (!$voteStmt->execute(array('id' => $id, 'ip' => $ip, 'host' => $hostip,
'ts' => $ts, 'vote' => $vote))) {
+ return false;
+ }
+
+
+ // Get latest vote tallies for this note
+ $voteStmt = $dbh->prepare("SELECT SUM(votes.vote) AS up, (COUNT(votes.vote)
- SUM(votes.vote)) AS down FROM votes WHERE votes.note_id = :id");
+ if (!$voteStmt) {
+ return false;
+ }
+ if (!$voteStmt->execute(array('id' => $id))) {
+ return false;
+ }
+ if (false === $voteResult = $voteStmt->fetch(PDO::FETCH_ASSOC)) {
+ return false;
+ }
+ // Return the new vote tally for this note
+ return $voteResult['up'] - $voteResult['down'];
+}
+
+// Initialize global JSON response object
+$jsonResponse = new stdclass;
+$jsonResponse->status = false;
+
+
+// Validate the request
+if (!isset($_SERVER['REQUEST_METHOD']) ||
strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') {
+ $jsonResponse->message = "Invalid request...";
+ echo json_encode($jsonResponse);
+ exit;
+}
+
+// Initialize global PDO database handle
+try {
+ $dbh = new PDO('mysql:host=localhost;dbname=phpmasterdb', 'nobody', '');
+} catch(PDOException $e) {
+ $jsonResponse->message = "The server could not complete this request.
Please try again later...";
+ echo json_encode($jsonResponse);
+ exit;
+}
+
+// Check master DB for hostip and clientip limits and other validations
+if (($jsonResponse->votes = vote_validate_request($dbh)) === false) {
+ $jsonResponse->message = "Unable to complete your request at this time.
Please try again later...";
+ echo json_encode($jsonResponse);
+ exit;
+}
+
+// If everything passes the response should be the new jsonResponse object
with updated votes and success status
+$jsonResponse->status = true;
+echo json_encode($jsonResponse);
diff --git a/fetch/user-notes.php b/fetch/user-notes.php
index e941cfe..78e77b2 100644
--- a/fetch/user-notes.php
+++ b/fetch/user-notes.php
@@ -4,25 +4,36 @@
if (!isset($_REQUEST['token']) || md5($_REQUEST['token']) !=
"19a3ec370affe2d899755f005e5cd90e")
die("token not correct.");
-@mysql_connect("localhost","nobody","")
- or exit;
-@mysql_select_db("phpmasterdb")
- or exit;
-
-$query = "SELECT DISTINCT id,note.sect,user,note,UNIX_TIMESTAMP(ts) AS ts,";
-$query .= "IF(votes=0, 10, rating/votes) AS rate";
-$query .= " FROM note";
-
-//Only select notes that have been approved
-$query .= " WHERE status is NULL";
+// Changed old mysql_* stuff to PDO
+try {
+ $dbh = new PDO('mysql:host=localhost;dbname=phpmasterdb', 'nobody', '');
+ $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+} catch (PDOException $e) {
+ // Old error handling was to simply exit. Do we want to log anything
here???
+ exit;
+}
-$query .= " ORDER BY sect,rate DESC,ts DESC";
+try {
+ $query = "SELECT DISTINCT id,note.sect,user,note,UNIX_TIMESTAMP(ts) AS
ts,";
+ $query .= "IF(votes=0, 10, rating/votes) AS rate";
+ $query .= " FROM note";
+ //Only select notes that have been approved
+ $query .= " WHERE status is NULL";
+ $query .= " ORDER BY sect,rate DESC,ts DESC";
-$res = @mysql_query($query) or exit;
+ $stmt = $dbh->prepare($query);
+ $stmt->execute();
+ $resultset = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+ $getvotes = $dbh->prepare("SELECT SUM(votes.vote) AS up,
(COUNT(votes.vote) - SUM(votes.vote)) AS down FROM votes WHERE votes.note_id =
?");
+} catch (PDOException $e) {
+ // Old error handling was to simply exit. Do we want to log anything
here???
+ exit;
+}
// Print out a row for all notes, obfuscating the
// email addresses as needed
-while ($row = mysql_fetch_array($res, MYSQL_ASSOC)) {
+foreach ($resultset as $row) {
$user = $row['user'];
if ($user != "[email protected]" && $user != "[email protected]") {
if (preg_match("!(.+)@(.+)\.(.+)!", $user)) {
@@ -31,6 +42,17 @@ while ($row = mysql_fetch_array($res, MYSQL_ASSOC)) {
} else {
$user = '';
}
+ // Calculate the votes for each note here
+ try {
+ $getvotes->exucute(array($row['id']));
+ $votes = $getvotes->fetch(PDO::FETCH_ASSOC);
+ if ($votes === false) {
+ $votes = array('up' => 0, 'down' => 0);
+ }
+ } catch(PDOException $e) {
+ $votes = array('up' => 0, 'down' => 0);
+ }
+ // Output here
echo "$row[id]|$row[sect]|$row[rate]|$row[ts]|$user|",
- base64_encode(gzcompress($row['note'],3)),"\n";
+
base64_encode(gzcompress($row['note'],3)),"|$votes[up]|$votes[down]\n";
}--
PHP Webmaster List Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php