Detect finish of "php://output" with window.open - javascript

I use PhpSpreadsheet for export mysql data in this way:
Page 1:
button trigger window.open to page with script for export
window.open('/export.php?data.., '_self');
Page 2 (export.php):
Whole system for export and php://output
ob_end_clean();
ob_start();
$objWriter->save('php://output');
exit;
Can I somehow understand if the export page has finished?
I need this for trigger a overlay.
What i have tried?
Looking in stackoverflow I tried this solution but it didn't work:
overlay.style.display = "block";
let myPopup = window.open('/export.php?data.., '_self');
myPopup.addEventListener('load', () => {
console.log('load'); //just for debug
overlay.style.display = "none";
}, false);

This will execute an ajax request which will result in a download without refreshing the page with jQuery
<button id='download'>Download Spreadsheet</button>
<form method='get' action='/export.php?' id='hiddenForm'>
<input type='hidden' name='foo' value='bar' />
<input type='hidden' name='foo2' value='bar2' />
</form>
$(document).on('click', '#download', function (e) {
e.preventDefault();
$('#hiddenForm').submit();
});
Make sure your PHP outputs the correct content type
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
Another Option
Based on this post, there isn't an api available to truly detect the loading of a javascript window object across all different browsers. This method uses a defer callback and postMessage approach to acommodate most modern browsers.
function defer (callback) {
var channel = new MessageChannel();
channel.port1.onmessage = function (e) {
callback();
};
channel.port2.postMessage(null);
}
var awaitLoad = function (win, cb){
var wasCalled = false;
function unloadListener(){
if (wasCalled)
return;
wasCalled = true;
win.removeEventListener("unload", unloadListener);
win.removeEventListener("pagehide", unloadListener);
// Firefox keeps window event listeners for multiple page loads
defer(function (){
win.document.readyState;
// IE sometimes throws security error if not accessed 2 times
if (win.document.readyState === "loading")
win.addEventListener("load", function loadListener(){
win.removeEventListener("load", loadListener);
cb();
});
else
cb();
});
};
win.addEventListener("unload", unloadListener);
win.addEventListener("pagehide", unloadListener);
// Safari does not support unload
}
w = window.open();
w.location.href="/export.php?data=foo";
awaitLoad(w, function (){
console.log('got it')
});

I will give +1 to #Kinglish answer because awaitLoad function can help, in my case i used ajax instead with this method Link answer
What is it about?
Create an Ajax call with json type to export page and use done to catch JSON
like:
overlay.style.display = "block"; //active overlay
$.ajax({
url: "/export.php",
type: "GET",
dataType: 'json',
data: {
data: data
}
}).done(function(data) {
var $a = $("<a>");
$a.attr("href", data.file);
$("body").append($a);
$a.attr("download", "nameoffile.xls");
$a[0].click();
$a.remove();
overlay.style.display = "none"; //deactive overlay
});
In PHP page catch php://output with ob_get_contents then return json like:
$xlsData = ob_get_contents();
ob_end_clean();
$response = array(
'op' => 'ok',
'nomefile' => 'nameofile',
'file' => "data:application/vnd.ms-excel;base64,".base64_encode($xlsData)
);
die(json_encode($response));
The last step is create, click and remove a fake link.

Related

Why XmlHttpRequest wait until complete PHP response (proc_open) even with flush?

I 'm trying to execute commands (wp cli) with xhr.
My problem is when i call my file deploy.php with the javascript.
Without JS call the script works, the flush is immediate.
When i call deploy.php in a XmlHttpRequest, the response wait until the end of the php execution.
I try different commands (grep / wp cli / find) but the result is the same.
I work on WSL Debian + Chrome.
// PHP
public function liveExecuteCommand($cmd, $ajax = false)
{
ob_start();
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("file", "error-output.txt", "a")
);
$output = '';
$process = proc_open($cmd, $descriptorspec, $pipes);
if (is_resource($process)) {
fwrite($pipes[0], '<?php print_r($_ENV); ?>');
fclose($pipes[0]);
while ($s = fread($pipes[1], 8192)) {
$output .= $s;
print $s;
$this->doFlush();
}
fclose($pipes[1]);
$return_value = proc_close($process);
//echo "La commande a retourné $return_value\n";
}
if ($ajax == false) {
return $output;
}
}
$obj->liveExecuteCommand($cmd, true);
die();
// JS
function getLiveStream() {
var ajax = new XMLHttpRequest();
var url = 'https://www.monsite.local/deploy.php';
ajax.open('GET', url, true);
ajax.onprogress = function() {
document.getElementById("xhr_cmd_result").innerHTML = ajax.responseText;
console.log('onprogress');
}
ajax.onload = function() {
console.log('onload');
}
ajax.onreadystatechange = function() {
document.getElementById("xhr_cmd_result").innerHTML = ajax.responseText;
console.log('statechange');
}
ajax.send();
}
window.addEventListener('DOMContentLoaded', (event_loaded) => {
document.getElementById("xhr_cmd").onclick = getLiveStream;
});
In the Google chrome console, the result display all status directly (after 1 min), like the php result.
statechange
onprogress
statechange
onprogress
statechange
onprogress
statechange
onload
I would like have a console.log every time that the flush is called.
No problem when i execute the php file in the browser, the problem is certainly in the javascript.
How do I solve the problem?
Let me explain you in simple words.
Javascript's XMLHttpRequest(AJAX) call will request to server. It will only waits for response from server(final output from your php page), irrespective to internal process of server.

passing data using post array in java-script

i am try to load B.php from A.php after execution in the function and pass some data using a post array from A.php to B.php within same time.
code list as follows
A.php
<script type="text/javascript">
alert_for_the_fucntion();
window.location.href = "B.php";
function alert_for_the_fucntion() {
$.post("B.php", {action: 'test'});
}
</script>
B.php
<?php
if (array_key_exists("action", $_POST)) {
if ($_POST['action'] == 'test') {
echo 'ok';
}
}
?>
for testing purpose i tried to echo something in the B.php. but currently this is not working. have i done any mistakes? or is there any possible method to do this.
Your code does this:
Tells the browser to navigate to B.php (using a GET request)
Triggers a POST request using XMLHttpRequest
The POST request probably gets canceled because the browser immediately leaves the page (and the XHR request is asynchronous). If it doesn't, then the response is ignored. Either way, it has no effect.
You then see the result of the GET request (which, obviously, doesn't include $_POST['action']) displayed in the browser window.
If you want to programmatically generate a POST request and display the result as a new page then you need to submit a form.
Don't use location. Don't use XMLHttpRequest (or anything that wraps around it, like $.ajax).
var f = document.createElement("form");
f.method = "POST";
f.action = "B.php";
var i = document.createElement("input");
i.type = "hidden";
i.name = "action";
i.value = "test";
f.appendChild(i);
document.body.appendChild(f);
f.submit();
If you want to process the results in JavaScript then:
Don't navigate to a different page (remove the line using `location)
Add a done handler to the Ajax code
e.g.
$.post("B.php", {action: 'test'}).done(process_response);
function process_response(data) {
document.body.appendChild(
document.createTextNode(data)
);
}
Try this:
Javascript:
<script type="text/javascript">
window.onload = alert_for_the_fucntion;
function alert_for_the_fucntion() {
$.post("B.php",
{
action: 'test'
},
function(data, status){
if(status=="success"){
alert(data);
}
}
);
}
</script>
PHP
<?php
if(isset($_POST['action'])){
echo $_POST['action'];
}
?>

jQuery - Downloading Textarea Contents

How can I download the textarea value/contents when I click a button? It should act like PHP:
<?php
$file = 'proxies.txt';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
?>
I just can't find any way on here to do it. I don't want it to make a href to click a second time to download. I just want to click a button and it will download a txt file containing the textarea's contents.
My current code that wont work:
$('#test').click(function() {
contentType = 'data:application/octet-stream,';
uriContent = contentType + encodeURIComponent($('#proxiescontainer').val());
$(this).setAttribute('href', uriContent);
});
Explanation:
#test is the a tag wrapping the button;
#proxiescontainer is the textarea itself;
So how can I get it to be a onClick download of the textarea's contents?
My AJAX:
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "grab.php", true);
xhttp.send();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
var t = $('#proxiescontainer').scrollTop(), $d2 = $('#proxiescontainer').replaceWith('<button type="button" id="download" class="form-control button">Download</button><textarea id="proxiescontainer" class="form-control message-input" style="height: 250px!important;">' + xhttp.responseText + '</textarea>');
if (t){ $('#proxiescontainer').scrollTop(t + $d2.outerHeight()); }
}
}
Using existing js setAttribute() is not a jQuery method ; to use on DOM element remove jQuery() wrapper
$('#test').click(function() {
contentType = 'data:application/octet-stream,';
uriContent = contentType + encodeURIComponent($('#proxiescontainer').val());
this.setAttribute('href', uriContent);
});
alternatively using Blob createObjectURL() , download attribute
$("button").click(function() {
// create `a` element
$("<a />", {
// if supported , set name of file
download: $.now() + ".txt",
// set `href` to `objectURL` of `Blob` of `textarea` value
href: URL.createObjectURL(
new Blob([$("textarea").val()], {
type: "text/plain"
}))
})
// append `a` element to `body`
// call `click` on `DOM` element `a`
.appendTo("body")[0].click();
// remove appended `a` element after "Save File" dialog,
// `window` regains `focus`
$(window).one("focus", function() {
$("a").last().remove()
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<textarea></textarea>
<button>download</button>

load content of a page using only javavascript noe jquery

i working on a simple script that load users last posts in there blog and website !
the page is works well without any problem !
this is an example : http://parsclub.net/tools/widget/load-rss.php?u=reza-shady&l=5&w=200&c=4DC7FF
i want to load that link blow in external page !
for that i used this script and put it on a file
<?php
$user = trim($_GET["u"]);
$limit = trim($_GET["l"]);
$width = trim($_GET["w"]);
$color = trim($_GET["c"]);
header("Content-Type: text/javascript; charset=utf-8");
?>
document.write('<div id="parsclub_widget"><img src="http://parsclub.net/themes/parsclub/imgs/loading_posts.gif" style="margin:20px;display:inline-block;"/></div>');
function ajaxRequest() {
var activexmodes = ["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"]
if (window.ActiveXObject) {
for (var i = 0; i < activexmodes.length; i++) {
try {
return new ActiveXObject(activexmodes[i])
} catch (e) {
}
}
} else if (window.XMLHttpRequest) return new XMLHttpRequest()
else return false;
}
function load_widget() {
var mygetrequest = new ajaxRequest()
if (mygetrequest.overrideMimeType) mygetrequest.overrideMimeType('text/html')
mygetrequest.onreadystatechange = function () {
if (mygetrequest.readyState == 4) {
if (mygetrequest.status == 200 || window.location.href.indexOf("http") == -1) {
var data = mygetrequest.responseText;
document.getElementById("parsclub_widget").innerHTML = data;
} else {
alert("خطایی در هنگام دریافت اطلاعات رخ داده است");
}
}
}
mygetrequest.open("GET", "http://parsclub.net/tools/widget/load-rss.php?u=<?= $user ?>&l=<?= $limit ?>&w=<?= $width ?>&c=<?= $color ?>", true);
mygetrequest.send(null);
return false;
}
load_widget();
but it don't work when i put it on a external page
you can see the result here !
http://up.pc-t.ir/New%20Text%20Document.html
i know i cant simply load it with jquery load() function but i want it pure JavaScript
can anyone help me with this ?
so sorry for my bad English
EDIT
#merlin-denker 10x for your help i found solution for my problem by adding this headers to the load-rss.php file
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Headers: Content-Type');
As Barmar already stated in a comment, the AJAX Request is failing because of the same origin policy.
The solution to this is to add a PHP-Script to your Website that simply reads the content of the other URL and echoes it.
<?php echo file_get_contents(YOUR_URL_HERE); ?>
Then let your Javascript call the script that is located on the same webserver and it will work.
Read more here: http://www.php.net/manual/function.file-get-contents.php

php inside javascript alternative

In the code below after user click in cancel button It will call the function botao_excluir(). Inside of this function I want to run the cancela_cielo() php function. But I know that is impossible to run PHP inside JavaScript. So Could someone please tell me a way to do this?
PHP
<?php
$id=$row['id_temp_transaction'];
if($row['status']!=9)
{
echo "<input type = \"button\" name=\"cancel\" value = \"Cancel\" onclick= \"botao_excluir()\" >";
}
?>
JavaScript
<script>
function botao_excluir()
{
var r=confirm("Press OK to confirm the cancel")
if (r==true)
{
<?php cancela_cielo($row['tid'], $row['numero_afiliacao'], $row['chave_utilizada']); ?>
alert("Transaction Canceled")
}
else
{
alert("Cancel aborted")
}
}
You can do this using ajax
this will send the request to page.php as example the request will be executed in php and the data will be returned.
function botao_excluir()
{
var r=confirm("Press OK to confirm the cancel")
if (r==true)
{
xhr = new XMLHttpRequest()
xhr.open("POST","page.php",false);
xhr.send();
// response will be assigned to data variable
data = xhr.responseText
alert("Transaction Canceled")
}
else
{
alert("Cancel aborted")
}
}
you can read more about ajax and php here
http://www.w3schools.com/php/php_ajax_php.asp

Categories

Resources