I am implementing Google Wallet for Digital Goods in a website, using PHP and HTML/JavaScript. I have achieved a successful Wallet transaction in the sandbox setting. So far, so good.
Now, in order to ensure the purchase is a secure transaction, I want to check whether the orderId that comes back in the successHandler is equal to the orderId received via a POST from Google in my postback file on the server.
I know a reasonable bit about PHP, less so about Javascript. After having studied all Google Wallet entries in StackOverflow and after having read over and over again the Google Wallet Merchant Setup pages, I still cannot figure out the proper code to compare the orderId coming from the successHandler and the orderId from the postback file. It seems to me that the successHandler's orderId (which I am guessing can be written as result.response.orderId which I have seen in other StackOverflow answers) is defined in Javascript, while the one from the postback file (which I call here postback-orderId) is defined in PHP.
How can you compare the two? One is a Javascript variable, the other a PHP variable.
I guess the best place to compare these variables is in the successHandler function. But how do I get a PHP variable from the postback file (called $orderId in that file) into a Javascript function which is used in another file?
I show what I have so far as my PURCHASE file and what I have as my POSTBACK file.
PURCHASE FILE
<?php
include ('sessionstart.inc');
require_once 'generate_token.php';
echo "
<!DOCTYPE html>
<html>
<head><meta name='viewport' content='width=device-width, initial-scale=1,maximum-scale=1'>
<title>Digital Goods Application</title>
<script src='https://sandbox.google.com/checkout/inapp/lib/buy.js'></script>
<script type='text/javascript'>
//Success handler
var successHandler = function(result){
if (result.reponse.orderId == postback-orderId) {
if (window.console != undefined) {
console.log('Purchase completed successfully.');
}
}
}
//Failure handler
var failureHandler = function(result){
if (window.console != undefined) {
console.log('Purchase did not complete.');
}
}
function purchase(jwt_value) {
runDemoButton = document.getElementById('runDemoButton')
google.payments.inapp.buy({
'jwt': jwt_value,
'success': successHandler,
'failure': failureHandler
});
return false;
}
</script>
</head>
<body>
<div>
<p>Buy 5 Search Credits to continue searching The Clock Register.</p><br />
<button id='runDemoButton' value='buy' class='buttons' onclick='purchase(\"$jwtToken\");'><b>Buy</b></button>
</div>
</body>
</html>";
?>
POSTBACK FILE
<?php
include ('sessionstart.inc');
include_once ('JWT.php');
$encoded_jwt = $_POST['jwt'];
$decodedJWT = JWT::decode($encoded_jwt,"mySecretKey");
$orderId = $decodedJWT->response->orderId;
header("HTTP/1.0 200 OK");
echo $orderId;
?>
</body>
</html>
Any help much appreciated!
You have to remember that the rendering of your page (and the buy action) happen long before the postback is dispatched / received by your server, as such, you can not have the postback-orderID in your page. You will have to do the following:
Your postback url target file / script should log the data received on your server (in a file or database).
You will need to write another php file / script on your server that can retrieve data from the logs in 1 above and does the comparison to check whether the orderID in the successHandler has been logged.
The success handler will have to make a call to the script in 2 above with, at least, the orderID as a parameter. (do not worry about the ajax call, it is simply javascript)
This may seem convoluted and long but can be achieved in less than 20 lines of code (both php and javascript / ajax).
EDIT
1. Updated postback.php to include logging
<?php
require_once 'JWT.php';
$encoded_jwt = $_POST['jwt'];
$decodedJWT = JWT::decode($encoded_jwt, $sellerSecret);
$orderId = $decodedJWT->response->orderId;
header("HTTP/1.0 200 OK");
echo $orderId;
$logfile = "logfile.txt";
if (!file_exists($logfile)) {
touch($logfile);
chmod($logfile, 0777);
}
$orderIDS = file($logfile); //reads file into array
$orderIDS[] = $orderId; //append new orderID to array
file_put_contents($logfile, $orderIDS); //save the new array to file
?>
EDIT 2
second script IDSearch.php to search for orderIds
<?php
$orderSearch = $_GET['orderID'];
$logfile = "logfile.txt";
if (file_exists($logfile)) {
$orderIDS = file($logfile); //reads file into array
echo (in_array($orderSearch, $orderIDS)); // either true or false is returned
} else {
echo 'Error';
}
?>
EDIT 3
Finally, amending your successhandler to call the IDSearch.php script
var successHandler = function (result) {
if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else { // code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
if (window.console != undefined) {
console.log(xmlhttp.responseText);
}
}
}
xmlhttp.open("GET", "IDSearch.php?orderID=" + result.reponse.orderId, true);
xmlhttp.send();
}
PS. In the handler, make sure you have the absolute path to the web resource of IDSearch.php
Am not a PHP developer so this is more "conceptual" than specific -
The overall idea is that you would persist the data you received from the (server side) POST from Google (aka "the PHP variable" you received at your postback url) somehow - e.g. a database.
You then have options on what to do next (to compare) -
perhaps an ajax call in your success handler to your server (that obtains the persisted data to) verify/compare the "javascript variable/orderId" with the "Php variable/orderId", before doing x
perhaps redirect in your success handler and send the "javascript orderId" as some value (query string, POST data, etc.) to a target that does the verification/comparison same as above (from server/db), and then do x
So its about persisting the data for later verification.
Hth....
Update (above disclaimer applies) :)
I set $orderId in the POST-back file into a SESSION as follows: $_SESSION['orderid'] = $orderId; However, when I check on the value of $_SESSION['orderid'] it is empty.
If I understood correctly, you're setting a Session Variable from Google's server-side Postback which means the request/session isn't "tied" to the browser/client. It was a server side POST - the browser, where the payment process is happening has no knowledge of it - it wasn't involved in the postback at all (the "client" in that case was some Google machine).
In other words, the browser has no "knowledge" of that (separate/server-side) "session", it either has no "sessionID" (cookie) nor one that would match (remember it was "some Google machine" that made the request when you set a session variable)
Hth....
Related
I've been stuck on this for the past day and it feels like I am missing something.
My assignment is:
Create a php file register.php which allows users to input their Name, Last name, Username and Email(via an HTML form) and then do some server-side verification on this data.
This file would also serve as an html form where users could input the data.
For the Username input field I have to, on each keystroke, check if a user with that username already exists in my database.
This has to be accomplished using Javascript by sending a request to register.php with Ajax.
I know how to run the necessary query to search my database based on a certain username. That part is not a problem.
What I can't get to work is
using Javascript/Ajax to send a request to register.php
getting register.php to run a query based on the inputed username, since I don't know how to recieve the request
getting register.php to "return" a response without writing it out in the DOM
What I've tried so far:
let username= document.getElementById('username');
username.addEventListener('input', validateUsername);
function validateUsername(){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// Typical action to be performed when the document is ready:
console.log(xhttp.responseText);
}
};
xhttp.open("POST", "../obrasci/registracija.php", true);
xhttp.send("username="+username.value);
}
this part works and I'm getting the whole HTML document back. I know that because the whole structure is being printed into the console.
now this is the part that I can't get to work. In PHP I've got this so far and I can't get the script to do anything with the username.
if( isset($_POST['username']) ){
json_encode($_POST['username']);
}
Edit: I forgot to add that this site needs to process the data sent with ajax dynamically(if that username is taken, mark the input as not okay until the user chooses a username that's not taken).
That might be a problem in the way I'm using this since the if in PHP only gets tested on first load?
Any help is appreciated.
First, you can check whether or not the request was sent as a POST request (opening register.php in your browser will be a GET request).
You can wrap your form handling by something like this
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// check if username exists
if (isset($_POST['username'])) {
echo 'username: ' . $_POST['username'];
die;
} else {
echo 'no username';
die;
}
}
change the code accordingly, use echo json_encode($data) to return your data in JSON format.
In your request, you might need to add the right header to tell PHP how to interpret the body sent with the request.
function validateUsername(){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// Typical action to be performed when the document is ready:
console.log(xhttp.responseText);
}
};
// add this line
xhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhttp.open("POST", "../obrasci/registracija.php", true);
xhttp.send("username="+username.value);
}
Also, make sure you have the right naming. In your code example, you refer to your input as the variable username, but you add the event listener to kor_ime, I don't know if you updated something to english and forgot other parts of it for this question or if that is your actual code
let username= document.getElementById('username');
username.addEventListener('input', validateUsername); // here change kor_ime to username and update the function name, you can omit the extra function wrapper
I have a .js file hosted on domain1.com, but for this to work correctly I need to add a PHP code at the beginning. The reason for this is to bypass some restriction on Safari for my script and it requires me to create a session. The PHP code creates a session through a url to domain2.com. There is no browser redirection or anything, the user stays in the domain1.com. I want to have a single .js file in domain1.com so maybe an AJAX solution is what I need. Here it is:
<?php
session_start();
if (!isset($_SESSION['isIFrameSessionStarted']))
{
$_SESSION['isIFrameSessionStarted'] = 1;
$redirect = rawurlencode('http://' . "{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}");
header('Location: domain2.com/start-session.php?redirect=' . $redirect);
exit;
}
?>
The start-session.php file is hosted on domain2.com does not need any changes, it contains this:
<?php
session_start(); // create the session cookie
$redirect = rawurldecode($_GET['redirect']);
header('Location: ' . $redirect); // redirect back to domain
exit;
?>
Let me combine what you requested in comments:
I have a .js file hosted on domain1 ... I want to have a single js file and I can't put PHP into that ... the whole purpose of this is for domain1 to not have any php code or php file. ... The reason is because I want it cross-domain and the session to be created from domain2.
It sounds like your issue might be related to the Safari iFrame session cookie problem, especially because you have if (!isset($_SESSION['isIFrameSessionStarted'])) in one of your code blocks. I will continue with this assumption.
Summary of the problem for other readers:
Upon embeding an IFrame from one domain into a website of a different domain, you will quickly realise that Internet Explorer and Safari are blocking the cookies (and thus the session variables) of the website inside the IFrame (ref).
Attempted solutions that didn't pan out:
Safari 3rd party cookie iframe trick no longer working?
Internet Explorer & Safari: IFrame Session Cookie Problem
IFrame must die
Safari: Setting third party iframe cookies
PHP Session in iFrame in Safari and other browsers
My solution:
Essentially, PHP session "hijacking". It works surprisingly well where the above solutions failed. This is the essential solution. Please do any security enhancements* and URL-prettifying you like. Basically, we retrieve the PHP session ID through redirects and pass this to the iframe. Instructions are in the comments.
In your domainA.com head place this:
<script src="session.js"></script>
session.js (on domainA.com):
// Location of the domain B session starter
var sessionScriptURL = "http://domainB.com/start-session.php";
var refQSparam = "phpsessionid";
// Check if we have the phpsessionid in the query string
var phpsessionid = getParameterByName(refQSparam);
if(phpsessionid === null) {
// Not in the query string, so check if we have it in session storage
var sessionStore = sessionStorage.getItem(refQSparam);
if(sessionStore === null) {
// We have no session storage of the PHP session ID either, redirect to get it
top.location = sessionScriptURL + "?redirect=" + encodeURIComponent(self.location.href);
} else {
// phpsessionid was found in session storage. Retrive it
phpsessionid = sessionStore;
}
} else {
// Save the phpsessionid to session storage for browser refresh
sessionStorage.setItem(refQSparam, phpsessionid);
// Optional: Redirect again to remove the extra query string data
}
// Helper to get QS values
function getParameterByName(name) {
return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20'))||null;
}
session-starter.php (on domainB.com):
<?php
session_start(); // create the session cookie
$redirect = rawurldecode($_GET['redirect']);
// redirect back with the php session ID
// Optional: encode this information
$href = $redirect . '?phpsessionid=' . session_id();
header('Location: ' . $href);
exit;
HTML (in the body, on domainA.com):
Append PHP session information to the iframe src.
<script>
document.write('<iframe src="http://domainB.com/embedded-script.php?phpsessionid='+phpsessionid+'"></iframe>');
</script>
embedded-script.php (on domainB.com, in an iframe):
<?php
// Use the phpsessionid passed in
$phpsessionid = rawurldecode($_GET['phpsessionid']);
// REF: http://php.net/manual/en/function.session-id.php
function session_valid_id($session_id) {
return preg_match('/^[-,a-zA-Z0-9]{1,128}$/', $session_id) > 0;
}
// Check that this is potentially a valid session ID
if(session_valid_id($phpsessionid)) {
// Set the session to the one obtained in session-start.php
session_id($phpsessionid);
}
session_start(); // Only call this after session_id()!
// Rest of your code
*Considerations:
Don't actually use document.write, use jQuery or document selectors.
Encode the PHP session ID
Perform another redirect back to the base URL of domainA.com to remove the ?phpsessionid= in the URL for a cleaner look.
If you decide to call session-starter.php with AJAX instead, you will get a new PHP session ID every time for the same reason. The iframe will successfully use this session ID, but if you open a new page to domainB.com, the session will yet again be different.
If you want to run PHP within a file extended with .js, you can do this by telling your apache web server. Add the following directive to the .htaccess or directly to the apache config:
AddType application/x-httpd-php .js
After this is done, your server will run the included PHP code as soon as the file is requested from the server.
Update:
If you want to use sessions with JavaScript, you can do this with an AJAX solution. For this implement a web service on the server which should store the session values. Programming language for implementation can be PHP or another one which can be run by the web server. Request the web service with JavaScript. Here is an answer with an example.
If you want to redirect in Javascript, you can't use a PHP redirect which you have called from AJAX. You can pass the URL you create in PHP and send it back to JavaScript and do the redirect from there. You can do something like:
PHP:
session_start();
if (!isset($_SESSION['isIFrameSessionStarted'])) {
$_SESSION['isIFrameSessionStarted'] = 1;
$redirect = rawurlencode('http://' . "{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}");
echo json_encode(array('url' => $redirect));
}
JavaScript:
$.get('phpfile', function(result) {
if (!result) return;
var data = JSON.parse(result);
window.location.href = decodeURIComponent(data.url);
});
Don't know what you're trying to achieve exactly but let's say you want to go from php to js and back to php you could trying something like this:
Solution 1: Using XMLHttpRequest
In PHP (domain1.com):
<?php
$parameter = ""; //If you'll like to add a parameter here
echo "<script type='text/javascript'>window.addEventListener('DOMContentLoaded',". "function () { goToJS('$paramter');});</script>";
?>
In JS:
window.goToJS = function (parameter) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
//You can redirect back to a php file here
document.location.href = "domain1.com";
//You can view feedback from that php file you sent the stuff to here - just for testing
alert("feedback" + xmlhttp.responseText);
}
}
xmlhttp.open('GET', 'http://domain2.com/start-session.php?q=' + parameter, true);
xmlhttp.send();
}
Not sure about your redirect links and stuff but yeah this should pretty much work. Did something similar a while back
Solution 2: Using ajax
Using ajax you could have a JS script as follows. (type could be POST or GET, Used an example where you sent some json to the php file. Can change the data sent if you properly describe to me what you wish to send. Alternatively could be null also
In JS:
function init_() {
$.ajax({
type: 'POST',
url: 'http://domain2.com/start-session.php',
data: {json: JSON.stringify(selectedEvent)},
dataType: 'json'
}).done(function (data) {
console.log('done');
console.log(data);
}).fail(function (data) {
console.log('fail');
console.log(data);
});
}
In PHP:
Let's say you sent a javascript json to PHP. You could use it in PHP as follows:
<?php
$status_header = 'HTTP/1.1 ' . 200 . ' ' . 'OK';
header($status_header);
header('Content-type: text/javascript');
$json = json_decode($_POST['json']); //Do whatever you want with the json or data sent
echo "This is the returned data"; //Echo returned data back to JS or wherever
?>
why don't just use script directly (if you put this script on top of file it will wait the script to finish creating session in domain2 anyway. (I guess you have iframe in domain1 that call to domain2?)
<script src="http://domain2.com/start-session.php"></script>
USe jquery and jqxhr object for this request, no need send browser to second server, from domain1 you can request to browser load page to init session, and your client never see that.
//include jquery min library and do next code
$(document).ready(function (){
var jqxhr = $.get( "http://domain2.com/start-session.php", function() {
alert( "success" ); //some action for success
})
.done(function() {
alert( "second success" ); //when all is done (success done)
})
.fail(function() {
alert( "error" ); //some action for error
})
.always(function() {
alert( "finished" ); //some end action for anycase
});
});
you can delete .done function, .fail function, and always function as you wish.
NOTE: ready function is to make sure, that domain1 page completely load, and then run script.
reference https://api.jquery.com/jquery.get/
I know that in JS, you can use the success of an AJAX function as the trigger to start other events...
So I have just loaded a new page using AJAX. And through this I have also passed some parameters, this is what I have passed:
xmlhttp.open("GET","register-form.php?one="+wordChoiceOne+"&two="+wordChoiceTwo+"&three="+wordChoiceThree,true);
So I now have the variables $one, $two, $three in PHP
I want to complete a couple of tasks using these (concatenate, capitalise, assign etc) before outputting onto the page. However I don't want this to be bound to the click of a button or anything, I want it to be bound to the success of the AJAX load.
How can I now start these actions in PHP?
Pseudo-code:
function setUsername() // RUN ON AJAX SUCCESS{
// capitalise first letter of one two and three
// concatenate together
// Store in variable $username
}
Then ECHO USERNAME OUT
ETA. I have already written the AJAX request and it works fine. Now it's loaded, I want to perform this PHP function, binding the trigger of that function to the success of the AJAX load:
<?php
$_GET['one'], $_GET['two'] and $_GET['three'];
// Capitalise first letter
$one = ucfirst($one);
$two = ucfirst($two);
$three = ucfirst($three);
$username = $one . $two . $three;
?>
EDIT: OK so it appears I can't explain myself, or I haven't understood what is required for this functionality. But here is what I need to happen in plain english, with links.
I am building a registration system. Instead of letting people type in their own username, I have a username builder. You can see this here:
http://marmiteontoast.co.uk/fyp/login-register/register-username-builder.php
Step One in Javascript
You drag the tiles into the boxes, hit the button that shows up. When you have all three, you hit the big green button. Up until this point, we are all in jQuery, and we have the following three variables stored:
wordChoiceOne - the first word you choose
wordChoiceTwo - the second word you choose
wordChoiceThree - the third word you choose
These are stored as JS variables.
Step Two PHP time
So now that I have these three stored variables I wish to move away from JS and start using PHP. I have already built a successfully working registration but it uses the username as an input rather than this when helps you "build" your own.
My research has led to the understanding that because of the client side to server side switch the only way that I can successfully pass these variables into PHP is through an AJAX request. This seems pretty handy to me because I would like the registration form I have already built to be loaded into the page asynchronously. So I asked for some advice about how to "share" these jQuery values through the AJAX request and was helped with the following, to pass them through the URL:
xmlhttp.open("GET","register-form.php?one="+wordChoiceOne+"&two="+wordChoiceTwo+"&three="+wordChoiceThree,true);
My understanding (and maybe I'm wrong? Please let me know and explain if I am...) is that this assigns the already existing variables of wordChoiceTwo etc to a PHP variable of $two. Is this right?
So now I have PHP variables $one, $two and $three...
Running the PHP
Perhaps this is because I am more used to working with JS, but with JS you have to do something (button click etc) to be able to enact a function. I know that one such do something is a successul AJAXC request but that isn't PHP. So my question... and this was really the only question I had, is ** how do you start the running of a PHP function when you've just loaded somethhing through AJAX?** I want to start running a php function called `setUsername" on this page. But I don't want the user to have to press a button to make this start, I want it to be bound to the success of the AJAX completion or something similar to this, as I understand that might be JS only.
This is the AJAX call I already have in place:
function saveUsername(wordChoiceOne, wordChoiceTwo, wordChoiceThree){
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("login-register-wrapper").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","register-form.php?one="+wordChoiceOne+"&two="+wordChoiceTwo+"&three="+wordChoiceThree,true);
xmlhttp.send();
}
Add a json header type and echo
$_GET['one'], $_GET['two'] and $_GET['three'];
// Capitalise first letter
$one = ucfirst($one);
$two = ucfirst($two);
$three = ucfirst($three);
$username = $one . $two . $three;
header('Content-type: application/json');
echo json_encode(array('username'=>$username)); // <---
then in your js, bind a function to the success of the call:
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
//xmlhttp.responseText;
}
}
edit, because there seems to be some confusion:
Just because an ajax call reaches your php script doesn't mean it's executed. The request by nature will sit and wait for a reply. This reply can contain data if your php echo's it.
edit 2 so you can wrap your head around the principle of it, here's an oversimplification of what I think you want:
file 'ajax.html':
<div id="name"></div>
<script>
function myName(first, last) {
var req = new XMLHttpRequest();
req.open('GET', 'ajax.php?first='+first+'&last='+last);
req.onreadystatechange = function() {
if(req.readyState==4 && req.status==200) {
data = JSON.parse(req.responseText);
document.getElementById('name').innerHTML = data.username;
}
}
req.send();
}
myName('john', 'doe')
</script>
file 'ajax.php':
$first = $_GET['first'];
$last = $_GET['last'];
header('Content-type: application/json');
echo json_encode(array('username'=>ucwords($first) . ' ' . ucwords($last)));
this is generally how AJAX is used
I have a js file. Is it possible to do inside the js file a php coding? On my header I include my js file like this.
<script type="text/javascript" src="js/playthis.js"></script>
now inside my jsfile:
function getURL(e) {
alert(e+' javascript varibale');
<?php $url; ?> = e;
alert('<?php echo $url; ?>'+' php variable');
}
in my php file
<?php $url = "www.google.com"; ?>
<a href="#" onclick="getURL('<?php print $url; ?>');" class="title">
It's not working. Is there something wrong?
you have to make a new object for Ajax transaction named XMLHTTP REQUEST in some browsers and in I.E this is ActiveXObject basically; and this object belong to window object;
so the first step is:
if ( window.XMLHttpRequest ) {
XHR = new XMLHttpRequest();
}
else if ( window.ActiveXObject ) {
XHR = new ActiveXObject("Microsoft.XMLHTTP");
}
else {
alert("You Cant see because Your Browser Don't Support Ajax!!!\n Change Your Browser To A Modern One");
}
now, you have the right object
in next step, there is some methods for XHR object for send and receive you should know:
1/ onreadystatechange
2/readyState
3/status
4/open
5/send
6/setRequestHeader
first open a connection with open:
XHR.open("POST", url, true);
as you know, post is method of sending, and now you have to set the url you want to information send to, for example if you want to send the variable to the test.php, then the url is test.php...
true means the request will sent asynchronously..
next is set your request header, because your are using post method, in get method you don't need this:
XHR.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
next is sending the request with send method with this format send(name, value):
XHR.send('value=' + value);
first string 'value=' is the index of $_POST that you will get in php, so in your php code, you'll give this with $_POST['value'], if you set the name to 'name=', in php you have $_POST['name'], be careful that in Ajax send param you have to use = after the name of data, but in php the = is not used...
after you sent the request; it's time to mange response:
XHR.onreadystatechange = function() {
if ( XHR.readyState == 4 && XHR.status == 200 ) {
document.getElementById('your target element for show result').innerHTML == XHR.responseText;
}
}
XHR.readyState == 4 and XHR.status == 200 means every thing is O.K.
this is the basics of Ajax as you wished for; but there is so many information for Ajax, and either you can use jQuery Ajax method that is so simple and flexible; But as you want I described the basics for you...
No it's not possible to have PHP code inside JS file.
You can make $.ajax call to a PHP file and that file can handle the setting of the variable required.
Hope this helps.
There are a few ways to handle this.
1 - Have .js files parsed by php. You will need to change your webserver configuration to do this.
2 - Use AJAX to interact with php.
3 - Have php render an additional JS snippet in the body onload event that sets this JS parameter (but still have the library as a seperate file).
this is not necessary, when you print the url with print $url in onclick attribute inside the php page as an argument for getURL function, it means the value of $url will be sent to the function with name getURL in your js file...
so, you have to write:
alert(e);
and if you are just asking, as the other friends told, you should use Ajax for this...
when you assign a variable to a function as an argument, just like getURL(e), the time that you call the function,getURL('print $url") you have to set the value of that variable, so, the program set the value you give to the function to the default variable...e = $url
you can change .js file to .php file and work with javascript and php together
change this
<script type="text/javascript" src="js/playthis.js"></script>
to this
<script type="text/javascript" src="js/playthis.php"></script>
I have a hosing account. (cPanel or DirectAdmin)
So I don't have root access, i can't use exec() or shell_exec() functions (Blocked by Server Admin).
I know best way for chat is socket programing but it needs Terminal Commands like:
PHP ./server.php
But i don't have access to the Terminal.
I did too many searches and found some methods but I'm not sure for performance because they are using a Javascript command setTimeout() for connecting to the chat database or file.
I think if i used setTimeout('refresh()',1000) there is a better way instead of connecting to the chat database every 1 sec.
my method:
refresh=function()
{
//there is flag in session, true means there is new message from sender (session_set_save_handler)
//check flag value in the session, if its true then refresh chat database
}
setTimeout('refresh()',1000)
I used a flag because i dont want to connect to the database every 1 sec, maybe there is no new messages from sender, but we're forcing the server to refresh every 1 sec.
Is my method better or not ? is there a better way for build a chat script without Server Root access?
Thanks alot.
Sorry for bad English
That solution will definitely work, using setTimeout to check for new messages every second or so. There are other technologies such as comet although these are not possible in PHP, as stated in the question.
Here is an example that uses PHP and stores chat history in an SQL database, the ajax function to get new chat messages:
//Updates the chat
function updateChat(){
$.ajax({
type: "GET",
url: "update.php",
data: {
'state': state,
'file' : file
},
dataType: "json",
cache: false,
success: function(data) {
if (data.text != null) {
for (var i = 0; i < data.text.length; i++) {
$('#chat-area').append($("<p>"+ data.text[i] +"</p>"));
}
document.getElementById('chat-area').scrollTop = document.getElementById('chat-area').scrollHeight;
}
instanse = false;
state = data.state;
setTimeout('updateChat()', 1);
},
});
}
As you can see the last line uses setTimeout to call the function every 1 second.
Messages are sent separately by a different function:
//send the message
function sendChat(message, nickname) {
$.ajax({
type: "POST",
url: "process.php",
data: {
'function': 'send',
'message': message,
'nickname': nickname,
'file': file
},
dataType: "json",
success: function(data){
},
});
}
As I mentioned in my comment above, there are some advantages to using server technologies other than PHP. Most PHP solutions use a database to persist chat messages between requests to the server, this creates a lot more server overhead than is really needed, a node.js solution can instead store the messages in an array that stays in memory within the server, and in addition use sockets see here for an example.
Edit - to cache an sql query in memory
If you are using MySQL it is possible to prepend your query with a comment to imply that the query should be cached in memory, something like:
$res = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT message FROM chatroom WHERE id = $roomId");
For more information see example 1, here. The example times the queries and could be useful as a benchmark on your Server.
Caching can occur on the server even if the code does not explicitly ask for it, after all the amount of memory required to store the contents of a chatroom is very small - it's only a few lines of text! The example I took the Javascript code from, above, stores the text in a file, which would almost certainly be stored in memory on the Web Server. If the db server is running on the same host as the web site then the request may well not result in any disk activity, making the overhead also very small. The webserver / db connection may also be in memory rather than sockets.
The best solution will very much depend on your server setup, best to get something working, then optimise it. I do know from experience that the node.js solution is very fast.
Edit - Answer to flag question
Setting a flag in the client Javascript would not work, as other clients could submit messages without the flag for the current client being reset. Setting a flag in the PHP on the server is tricky, persistent variables that are not specific to clients (from sessions or cookies), and not stored in databases have to be saved in files: PHP: persistent variable value. The static keyword is not quite the same as it would be in C or similar language. This is one of the main advantage of using Node.js, persistent arrays are very easy to create.
One solution would be to save the messages as json in a file, append each new message as it is received, and return the whole file to the user, once a second. The file could be restricted to 100 lines or so, this would ensure that it stays stored in cache memory somewhere (ramdisk, OS disk cache, or at worse hardware cache on the harddisk itself).
I once made a simple chatting script when i was still learning web development. You can use following javascript functions to make your little chatting messenger:
Fetch messages from db through ajax after every 1 second
function fetchMessage()
{
var xmlhttp;
if (window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();
}
else
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
flag_loading=1;
document.getElementById("chat").innerHTML=xmlhttp.responseText;
var objDiv = document.getElementById("chat");
objDiv.scrollTop = objDiv.scrollHeight;
}
/*else if (flag_loading=0)
{
document.getElementById("chat").innerHTML="loading...";
}*/
}
xmlhttp.open("GET", "fetchmessage.php", true);
xmlhttp.send();
}
setInterval("fetchMessage()",1000);
Server side script fetchmessage.php goes here
<?php
session_start();
include('connect.php');
$user_id=#$_GET['user_id'];
$sql="select m.user_name,m.message,m.post_time from message m where m.user_id='".$_SESSION['current_user']['user_id']."' or m.reciever_id='".$_SESSION['current_user']['user_id']."' ";
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)) {
echo "<br><font size=2 color='brown'><b>".$row['user_name'].":</b></font> ".$row['message']."</br>";
echo "<font size=1 color='blue'>(".$row['post_time'].")</font>";
}
?>
This function sends your message to the other user (chatting with you)
function addMessage(reciever_id, user_id, message) {
if (message=='') {
window.alert("Enter some message.");
} else if (reciever_id=='none') {
window.alert("Select any friend.");
} else {
var xmlhttp;
if (window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();
}
else
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4)
{
document.getElementById('message').value="";
}
}
xmlhttp.open("GET", "addmessage.php?user_id="+user_id+"&message="+message+"&reciever_id="+reciever_id, true);
xmlhttp.send();
}
}
Server side script addmessage.php goes here
<?php
session_start();
include('connect.php');
if (!isset($_SESSION['current_user'])) {
header("location:index.php?error=Please Login First!");
}
else {
$user_id=$_GET['user_id'];
$message=$_GET['message'];
$reciever_id=$_GET['reciever_id'];
mysql_query("INSERT INTO message VALUES (NULL, '".$_SESSION['current_user']['user_id']."', '".$reciever_id."', '".$_SESSION['current_user']['user_name']."', '".$message."', NOW())") or die(mysql_error());
}
?>
You can also check for online users/friends using this script
function checkOnline() {
var xmlhttp;
if (window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();
}
else
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById('online_friends').innerHTML=xmlhttp.responseText;
//window.alert(xmlhttp.responseText);
}
}
xmlhttp.open("GET", "onlinefriends.php", true);
xmlhttp.send();
}
setInterval("checkOnline()", 1000);
Server side script for onlinefriends.php goes here
<?php
session_start();
include('connect.php');
$query_online=mysql_query("SELECT user_name FROM user WHERE user_status=1 AND user_name!='".$_SESSION['current_user']['user_name']."' ") or die(mysql_error());
while ($row=mysql_fetch_array($query_online)) {
echo "<font size=4 style='font-style:italic; font-family:Georgia, 'Times New Roman', Times, serif'>".$row[0]."</font><br>";
}
?>
And ask me if you feel it difficult to implement, i'll help you further :)
If you don't (or can't) use socket, mixing a low-weight response php page with auto refreshing script in each client with jquery ajax in a certain couple of time is best solution. but it's performance is very depended on total of your active chat pages!
for better performance and decreasing server's processing time i think making a custom session handlers for accessing to all of active sessions is a good way to check if any new message has been received for reader instead of checking database every time.
and for saving bandwidth especially in high traffic time you can change JavaScript next setTimeout delay with received response from ajax.
another solution is to set read flag for each message in your database in order to send just new messages with json instead of reloading all of messages in every update.