Yii2: refresh() not working after sending response content - yii2

I have a ActiveForm which I use to get some data from and when I click the send button it will run the model (in this case a csv file generator) but the refresh is not working, when I remove the method it will refresh.
After some testing it seems that fputcsv() will stop the script, so that everything that comes after this will not run.
view
public function actionIndex()
{
$model = new Export();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$fields = Yii::$app->request->post('Export');
\backend\models\Export::generate();//this prevents the refresh
Yii::$app->session->setFlash();
return $this->refresh();
} else {
return $this->render('index' , ['model' => $model]);
}
}
model
static public function generate()
{
header('Content-Encoding: UTF-8');
header('Content-Type: text/csv; charset=UTF-8');
header('Content-Disposition: attachment; filename="sample.csv"');
header("Pragma: no-cache");
header("Expires: 0");
$data = [array comes here];
$fp = fopen('php://output', 'w') or die("Unable to open file!");
fputs($fp, $bom =( chr(0xEF) . chr(0xBB) . chr(0xBF) ));
foreach ( $data as $line ) {
fputcsv($fp , $line , ';' );
}
stream_get_contents($fp);
fclose($fp);
}

Controller::refresh() uses Location header to reload page. Since headers need to precede the content, you cannot add new header after content was sent. Your Export::generate() method sends content, so you cannot add any header after that, thus $this->refresh() do not work.
Prior to Yii 2.0.14 there was a bug and framework simply ignored that you're trying to send header after content has been send. If you upgrade Yii, you should get "nice" Exception in this case.
If you're trying to display nice page after downloading file, your approach is incorrect. You can't really return file and then redirect to different page. You should first display nice HTML page and inside of it redirect user to download page (for example by using <meta http-equiv="refresh" content="0; url=http://example.com/" /> in head or creating hidden form and submitting it by JavaScript). After downloading the file user will stay at this nice page, so from UX perspective everything should be OK.

Related

HTML5 - Server side events - Using external text file as data input

I am attempting of using a plain text-file (text.txt) as part of html5 - server side events.
Currently I am not seeing any printout of text in browser. If just running this line, without using an external file for input data, it works:
echo "data: test\n\n";
Question: What do I need to adjust to make the external file data to be visible in the browser, assuming the setup of below files?
My html file
<h1>SSE</h1>
<div id="result"></div>
<script>
// Create an object
var source = new EventSource("updater.php");
// Detect message receipt
source.onmessage = function(event) {
// Write the received data to the page
document.getElementById("result").innerHTML += event.data + "<br>";
};
</script>
my php file
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
// Include files
echo include("text.txt");
flush();
?>
my text file:
"data: t1972\n\n";
The solution for the question, works if using [file_get_contents] as specified below.
$data = file_get_contents('text.txt');
echo "data: " . $data . "\n\n";
This also means that the file [text.txt] is left with only text, removing the [data: ] and [\n\n].

AS3 ALIVEPDF saving via method.remote (PHP) no longer working

The SWF is located on a web server. I am calling the function using this code in AS3...
myPDF.save(Method.REMOTE, "http://www.example.com/generator/createpdf.php",
Download.ATTACHMENT, "line.pdf");
Here is my PHP script located on the server...
$method = $_GET['method'];
$name = $_GET['name'];
if ( isset ( $GLOBALS["HTTP_RAW_POST_DATA"] )) {
// get bytearray
$pdf = $GLOBALS["HTTP_RAW_POST_DATA"];
// add headers for download dialog-box
header('Content-Type: application/pdf');
header('Content-Length: '.strlen($pdf));
header('Content-disposition:'.$method.'; filename="'.$name.'"');
echo $pdf;
} else echo 'An error occured.';
It used to work, but stopped a while back. Any help would be greatly appreciated.
1) This stopped working for me as well, until I added the following -
if(!$HTTP_RAW_POST_DATA){
$HTTP_RAW_POST_DATA = file_get_contents(‘php://input’);
}
2) I also patched /src/org/alivepdf/pdf/PDF.as::save() per this post enter link description here

