Closed zillion42 closed 1 year ago
EDIT: I step by step debugged the whole process now.
The Pdf is in fact created, but it won't download in the response. It shows and empty chrome tab, later the:
register_shutdown_function(function () use ($tmpfname) {
if (File::exists($tmpfname . '.pdf')) {
File::delete($tmpfname . '.pdf');
}
});
deletes the file... Just tried with Firefox, same result.
I also created the tex blade and tried:
return (new LaraTeX('latex.tex'))->with([
'Name' => 'John Doe',
'Dob' => '01/01/1990',
'SpecialCharacters' => '$ (a < b) $',
'languages' => [
'English',
'Spanish',
'Italian'
]
])->download('test.pdf');
I also tried
->inline('test.pdf');
->content();
neither works.
If I try ->savePdf('C:\Users\User\Desktop') I get:
ErrorException
rename(D:\Apache24_htdocs\projects\storage\app\qnp1882.pdf,C:\Users\User\Desktop): Access denied (code: 5)
This works:
/**
* Download file as a response
*
* @param string|null $fileName
* @return Illuminate\Http\Response
*/
public function download($fileName = null) {
if (!$this->isRaw) {
$this->render();
}
$pdfPath = $this->generate();
if (!$fileName) {
$fileName = basename($pdfPath);
}
if (file_exists($pdfPath)) {
header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($pdfPath));
header('Accept-Ranges: bytes');
@readfile($pdfPath);
}
}
but not using response. 👎
I also created the tex blade and tried:
return (new LaraTeX('latex.tex'))->with([ 'Name' => 'John Doe', 'Dob' => '01/01/1990', 'SpecialCharacters' => '$ (a < b) $', 'languages' => [ 'English', 'Spanish', 'Italian' ] ])->download('test.pdf');
I also tried
->inline('test.pdf'); ->content();
neither works.
If I try ->savePdf('C:\Users\User\Desktop') I get:
ErrorException rename(D:\Apache24_htdocs\projects\storage\app\qnp1882.pdf,C:\Users\User\Desktop): Access denied (code: 5)
Saving a file outside of your laravel app is not working out of the box and security-wise also not recommended. The savePdf method can be used if you want each pdf saved somewhere inside of your laravel app storage. Note: This comment is just a side-note. I am trying to think about other reasons why your PDF generation doesn't work in Windows
Hi @zillion42
I prepared my windows system now in the following way:
First I was able to figure out that after adding the texlive path to my PATH environment variable did not help, as phpinfo()
didn't recognized the change. So inside some log files on my system I was able to find out that "pdflatex" was not recognized as a command.
Using the absolute path C:\texlive\2023\bin\windows\pdflatex.exe
in the config binPath
did the trick in that moment.
After some research I got tired and restarted my machine. After that phpinfo()
did actually have the texlive path from my PATH system environment variable in the PHP Path variable.
Changing back the binPath
to pdflatex
then made me beeing able to run dryrun and a PDF has been downloaded successfully.
So my question to you would be:
dd(phpinfo());
inside laravel and check the PATH variable there and confirm that the path is there?Thank you so much for your feedback.
Kind regards, Ismael
Hi,
Did you restart your computer after changing your PATH environment variable? Sure, more than once, but actually in windows it is enough to restart the console (cmd prompt) after adding the path. I don't quite understand why you were searching the texlive path in phpinfo, but I guess the php PATH should be the same as the system PATH. I never had any issues with PHP finding pdlatex.exe, that was never a problem. But just for testing purposes I also added the complete path which is C:\texlive\2023\bin\windows\pdflatex.exe - That works just the same.
Also like I said, laratex actually generates the pdf, so it definitely works. I'm sorry the title of this issue is a bit misleading, I only found out it works after setting some breakpoints and using the debugger.
The problem is that the response does not download the file, before it gets deleted by the shutdown function. So the pdf is there for a brief moment, then gets deleted again. The response however does not trigger a file download.
I'm suspecting more something not working with:
\Event::dispatch(new LaratexPdfWasGenerated($fileName, 'download', $this->metadata));
return \Response::download($pdfPath, $fileName, [
'Content-Type' => 'application/pdf',
]);
EDIT: Another possible issue might be a problem with the forward and backslash notation, it is always troublesome. Note the pdlatex logs writes:
Output written on D:\Apache24_htdocs\project\storage\app/vr0E5B8.pdf (1 page, 35744 bytes).
Anyway Thank you so much for testing this so quick on a windows machine. Please note, I am not using PHP 8, but 7.4 together with laravel framework 8.75
"require": {
"php": "^7.3|^8.0",
"directorytree/ldaprecord-laravel": "^2.5",
"doctrine/dbal": "^3.3",
"guzzlehttp/guzzle": "^7.0.1",
"illuminate/support": "^8.83",
"ismaelw/laratex": "^1.0",
"laravel/framework": "^8.75",
"laravel/sanctum": "^2.11",
"laravel/tinker": "^2.5",
"phpoffice/phpspreadsheet": "^1.23"
},
EDIT2:
Saving a file outside of your laravel app is not working out of the box and security-wise also not recommended. The savePdf method can be used if you want each pdf saved somewhere inside of your laravel app storage. Note: This comment is just a side-note. I am trying to think about other reasons why your PDF generation doesn't work in Windows
That is true, but since the whole project runs only inside the intranet of our organization, security issues are thankfully not so relevant. This Hack that I used now, although not very secure at least works for the moment.
My apologies. You are right. You did mention the PDF gets generated.
What I couldn't read from your messages is if any exception is thrown?
Or everything seems to be fine but nothing happens?
If you wish I can continue the troubleshooting or we try to troubleshoot it on your end together?
I remember having someone that was able to use laratex using windows and PHP 7.4 so that should also be no issue here.
Since unfortunately you can not reproduce the issue, it would make sense to debug it on my end.., There is no exception thrown unfortunately, I will provide some screenshots.
Also I did try using a mix of slashes in windows. So in the same path a mix of back- and forwardslashes. Windows is actually pretty good in handling this. But to try it would be maybe an option to replace everything with forwardslashes.
pressing the export button routes directly to the named route clerk_export which triggers the export function in the clerkController:
Route::prefix('sachbearbeiter')->controller(ClerkController::class)->group(function () {
Route::get('/', 'index')->name('clerks_index');
Route::get('erstellen', 'create')->name('clerk_create');
Route::get('export', 'export')->name('clerk_export');
clerkController.php:
public function download(){
return (new LaraTeX('latex.tex'))->with([
'Name' => 'John Doe',
'Dob' => '01/01/1990',
'SpecialCharacters' => '$ (a < b) $',
'languages' => [
'English',
'Spanish',
'Italian'
]
])->download('test.pdf');
}
public function export(Request $request) {
$this->download();
}
This then leads me to a blank white tab, nothing happens there.
using:
// Folder in your storage folder where you would like to store the temp files created by LaraTeX
'tempPath' => "app\/",
leads to:
Output written on D:\Webappsrv_c_httpd_Apache24_htdocs\krankenhilfe_soz\storage
\app\//6RE505B.pdf (1 page, 35547 bytes).
using:
// Folder in your storage folder where you would like to store the temp files created by LaraTeX
'tempPath' => "app//",
leads to:
Output written on D:\Webappsrv_c_httpd_Apache24_htdocs\krankenhilfe_soz\storage
\app///h8S3112.pdf (1 page, 35547 bytes).
using:
// Folder in your storage folder where you would like to store the temp files created by LaraTeX
'tempPath' => "app\\",
leads to:
Output written on D:\Webappsrv_c_httpd_Apache24_htdocs\krankenhilfe_soz\storage
\app\/POyA89B.pdf (1 page, 35547 bytes).
using:
// Folder in your storage folder where you would like to store the temp files created by LaraTeX
'tempPath' => "app/\\",
leads to:
Output written on D:\Webappsrv_c_httpd_Apache24_htdocs\krankenhilfe_soz\storage
\app/\/xaG198C.pdf (1 page, 35547 bytes).
:-) any more suggestions...
It looks totally fine after generation:
If all this seems to work just fine I am thinking if we should focus on the response which is Laravel specific and not LaraTeX specific. I am just thinking about that because on Line 203 everything seems to be fine and as to my understanding a PDF file exists inside your storage/app folder.
Maybe a stupid question. but did you ever try to put a random file into your storage path and download it using the Response class?
Now that you say it, I haven't actually. I just looked at how I download PhpOffice Excel files. Edit: Note, this is ancient code, that I copied from older projects, without thinking to much about it
// Redirect output to a client’s web browser (Xlsx)
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="' . $filename . '.xlsx"');
header('Cache-Control: max-age=0');
// If you're serving to IE 9, then the following may be needed
header('Cache-Control: max-age=1');
// If you're serving to IE over SSL, then the following may be needed
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
header('Pragma: public'); // HTTP/1.0
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save('php://output');
exit;
But I tested it now, and using the Response class also works without any problems. I'm unsure about the header here, but it works.
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save($path = storage_path('download.xlsx'));
return response()->download($path, $filename . '.xlsx')->deleteFileAfterSend();
$writer belongs to PhpOffice
namespace PhpOffice\PhpSpreadsheet;
use PhpOffice\PhpSpreadsheet\Reader\IReader;
use PhpOffice\PhpSpreadsheet\Shared\File;
use PhpOffice\PhpSpreadsheet\Writer\IWriter;
This is actually getting super weird. So at the moment everything seems to works and should be working but it just doesn't. How I cannot replicate the issue on my side it is quiet hard to think of something without having a hands-on.
Things I would like to test would be
If it is an option for you we can maybe even arrange a Teams call to get this working for you.
This is dd of the download
Symfony\Component\HttpFoundation\BinaryFileResponse {#1364 ▼
#file: Symfony\Component\HttpFoundation\File\File {#1366 ▼
path: "D:\Webappsrv_c_httpd_Apache24_htdocs\krankenhilfe_soz\storage\app"
filename: "Bf682FC.pdf"
basename: "Bf682FC.pdf"
pathname: "D:\Webappsrv_c_httpd_Apache24_htdocs\krankenhilfe_soz\storage\app\Bf682FC.pdf"
extension: "pdf"
realPath: "D:\Webappsrv_c_httpd_Apache24_htdocs\krankenhilfe_soz\storage\app\Bf682FC.pdf"
aTime: 2023-03-23 09:54:39
mTime: 2023-03-23 09:54:39
cTime: 2023-03-23 09:54:39
inode: 4222124650748109
size: 35547
perms: 0100666
owner: 0
group: 0
type: "file"
writable: true
readable: true
executable: false
file: true
dir: false
link: false
linkTarget: "D:\Webappsrv_c_httpd_Apache24_htdocs\krankenhilfe_soz\storage\app\Bf682FC.pdf"
}
#offset: 0
#maxlen: -1
#deleteFileAfterSend: false
#chunkSize: 8192
+headers: Symfony\Component\HttpFoundation\ResponseHeaderBag {#1365 ▼
#computedCacheControl: array:1 [▼
"public" => true
]
#cookies: []
#headerNames: array:5 [▼
"content-type" => "Content-Type"
"cache-control" => "Cache-Control"
"date" => "Date"
"last-modified" => "Last-Modified"
"content-disposition" => "Content-Disposition"
]
#headers: array:5 [▼
"content-type" => array:1 [▼
0 => "application/pdf"
]
"cache-control" => array:1 [▼
0 => "public"
]
"date" => array:1 [▼
0 => "Thu, 23 Mar 2023 09:54:39 GMT"
]
"last-modified" => array:1 [▼
0 => "Thu, 23 Mar 2023 09:54:39 GMT"
]
"content-disposition" => array:1 [▼
0 => "attachment; filename=test.pdf"
]
]
#cacheControl: array:1 [▼
"public" => true
]
}
#content: null
#version: "1.0"
#statusCode: 200
#statusText: "OK"
#charset: null
}
Teams is not so easy here because of the proxy we use, but we have a jitsi where I could share my screen, I Just don't want to post addresses here.
Your response looks exactly the same like mine on my windows machine.
Another question: do you have the php_fileinfo PHP extension enabled? I guess probably yes but excluding always helps. Or in general I am thinking about uncatched exceptions from the apache and php front.
So maybe you could also check things like the "max_execution_time" runtime setting in PHP, and check the apache error_log in your xampp setup. I am just trying to think of all the issues I had in all my time and come up with a possible cause
Wait a minute.
After checking your code I realized one thing.
public function download(){
return (new LaraTeX('latex.tex'))->with([
'Name' => 'John Doe',
'Dob' => '01/01/1990',
'SpecialCharacters' => '$ (a < b) $',
'languages' => [
'English',
'Spanish',
'Italian'
]
])->download('test.pdf');
}
public function export(Request $request) {
$this->download();
}
Your download method returns a file but your export method doesn't actually return anything.
Can you try changing
$this->download();
to return $this->download();
EDIT:
I was able to replicate the white empty tab when I removed the return
on my end. In that case I am not actually returning a file.
Hi, I actually have quite some work ahead of me at the moment, I also think it's weird by now.
max_execution_time=1440
extension=fileinfo
WOW
Your download method returns a file but your export method doesn't actually return anything.
Can you try changing
$this->download();
to
return $this->download();
EDIT: I was able to replicate the white empty tab when I removed the
return
on my end. In that case I am not actually returning a file.
That was it... omg, thx for all the trouble. I was beginning to suspect it must be something really stupid on my part. I think I'll donate you a coffee for this.
You sponsored my next beer (or two)!
Thanks so much again.
Edit: I guess I can close this issue now 🤦
haha amazing. Well that happens. Whenever I have an issue like this I end up face-palming myself for wasting valuable time on a syntax or thinking error.
You are very welcome - and I am here if there is anything else I can help you with! 🥳
Oh and thank you so much for the donation! Much appreciated!
I'm sorry to bother you so much, but I have another question real quick. Should I open another issue?
I have this kind of array each entry has a model and a collection of models:
I'm passing it to the tex blade like so:
return (new LaraTeX('clerk.clerk_export_tex'))->with($daten)->download('test.pdf');
and I get
@zillion42 no worries.
Please reference this in a new issue and we can look at it together :)
Hi,
I have texlive installed in C:\texlive\2023\bin\windows I also added this to my path environment variable, running pdflatex in the cmd prompt works.
If I run
return (new LaraTeX)->dryRun();
with default config/laratex.php:
I get a Str::random(10) file 1 x vr0E5B8 1 x vr0E5B8.log 1 x vr0E5B8.aux
in my app directory
The log reads:
but the file is not there, it's also not downloaded automatically.
I already tried all combinations of
None seems to work.
If I rename vr0E5B8 into vr0E5B8.tex, I can double click open it with texworks and compile it just fine.
What am I doing wrong?
Running Win10 Pro, 22H2, 19045.2728 with Apache 2.4 (Xampp), PHP Version => 7.4.7