I have a Model Class which has a function which takes an array of filenames as an argument. It runs a foreach on the files and processes them.
The 1st line of the foreach is $_SESSION["file_processing"] = $file;
I have a js function that is called periodically and fetches $_SESSION["file_processing"] and outputs it in a div. This is how i plan to show to the user what file is being processed at the moment.
My js Functions :
function call_files_all_together() {
alert("You will start getting emails for all files. Thanks !");
var log = setInterval(function(){ProcessingFilesLog()},5000);
$("#ajax-loader-gif").html("<img src = \"/images/ajax-loader.gif\" />");
$.ajax({
type : 'POST',
url : '/query-set/create-all-files/'
}).done(function(data) {
alert(data);
clearInterval(log);
$("#ajax-loader-gif").empty();
});
}
function ProcessingFilesLog() {
console.log("get log called");
$.ajax({
type : 'POST',
url : '/query-set/file-log'
}).done(function(data){
console.log(data);
if(data != "")
$("#files-log").append(data + "<br/>");
else
console.log("empty data");
});
}
My controller function is below :
public function createAllFilesAction() {
$this->_helper->viewRenderer->setNoRender();
$this->_helper->layout->disableLayout();
$qs = new Model_QuerySet;
$qs->createAllFiles();
echo "Files Sent!";
// unset($_SESSION["file_processing"]);
}
public function FileLogAction() {
$this->_helper->viewRenderer->setNoRender();
$this->_helper->layout->disableLayout();
$log = $_SESSION["file_processing"] ;
var_dump($_SESSION);
echo $log;
}
My Model Functions :
public function createAllFiles() { #all
$db = Zend_Db_Table::getDefaultAdapter();
$ex = new Model_ExcelHandling;
foreach ($this->filename as $name=>$data){
echo $name.PHP_EOL;
$_SESSION["file_processing"] = $name;
//Do my things here.
}
}
The 1st time I run the script, I do not see the key "file_processing" in the $_SESSION array. The second time I run it, I see that $_SESSION["file_processing"] holds the value of last file that was processed when executed previously.
I seems like $_SESSION gets updated only after the loop ends or something down those line, I am not 100% sure.
I would appreciate any help..
Thank you
The $_SESSION variable is only updated after the script finishes, according to php.net:
Session data is usually stored after your script terminated without the need to call session_write_close(), but as session data is locked to prevent concurrent writes only one script may operate on a session at any time. When using framesets together with sessions you will experience the frames loading one by one due to this locking. You can reduce the time needed to load all the frames by ending the session as soon as all changes to session variables are done.
You will need to use something other than $_SESSION to persistently store the data, because I don't believe you can get $_SESSION to save multiple times for in a single script/request. One possible solution is to save the data in a database. It is up to you to figure out which persistent storage method you wish to use.
EDIT:
I may have spoken too soon. Perhaps you can use session_write_close() and then follow it up with session_start() after each assignment to the $_SESSION variable.
Related
I am developing a plugin in which I get data from API, and then the user has an option to add this data to the cart and purchase the product. Everything works perfectly, except once we reload the page, the user cart value gets lost. How can I solve this?
I think one solution is, If we add the cart object to the session, it will be easy to use that session value to get the cart object. For this, I added the below function
my_file.js
function savecartObj(cartObj) {
$.post(
'cartObj.php',
{
cartobj : cartObj
},
function success(data) {
console.log(data);
}
);
}
and in my cartObj.php
<?php
/** Set up WordPress environment, just in case */
$path = preg_replace('/wp-content(?!.*wp-content).*/','',__DIR__);
require_once($path.'wp-load.php');
session_id() || session_start();
nocache_headers();
$_SESSION['ajjx'] = $_POST;
$value = '';
if (array_key_exists('ajjx', $_SESSION)) {
if (array_key_exists('cartobj', $_SESSION['ajjx']) {
$value = $_SESSION['ajjx']['cartobj'];
}
}
Header('Content-Type: application/json;charset=utf8');
die(json_encode(array(
'result' => $_SESSION['ajjx']['cart_obj'],
)));
Now I can see that $_SESSION['ajjx']['cart_obj'] is set and in console.log(data); I can see the session value. How can i use this value from $_SESSION['ajjx']['cartobj'] as cartobj in my_file.js
What I need is will create one file named get_session.php and in
that file, I will call the value of $_SESSION['ajjx']['cart_obj'] .
And then once my plugin is loaded I will call the value in
get_session.php & need to take the obj from the file and then add that value to add to cart function in the my_file.js. In that way, page reload doesn't
affect my cart.
Update
For getting the value I write the following function in my my_file.js
function get_cartObj(){
$.post(
'get_cartObj.php',
function success(data) {
console.log(data);
}
);
}
and in get_cartObj.php
<?php
/** Set up WordPress environment, just in case */
$path = preg_replace('/wp-content(?!.*wp-content).*/','',__DIR__);
require_once($path.'wp-load.php');
session_id() || session_start();
nocache_headers();
Header('Content-Type: application/json;charset=utf8');
json_encode(array(
'result' => $_SESSION['ajjx']['cart_obj'], // This in case you want to return something to the caller
));
but here get_cartObj() is not working as expected. No data coming in console.log(data);
The same way you saved it. Actually you can add a parameter to (save)CartObj:
function cartObj(operation, cartObj) {
$.post(
'cartObj.php',
{
op : operation,
cartobj : cartObj
},
function success(data) {
console.log(data);
}
);
}
and in the PHP code (7.4+ required because of the ?? operator)
if ($_POST['operation'] === 'set') {
$_SESSION['ajjx']['cartObj'] = $_POST['cartObj'] ?? [ ];
}
$value = $_SESSION['ajjx']['cartObj'] ?? [ ];
Header('Content-Type: application/json;charset=utf8');
die(json_encode(['result' => $value]));
Now calling the function with 'set' will save the Javascript cart into session, using 'get' will recover the cart.
update
You can also do it like this:
assuming that your page might receive a cart or it might not,
and you will always run the same AJAX code regardless,
then the PHP code must avoid removing the cart if the cartObj parameter is empty (you will need a different call to remove the cart when you need to do this; or you may do it from PHP).
session_id()||session_start();
if ('set' === $_POST['operation'] && !empty($_POST['cartObj'])) {
$_SESSION['ajjx']['cartObj'] = $_POST['cartObj'];
}
Header('Content-Type: application/json;charset=utf8');
die(json_encode(['result'=>$_SESSION['ajjx']['cartObj']??[]]));
This way, if you reload the page but the POSTed cart is now empty (because it's a reload), the AJAX script will not update the session, and it will return the previous session value.
Before im going to answer the question i have some dubt to clear, it looks like you are in a wordpress environment but you are not using his AJAX standard procedures. Check it out here https://codex.wordpress.org/AJAX_in_Plugins
About the issue since JS is client side and PHP is server side you need something to have the values available in JS. I can think of two option:
Print into the page with some PHP a little script tag which is made like this:
<script>
var myObjectVar = '<?php echo json_encode($_SESSION['ajjx']['cart_obj']); ?>';
</script>
You make a new AJAX call as soon as the page load to read that same value from PHP again and then use it to make what you need to do
i want to get data echoed in the remote php after i sent the main request and before i get the complete response.
the intent is to show "i am almost there - 5 items remaining" or similer...
This is my current js script:
function getdetails(){
$("div#urltable").fadeOut('fast');
$("div#ajaxLoading").fadeIn('fast');
var checkurl = $('input#remoteurl').attr('value');
if($("#checkBrokenLinks").prop('checked') == true){
var checkonline = 'check';
}
else {
var checkonline = 'skip';
}
$.ajax({
type: "POST",
url: "ajax-outlink_checker.php",
data: {checkurl:checkurl, checkonline: checkonline}
}).always(function(data) {
var $response = $(data);
var whileRuningCount = $response.filter('#whileRuningCount').html();
$("div#whileRuningCount").fadeOut('fast');
$("div#whileRuningCount").fadeIn('fast');
$("div#whileRuningCount").html(whileRuningCount);
}).done(function(result) {
var $response=$(result);
var urltable = $response.filter('#urltable').html();
var whileRuningCount = $response.filter('#whileRuningCount').html();
$("div#ajaxLoading").fadeOut('fast');
$("div#urltable").fadeIn('fast');
$("div#urltable").html(urltable);
});
}
As you can see
i added .always() trying to grab the echo's the run in the php file.
but... i guess i missunderstand how to make it work and if .always
is even the way to go about it.
Any help would be most apreaciated.
Best regards, Sagive.
You'll need to make 2 separate ajax calls. 1 for the initial request, and then a second one repeated as often as needed to check for status updates. The action responder will need to update some variable for the status responder to check. How you communicate the status to the other responder is up to you. One method is to simply use a file. Your action responder will call handleaction() while the status responder will only call statuscheck():
<?php
function handleaction()
{
$actions_left = 0;
while ($actions_left > 0)
{
perform_action();
status_update(--$actions_left);
}
}
function status_update($remaining)
{
$filename = "/" . session_id() . "_action_status.txt";
$fh = fopen($filename, "w");
fputs($fh, $remaining);
fclose($fh);
}
function statuscheck()
{
$filename = "/" . session_id() . "_action_status.txt";
echo #file_get_contents($filename); // js treats empty response as 0.
}
?>
.always() is not for that. It just means that whether the request was success/done() or fail() run what is in that snippet.
If you are trying to show an "almost there.." message, a better way would be to have another async call to the server which polls every N seconds, looks at some data state in the server, (a flag maybe?) and based on that shows a message in the front end..
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 was wondering if it's possible to long poll using $.getJSON and what the proper front and back end logic would be.
I've come up with this so far but haven't tested it yet since I'm pretty sure there is wrong and/or missing logic.
Here is the JS:
function lpOnComplete(data) {
console.log(data);
if (!data.success) {
lpStart();
}
else {
alert("Works!");
}
};
function lpStart() {
$.getJSON("http://path.to.my.URL.php?jsoncall=?", function(data) {
// What happens when no data is returned
// This is more than likely since there
// is no fall back in the PHP.
lpOnComplete(data);
});
};
PHP:
$time = time();
while((time() - $time) < 30) {
// only returns data when it's new.
$data = checkCode();
// What would be the proper way to break out
// and send back $data['success'] = false
// so the JS loop can continue?
if(!empty($data)) {
echo $_GET["jsoncall"] . "(" . json_encode($data) . ")";
break;
}
usleep(25000);
}
From what you've got there, the Javascript is going to make multiple requests to the server and each one is going to spin up that infinite loop, and never go anywhere. I'd suggest something like: js:
$.getJSON("http://my.site/startAsyncWork.php", null, function(data){
waitUntilServerDone(data.token, function(response){
alert("done");
});
});
function waitUntilServerDone(token, doneCallback){
$.getJSON("http://my.site/checkIfWorkIsDone.php", {"token": token}, function(response){
if(response.isDone){
doneCallback(response);
}
else{
setTimeout(function(){
waitUntilServerDone(token, doneCallback);
}, 1000);
}
});
}
I don't know php, so I'm not going to write sample code for that side, but basically, startAsycWork.php makes up a random token that associates to the request. Then it spawns a thread that does all the work needed, and returns the token back to the response.
When the worker thread is done, it writes the results of the work out to a file like token.dat (or puts it in a cache or whatever).
checkIfWorkIsDone.php checks for the existence of token.dat, and returns false if it doesn't exist, or returns the contents if it does.
Good day. I am having the following code snippet in init.php.
<?php
include_once("config.php");
include_once(__SITE_PATH . 'view/' . $_REQUEST['page'] . EXT);
$loginobj = new $_REQUEST['page']($_REQUEST['billingentitynuber']);
$text = $loginobj->$_REQUEST['content']();
echo $text;
?>
In Jquery I am having the function Jquery_event.js
$("#entertoapp").click(function()
{
alert($("#btval").val());
$.ajax({
type: "POST",
url: "init.php?page=processing&content=enterintoapplication&btval=" + $("#btval").val(),
success: function(msg) {
alert(msg);
if(msg==1)
window.location.href='index.php?page=processing&content=mycontent';
}
});
});
In processing.php I am having
<?php
class processing
{
public function enterintoapplication()
{
global $billingentityname;
$_SESSION['btval'] = $billingentityname;
echo $billingentityname;
}
}
?>
My problem is I am getting all the parameters in the init.php. But when I call a function I need to get in the processing.php in the enterintoapplication function (i.e. I am expecting btval in the enterintoapplication function). How can I achieve this? I tried to get $_REQUEST['btval'] within the function. But I didn't get.
Try assigning the values to variables, for example this works for PHP 4:
class processing
{
function enterintoapplication()
{
echo "hello";
}
}
$className="processing";
$functionName="enterintoapplication";
$loginobj=new $className();
$text=$loginobj->$functionName();
echo $text;
Paste it here to verify it works: http://writecodeonline.com/php/
Pls,pay attention to "$functionName", here it keeps the "$".
Nevertheless, for security reasons, you should be attentive to what people can do if they change the value "page".
I don't understand your problem correctly, but with some general information, you should get out of this.
$_REQUEST is a superglobal, that means that variable will always be accessible from everywhere within your script. If your problem is you can't find the btval variable that was in your URL, you are doing something else wrong. If your url=http://someUrl/test.php?btval=banana you should always get banana if you evaluate $_REQUEST['btval']. $_SESSION is another superglobal to access the PHP session, and has nothing to do with URL variables.
My guess:
Try changing
$_SESSION['btval'] = $billingentityname;
into
$billingentityname = $_REQUEST['btval'];
In that case, your real mistake was that you've put the two variables in this assignment in the incorrect order. $a = $b means: put the contents of $b into $a.