fputcsv and fwrite not working

I have followed the explanation given here to write the query result to a file.
But in this case I have to open and write the files headers first. Then keep writing/appending the query results one by one for multiple queries. This appending part I have written as a function. The problem that my script write the file with the headers (from the first part) only, it does not follow the fputcsv commands present in the function when it is called. Can you help me in solving this.
Here is my code to first open the file:
<?php
$fp = fopen('php://output', 'w');
$headers = array("Index","Gene_symbol","Gene_Name","Human_entrez","Rat_entrez","Mouse_entrez","DbTF","PMID");
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="export.txt"');
fputcsv($fp, $headers,chr(9));
header('Pragma: no-cache');
header('Expires: 0');
?>
Then the query part is somewhat like this (I have multiple of such query parts each one calling the same function) :
<?php
if (is_numeric($sterm))
{
$query="select * from tf where entrez_id_human=$sterm || entrez_id_rat=$sterm || entrez_id_mouse=$sterm";
$result=mysql_query($query) or die(mysql_error());
if (mysql_num_rows($result)==0)
{echo "<tr><td align='center' colspan=6> $sterm not found! </td> </tr>";}
elseif (mysql_num_rows($result)>0)
{result_disp($result);}
}
?>
then writing the result to file via a function is here:
<?php
function result_disp($results)
{
if($fp && $results)
{
while ($rows = mysql_fetch_row($results))
{
fputcsv($fp, array_values($rows),chr(9));
} die;
}
}
And finally closing the file at end of script
fclose($fp);
?>
Thanks
Your first problem is that your file handle does not have scope within the function. The best way in my opinion is to pass it into the function:
....
elseif (mysql_num_rows($result)>0)
{result_disp($result, $fp);}
....
function result_disp($results, $fp)
{
if($fp && $results)
{
while ($rows = mysql_fetch_row($results))
{
fputcsv($fp, array_values($rows),chr(9));
} //DO NOT PUT "die()" HERE
}
}
Your second problem is the "die()" statement inside the function. The purpose of "die()" is to stop the script entirely. It is PHP suicide. So, if you leave it in, your script will halt at the end of the first call of result_disp. That means not only would you never reach fclose($fp), you'll never reach any other call to result_disp.
Your third problem is that you are using mysql_* functions. These are deprecated (no longer in use) for several reasons. I have personal experience with database connection freezes caused by it. You should switch to mysqli or PDO.

How can I use html5 cache manifest with CakePHP?

I want to use the html5 cache manifest technology with CakePHP,
but I don't know where to place the cache manifest in CakePHP,
I've searched for a solution, but I do not found anything.
Can you help me?
The best and easiest way to access one manifest file in all views is to look at your layouts, for example
View/Layouts/default.ctp
and replace <html> with
<?php echo "<html manifest='".$this->webroot."manifest.php'>"; ?>
in which manifest.php is located in
app/webroot/manifest.php
and looks something like this:
<?php
header('Content-Type: text/cache-manifest');
echo "CACHE MANIFEST\n";
echo "\n\nNETWORK:\n";
echo "*\n";
echo "\n\nCACHE:\n";
echo "# Version: 1\n";
?>
So the manifest.php is only needed once and can be used for all views.
HINT:
For a dynamic manifest-file you can use a code snippet from here:
http://nial.me/2010/01/using-the-html5-cache-manifest-with-dynamic-files/
I tried this solution, putting the manifest in default.ctp, but it causes some problems, all my pages was cached... i think it's discribed in the spec "...the page that referenced the manifest is automatically cached even if it isn't explicitly mentioned".
...couse this all my pages was being cached, manifest is checked in each page. And when another user logs in they see the last user homepage and other pages.
The final solution: create a redirect/loading page
1 - create the redirect page:
I had create the Pages/redirect.ctp file and the function redirect(){} in the Pages controller. A simple page, just with a hello message and a loading bar based on the applicationCache progress event:
var appCache = window.applicationCache;
appCache.addEventListener('progress', function(event) {
console.log(event.loaded + " of " + event.total + " files...");
//make some changes in the page' loading bar
}, false);
2 - Load manifest only in the redirect page:
In the View/Layouts/default.ctp I filtered the tag to show the manifest only in the redirect page:
<? if($this->request->params['controller']=='pages' &&
$this->request->params['action']=='redirect'): ?><html
manifest="<?=$this->webroot?>manifest.php">
<? else: ?>
<html >
<?
endif; ?>
3 - Use the redirect page in the auth component to lead my user
to redirect page after login:
In the appController a setted auth component like this
public $components = array (
'Session',
'Auth' => array (
'authError' => "user or password invalid",
'unauthorizedRedirect' => "/pages/redirect?err=login",
'loginRedirect' => "/pages/redirect",
'logoutRedirect' => "/",
'loginAction' => "/user/login",
'authorize' => array ('Controller')
)
);
now only the elements putted in the manifest will be cached. The redirect page is cached (according the spec) but the applicationCache event updates the page torning this "dinamic".
If you mean the manifest file it should go into /app/webroot, the directory that your vhost should also use for the site. besides this there is nothing really related to CakePHP with this.
Have a look at this: http://www.html5rocks.com/en/tutorials/appcache/beginner/

