As I'm developing my WebIDE, I keep coming up with questions that I cannot answer myself. This is because the project is supposed to help others create what they would "normally" create, but faster (i.e. as automated as possible). In this light, my question is how to you implement a PHP backend?
Here is what I do. I like to create "functions" that the client JavaScript can call. Usually, I send (via POST and JSON) a variable called "action" which holds the name of the "function" I am calling (as well as any arguments I wish to send it). The PHP code, then, looks something like this:
if(issset($_POST['action'])) {
//function foo(arg1,arg2)
if($_POST['action'] == 'foo') {
$arg1 = $_POST['arg1'];
$arg2 = $_POST['arg2'];
//do stuff
}
}
I can still reference other real functions I create in PHP, but I find that this is a nice way to organize everything and easy to implement in both JavaScript and PHP.
What do you do?
Edit 1: Ok, based on the first two answers to this question, I do not think I am explaining myself well.
I am asking how do you create a PHP back end. The idea is that you have your AJAX client written in JavaScript (or maybe something else, it doesn't matter), and then it will call your backend PHP with POST or GET data. Based on this data, your backend will do what it needs to do (maybe it will simply update the database, and maybe even return information, again: it doesn't matter).
The question now is: how do you tell it what to do? What do you send via POST/GET and how do you interpret it in your backend?
I send all data to the backend in a big GET array.
actionpage.php?action=post¶meters[parameter1]=value1¶meters[parameter2]=value2
If you print_r($_GET), on the PHP side you'll see:
array(
"action" => "create",
"parameters" => array("parameter1"=>"value1","parameter2"=>"value2")
)
What this does is allow you to loop through your parameters. You can say in the pap
if($_GET['action'] == 'create'){
foreach($_GET['parameters'] as $key=>$value){ //something
The question now is: how do you tell
it what to do? What do you send via
POST/GET and how do you interpret it
in your backend?
Choose your own conventions. For example use an "action" value in your JSON data that tells the action, then add more parameters. You can spy on various websites's Ajax messages with Firebug extension in Firefox if you want to see what other websites do.
For example the Json POST data could be:
{
action: "create",
fields: {
firstname: "John",
lastname: "Doe",
age: 32
}
}
To which you could reply with the ID of the newly created record.
To delete the record:
{
action: "delete",
keys: {
id: 4654564
}
}
etc.
In the php ajax handler you could have something as simple as a switch:
$jsonData = Services_Json::decode($_POST['json']);
switch ($jsonData->action)
{
case "save":
if (validate_json_data($jsonData->fields))
{
UsersPeer::create($jsonData->fields);
}
break;
case "delete":
/* etc */
}
// return a json reply with
$jsonReply = new stdClass;
$jsonReply->status = "ok";
$jsonReply->statusMessage = "Record succesfully created";
echo Services_Json::encode($jsonReply);
exit;
Javascript, say prototype Ajax.Request responder function will output the error message in a specially created DIV if "status" is not "ok", etc...
I use a front page controller which handles my routing. If you set up mod-rewrite you can have very clean endpoints where the first segment of your url refers to the controller (class) and then the subsequent segments would refer to the methods inside followed by the parameters being passed to the method.
http://domain.com/class/method/param1/param2
this website will answer all your ajax questions. I found it really helpful.
http://ajaxpatterns.org/XMLHttpRequest_Call
You need to organize functions? It's called 'class'.
/// todo: add error processing
$name=$_GET['action'];
$args=json_decode($_GET['args']); /// or just subarray, doesn't matter
/// 'Action' is constant here but in reality you will need more then one class for this
/// because you will want modules in your framework
if(method_exists('Action',$name))
call_user_func_array(array('Action',$name),$args);
else { /* incorrect parameters processing */ }
/// Ajax-available functions are here
class Action
{
public static function action1()
{
echo 'action1';
}
public static function action2()
{
echo 'action2';
}
}
I do something very similar. What you need is a JSON object to pass back to the javascript. When you are done with your PHP, you can call json_encode to pass an object back to the front end. From there you can do more with it in Javascript or format it however you want.
There is more information on a similar question here:
Best way to transfer an array between PHP and Javascript
Edit: After reading your edit, I think what you are doing is fine. When you send the AJAX request from Javascript include a variable like "action", or whatever youd like. From there you can check what the action is via a case and switch statement.
I usually write the php functions as normal functions.
fn1(arg1, arg2){
//do stuff here
}
fn2(arg3){
//do stuff here
}
I pass the name of the function in a variable called action. Then do this:
foreach($_POST as $key => $value)
$$key = $value;
To assign create variables of the same name as the arguments.
Then use a switch-case to call the appropriate function like so:
switch($action){
case 'fn1':fn1(arg1,arg2);
break;
case 'fn2':fn2(arg3);
break;
}
Is this what you are looking for?
Edit: You could use the PHP SOAP and XML-RPC extension to develop a webservice, where if you specify the function name in the SOAP request, that function will be automatically executed (you don't have to write the switch-case or if). I've used it in Java, but am not sure how exactly it works in PHP.
Related
Main issue was solved in comments, although one of the bonus questions is still open and the other's solution could use some improvement
All of this takes place on a webhosting service, the folder structure is as follows:
The JavaScript and PHP files are in /public_html/, the JSON is in /public_html/data/.
In my JS code, I'm sending a POST request with some data for my JSON file:
console.log(objdata.buildings[0].coords);
var params = JSON.stringify(objdata);
if (objdata.buildings[0].coords != " "){
$.ajax({
type: "POST",
data: params,
url: "writecoords.php",
success: function(data){
console.log(params);
console.log(data);
console.log("AJAX success");
},
error: function(){
console.log("failed to send POST");
alert("error");
}
});
}
PHP file:
<?php
function debug_to_console($data){
if(is_array($data) || is_object($data))
{
echo("\n".json_encode($data));
} else {
echo("\n".$data);
}
}
$newJSON = json_decode(file_get_contents('php://input'));
debug_to_console($newJSON);
if (is_writable('data/strogi.json')) {
$a = file_put_contents('data/strogi.json', $newJSON);
if(! $a)
debug_to_console("Wrote nothing");
debug_to_console("PHP write success");
} else {
debug_to_console("PHP write failed");
}
?>
As you can see, I perform a check at every possible point to see if I'm actually processing non-empty data -- I log the value of the key in question, the AJAX request is sent only if it was changed, I log the data being sent and I log the data my PHP file receives and decodes.
I also check if the file is writable to avoid a possible permission problem, and only then I try to write to the file. The file comes out empty and I get the following outputs in console
params is my JSON object as a single line;
data is: my JSON object as a single line with line breaks before every new object and all cyrillic converted to \u format, "Wrote nothing!", "PHP write success";
"AJAX success"
If I check the strogi.json file after this, it's absolutely empty.
To rule out a problem with the format of passed JSON object, I tried writing to a simple test.txt file in the same directory as the .php, which turns out empty as well.
I tried using the method described here, but nothing changed.
I tried using a FTP upload (the method is pointed out somewhere in the comments here), and I got "No such file or directory" returned both for the strogi.json and test.txt files. I used both public_html/test.txt and test.txt as file name.
I tried using the combination of locks FILE_APPEND | LOCK_EX, and no changes happen to either of the files.
My questions are:
Why?
Can a different solution be used if all of this is taking place in the .done() callback for $.getJSON() called on the same file?
Follow-up question worthy of a separate section:
coords is a 3-dimensional array
[
[[x1,y1],[x2,y2],...]]
]
where the external array contains up to two arrays. The first array contains points of the external polygon and (if present) second array contains points of the internal polygon that serves as a cutout.
The code in question is an attempt to make submitting the coords array to strogi.json work for at least one object.
What I'm trying to do, in general, is
$.getJSON() the data/strogi.json file
go through the buildings[] array of objects inside it in the .done()
callback
for each object, check if "coords" is " " (default value)
If it is, a constructor is called to build a polygon using a map API, and when construction is finished, $.ajax is used to submit coords extracted through one of API's functions.
As of now, I'm submitting the whole JSON object, because I'm only working with one of the inner objects, but I imagine resubmitting the whole thing is excessive with multiple objects presented.
Is there a way to pass objdata.buildings[i].coords with the index i to PHP to change the "coords" key value in JSON for a certain buildings[i] object?
Do I need to make any changes to the way I'm processing data to make my JSON valid upon further reads? I assume I'd have to change the "coords" value from [[[x1,y1],[x2,y2]]] (the way it's passed now) to something like this (pastebin because there's no code formatting even though I'm using the 4 space indent)
for it to work, right? How do I do that? partly solved by going through the array in JS with two for() loops and applying toString() to every coordinate, there's gotta be a better way
I have a website entirely coded with PHP. Let's consider the simple example in which a PHP script generates HTML/CSS code from data about a list of fruits, fetched in a MySQL data base :
<?php
function displayFruit( $fruit ) {
echo('<div>');
echo('<span class="fruit-color">Coulor : '.$fruit['color'].'</span>');
...
// display some other parameters of the fruit, with maybe some complex styles, etc.
...
echo('</div>');
}
// Get infos from dabase
$fruits = getAllFruitsFromDatabase();
// Display infos
foreach( $fruits as $fruit ) {
displayFruit( $fruit );
}
?>
Now, I want to add interactivity and to allow the user to filter according to some fruits characteristics (color, etc.) so that only the corresponding fruits are displayed.
So I add some controls and link them to Javascript AJAX queries. These queries will return the same type of data (even though not the same format) as what getAllFruitsFromDatabase() returned, and I want this data to be displayed the same way displayFruit() displayed it.
However, the issue here is that the display/styling process will now have to occur on the client side and not anymore on the server side.
Is there a technical way to factorize the PHP code (the one of displayFruit() ) and the Javascript code that will have to be used, so that there only exists one place where the HTML display code is written (and not once in PHP, and once again in JS) ?
What you describe is a very common problem for interactive web apps and there is not really one 'correct' solution for it. : )
It really depends on what you want in terms of PHP-vs-JS balance, but here are two possible solutions that avoid duplication of the HTML rendering code:
1. Always create the mark-up in Javascript, even on the initial page load
This works well if you want the bulk of your code to be on the client-side. In this solution, you wouldn't have a displayFruit($fruit) function in PHP, but you'd have the equivalent in your Javascript. You would render your page 'frame' on page load, and then do your AJAX call on the document-ready event.
2. Always create the mark-up in PHP, even on the filter-AJAX calls
This is perhaps a more balanced approach and has the advantage that you could design your code such that it's possible to run even if the client has Javascript disabled.
One way to do this is to pass an optional parameter to your page rendering function (in the PHP code) that will make it render only the data part, e.g. something like this:
function renderPage($filters = false, $dataOnly = false)
{
if (!$dataOnly) {
// Output the top of the page
}
// Output the data
// If $filters is not false, the getFruitsFromDatabase call will return filtered data
$fruits = getFruitsFromDatabase($filters);
foreach( $fruits as $fruit ) {
displayFruit($fruit);
}
if (!$dataOnly) {
// Output the bottom of the page
}
}
When your PHP script is called via AJAX, you pass your filters to the first argument of the renderPage function and true to the second argument.
Note on front-end frameworks:
exussum and Michael Chaney have mentioned Javascript frameworks. While I haven't used any of those myself, they look fantastic!
So If you're ready to invest time in re-writing your display logic in JS, then go for it. However, if you don't have much time and would like to re-use as much of your original PHP code as possible, then I would go for solution number 2. The decision probably also depends on the size and design of your existing code.
EDIT: had forgotten to add a $filters argument to the example function
EDIT 2: comment on front-end frameworks mentioned by others in comments
I have a page that asks for a country code in a ComboBox, and I want it to load some other ComboBox with certain values that depend on the first one.
The secondary data should be loaded using a function inside a PHP class, whose instance I need to capture. I'm still not very familiar with AJAX and jQuery, so that's my problem.
My code is like this (I omitted the most obvious parts, of course):
new.html
<script src="findIDTypes.js"></script>
<form>
<select id="country_id" onchange="findIDTypes(this.id)">
<option value="AR">Argentina</option>
<option value="BR">Brazil</option>
</select>
</form>
dbfunctions.php
class DBConn {
public function GetInstance($host = FALSE, $user = FALSE, $pass = FALSE) {
static $_instance = FALSE;
if ($_instance === FALSE) {
if ($host == FALSE || $user == FALSE || $pass == FALSE) {
// Error! Can't instantiate
}
$_instance = new DBConn($host, $user, $pass);
}
// OK!
return $_instance;
}
public function findIDTypes($country_id) {
// Returns array of value pairs (Code, Description)
}
}
findIDTypes.js
function findIDTypes(value_to_search) {
// ???
}
What I need my AJAX/jQuery (not sure which) function to do is:
Capture the instance of DBConn
Call the instance function "findIDTypes()" in the PHP class
Retrieve the array of (C,D) pairs and load them, one by one, on the secondary combobox
What exactly do I need to do to complete steps 1 and 2, if it's possible at all?
Thanks! :)
php and javascript are entirely different, and while you can use php to generate javascript code before the page is rendered, you cannot call php functions from javascript.
This is because php runs on the server, and javascript (which the exception of Node.js!) runs in the browser.
To solve this, you need to expose your php as an API using HTTP GET or POST methods.
Steps
Build your php page to accept $_GET url query parameters or $_POST parameters, in one form or another.
Decide upon a method of communicating your data on the server end back to your browser's javascript/ajax. For this, I highly recommend json for an innumerable number of reasons. It easily integrates with php via json_encode() and json_decode(), and javascript via JSON.parse() and JSON.stringify().
Once you've established your "API" as it were in php, you can easily use jQuery's $.ajax to send and retrieve data to your php. Since your example is relatively simple, it may be as easy as something like http://yoursite.com/?init=DBConn_GetInstance and handling the $_GET['init'] function, then outputting the results of your function.
I have a data javascript file, which is being dynamically added to website via some custom code.
This file comes from a third party vendor, who could potentially add malicious code in the file
Before this file is added to the website, I would like to parse through it, and look for malicious code, such as redirects or alerts, that inherently get executed upon a files inclusion in the project/website.
For example, my js file could look like this :
alert ('i am malicious');
var IAmGoodData =
[
{ Name :'test', Type:'Test2 },
{ Name :'test1', Type:'Test21' },
{ Name :'test2', Type:'Test22' }
]
I load this file into a object via a XMLHttpRequest call, and when this call returns, I can use the variable (which is my file text) and search it for words:
var client = new XMLHttpRequest();
client.open('GET', 'folder/fileName.js');
client.onreadystatechange = function()
{
ScanText(client.responseText);
}
client.send();
function ScanText(text)
{
alert(text);
var index = text.search('alert'); //Here i can search for keywords
}
The last line would return index of 0, as the word alert is found at index 0 in the file.
Questions:
Is there a more efficient way to search for keywords in the file?
What specific keywords should i be searching for to prevent malicious code being run? ie redirects, popups, sounds etc.....
Instead of having them include var IAmGoodData =, make them simply provide JSON (which is basically what the rest of the file is, or seems to be). Then you parse it as JSON, using JSON.parse(). If it fails, they either didn't follow the JSON format well, or have external code, and in either case you would ignore the response.
For example, you'd expect data from the external file like:
[
{ Name :'test', Type:'Test2' },
{ Name :'test1', Type:'Test21' },
{ Name :'test2', Type:'Test22' }
]
which needs to be properly serialized as JSON (double quotes instead of single quotes, and double quotes around the keys). In your code, you'd use:
var json;
try {
json = JSON.parse(client.responseText);
catch (ex) {
// Invalid JSON
}
if (json) {
// Do something with the response
}
Then you could loop over json and access the Name and Type properties of each.
Random Note:
In your client.onreadystatechange callback, make sure you check client.readyState === 4 && client.status === 200, to know that the request was successful and is done.
This is extremely difficult to do. There are no intrinsically malicious keywords or functions in JavaScript, there are malicious applications. You could be getting false positives for "malicious" activity and prevent a legitimate code with a real purpose from being executed. And at the same time, anyone with a little bit of imagination could bypass any "preventive" method you may implement.
I'd suggest you look for a different approach. This is one of those problems (like CAPTCHA) in which it's trivial for a human to solve while for a machine is practically impossible to do so. You could try having a moderator or some human evaluator to interpret the code and accept it.
You should have them provide valid JSON rather than arbitrary Javascript.
You can then call JSON.parse() to read their data without any risk of code execution.
In short, data is not code, and should not be able to contain code.
You shouldn't. The user should be allowed to type whatever they want, and it's your job to display it.
It all depends on where it is being put, of course:
Database: mysql_real_escape_string or equivalent for whatever engine you're using.
HTML: htmlspecialchars in PHP, createTextNode or .replace(/</g,"<") in JavaScript
JavaScript: json_encode in PHP, JSON.stringify in JavaScript.
At the end of the day, just don't be Yahoo
how do we check if table is empty with cakephp and ajax? In my index.ctp I have an image that when clicked, it will inform the user if the table is empty or not. If it's empty, an alert box will appear, and if it's not, it will be redirected to another page.
<?php
echo $this->Html->image('movie.png', array('onclick'=>'check()'));
?>
JAVASCRIPT:
function check(){
//check browser comp, create an object
object.GET("GET", url, false);
//rest of the code here
}
MoviesController.php
function index(){
//something here
$moviecount=$this->Movies->find('count');
$this->set('moviecount', $moviecount);
}
I know how to do it using the normal PHP coding, but with cakephp, and since I am new, I dont know yet. For regular PHP coding, I used the GET method for AJAX, and I can specify the URL for the PHP query inside the GET function. I don't know how to do it using cake.
You need to set the layout to AJAX then render your view. I strongly recommend not to use the index() method for this. Instead you can define a whatever() method in the MoviesController:
function whatever(){
//It is not a bad idea to do this only for GET - use the RequestHandlerComponent
$this->layout = 'ajax';
$moviecount=$this->Movies->find('count');
$this->set('moviecount', $moviecount);
}
The in the view file whatever.ctp:
echo json_encode(array('moviecount' = $moviecount));
//It is a good idea to add an isset() ternary check here like:
// echo isset($moviecount) ? json_encode(array('moviecount' => $moviecount)) : json_encode(false);
Notice that I am creating an array and encoding it to JSON. This is the way to convert variables to and from JSON. To decode use json_decode() of course.
The Client-side code really depends on what you're using to make the AJAX call but let us say that the call succeeded and you got the data back in the data variable:
//Make the AJAX call to example.com/movies/whatever via GET
//Check what data is but it should definitely be an array
if (data['moviecount']) {
//If moviecount is 0 it will go in the else statement - 0 i falsey
window.location = 'example.com/redirect/url';
} else {
alert('No records');
}
I advice against using alert() to inform the user that there are no records. Better put it somewhere in the page - in some div or whatever. Since this is an AJAX request it could be repeated many times. Consecutive use of alert() is not really user-friendly in this case.