I have a page with a WYSIWYG editor the user can use. After editing, they can press a button, and the javascript should POST the current page to a save.php file and refresh the page with new information.
There are two problems. The first is that initially the page doesn't load with the updated file. The user has to refresh the page to see it updated (maybe it just takes an extra second to write the file?). The second problem, is that after the first time the temporary file was created, it cannot be overwritten, so the page never updates after the first refresh. Here are the snippets I'm working with:
Javascript function on the WYSIWYG editor page (editor.php):
function refresh(html,username,info)
{
$.post("save.php", { html: html, username: username } );
window.location = 'editor.php?info=' + info;
}
save.php file
$html = $_POST['html'];
$username = $_POST['username'];
file_put_contents('temp/' . $username . '.txt', $html);
As the browser may not have issued the POST request before navigating to the next page, use the success callback from the post to do the relocate:
function refresh(html,username,info) {
$.post("save.php", { html: html, username: username }, function() {
window.location = 'editor.php?info=' + info;
});
}
As other people have already commented, using data directly from a form post without sanitising it is a really bad plan and opens your server up to all kinds of malicious attacks. Have a look at some of these questions: https://stackoverflow.com/search?q=sanitize+php
If the data is getting to your server ok, make sure that the access permissions on the directory 'temp' allow write access from the web server user (if you have access to SSH to your server, run chmod go+w /path/to/temp, otherwise most FTP programs allow you to set file permissions too).
why not use fopen and fwrite?
simply use:
$html = $_POST['html'];
$username = $_POST['username'];
$file = "temp/" . $username . ".txt";
if (!file_exists($file)) {
$files = fopen($file, "x+");
} else {
$files = fopen($file, "w+");
}
if(fwrite($files, $html)) {
echo "Success!";
} else {
echo "Failure!";
}
for the php and to make the refresh work in js, try putting the statement in the success function like this:
function refresh(html,username,info) {
$.post("save.php", { html: html, username: username },
function (response) {
window.location = 'editor.php?info=' + info;
console.log(response);// for debugging :)
});
}
The ajax request is asynchrone so the writing operation can be in progress when the redirection is started. You have to listen to the finished exent of the $.post action to do the redirect.
Related
I have a page that allows users to upload multiple files and preview them without refreshing the page using jquery. In php I generate a unique file_id for each filename which I would then like to pass back in to JQuery and use it to load up the preview image etc.
I hope I have explained myself clearly.
Thanks for any pointers!
The PHP code:
// php code to upload file and generate unique file id. then...
if (move_uploaded_file($main_image, $file)) {
echo "success";
echo $file_id; // <--- I WANT TO PASS THIS VARIABLE BACK IN TO JQUERY
} else {
echo "error";
}
The J Query Code:
$(function(){
var btnUpload=$('#upload_main');
var mestatus=$('#mestatus');
var button=$('#button');
var files=$('#main_file');
new AjaxUpload(btnUpload, {
action: 'classified-ads/upload-classified-image.php?filenumber=1',
name: 'file1',
onSubmit: function(file, ext){
if (! (ext && /^(jpg|png|jpeg|gif|'')$/.test(ext))){
// extension is not allowed
mestatus.text('Only JPG, PNG or GIF files are allowed');
return false;
}
mestatus.html('<img src="extras/ajaxuploader/progress_bar.gif" height="30" width="340">');
button.html('Loading...');
$('#upload_main').removeClass('hover').addClass('upload_button_loading');
},
onComplete: function(file, response){
//On completion clear the status
mestatus.text('Photo Uploaded Sucessfully!');
button.html('Change Photo');
$('#upload_main').removeClass('upload_button_loading').addClass('upload_button');
//On completion clear the status
files.html('');
//Add uploaded file to list
if(response==="success"){
var file2 = file.replace(/\s/g, "_");
var file_id= file_id;
$('<div></div>').appendTo('#main_file').css('background-image', "url(/ht/classified-ads/temp_images/prev1_<?php echo $parsed_user;?>_"+file_id+")").addClass('main_success');
$("#image1_temp").val("main1_<?php echo $parsed_user;?>_"+file_id+"");
$("#thumbnail_temp").val("thumbnail_<?php echo $parsed_user;?>_"+file_id+"");
} else{
$('<li></li>').appendTo('#main_file').text(file).addClass('error');
}
}
});
});
In your PHP:
$response = array('result' => 'success', 'file_id' => $file_id);
echo json_encode($response);
In your jQuery:
var obj = $.parseJSON(response);
You would then check whether the response was a success with if (obj.result == 'success') and you'd get your file_id with obj.file_id
The simplest way is to do this allowing for MULTIPLE values to be returned:
// Make a variable to hold data to send back and keep track of your separator
$data = '';
$separator = 1;
// Put this in a loop, your loop will depend on how many file uploads you have
// I did not do the loop for you
if (move_uploaded_file($main_image, $file)) {
// echo "success"; Take this out
if ($separater==1){
$data .= $file_id;
} else {
$data .= ','.$file_id;
}
$separater++;
}
// Now outside the loop echo the results back
echo $data;
With this info echoed back you can manipulate it with Javascript (Jquery). Just use something like spli(','); which gives you an array of the file names you needed.
If you only want one value to come back, meaning you only have one file id to send back foregt everything about the loop and the PHP would be this:
if (move_uploaded_file($main_image, $file)) {
// echo "success"; Take this out
$data = $file_id;
// Now echo the results back
// Its been a while since I've done this but there may be times its ok to use return
echo $data;
} else {
// Handel error here
echo "error";
}
Now based off your code this echoed information should be picked up and processed here:
onComplete: function(file, response){ ... }
Instead of looking for "Success" you need to change your code to look for a file id or something like error instead (which is easier) like so:
if(response!=="error"){
// Now you can use your variable "response" here since it contains the file id
} else {
// Handle the error
}
The reason I gave you a long explanation about getting multiple values back is because that is more common as you start making more advanced forms and it wouldn't hurt to use now. This way you can allow multiple file uploads for example. What I do for example when using AJAX is echo back something like this:
1::value,value,value
Now I just split that into arrays first by :: and then by , this line for example says No Error Happened (1 which as we know is also TRUE) and here is your data: value,value,value which you can now use for things in your Jquery or just print to the document.
You should look at the Jquery AJAX page for in depth examples and explanations, it explains the trouble you ran into getting results back. Look at .done .success .complete especially.
I have this script in a .html file on my page and im trying to just run the getip.php file from here rather than to rename the file to .php. I tried this ajax call but its not working and not logging the ip in the logfile.txt. Please let me know what I am doing wrong.
Ajax in the head of the .html file:
<script>
$(document).ready(function() {
$.ajax({
type: "GET",
url: "getip.php",
}); // Ajax Call
}); //event handler
</script>
Code from getip.php:
<?php
// location of the text file that will log all the ip adresses
$file = 'logfile.txt';
// ip address of the visitor
$ipadress = $_SERVER['REMOTE_ADDR'];
// date of the visit that will be formated this way: 29/May/2011 12:20:03
$date = date('d/F/Y h:i:s');
// name of the page that was visited
$webpage = $_SERVER['SCRIPT_NAME'];
// visitor's browser information
$browser = $_SERVER['HTTP_USER_AGENT'];
// Opening the text file and writing the visitor's data
$fp = fopen($file, 'a');
fwrite($fp, $ipadress.' - ['.$date.'] '.$webpage.' '.$browser."\r\n");
fclose($fp);
?>
Have you tried $.post() function instead? Example:
<script>
$(document).ready(function() {
$.post('getip.php'); // Ajax Call
}); //event handler
</script>
You can also add a callback as a second parameter.
I would use the full URL for the ajax call. Depending on your framework you might not be hitting the intended endpoint. You could try echo 'test'; in your php file and adding a done handler to your ajax call to make sure you're hitting the php file in the first place:
.done(function( data ) {
alert(data);
});
I have a simple registration form and the new comers will be registered with an ajax function. There I create a $_SESSION['is_logged'] when the registration is finished.
On var_dumb I get that the var is set. But when redirect on another page it is empty (I have included already the session_start() on the both pages...
I have read somewhere in the net that:
"Sessions are ONLY written on a page load/refresh".
Is this the case, or I have to look for some other issues within my code.
the ajax:
$.ajax({
url:"../controllers/register.php",
type:"POST",
data:res,
success: function(responce){
if (responce==1) {
$('#msg').addClass('msg-warning');
$("#form").css('display',"none");
$('#msg').append("<p>It seems that you have already submited the form. Click to "+
" <a href='login.php'>log-in</a> or to <a href='register.php'>register</a>.</p>");
}
else if (responce==2) {
$('#msg').addClass('msg-warning');
$("#form").css('display',"none");
$('#msg').append("<p>You have successfully created account. Click to "+
" <a href='start.php'>welcome</a> to start your .</p>");
$('.menu').append("<li><a href='logout.php'>Log out</a></li>")
}
else{
$('#msg').text(responce);
}
},
error: function(){
$('#msg').text("Opss, try again");
}
});
the register.php file:
if (isset($_SESSION['submited'])) {
echo 1;
exit;
}
include_once('../models/functions.php');
// Give the post parametters to another var
$arr=$_POST;
// function for uploading
$reg = registerMe($arr);
if ($reg === true) {
$_SESSION['submited']=1;
$_SESSION['is_logged']=1
echo(2);
}
else{
echo($reg);
}
exit;
The session_start(); is included in the header of the first page where from the ajax is started.And the second page - where the $_SESSION['is_logged'] is lost, again the session_start(); is part of dc_header(); function. start.php:
<?php
dc_header("Речник|Регистрация");
if (!isset($_SESSION['is_logged'])) {
#header("location: ../views/login.php");
var_dump($_SESSION);
}
?>
add
session_start();
to the top of register.php
You need to specify session_start, so your server who was commanded to execute "register.php" (either from ajax, direct call, browser scripts, cron job or whatever possible you-name-it) will handle the execution and the setting of $_SESSION variables in reference to the connected clients session. Server won't guess by itself that this is an "ajax call from an already session_start page". You need to specify that whatever is done in register.php is done in the current client's session.
I'm looking for a PHP component for asynchronous data processing.
Basically what I need is to display a page with a progress bar that's refreshed with javascript which displays the progress on some data processing.
On the backend you'll define your data process limit. This is the start, end and function to call for processing individual items.
There are plenty of solutions for this on CMS and frameworks. I'm looking for something in raw PHP that I can include in my application.
I did something similar not too long ago. I wrote a function that logs the progress to a text file as a JSON object. Then I wrote a PHP function that returns that JSON object to the browser at certain intervals as requested by jQuery.
My PHP code looks similar to this:
function logProgress($task, $status, $progress) {
$basedir = "/var/www/" . SITE_ROOT . "/";
$log_file = $basedir . "logs/progress.log";
$logFileContent = file_get_contents($mrp_log_file);
if($logFileContent){
$logFileArray = json_decode($logFileContent, TRUE);
} else {
$logFileArray = array();
}
$logFileArray[$task]=array('task'=>$task,'status'=>$status,'progress'=>$progress);
$logFile = fopen($log_file, 'w+') or error_log("Failed to open progress file $mrp_log_file for writing");
fwrite($logFile, json_encode($logFileArray));
fclose($logFile);
}
Retrieving the data is as simple as this:
function readProgressLog() {
//Returns a JSON object stored in the progress log.
$basedir = "/var/www/" . SITE_ROOT . "/";
$log_file = $basedir . "logs/progress.log";
$logFileContents = file_get_contents($log_file);
return $logFileContents;
}
From jQuery, you would make two AJAX calls, one to initiate your process, and one to poll the text file. My javascript for the polling call looks like this:
function updateProgress() {
var data = {
action:'getProgressUpdate'};
var settings = {success: function(json){
var done = false;
if(json!=null) {
//Put your code to update the progress bar here.
//I look for a JSON property called Done to flag the process as completed.
if(json.Done==null) {
var t2 = setTimeout("updateProgress()", 1000);
} else {
clearTimeout(t2);
done = true;
clearProgressLog();
}
} else {
var t2 = setTimeout("updateProgress()", 1000);
}
},
data:data,
cache:false,
type: 'POST',
dataType:"json"};
$.ajax('/ajax/polling.ajax.php', settings);
}
One thing I noticed is that you should make sure your polling AJAX call uses a different PHP file than your process AJAX call, otherwise your polling call won't finish until the process call is finished.
I'm a WordPress designer, I developed a contact form for one of my themes that's validated via jQuery.
Please check the code below, then read the notes beneath.
$('.submitemail') .click(function() {
//VALIDATION CODE GOES HERE
if ( /*VALIDATED SUCCESSFULLY*/ ) {
$.ajax({
type: 'POST',
url: templatePath+'/lib/scripts/sendEmail.php',
data: 'visitorname=' + visitorname + '&visitoremail=' + visitoremail + '&visitormessage=' + visitormessage,
success: function(contactResults) {
//SUCCESS CODE
}
});
}
});
Notes:
sendEmail.php is a correct script that sends email using PHPmailer class.
templatePath variable has the value of the full template path which looks like this: http://somedomain.com/wp-content/themes/themename
The jQuery code above is located in lib/scripts/jfunctions.js (same directory of the php script)
The whole process (ajax and php) works perfectly as expected in many servers, (tested in two servers by me and other servers by my theme users).
The Problem:
In SOME servers, the success handler is not triggered while the ajax call to sendEmail.php is actually passed successfully and the php script is processed and email is sent.
When I check with firebug to see why the success handler is not triggered, firebug shows "not found 404 error", It's like a false alarm.
Possible causes:
I think some servers is configured to block such ajax calls.
What might be the cause for this weird issue? How to fix it?
Thanks in advance.
#nowk: sendEmail.php code is:
<?php
// Code for loading WordPress environment goes here //
$themeName_optionTree = get_option('option_tree');
$name = trim($_POST['visitorname']);
$email = $_POST['visitoremail'];
$message = $_POST['visitormessage'];
$site_owners_email = $themeName_optionTree['owner_email'];
$site_owners_name = $themeName_optionTree['owner_name'];
$email_subject = $themeName_optionTree['email_subject'];
$success_message = '<p class="success-box">' . $themeName_optionTree['success_message'] . '</p>';
if (strlen($name) < 2) {
$error['name'] = 1;
}
if (!preg_match('/^[a-z0-9&\'\.\-_\+]+#[a-z0-9\-]+\.([a-z0-9\-]+\.)*+[a-z]{2}/is', $email)) {
$error['email'] = 1;
}
if (strlen($message) < 2) {
$error['message'] = 1;
}
if (!$error) {
require_once('PHPMailer_v5.1/class.phpmailer.php');
$mail = new PHPMailer(true);
try {
$mail->From = $email;
$mail->FromName = $name;
$mail->Subject = $email_subject;
$mail->AddAddress($site_owners_email, $site_owners_name);
$mail->Body = $message;
$mail->Send();
echo $success_message;
} catch (phpmailerException $e) {
echo '<p class="warning-box">' . $e->errorMessage() . '</p>';
} catch (Exception $e) {
echo '<p class="warning-box">' . $e->getMessage() . '</p>';
}
}
?>
Please note that the above code executes perfectly even when ajax returns 404, weird huh!.
Since the server sends a 404 (for god knows what reason), there are two ways to fix/circumvent this:
Ignore the HTTP response code and change success to complete in the jQuery ajax call, so that the handler is executed when the request is done no matter the server response. You know the server response (it always works). The HTML should still be available in the jQuery complete handler.
Overwrite the 404 that something sends on the server (probably something Wordpress) by executing (before printing any output): header('HTTP/1.1 200 OK'). Since the script is executed, this will overwrite the crazy 404 and jQuery will receive that 200 and execute the success handler.
You could try both =) I'm pretty sure the first one will work (but that's not so clean). I'm also pretty sure the 2nd will work, but I don't know Wordpress well enough to make promises =)
I'm guessing it's because Wordpress already has an AJAX mechanism built in and it stops you from implementing it on your own. This page explains how to add AJAX to plugins:
http://codex.wordpress.org/AJAX_in_Plugins
Here's a snippet from the page:
Ajax on the Administration Side
Since Ajax is already built into the core WordPress administration screens, adding more administration-side Ajax functionality to your plugin is fairly straightforward, and this section describes how to do it.
Here's a short example. All this will be in one file.
First, add some javascript that will trigger the AJAX request:
<?php
add_action('admin_print_scripts', 'my_action_javascript');
function my_action_javascript() {
?>
<script type="text/javascript" >
jQuery(document).ready(function($) {
var data = {
action: 'my_action',
whatever: 1234
};
// since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
$.post(ajaxurl, data, function(response) {
alert('Got this from the server: ' + response);
});
});
</script>
<?php
}
Then, set up a PHP function that will handle that request:
<?php
add_action('wp_ajax_my_action', 'my_action_callback');
function my_action_callback() {
global $wpdb; // this is how you get access to the database
$whatever = intval( $_POST['whatever'] );
$whatever += 10;
echo $whatever;
die(); // this is required to return a proper result
}
That's it! You will need to add a few details, such as error checking and verifying that the request came from the right place ( using check_ajax_referer() ), but hopefully the example above will be enough to get you started on your own administration-side Ajax plugin.
NOTE: Since Version 2.8, The javascript global variable ajaxurl can be used in case you want to separate your javascript code from php files into javascript only files. This is true on the administration side only.
As seen here https://cooltrainer.org/fixing-false-404-headers-on-external-pages-including-wp-blog-header-php/ this solution tested and works well:
require_once("path/to/wp-config.php");
$wp->init();
$wp->parse_request();
$wp->query_posts();
$wp->register_globals();
$wp->send_headers();
Without digging into the problem, you might check that the ajax request is actually going where you think it is going. There could be several things going on here, such as the server is set up to redirect any requests to /wp-content/ somewhere else.
Capture some header information using firebug, and perhaps livehttp headers.