forked from NickCarneiro/PillowChat
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchat.php
More file actions
146 lines (123 loc) · 4.48 KB
/
chat.php
File metadata and controls
146 lines (123 loc) · 4.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
<?php
//Install PHPillow using PEAR
require("PHPillow/bootstrap.php");
require ("documents.php");
require ("views.php");
require("settings.php");
phpillowConnection::createInstance('localhost', 5984, COUCHDB_USER, COUCHDB_PASSWORD);
phpillowConnection::setDatabase(COUCHDB_DATABASE);
function tripHash($password){
//TODO: Talk to someone smart about cryptographic hash functions
//This appears to work well, but there could be a flaw.
//based on wikipedia description of algo
$tripcode = substr(crypt($password, TRIPCODE_SALT), -10, 10);
return $tripcode;
}
function validMessage($json){
//make sure username is appropriate length and alphanumeric plus underscore
if(strlen($json->username) > 30 || strlen($json->username) < 3){
return false;
}
$alphanumeric = '/^[0-9a-zA-Z_]+$/';
if(!preg_match($alphanumeric, $json->username)){
return false;
}
//make sure message isn't too long.
if(strlen($json->message) > 1000){
return false;
}
//sanity checks on password
if(strlen($json->password) > 100){
return false;
}
return true;
}
if (isset($_POST['json'])){
try{
$json = json_decode($_POST['json']);
if(isset($json->message)){
if(validMessage($json)){
//client is sending message
$doc = new chatDocument();
$doc->message = $json->message;
$doc->username = $json->username;
//apply tripcode algorithm
$doc->tripcode = tripHash($json->password);
list( $msecs, $uts ) = split( ' ', microtime());
$currentMs = strval(floor(($uts+$msecs)*1000));
$doc->timestamp = $currentMs;
$doc->save();
}
}
//send back new messages to client
//every time a user sends a message or polls for new messages,
//we send back all messages newer than the client's lastTimestamp
if(isset($json->lastTimestamp)){
$startMs = $json->lastTimestamp - 5;
//send last 3 seconds through 100ms in the future, just in case.
list( $msecs, $uts ) = split( ' ', microtime());
$currentMs = floor(($uts+$msecs)*1000) + 100;
//When a client first joins the chat, the lastTimestamp is 0.
//In this case we want to send a handful of recent messages to give some context
if($startMs < 0){
$doc = chatView::messages(
array( 'endkey'=> strval($startMs),'startkey'=>strval($currentMs), 'limit'=>5, 'descending'=>true) );
$response = array_reverse($doc->rows);
} else {
//send client all messages after its latest
$doc = chatView::messages(
array( 'startkey'=> strval($startMs),'endkey'=>strval($currentMs)) );
$response = $doc->rows;
}
echo(json_encode($response));
//To show a list of users in the chat room, we look at all chatDocuments
//modified in the last 5 seconds. Instead of creating a separate user document
//we hold a chatDocument with an empty message property for every user. Every time
//a user polls for new messages, we update the timestamp on this empty chatDocument.
//update last activity timestamp
$doc = singleUserView::singleuser();
$recordExists = false;
foreach($doc->rows as $row){
if($row['value']['username'] == $json->username
&& $row['value']['tripcode'] == tripHash($json->password)){
$recordExists = true;
//got id of record to update
$doc = new chatDocument();
$doc->fetchById($row['id']);
$doc->timestamp = strval($currentMs);
$doc->save();
break;
}
}
if(!$recordExists){
//create chat document with empty message field
//to hold timestamp of last activity
$doc = new chatDocument();
$doc->message = "";
$doc->username = $json->username;
//apply tripcode algorithm
$doc->tripcode = tripHash($json->password);
list( $msecs, $uts ) = split( ' ', microtime());
$currentMs = strval(floor(($uts+$msecs)*1000));
$doc->timestamp = $currentMs;
$doc->save();
}
}
if(isset($json->getUsers)){
//send back json list of users currently in the chat
list( $msecs, $uts ) = split( ' ', microtime());
$currentMs = floor(($uts+$msecs)*1000) + 100;
$startMs = $currentMs - 5000;
//users are considered present in the chat if they have polled for new
//messages in the last 5 seconds
$doc = userView::users(
array( 'startkey'=> strval($startMs),'endkey'=>strval($currentMs)) );
echo(json_encode($doc->rows));
}
} catch(phpillowResponseConflictErrorException $e){
//couchdb sometimes throws updateconflict exceptions
//send the client back a json encoded error message
echo('{"error":"'.$e->getMessage().'"}');
}
}
?>