PHP bulk processing solution - php

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.

Related

Save API response to server as JSON file with AngularJS

I'm trying to create an app in AngularJS that aggregates data from multiple APIs. With some public APIs there are request limits and much of the data I want to pull is not updated very frequently, so only one request a month for a particular ID is necessary. To get past this, I've set up a Factory that first checks for a local file on the server, if it is not present, it then goes to the API and performs a GET request.
From there, once the request is complete, I want to save that file to the server with a name set by a field in the response.
I've found some examples using PHP with AngularJS but I'm not sure on how to save the JSON file with the dynamic name...or if this is even the best thing to do in order to avoid the request limits.
var apiUrl = 'https://example.com/api?userID=';
$http.get(apiUrl + $stateParams.userID).
success(function(data) {
$scope.content = data;
$scope.userID = data.userID
function(){
$http.post('saveJson.php', $scope.content).then(function() {
// log success
});
};
}).
error(function() {
// log error
});
PHP
<?php
$json = file_get_contents("php://input");
$file = fopen('/var/www/USERID.json','w+');
fwrite($file, $json);
fclose($file);
?>
If you do this in a service, and just call a method from a view button click, it would be more like this:
angular.module('app.services', [
])
.service('MyService', function ($http) {
var MyService = this;
this.aggregatedData = { content: [], filename: null };
this.apiUrl = 'https://example.com/api?userID=';
this.saveUrl = 'saveJson.php';
this.getData = function (url) {
return $http.get(url + $stateParams.userID).then(function (response) {
MyService.aggregatedData.content.push(response.data);
});
};
this.saveData = function (url, fileName) {
this.aggregatedData.filename = fileName;
return $http.post('saveJson.php', this.aggregatedData).then(function () {
// do something with the post response if desired
});
};
})
Then wire up buttons in your view to fetch and save by having the controller call the service methods.

Ajax, JQuery & PHP - Passing PHP variable to JQuery

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.

Ajax response while remote php runs

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..

AJAX long polling - waiting for php to finish while trying to get to another page

I want to create notification system in my company's erp similar to Facebook one. To maintain good performance, I use long polling - looped ajax querying php script for number of seconds.
Everything works fine, until I try to go to another page inside ERP. When I click any link on the page, everything freezes waiting until background php script is completed, even if I manually killed ajax connection.
JS script is included on every page and starts itself on page load.
function notificationsObject(){
var nl = new Object();
nl.startAjax = function(data){
if(nl.ajaxObject != null) try{ nl.ajaxObject.abort() } catch(e){} finally{nl.ajaxObject = null}
nl.ajaxObject = $.ajax({
url: nl.ajaxUrl, //declared before function declaration
type: 'POST',
data: {data: data}
}).done(function(responseText){nl.ajaxSuccess(responseText)
}).fail(function(responseText){nl.ajaxFail(responseText)});
}
nl.ajaxSuccess = function(response){
console.debug(response);
nl.startAjax();
}
nl.ajaxFail = function(response){
//#todo some code here
}
nl.killConnection = function(){
if(nl.ajaxObject != null) try{ nl.ajaxObject.abort() } catch(e){} finally{nl.ajaxObject = null}
console.debug('killing');
}
(more code here)
return nl;
}
init code looks like this
$(document).ready(function(){
var notifications = notificationsObject();
notifications.startAjax({name: 'startup'});
setTimeout(function(){window.onbeforeunload = function(){notifications.killConnection()};}, 1000);
});
and there's also some PHP code:
public function executeUsersNotificationListener(){
ignore_user_abort(false);
ob_end_flush();
$this->getResponse()->setHttpHeader("Cache-Control", "no-cache");
$this->getResponse()->setHttpHeader("Pragma", "no-cache");
$this->getResponse()->setHttpHeader("Expires", 0);
$timeLimit = 30;
set_time_limit($timeLimit+1);
echo 'test';
$i = 0;
while($i++ < $timeLimit){
echo " ";
sleep(1);
}
return sfView::NONE;
}
as you can see above, I did some research and used ignore_user_abort and so on, but it won't work.

How to get information with AJAX?

I try to get information with ajax from my php class but it doesn't work.
PHP Static class:
static public function showOnlineUsers() {
$db = Db::getInstance();
$time = time() + (24 * 60 * 60);
$sql = 'SELECT * `'._DB_PREFIX_.'prestaChat_users` WHERE `lastActivity`="1333333092"';
$users = $db->ExecuteS($sql);
$count = count($users);
throw new Exception($users);
}
Ajax php file:
require "prestaChat.php";
$type = strtolower($_POST['type']);
$array = array('getusers', 'getmessages');
if(in_array($type, $array)) {
// switch($type) {
// case 'getusers': prestaChat::showOnlineUsers();
// break;
// }
try {
prestaChat::showOnlineUsers();
} catch (Exception $exc) {
print_r($exc->getMessage());
}
}
jQuery $.ajax query:
$.ajax({
type: 'POST',
url: 'modules/prestaChat/ajax.php',
data: {'type': 'getusers'},
success: function(asd) {
console.log(asd);
}
});
So where is the false? I'm newbie in object-oriented php and last ajax thing which I create with jquery (ajax) and oop php works fine, but it send information doesn't get it...
I recently had issues using ajax and couldn't find the false for awhile. I don't know if the same reason I was getting mine, is why you are getting yours but I had my handler php file/script in the same directory as my javascript file calling the handler so I put my url as 'handler.php' but that was actually wrong. Even though they were in the same folder, the main script evoking those scripts was not in the js folder so I needed to change my url to 'js/handler.php' and it worked.
Like I said, I dunno if this is the case from what you presented, but the hierarchy is worth looking at.

Categories