So I’m working on a To Do App and I used Ajax to send data to PHP when a task is clicked to be marked as completed. PHP then sends an SQL query to MySQL and changes the value in the completed column from 1 to 0 or visa vera. Originally, I tried to send a PHP header to go back to that page but it didn’t work so after the request was sent I wrote some JavaScript code to refresh the page and the task is now marked as completed and I have a css style for that. I was wondering, I thought the purpose of Ajax was to not have to reload the whole page so idk if I’m using Ajax wrong and there is a better way to do this? The project works but I just want some feedback on my code I guess.
main.js:
for(i=0; i < div.length; i++){
div[i].addEventListener("click", function(e){
let xhr = new XMLHttpRequest();
xhr.open('POST', 'process_complete.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
let task_num = e.target.getAttribute("id");
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
location.reload();
}
}
xhr.send(JSON.stringify(task_num));
});
}
process_complete.php:
if(isset($_SERVER['HTTP_X_REQUESTED_WITH'])){
$data = file_get_contents('php://input');
$id = json_decode($data);
$sql = mysqli_query($conn, "SELECT * FROM tasks WHERE Num = '$id'");
if($sql === false){
printf("error: %s\n", mysqli_error($conn));
}
while($row = mysqli_fetch_row($sql)){
if($row[3] === "1") {
$mysqli_update = mysqli_query($conn, "UPDATE tasks SET Completed = 0 WHERE Num = '$id';");
} else {
$mysqli_update = mysqli_query($conn, "UPDATE tasks SET Completed = 1 WHERE Num = '$id';");
}
}
}
I thought the purpose of Ajax was to not have to reload the whole page
It is.
You are supposed to write JavaScript that modifies the DOM of the current page at the point where you have location.reload().
So there is a third step you may be missing. You have passed the data and fetched it into the PHP page, however you need to pass it back. In order to do that, you first place an echo inside the PHP page which will work in much the way that return works with a function in PHP. Once you have done that, you will need to make sure AJAX takes in that returned value, and then make sure you have a function that includes this AJAX and uses that value to replace, append, or removes whatever content the AJAX is using. This is a lot easier to do if you use an extension of AJAX like the .post() found in the JQUERY framework.
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
Summary: I have a solution I've built for monitoring variables and code processing in my environment. It works well for static pages, and the code below is a usable solution for that. However, if the page includes ajax calls which updates common variables after the page runs, this monitoring method isn't useful. To make it do so, I want to figure out a way to piggyback off an ajax call that will story information that's run in place, but I can't figure out how to work it into this code.
I have the following error checking file for php that I use in my development environment, the following using a magic function, register_tick_function, to store code as its run and show the variables for each step. Including it on a page allows the tick process to run...
<?php
register_tick_function(function(){
if (isset($GLOBALS["developer_debug"]) && $GLOBALS["developer_debug"] == 'active'){
$backtrace = debug_backtrace();
$line = $backtrace[0]['line'] - 1;
$file = $backtrace[0]['file'];
if ($file == __FILE__) return;
static $fp, $cur, $buf;
if (!isset($fp[$file])) {
$fp[$file] = fopen($file, 'r');
$cur[$file] = 0;
}
if (isset($buf[$file][$line])) {
$code = $buf[$file][$line];
} else {
do {
$code = fgets($fp[$file]);
$buf[$file][$cur[$file]] = $code;
} while (++$cur[$file] <= $line);
}
$line++;
if (defined('ERR_LOG')){ $error_log = ERR_LOG; } else {
$error_log = "../logs/error_log";
}
error_log("\n==========================================================\n", 3, $error_log);
error_log("\n $file : $line :: $code \n", 3, $error_log);
error_log("\n Variables: \n" . print_r(get_defined_vars(), true) . "\n", 3, $error_log);
$GLOBALS["_TROUBLESHOOTING"][] = "<code>\n $file : $line ::: ". htmlentities($code, ENT_QUOTES) . " \n</code>";
}
}, ["_SERVER" => $_SERVER, "_COOKIE"=>$_COOKIE, "_REQUEST"=>$_REQUEST, "_SESSION"=>$_SESSION, "_GLOBALS"=>$GLOBALS]);
// To use...
// declare(ticks=1);
// include_once('debug.php');
and in my direct page loads (such as index.php) I can include this js:
$(document).ready(function() {
var dev_top_button = document.createElement("Button");
dev_top_button.innerHTML = "Top Dev Data";
dev_top_button.style = "top:0;right:75%;position:absolute;z-index: 9999"
document.body.appendChild(dev_top_button);
var dev_bottom_button = document.createElement("Button");
dev_bottom_button.innerHTML = "Bottom Dev Data";
dev_bottom_button.style = "top:0;right:50%;position:absolute;z-index: 9999"
document.body.appendChild(dev_bottom_button);
$(dev_top_button).click(function(){
$("#debug_top").toggle();
});
$(dev_bottom_button).click(function(){
$("#debug_bottom").toggle();
});
});
and this on the page itself:
echo "<div class='debug_outer' id='debug_top'><h3>Developer Information</h3><div class='debug_inner'><pre>";
if (isset($GLOBALS['_TROUBLESHOOTING']) && is_array($GLOBALS['_TROUBLESHOOTING']) && ! empty($GLOBALS['_TROUBLESHOOTING'])) {
$troubleshooting_return_array = $GLOBALS['_TROUBLESHOOTING'];
} else {
$troubleshooting_return_array = ['Empty'];
}
echo print_r(["_COOKIE" => $_COOKIE, "_REQUEST" => $_REQUEST, "_SESSION" => $_SESSION, "_TROUBLESHOOTING" => $troubleshooting_return_array, "_SERVER" => $_SERVER, "_GLOBALS" => $GLOBALS], true);
echo '</pre></div></div>';
(And a similar output at the end of the page)
So, for most pages, this method to quickly check out page variables works great. And results in a nice javascript button to where I can quickly check what my start and end variables are on a page, along with a _TROUBLESHOOTING array I can easily dump whatever values I want to for quick looking over at page start and end.
So this system has been working pretty well for me for quite awhile now. The problem, however, comes with ajax calls. I've tried several different ways, but ajax calls generally want and expect data in a certain format. I'm -wanting- to make a third div for displaying data, along with a button for it, but I'm having a hard time figuring out how to piggyback any output data along with an ajax call, and it has to be called when the ajax is called in order to get how all the variables change and to track anything I'm troubleshooting. Sure, I can put an output to the error logs each time, but that's way slower on workflow and requires grepping through all the output since the last time the logs were cleared rather than simply seeing what my data is as I'm manipulating it.
Does anyone have a good idea to piggyback off of ajax calls to take use of these existing kinds of calls? Because messing with the returned values of the ajax calls will always result in bad data for the ajax call itself.
Solution was fairly straightforward after I thought about it for a while:
For ajax requests, send the data to a sub-array in session; a sub-array that's normally ignored by by the normal two print outs. Then, have a third button that's an ajax request that specifically fetches the value of that sub-array. The sub-array can be specifically filled with a sub-sub array for each ajax call that has been done, and then when fetched by the third button, it creates a div to share it and then empty the sub-array (otherwise it will bloat way too quickly), allow seeing all ajax calls since the last time the button was clicked (and appending them to the existing list, if still on the same page.)
I'm working on a piece of some software that will grab information from a mysql database and throw it onto our form dynamically. I'm running into a couple problems, though. I'll give a quick rundown of some functionality.
When the form loads, we have a ton of selection lists. These are all populated through arrays with various keys/values in php. When I select an option from one list, we'll call it a "customers" list, on-click I need to check if that customer has a special flag (stored in the database), and update another selection list based on that data.
How I understand the core of my solution is I need to have a javascript trigger on-click, which I have. The function that is called references a php page that handles the database query through a class and it's function.
<script>
function setService()
{ // The customer's "id" grabbed from the aforementioned customer selection list
customer = $('#customer').val();
$.get('thePage.php?key=setService?customer='+customer);
}
</script>
This function then talks to my php. The CustomerProvider class works 100%. I have tested that thoroughly on other pages. The problem arises when I try to actually get my selection list to change.
<?
if(isset($_GET['key']) && $_GET['key'] == 'setService')
{
$customer = $_GET['customer'];
$customer = intval($customer);
$s = CustomerProvider::getHasContract($customer);
if ($s != '')
{ ?> <script>var element = document.getElementById('ticket_service');
element.value = 'Contracted Hours';</script> <? }
else return;
}
?>
I'm coding in javascript literally for the first time ever and they kinda just threw me on this project. I know that my portion isn't being read as html or output as I intend. I know that every other part of the php and the first bit of javascript seems to be executing okay. Any help would be incredibly appreciated.
You seem to be on the right track but just for your own sanity here are a couple pointers. You shouldn't be returning Javascript from PHP for a situation like this. Instead you should be relying on Javascript promises to wait for a response containing just the data and continue the execution of your client code once you have your values returned. Take a look at this:
<script>
function setService() { // The customer's "id" grabbed from the aforementioned customer selection list
customer = $('#customer').val();
$.get('thePage.php?key=setService?customer=' + customer, function(data) {
console.log(data + ' was returned from your php script!');
if(data.hasContract=='1')
$('#ticket_service').val('Contracted Hours');
else
$('#ticket_service').val('No Contracted Hours');
});
}
</script>
And then your PHP script will just look like this:
<?
if(isset($_GET['key']) && $_GET['key'] == 'setService')
{
$customer = $_GET['customer'];
$customer = intval($customer);
$s = CustomerProvider::getHasContract($customer);
if ($s != ''){
$hasContract = 1;
}
else
$hasContract = 0;
echo json_encode(array('hasContract' => $hasContract));
}
?>
Therefore returning only the data needed for the client app to continue... not application logic
Your code isn't doing anything with the output of the PHP script. If you want the output to be inserted somewhere in the DOM, you should use .load() rather than $.get.
$("#someelement").load('thePage.php?key=setService?customer='+customer);
This will put the output into <div id="someelement">. If the output contains <script>, the script will be executed.
If you know the result is just a script, you could use $.getScript() instead of $.get. Then the output should just be the Javascript, not enclosed in HTML tags like <script>.
The problem here is that you are not using the result from the server. Your JavaScript may indeed be correct, but the browser never sees or runs it. From the docs:
Request the test.php page, but ignore the return results.
$.get( "test.php" );
Try this code, which utilizes the $.getJSON() shortcut function. I've written two versions, which you can see commented in the code. One moves the logic for determining contract status into the JS. Either should work.
PHP
<?
if(isset($_GET['key']) && $_GET['key'] == 'setService')
{
$customer = $_GET['customer'];
$customer = intval($customer);
$s = CustomerProvider::getHasContract($customer);
// Default output
$output = array('hasContract' => false);
// Customer has contract
if ($s != '')
$output['hasContract'] = true;
echo json_encode($output)
// Alternative: PHP just returns getHasContract, JS determines action
// (this would replace $ouput, conditional, and echo)
// echo json_encode(array("hasContract" => $s));
}
?>
JavaScript
function setService()
{ // The customer's "id" grabbed from the aforementioned customer selection list
customer = $('#customer').val();
$.getJSON('thePage.php?key=setService?customer='+customer, function(result) {
// Alternative
// if (result.hasContract != "")
if (result.hasContract)
{
var element = document.getElementById('ticket_service');
element.value = 'Contracted Hours';
}
});
}
As others wrote, your code doesn't do a thing with the GET variables.
the element "ticket_service" doesn't exists on page and even if it was, the code has no impact on the page that sent the request, you should print/echo the result you want to display/return and then manipulate it with JS/Jquery.
since I'm against GET and pro POST which is safer method, here's an example with POST:
JS:
function postSomthing(customerID){
$.post(
'thePage.php',
{key:'setService',customer:customerID},
function(data){
if(data!='x'){
$('#ticket_service').val(data)
}
else{alert('no ticket');/*whatever you want to do*/}
});
}
PHP(thePage.php) :
if(isset($_POST['key']) && $_POST['key'] == 'setService'){
$customer = intval($_POST['customer']);
$s = CustomerProvider::getHasContract($customer);
if ($s != ''){echo 'x';/* false, or whatever you want*/}
else{echo 'Contracted Hours';}
}
notes:
you should create an element with the id "ticket_service" in the viewed page and not in the backstage one.
How can I make my Excel file work as a web page where people can enter data and it will stay there? I am new to this!
Required technologies for this exercise: JavaScript, JQuery, PHP, AJAX and MySQL. And Excel! All this requires a minor edit, only adding 3 lines of text to the generated html page.
A running demonstration is at https://ip.jawfin.net
I'd like to state that the html of Excel Save As has been badly maligned - Excel 2013 generates a very clean html, its styles are built into the comments (so only 1 file is produced, no CSS), it's well indented and easy to read. The only down-side is the names of classes of the styles are rather arbitrary! No JavaScript, just plain html - it's a nice place to start then refine in Notepad++ or your favourite editor. Mind you, the lack of CSS may come back to bite you, for extensive use I would recommend extracting the comments to build a CSS from.
Firstly, our Excel. Here's one I made, and this is for a simple application which puts your IP in the cell you select on the screen. (My practical use of this method was for a month scheduler, this "pick a colour" is good to demonstrate all the features and I hope will be easily adaptable.) One change though, I scramble the visitor's IP as a protection.
Here's my Excel file: https://ip.jawfin.net/ip.xlsx
We don't export the whole spreadsheet, just select the cells you want which will make up the webpage. In my case: -
With the cells selected, go into File / Save As, pick your folder, Save as Web Page (*.htm), choose only the Selection, give it a Title if desired, name it index.htm and Save!!
Now, rename index.htm to index.php as we will putting php code in it. Now for the 3 lines of code to make this an interactive webpage. Between the </body> and </html> at the bottom insert these 3 lines: -
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<?php include 'excel.php';?>
<script src="excel.js"></script>
so we have: -
</body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<?php include 'excel.php';?>
<script src="excel.js"></script>
</html>
The 1st line importing JQuery for our AJAX to work.
The 2nd is to get the user's IP. Note, this can do a lot more if required, for instance in my implementation I use it to log into a phpBB forum and get the logged-in username and permissions. This php also shows how we can pass server php variables to the local javascript.
The 3rd line is the brains, doing all the work and communicating with the server for updating and fetching data.
(You know, this really could just be one line of code if I embedded the script lines as echo's in the php - but that loses readability in my opinion.)
For the database: on your webserver log into your panel and create a new database for this app.
Then log into your phpMyAdmin to create the table[s] your application needs.
In this case it's one table, called cell_ip. Its structure: -
field:cell; type:integer; index:primary + unique
field:ip; type:text
Or as it appears in phpMyAdmin: -
The files this project uses are: -
index.php the one we just created in Excel, goes in the web folder
excel.php the file which fetches server-side variables (note we could also use this to inject dynamically created controls)
excel.js the script running local interface, also communicates with the server
server.php the database handler on the server, deals with the AJAX requests and database manipulations
settings.php just a means of storing the database configuration in a safe place
All these files go into the root of the web folder, except settings.php which goes in home, the folder above web, where the Internet cannot see it, but our server.php can.
Note the 4 php files are all doing completely different jobs: index.php is the web page they see, the only user visible php file. excel.php injects code into index.php, into the webpage, where it can get server-side settings for the client. server.php is like a program running on the server alone, an application which our webpage calls to save and load data into our server-side database. settings.php is just a glorified ini file, a quick means of storing sensitive info out of sight from the Internet.
All the source has relevant comments explaining the processes - but I'm willing to answer any questions I can, please note though that I am not an expert. So, without further ado, the work source codes.
(Edit: As I can't fit the full source here I'll provide links. Please let me know if there is a smarter/preferred way. As it is, I renamed these to .txt so it doesn't behave like a webpage!)
index.php - This too big to include, so download, or make it yourself from instructions above.
excel.php
<?php //excel.php
//Let's create a string specific to the user without giving away private info
$ip = $_SERVER['REMOTE_ADDR']; //I'm going with hashing the md5 of their IP, then mod'ing back to 12 digits (from 38)
$hash = fmod(hexdec(md5($ip)),1e12);
echo '<script>'; //clever means of getting a php variable into javascript
echo 'var user_ip = ' . json_encode($hash) . ';'; //replace $hash with $ip you want to see the real address!
echo '</script>';
?>
excel.js
//excel.js
$.ajaxSetup({ cache: false }); //needed to stop IE/Edge from caching AJAX GET requests
var cells = document.getElementsByTagName("td"); //array of all cells, excel assigns them type HTML table cell "td"
var updating = false; //prevent flicker if writing to the dataset and a read overwrites our status messages
var reentry = false; //prevent overlapping refresh. polls 1 a sec, 5 second time-out, could lead to massive overlap!
var addingStr = ' -- Adding IP --'; //const not used for backwards compatibility, IE9 etc.
var removeStr = ' -- Removing IP --';
var replaceStr = ' -- Replacing IP --';
for (var i = 0; i < cells.length; i++) { //you can assign different aspects by the .innerHTML
cells[i].style.cursor = 'cell'; //or 'pointer' - the default is the edit caret cursor which looks ugly
cells[i].id = i; //tag our elements, but note this is happening AFTER the DCOM scan so getElementById() won't work
cells[i].onclick = function() { cellClick(this); };
}
refreshScreen();
setInterval(function() { //ajax poll, refresh every second!
refreshScreen();
}, 1000);
function cellClick(cell) {
updating = true; //don't allow the refresh to remove our status comment in the cell
var mydata = 'action=';
if (cell.innerHTML == "" || cell.innerHTML == " ") {
cell.innerHTML = addingStr;
mydata += 'c'; //write into this cell the users IP
} else {
if (cell.innerHTML == user_ip) { //let's be smart and allow them to remove their own IP :)
cell.innerHTML = removeStr;
mydata += 'd'; //clear/delete this cell
} else { //it's someone else, hijack them!!
cell.innerHTML = replaceStr;
mydata += 'u'; //update this cell
}
}
mydata += '&cell=' + cell.id + '&ip=' + user_ip; //add our parameters
$.ajax({ //JQuery ajax, so much cleaner and safer than using JavaScript ajax
url: "server.php", //our server-side worker
type: 'POST', //database changes, use POST, we don't want a webcrawler or a cache hitting a GET with parameters
data: mydata,
timeout: 5000, //5 second should be ample, but if they lose connectivity allow it to fail
success:
function(data) {
updating = false;
if (data != 1) { //no matter what, in this CRUD only 1 record should have been affected
alert('Data update error. Parameters: ' + data + '. Result: ' + data);
}
refreshScreen(); //refresh screen with new data
},
error:
function(xhr, ajaxOptions, thrownError) { //put better error handling in if this fires too often!
// alert('Data = ' + mydata + '. Error # = ' + xhr.status + '. Message = '+thrownError); //uncommend to debug
updating = false;
refreshScreen();
}
});
}
function refreshScreen() {
if (updating) return; //just wait a second
if (reentry) return; //we're already pending a refresh
reentry = true;
var mydata = 'action=r'; //we want to Read the data - stored in a varible in case we turn on our error alert
$.ajax({
url: "server.php",
type: 'POST',
data: mydata,
timeout: 5000,
// dataType: 'json', //just saves us a line of formatting text on success. !!commented out, not debug friendly
success: function(data) { //on recieve of reply
reentry = false;
if (updating) return; //they clicked between the request and the return here, just wait it out, next second!
data = JSON.parse(data); //i prefer this instead of dataType:'json' so I check server script errors in the throw
var results = []; //get our data into a 2 dimensional array (has 2 dimensions as our query returned 2 fields
for(var x in data) { //get all the data ready before we touch the screen, cut down any possibly latency
results.push(data[x]);
}
for (var i = 0; i < cells.length; i++) { //reset screen
if (cells[i].innerHTML != removeStr) { //skipping the "Remove" messages (dirty read) - will clean up below if they were removed!
cells[i].innerHTML = ""; //clear field
}
}
for (var i = 0; i < results.length; i++) { //now we stuff our cells with the IPs we have
cells[results[i][0]].innerHTML = results[i][1]; //first array element is cell number, the second is the IP
}
//as the "Remove" status was skipped above need to loop again to clear any found
for (var i = 0; i < cells.length; i++) { //backwards clean
if (cells[i].innerHTML == removeStr) { //text is here as this cell didn't come through the SELECT
cells[i].innerHTML = ""; //clear field
}
}
},
error:
function(xhr, ajaxOptions, thrownError) { //uncomment alert for debugging
reentry = false;
// alert('Query = ' + mydata + '. Error # = ' + xhr.status + '. Message = '+thrownError);
//Note that xhr.status == 200 is an OK from the server but JSON invalid, so check for that first!
}
});
}
server.php
<?php //server.php
if (!isset($_POST['action'])) exit; //no action parameter, just leave. could echo an error message if required though
$action = $_POST['action'];
if (!strpos(' crud',$action)) { //note the space out front, or else it'll fail on 'c' as it returns zero, which = false
echo("Unknown action='$action'"); // took me ages to debug that, resulting in this line of code!!!!
exit; //otherwise not one of ours, quit before SQL stuff starts
}
require "../settings.php"; //lazy place to easily store settings out of reach from the Internet, parent of the web root.
//Be aware I used ".." - if this server.php is not in the webroot then the database.php is not out of reach.
//Note this method is easier than loading an .ini file and parsing it within an array.
if ($db_server == "") { //ASSERT: this should never fire as the require would fail on not find, but can't be too sure
echo "Problem getting database settings.";
exit;
}
$connection = mysql_connect($db_server, $db_username, $db_password); // Establishing Connection with Server
if (!$connection) {
echo "Error connecting to database.";
exit;
}
$db = mysql_select_db($db_database_ip, $connection); // Selecting Database
if (!$db) {
echo "Specific database not found.";
exit;
}
if ($action == 'c') { //note this will fail if there is a blank record against this cell, so check here
$cell = mysql_real_escape_string($_POST['cell']); //extract our parameter
$ip = mysql_real_escape_string($_POST['ip']);
if ($ip == "") {
echo "Cannot add blank IP in cell '$cell'";
} else {
$query = mysql_query("INSERT INTO cell_ip(cell, ip) values ('$cell', '$ip')"); //Create Query
echo $query; //always return the result, even if its unexpected. can hold error messages for debugging
}
}
if ($action == 'r') { //JSON our database back to the client.
//Note I am using the POST protol instead of GET, tidier on this server.php keeping all my server requests in one file
$result = mysql_query("SELECT cell, ip FROM cell_ip"); //Read Query
while ($row = mysql_fetch_row($result)) {
$table_data[] = $row;
}
echo json_encode($table_data); //return the whole dataset
}
if ($action == 'u') { //pinching someone else's cell with our ip, make sure the new ip exists too
$cell = mysql_real_escape_string($_POST['cell']);
$ip = mysql_real_escape_string($_POST['ip']);
if ($ip == "") {
echo "Cannot edit to a blank IP in cell '$cell'";
} else {
$query = mysql_query("UPDATE cell_ip SET ip = '$ip' WHERE cell = '$cell'"); //Update Query
echo $query;
}
}
if ($action == 'd') { //delete this cell
$cell = mysql_real_escape_string($_POST['cell']); //extract our parameter
$query = mysql_query("DELETE FROM cell_ip WHERE cell = '$cell'"); //Delete Query
echo $query;
}
mysql_close($connection); //Note this was never opened if the caller failed the "action" validation, being polite to our sql
?>
settings.php (this goes in root home, change the values in this to suit)
<?php //settings.php
$db_server='localhost';
$db_username='root';
$db_password='root_password';
$db_database_ip='excel_ip';
?>
Things to note: -
If your database relies on the cell number they may change if you edit your Excel and republish the html.
This demo relies on the cell numbers only because it is only a demo - for instance you could put text in the cells and use that to identify your relevant cells.
If you run your server on CloudFlare and change any of your .js or .php they get cached, so you need to purge those files on the CloudFlare (Caching) after you upload them.
SECURITY!!! Your JavaScripts will be available to the end user, they cannot not be, as JS runs on the client - not matter how packaged or encrypted they can be discovered. Do not have passwords or intellectual property in them. This also means your AJAX requests can be launched maliciously, be sure to put extensive handling and filtering in your server-side php's. I would also recommend employing a token + session handler to validate the calling client.
Final note: I wrote this for 2 reasons. First I wanted to read this in 10 years time so I can see how hacky and newby I am now (this is my second day as a web developer), and secondly I do not wish anyone to go through the shameful and humiliating experience which I did when asking for help on this project on StackOverflow (you won't find my question about that though, it got deleted). I hope this post is useful to somebody, I spent a whole day on designing it :)
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....