denied due to lack of policy file permissions

I can't get my Yahoo! Application Platform to run I keep getting denied access even though their policy file accepts requests from any domain.
OK: Policy file accepted: http://social.yahooapis.com/crossdomain.xml
Error: Request for resource at http://social.yahooapis.com/v1/user/<user id>/profile?oauth_signature_method=HMAC-SHA1&lang=en-US&oauth_consumer_key=<key>&oauth_token=<long ass token>&oauth_version=1.0&format=json&oauth_nonce=<blah blah>&oauth_timestamp=1262846353&region=US&oauth_signature=<foo bar> by requestor from http://<my domain>/YOSSimple.swf is denied due to lack of policy file permissions.
The url works btw, I editted some stuff out since it has my keys and stuff.
Links to the stuff I'm trying to do
http://developer.yahoo.com/flash/yos/
http://developer.yahoo.com/flash/yos/examples/simple/YOSSimple.fla
YOSSimple properly creates the url actually since if I type it in my browser I'm prompted if I want to download the file that contains information regarding my profile.
But it just wont open it in Flash.
I'm guessing that it's not loading the policy file automatically. You should try using
Security.loadPolicyFile("http://social.yahooapis.com/crossdomain.xml");
Do you have a webproxy installed with which you can monitor what files exactly are loaded? My favorite is Charles but there are also free FF plugins like Httpfox
EDIT:
I think I know what's going wrong. It's going wrong the other way around, the swf from yahoo is trying to access your swf, but doesn't have the correct permissions. Would you try
Security.allowDomain( 'http://social.yahooapis.com/' );
http://www.ieinspector.com/httpanalyzer/
use HTTP analyzer to see whats happening?
also check your not missmatching http://www. with http:// because flash treats them as different domains
also are you running the code locally on your machine. It could be your local security settings
A simple WebProxy will fix this:
<?php
// PHP Proxy
// Loads a XML from any location. Used with Flash/Flex apps to bypass security restrictions
// usage: proxy.php?url=http://mysite.com/myxml.xml
$session = curl_init($_GET['url']); // Open the Curl session
curl_setopt($session, CURLOPT_HEADER, false); // Don't return HTTP headers
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Do return the contents of the call
$xml = curl_exec($session); // Make the call
header("Content-Type: text/xml"); // Set the content type appropriately
echo $xml; // Spit out the xml
curl_close($session); // And close the session
?>
Modify the web proxy example above to support multiple options as follows:
$sOptions = "";
foreach($_GET as $sIndex => $sValue) {
if ($sIndex == 'url') {
$url = $sValue;
}
else {
if (strlen($sIndex) > 0) {
$sOptions .= "&" . $sIndex;
}
if (strlen($sValue) > 0) {
$sOptions .= "=" . $sValue;
}
}
}
$url .= $sOptions;
$session = curl_init($url); // Open the Curl session