JavaScript, PHP - Using server-sent events with multiple, unique users? - javascript

I'm brand-new to SSE. There are plenty of simple/introductory texts on server sent events
Here
Here
Here
But none of them touch on using the same SSE file for multiple different users.
For example:
I have a site, where users log on. While logged on, they can view data that is unique and private to them. I'd like each user to have live updates while they are logged in, which may or may-not contain sensitive information. To do so I am implementing server-sent events:
JS (Straight out of one of the links)
var source;
if (!!window.EventSource) {
source = new EventSource("sse.php");
} else {
...
}
source.addEventListener("message", function(e) {
... do stuff ...
}, false);
PHP
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Connection: keep-alive");
while (true) {
$data = \\ query DB or any other source
if ($data) {
sendMessage($someID, $data);
}
sleep(2);
}
function sendMessage($id, $data) {
echo "id: $id\n";
echo "data: $data\n\n";
ob_flush();
flush();
}
But using it this way, am I only sending the data to the user who opened the sse.php source (i.e. each EventSource("sse.php") is a new, unique connection)? Or will everyone logged on, who has initialized the connection, receive the same data?
This SO answer touches on multiple users, by using unique events:
echo "event: ping\n";
$msg1="This is first user";
echo 'data: {"msg": "' . $msg1 . '"}';
echo "\n\n";
echo "event: notify\n";
$msg2="This is second user";
echo 'data: {"msg": "' . $msg2 . '"}';
echo "\n\n";
And then only listening for a certain event:
var evtSource = new EventSource("sender.php");
evtSource.addEventListener("ping", function(e) {
var obj = JSON.parse(e.data);
var r_msg = obj.msg;
But that hardly seems reasonable. If each user is supposed to be receiving their own private feed, then this method would require me to hard-code a unique event for each user. AND, as the original answer mentions, it does not prevent a slightly above-average user from intercepting and reading all the other messages too.
And, on top of it all, the sse.php file doesn't know which user it's gathering data for, so it would have to do all users, all the time.
How do I create one sse.php file, that can handle an unlimited number of unique users, and only send the data to the appropriate user? So:
there must be a way to send some initialization data (i.e. unique user ID) to server-side file, and
there must be a way for only that one particular user to receive the information gathered

am I only sending the data to the user who opened the sse.php source
Yes.
Or will everyone logged on, who has initialized the connection, receive the same data?
No.
If each user is supposed to be receiving their own private feed,
then this method would require me to hard-code a unique event for each user
Luckily no! The SSE "event" is for sending different types of events down a single connection to a single user. A use-case might be Facebook wanting to use one event for sending chat updates, another event for sending friend requests, another for sending ads to show, etc.
In my book (Data Push Apps with HTML5 SSE, http://shop.oreilly.com/product/0636920030928.do - apologies for the plug!) I argue that it is redundant, and better included as part of the json object you are pushing.
And, on top of it all, the sse.php file doesn't know which user ...
Cookies are sent. So the typical approach is to first login the user, create a cookie that authenticates them, then call the sse script. If using a server system with sessions support (e.g. PHP), then the cookies are an implementation detail.
POST data, and custom headers, cannot be sent. So if cookies are not an option you'd have to use GET to post some authentication id (but as you note, that is not the best type of security).

An SSE is an open HTTP connection. So it will only send unique data to a user if that is how you program it. You can make this stateful by using session, cookies, IP addresses, etc. in the same was as any other HTTP request. The main limitation of SSE is that you cannot add any headers to request to connect.

Related

Simple PHP / SQL chat setup

I have a basic chat system set up that uses an SQL database and a PHP script -- when the user inputs a message, its sent to the database and then is retrieved and displayed. New messages are displayed every 5 seconds regardless.
All that being said, its fairly easy to just spam messages causing the website to stop responding at which point clicking any links will result in an error page, and no further messages will be input.
Is this a common scenario? How should I improve the chat's performance? Note: I'm really new PHP and JS/Jquery.
Here is the main script that is frequently called to update the html chatbox with new messages for the logged-in user:
Two auto-incremented values are compared to determine "new messages", the value of the last displayed message, and the value of the last message in the database.
<?php
session_start();
if (isset($_SESSION['logged_in']) && $_SESSION['logged_in'] == true) {
$alias = $_SESSION['username'];
$host = 'localhost';
$user = 'root';
$pass = '';
$database = 'vethergen_db_accounts';
$table = 'table_messages';
$user_table = 'table_user_info';
$last_id_table = 'table_chat_sync';
$connection = mysqli_connect($host, $user, $pass) or die ("Unable to connect!");
mysqli_select_db($connection,$database) or die ("Unable to select database!");
if ($redis->exists("/lastId/$alias"))
{
$last_id = $redis->get("/lastId/$alias"); //Gets the last id from cache...
}
else
{
$last_id_query = "SELECT last_id FROM $last_id_table WHERE alias = '$alias'";
$last_id_result = mysqli_query($connection,$last_id_query);
$last_id_rows = mysqli_fetch_array($last_id_result);
$last_id = $last_id_rows['last_id'];
// Now that you just read it, create a last_id cache entry for this user
$redis->set("/lastId/$alias", $last_id);
}
$query = "SELECT * FROM $table WHERE text_id > '$last_id'"; //SELECT NEW MESSAGES
$result = mysqli_query($connection,$query);
if ($result && mysqli_num_rows($result) > 0)
{
while($row = mysqli_fetch_array($result))
{
$color_alias = $row['alias'];
$text_color_query = "SELECT color FROM $user_table WHERE alias = '$color_alias'";
$text_color_result = mysqli_query($connection,$text_color_query);
$text_color_rows = mysqli_fetch_array($text_color_result);
$text_color = $text_color_rows['color'];
if ($row['alias'] === "Vether")
{
echo '<p id = "chat_text" style="color:'.$text_color.'">'.'<b>'.$row['alias'].': '.'</b>'.$row['text']."</p>";
echo '<p id = "time_stamp">'.$row['time'].'</p>';
echo '<p id = "chat_number">'.$row['text_id'].'</p>';
}
else
{
echo '<p id = "chat_text" style="color:'.$text_color.'">'.'<b class = "bold_green">'.$row['alias'].': '.'</b>'.$row['text']."</p>";
echo '<p id = "time_stamp">'.$row['time'].'</p>';
echo '<p id = "chat_number">'.$row['text_id'].'</p>';
}
echo '<hr class = "chat_line"></hr>';
$last_row_id = $row['text_id'];
}
//UPDATE LAST SYNC ID
$update_query = "UPDATE $last_id_table SET last_id = '$last_row_id' WHERE alias = '$alias'";
$redis->delete("/lastId/$alias");
mysqli_query($connection,$update_query);
}
else {echo '';}
?>
There is no specific right answer because your question is very general, but there are a few things that are obvious here. You have built a botteneck in your database where the more users you have, the more updates you are doing on the table_chat_sync.
As an aside, I have no idea why you are putting a constant (the table name) into PHP variables for your queries. At very least these should be php constants but that makes the syntax pretty painful. Your code is simpler and better just using the table names in the SQL.
InnoDB
Are you using InnoDB tables? You should be, given that you are updating a row and with InnoDB you have row level locking.
You also want to make sure that you have enough innodb buffer pool cache allocated to insure that the db is in memory. This will buffer your select activity a lot and buy you some head room.
MySQL EXPLAIN
You also need to do explain plans on your select query and insure that it is properly indexed so that the queries are being returned using indexes and you are not table scanning or having temporary tables created.
SQL queries against mysql are quite slow compared to getting data from cache, and the reality is that the full set of chat messages doesn't change much, and yet your system is repeatedly going to be querying the chat or a subset of it over and over again. For this reason, most sophisticated systems are using some sort of caching system or queuing. There is overlap between these two technologies and they tend to offer better scalability as well as support for concepts like publish/subscribe that fit chat very well.
Redis & Other backends
Redis as an example, could be the back end for chat and completely supplant the actual storage and retrieval of messages. The document database MongoDB is also an alternative option that has in-memory characteristics when the dataset can be controlled.
Using Redis with MySQL
Redis is often combined with an RDBMS and in your code there are a few places where it could be a great help. For example, you do this query repeatedly:
$last_id_query = "SELECT last_id FROM $last_id_table WHERE alias = '$alias'";
With redis you could do something like this:
if ($redis->exists("/lastId/$alias")) {
$last_id = $redis->get("/lastId/$alias");
} else {
$last_id_query = "SELECT last_id FROM $last_id_table WHERE alias = '$alias'";
$last_id_result = mysqli_query($connection,$last_id_query);
$last_id_rows = mysqli_fetch_array($last_id_result);
$last_id = $last_id_rows['last_id'];
// Now that you just read it, create a last_id cache entry for this user
$redis->set("/lastId/$alias", $last_id);
}
The only other detail is that when you update the last Id you would want to delete the redis key:
$redis->delete("/lastId/$alias");
Hopefully you can see that this would lower the load on mysql quite a bit, because no query will occur without a new message being added. This will buffer mysql quite a bit, and the same concept can be used to cache the other queries you are doing, such that you never require mysql queries unless you have a new user actively using Redis. I didn't go into this but you can set the expiration of a key to some period of time, so it will clean up old keys from non-active users.
Load Testing to understand your bottlenecks and capacity
Your choice of reliance on MySQL is something you will have to accept as limiting, although again you may be able to tune it so that within your use case and load, it runs acceptably, but that is impossible to predict without detailed configuration analysis and load testing. There are many load testing and stress testing tools that are FOSS, with Apache JMeter being one of the oldest ones, so I'll advise you to start with that.
Websockets
Last but not least, polling is inherently wasteful and most chat systems these days are built using websockets which is just a better fit for the task of having a sustained client-server connection. Websocket is client & Server code, and being that you are a PHP dev, there are a few projects that can help you out here, Ratchet being one that has been around for a while. There's a PHP client lib Pawl that shows you how to make a simple robust websocket connection.
You can add a Limit to the end of SELECT * FROM $table WHERE text_id > '$last_id' and that will keep some of the spam messages from slowing down the thread. Also you can prohibit duplicates on the INSERT statement.

Accessing session in PHP command line?

I understand that command line is no web server, so you can't access $_SESSION. But I don't know what else to do.
I've been following this tutorial to create a chat using websockets: http://www.phpbuilder.com/articles/application-architecture/optimization/creating-real-time-applications-with-php-and-websockets.html
My problem is that, I do not know how to get the username of the message sender securely. I could include it in the message send function but since it's in Javascript, everyone can just edit their username to someone elses.
How could I securely get the username of the user, which is $_SESSION['username']?
var Server;
Server = new FancyWebSocket('ws://0.0.0.0:9000');
send( "test" );
I'm open to all kind of suggestions, like alternatives to websockets. I'm creating a realtime chat for my website.
First alternative is, of course, AJAX requests. AJAX doesn't have the problems of not being able to quickly and easily access the sessions that WebSockets has. Any sufficiently frequent sample rate is indistinguishable from real time.
Now, to my rather long-winded solution implemented in WebSockets:
The HTTP headers are available to the WebSocket server during the handshake, including the cookies. In the server that you're using, PHP-Websockets, the headers are stored in the $headers property.
For instance:
var_dump($user->headers);
array(14) {
["get"]=>
string(8) "/echobot"
["host"]=>
string(14) "127.0.0.1:9000"
...snip...
["cookie"]=>
string(100) "PHPSESSID=jan9uknpc06mk4ddghph4870t1; MyCookie=My+Value%21%40%23%24%25; MyNonhttponlyCookie=My+Value"
}
These cookies were generated from
session_start();
$_SESSION['Hi!'] = array('Hello!', 'where' => 'world!');
setcookie('MyCookie', 'My Value;!##$%', 0, '/', '127.0.0.1', false, true);
setcookie('MyNonhttponlyCookie', 'My Value', 0, '/', '127.0.0.1', false, false);
Thus, the value of $user->headers['cookie'] is a semicolon and space (;) delimited collection of key value pairs, where the values are URL encoded and separated from its key with an equal sign. (PHP complains if you put reserved characters in the cookie name. Thus the cookie key can not contain any url encoded values.)
A quick way to extract these are as follows
$cookies = array();
$cookiesParts = explode('; ', $user->headers['cookie']);
foreach ($cookiesParts as $cookieParts) {
$interimCookie = explode('=', $cookieParts);
$cookies[$interimCookie[0]] = urldecode($interimCookie[1]);
}
var_dump($cookies);
array(3) {
["PHPSESSID"]=>
string(26) "jan9uknpc06mk4ddghph4870t1"
["MyCookie"]=>
string(14) "My Value;!##$%"
["MyNonhttponlyCookie"]=>
string(8) "My Value"
}
We now have the session ID. Double check with session_name(), which will give you the key of the cookie that actually holds the session ID.
We could serialize and unserialize the session file as stored in the server, which is pointed at by session_save_path()... but I want to cheat.
Because the built-in session system locks the session files, we can't just keep the session file open and constantly watch for changes, nor can we lock the file ourselves for long periods of time.
It would be ideal if we could use the __get() and __set() magic methods here in the same way we'd use the $_SESSION superglobal (such as $myUser->_session['key'] = 'value';), but PHP does not allow treating these methods as arrays. Instead, we have to set a more mundanely named method.
<?php
class MyUser extends WebSocketUser {
public $session_id; // gets set somewhere. Good place is probably is your implementation of the `connected($user)` abstract method.
public getSession($key) {
session_id($this->session_id);
session_start();
$val = $_SESSION[$key];
session_write_close(); // very important!
return $val;
}
public setSession($key, $value) {
session_id($this->session_id);
session_start();
$_SESSION[$key] = value;
session_write_close(); // still very important!
}
}
(Note: I'm also pointing my feature request at this question, to base my eventual implementation of cookie parsing and session handling here, so that I can remember my research tonight as I work.)

Concern with Facebook's login decoding sign_request performance

I am completely new to the Facebook API. I would like to incorporate Facebook login into my application. I am using the Javascript SDK on the front-end to log the user in and retrieve the user_id and signed_request from Facebook. I then plan to send these two pieces of information via AJAX to my server (either php/hack (hhvm), node, java, or whichever language I can determine is quickest for decoding) every time my logged in user does an action on my application to validate if the user is indeed logged in and is the person they say they are. For me to accomplish this, I need to decode the signed_request, for example in php:
function parse_signed_request($signed_request) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
$secret = "appsecret"; // Use your app secret here
// decode the data
$sig = base64_url_decode($encoded_sig);
$data = json_decode(base64_url_decode($payload), true);
// confirm the signature
$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
error_log('Bad Signed JSON signature!');
return null;
}
return $data;
}
function base64_url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
which then I will be able to extract the following JSON object:
{
"oauth_token": "{user-access-token}",
"algorithm": "HMAC-SHA256",
"expires": 1291840400,
"issued_at": 1291836800,
"user_id": "218471"
}
to be able to compare if the user_id the user sent over matches the one in the JSON object. Then if it matches I can complete my business logic (DB manipulation).
My big concern here is a user will be sending many requests to my server, so every time I will need to decode this signed_request which can really kill my server performance. I was thinking I maybe could call Facebook from my server, pass the user_id, and receive the signed_request string, which I can then match with the signed_request string the user sent over from the client_side and see if they match. This would be more efficient, but it does not seem Facebook offers anything like this. Is there any other methods besides the heavy performing decoding to validate a user? I have gone through quite a bit of the Facebook SDK's information but could not find a solution. If I must decode, which language/library would be the best performing at this type of operation?
PS. I plan on using cordova later to create a mobile app so I must use only Javascript on the front end and can't use a server language such as php to create html for the client.
Decoding the signed request will not kill your server. It's way fast than making an external request.
If you're using php you should look into the Facebook SDK for PHP and use this helper: https://developers.facebook.com/docs/php/FacebookJavaScriptLoginHelper/4.0.0

Tab specific cookies without using sessionStorage or any HTML5 features

I am interested in having users be able to login and logout with multiple user session cookies on my web app. Currently, authentication is done standard and a unique identifier allows me to authenticate a user when they visit our site back if they present an auth token that's available in their cookie. Typical use cases apply in that if the user logs out from one tab, it logs them out of another tab. Right now it requires having the user login from two unique browser instances in order to be able to login to two different accounts.
Is there a non-HTML5 way (using standard javascript cookies) to have tab-specific cookie identifiers? I'm assuming that there is no clear cut way of going about this and it would require some kind of hack + cooperation from the backend. If there is a solution that makes sense without using HTML5, that would be ideal.
You can't.
There are ways to deal with this condition, but none of them are simple.
If you want, you have to tell user to do like this: How to geek
From docs: Data stored using sessionStorage do not persist across browser tabs, even if two tabs both contain webpages from the same domain origin. In other words, data inside sessionStorage is confined to not just the domain and directory of the invoking page, but the browser tab in which the page is contained in. Contrast that to session cookies, which do persist data from tab to tab.
I achieved similar behavior some time back. So, what I do is something like this:
For this to work, you need to carry the sessionId in the url or as part of the page content.
When login page is loaded, delete the sessionId cookie.
When login for is submitted, server gives you login page along with sessionId in the url or as part of html response body.
From now onwards, before every server call, set the session cookie to the one that you have in the url or page content.
So, each tab will set its own cookie before any server call which would make the request land with the right session on the server.
Before anything, this solution works if you use relative URLs only! (for images, links and even Ajax calls)
Use sessions as you would in any ordinary scenario with one small change. Instead of identifying users with each session ID, you will identify a machine (a browser) by each session ID. So when requests arrive at server, it identifies a bunch of users who are using your website on that computer. Each user will have his own sub-identifier (it could be a sequential counter or a random number). Putting it simple, your session data (identified by session ID in the cookies) holds an associative array. Each entry of this array holds session data for one particular user identified by sub-identifier. For instance, in PHP, if your user's sub-identifier is user0, then you can access this user's session data like:
<?php
session_start();
$user_data = $_SESSION['user0'];
Next is how to pass on user's sub-identifier.
You can use webserver's URL rewrite. You need to come up with a pattern which can be considered as an ordinary folder name, while there's no folder named like that. For instance:
RewriteEngine On
RewriteRule ^user(\d+)\/(.*)$ $2?sub_id=$1 [QSA,L]
In this example, you are not allowed to have any folders like user0, user1 etc. If some request asks for http://domain.com/user0/index.php it will be rewritten to http://domain.com/index.php?sub_id=user0. Now in index.php you'll have:
<?php
session_start();
$user_data = $_SESSION[$_REQUEST['sub_id']];
And you should use $user_data instead of $_SESSION from this point forth. The only thing that remains is how to generate sub-identifier for the first time. That's relatively easy, you can:
<?php
session_start();
if (!isset($_REQUEST['sub_id'])) {
$sub_id = 0;
while (isset($_SESSION["user{$sub_id}"])) {
$sub_id++;
}
$_SESSION["user{$sub_id}"] = array();
header("Location: /user{$sub_id}".$_SERVER['REQUEST_URI']);
die();
}
else {
$user_data = $_SESSION[$_REQUEST['sub_id']];
}
At the end, everything will work only if all your URLs are relative! Each absolute URL which does not start with /user0/ will be considered a new user and will lead to a new entry in the session.
The benefit of this approach is that your current code will work with minimum effort, as long as URLs are already addressed relatively.
This is a simple example of how you can create a system in which a user can log in to multiple accounts. This is no safety checks and must be added. This code can be much better to write and optimize.
inc.php
https://github.com/maksa9/multiple-user-login/blob/master/inc.php
This file is included into each php script.
This part check which user is logged and which account is active. Here are functions that create the proper path to the php scripts according to the active account
// check which user is logged and which account is active
if(isset($_GET['user'])) $id_user = (int)$_GET['user'];
if($id_user > 0)
{
if(isset($_SESSION['user'][$id_user]))
{
$user_name = $_SESSION['user'][$id_user]['name'];
$user_email = $_SESSION['user'][$id_user]['email'];
}
else
gotToLoginForm();
}
// If the user id is not specified and there is a user session, finds another id
if($id_user == 0 and isset($_SESSION['user']))
{
$sess = $_SESSION['user'];
$id_user = (int)key($sess);
if(isset($_SESSION['user'][$id_user]))
{
$user_name = $_SESSION['user'][$id_user]['name'];
$user_email = $_SESSION['user'][$id_user]['email'];
define('ID_USER',$id_user);
gotToIndex();
}
else
gotToLoginForm();
}
define('ID_USER',$id_user);
loginform.php
https://github.com/maksa9/multiple-user-login/blob/master/loginform.php
Simple form to login with post method.
login.php
https://github.com/maksa9/multiple-user-login/blob/master/login.php
Login user. simulates a query to the database.
if(isset($_POST['email']))
if(isset($_POST['pass']))
{
$email = $_POST['email'];
$pass = $_POST['pass'];
$id_user = 0;
// simulates a query to the database
if($email === 'test1#test.com' and $pass === '111')
{
$id_user = 1;
$name='John Doe';
}
if($email === 'test2#test.com' and $pass === '222')
{
$id_user = 2;
$name = 'Doe John';
}
// login user
if($id_user > 0)
{
// checks if the user is already logged
if( !isset($_SESSION['user'][$id_user]))
{
$_SESSION['user'][$id_user] = array('email'=>$email, 'name'=>$name);
}
//go to main page
$page = ROOT.'user/'.$id_user.'/index.php';
header('Location: '.$page);
exit;
}
}
index.php
https://github.com/maksa9/multiple-user-login/blob/master/index.php
Main page of the application.
<div>
<h1>Welcome: <?php echo $user_name ?> (<?php echo $user_email ?>) [<?php echo $id_user ?>]</h1>
<p>Choose an account</p>
<p>Login with the another account</p>
<p>Log out</p>
</div>
swap.php
https://github.com/maksa9/multiple-user-login/blob/master/swap.php
Allows the user to choose the account.
foreach($_SESSION['user'] as $idus => $userA)
{
echo '<p>'.$userA['name'].' ('.$userA['email'].') ['.$idus.']</p>';
}
logout.php
https://github.com/maksa9/multiple-user-login/blob/master/logout.php
Logout user. Check for active user accounts and redirects them if any.
unset($_SESSION['user'][ID_USER]);
if(count($_SESSION['user']) == 0)
unset($_SESSION['user']);
// checks for active user accounts and redirects them if any
if(isset($_SESSION['user']))
{
$sess = $_SESSION['user'];
$id_user = (int)key($sess);
if(isset($_SESSION['user'][$id_user]))
{
$page = ROOT.'user/'.$id_user.'/index.php';
header('Location: '.$page);
exit;
}
}
.htaccess
https://github.com/maksa9/multiple-user-login/blob/master/.htaccess
Options +FollowSymlinks
RewriteEngine On
RewriteRule ^user\/([0-9]*)\/index.php$ index.php?user=$1 [NC,L]
RewriteRule ^user\/([0-9]*)\/logout.php$ logout.php?user=$1 [NC,L]
RewriteRule ^user\/([0-9]*)\/login.php$ login.php?user=$1 [NC,L]
RewriteRule ^user\/([0-9]*)\/loginform.php$ loginform.php?user=$1 [NC,L]
RewriteRule ^user\/([0-9]*)\/swap.php$ swap.php?user=$1 [NC,L]
RewriteRule ^user\/$ index.php [NC,L]
RewriteRule ^user$ index.php [NC,L]
You cant
When a cookie is created it is possible to control its visibility by setting its 'root domain'. It will then be accessible to any URL belonging to that root. For example the root could be set to "example.com" and the cookie would then be available to sites in "www.example.com" or "xyz.example.com" or "example.com". This might be used to allow related pages to 'communicate' with each other. It is not possible to set the root domain to 'top level' domains such as '.com' or '.co.uk' since this would allow widespread access to the cookie.
By default cookies are visible to all paths in their domains, but at the time of creation they can be retricted to a given subpath - for example "www.example.com/images".
so any tab which is having same root domain can access that cookie.
The session cookies are server specific AFAIK, so what you could do is set up different DNS names for the same server, e.g. subdomains like: session1.myserver.com, session2.myserver.com, session3.myserver.com
Well #dm4web's answer is kind of correct but you have to pay heed to his security warnings though. The best thing that you can do is take a bi-directional approach.
Direction One
Regular Login.
Create a Unique session ID and pass it via the URL.
Direction Two
Check Session via i) Logged In User and ii) Check Session ID via URL Param
Now, let's take an example:
$usrname: Fool
$psswd: dm4web
PHP Code
session_start();
//all inputs should be sanitized
$sql = "SELECT * FROM `users` WHERE `usrname`='".$usrname."' AND `psswd` = '".$psswd."'":
$dbh = new PDO('odbc:db', 'db2inst1', 'ibmdb2');
$count = $dbh->exec($sql);
if($count > 0){
//Guy is logged in
$a = session_id();
//**Use this $a in every URL parameter under current session**
}
else {
//Go f**k yourself >> to the user ;)
}
But you should notice that you can't directly jump into that user/pass match scheme. First you have to ensure that you find out if the user is already logged in or not. Also, based on the SESSION Cookie from PHP, you figure out that
If there is an active log in on the machine
If there is an active login on the URL [vide the $a from the session_id thing]
You match the URL parameter under all circumstances, cross reference with the SESSION cookie and proceed!
Good Luck!
Let me know if you've any more questions!

Using XMLHTTPRequest to extract data from Database

I want to extract some data from the database without refreshing a page. What is the best possible way to do this?
I am using the following XMLHTTPRequest function to get some data (shopping cart items) from cart.php file. This file performs various functions based on the option value.
For example: option=1 means get all the shopping cart items. option=2 means delete all shopping cart items and return string "Your shopping cart is empty.". option=3, 4...and so on.
My XHR function:
function getAllCartItems()
{
if(window.XMLHttpRequest)
{
allCartItems = new XMLHttpRequest();
}
else
{
allCartItems=new ActiveXObject("Microsoft.XMLHTTP");
}
allCartItems.onreadystatechange=function()
{
if (allCartItems.readyState==4 && allCartItems.status==200)
{
document.getElementById("cartmain").innerHTML=allCartItems.responseText;
}
else if(allCartItems.readyState < 4)
{
//do nothing
}
}
var linktoexecute = "cart.php?option=1";
allCartItems.open("GET",linktoexecute,true);
allCartItems.send();
}
cart.php file looks like:
$link = mysql_connect('localhost', 'user', '123456');
if (!$link)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db('projectdatabase');
if($option == 1) //get all cart items
{
$sql = "select itemid from cart where cartid=".$_COOKIE['cart'].";";
$result = mysql_query($sql);
$num = mysql_num_rows($result);
while($row = mysql_fetch_array($result))
{
echo $row['itemid'];
}
}
else if($option == 2)
{
//do something
}
else if($option == 3)
{
//do something
}
else if($option == 4)
{
//do something
}
My Questions:
Is there any other way I can get the data from database without
refreshing the page?
Are there any potential threats (hacking, server utilization,
performance etc) in my way of doing this thing? I believe a hacker
can flood my server be sending unnecessary requests using option=1,
2, 3 etc.
I don't think a Denial of Service attack would be your main concern, here. That concern would be just as valid is cart.php were to return HTML. No, exposing a public API for use via AJAX is pretty common practice.
One thing to keep in mind, though, is the ambiguity of both listing and deleting items via the same URL. It would be a good idea to (at the very least) separate those actions (or "methods") into distinct URLs (for example: /cart/list and /cart/clear).
If you're willing to go a step further, you should consider implementing a "RESTful" API. This would mean, among other things, that methods can only be called using the correct HTTP verb. You've possibly only heard of GET and POST, but there's also PUT and DELETE, amongst others. The reason behind this is to make the methods idempotent, meaning that they do the same thing again and again, no matter how many times you call them. For example, a GET call to /cart will always list the contents and a DELETE call to /cart will always delete all items in the cart.
Although it is probably not practical to write a full REST API for your shopping cart, I'm sure some of the principles may help you build a more robust system.
Some reading material: A Brief Introduction to REST.
Ajax is the best option for the purpose.
Now sending and receiving data with Ajax is done best using XML. So use of Web services is the recommended option from me. You can use a SOAP / REST web service to bring data from a database on request.
You can use this Link to understand more on Webservices.
For the tutorials enough articles are available in the Internet.
you're using a XMLHttpRequest object, so you don't refresh your page (it's AJAX), or there's something you haven't tell
if a hacker want to DDOS your website, or your database, he can use any of its page... As long as you don't transfer string between client and server that will be used in your SQL requests, that should be OK
I'd warn you about the use of raw text response display. I encourage you to format your response as XML or JSON to correctly locate objects that needs to be inserted into the DOM, and to return an tag to correctly handle errors (the die("i'm your father luke") won't help any of your user) and to display them in a special area of your web page
First, you should consider separating different parts of your application. Having a general file that performs every other tasks related to carts, violates all sorts of software design principles.
Second, the first vulnerability is SQL injection. You should NEVER just concatenate the input to your SQL.
Suppose I posted 1; TRUNCATE TABLE cart;. Then your SQL would look like:
select itemid from cart where cartid=1; TRUNCATE TABLE cart; which first selects the item in question, then ruins your database.
You should write something like this:
$item = $_COOKIE['cart'];
$item = preg_replace_all("['\"]", "\\$1", $item);
To avoid refreshing, you can put a link on your page. Something like, Refresh
In terms of security, it will always pay to introduce a database layer concerned with just your data, regardless of your business logic, then adding a service layer dependent on the database layer, which would provide facilities to perform business layer actions.
You should also take #PPvG recommendation into note, and -- using Apache's mod_rewrite or other similar facilities -- make your URLs more meaningful.
Another note: try to encapsulate your data in JSON or XML format. I'd recommend the use of json_encode(); on the server side, and JSON.parse(); on the client side. This would ensure a secure delivery.

Categories

Resources