Serving files via symfony2 - path to uploads directory - symfony

I have a problem setting a correct path to symfony2 uploads directory.
I am trying to provide user with files that they previously uploaded.
Firstly I tried the following code:
$response = new Response();
$d = $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$document->getWebPath()
);
$response->headers->set('Content-Disposition', $d);
as advised in the cookbook and How to get web directory path from inside Entity?.
This however resulted in the following error:
The filename and the fallback cannot contain the "/" and "\" characters.
Therefore I decided to switch to:
$filename = $this->get('kernel')->getRootDir() . '/../web' . $document->getWebPath();
return new Response(file_get_contents($filename), 200, $headers);
this however results in:
Warning: file_get_contents(/***.pl/app/../web/uploads/documents/2.pdf) [<a href='function.file-get-contents'>function.file-get-contents</a>]: failed to open stream: No such file or directory
My file that I want to serve is located in
/web/uploads/documents/2.pdf
What code should I use to provide this file to end users?

In order to serve binary files, it's better to use the BinaryFileResponse, which accepts the absolute file path as its argument. The setContentDisposition() doesn't accept file paths but file names ... and that argument is optional (you should only use it in case you want to change the name of the file being served to end-users):
use Symfony\Component\HttpFoundation\BinaryFileResponse;
$response = new BinaryFileResponse($filePath);
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT, $fileName
); // This line is optional to modify file name
Regarding the file path, you can keep using the code you showed, but slightly changed:
$filePath = $this->container->getParameter('kernel.root_dir')
.'/../web/'
.$document->getWebPath();

Related

Download all files in all folders from URL

I'd like to recursively download all files from nested folders from this URL to my computer in the same nested structure:
https://hazardsdata.geoplatform.gov/?prefix=Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings%20HYDA/
I've tried several different approaches, using curl and RCurl, including this and some others. There are multiple file types within this folder. But I keep running into cryptic error message such as Error in function (type, msg, asError = TRUE) : error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
I'm not even sure how to begin.
in their javascript you'll find the url https://hazards-geoplatform.s3.amazonaws.com/ and there you'll find a xml file containing the path to (seemingly?) all their files, from there it shouldn't be hard, so
1: download the XML list of files from https://hazards-geoplatform.s3.amazonaws.com
2: each of the XML's <content> tag describes a file or a folder. filter out all the tags that is not relevant to you, that means if the content->key tag does not contain the text Brookings HYDA, filter it out.
3: the remaining content tags contain your download path and save path, for every key tag that ends with /: this is a "folder", you can't download a fol6der, just create the path, for example if the key is
<Contents>
<Key>Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA/Hydraulics_DataCapture/Correspondence/</Key>
this means you should create the folders Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA/Hydraulics_DataCapture/Correspondence and move on, however if the key's value does not end with /, it means you should download it, for example if you find
<Contents>
<Key>Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA/Hydraulics_DataCapture/Correspondence/200724-CityBrookings-AirportInfo_Email.pdf</Key>
<LastModified>2022-03-04T17:54:48.000Z</LastModified>
<ETag>"9fe9af393f043faaa8e368f324c8404a"</ETag>
<Size>303737</Size>
<StorageClass>STANDARD</StorageClass>
</Contents>
it means the save filepath is Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA/Hydraulics_DataCapture/Correspondence/200724-CityBrookings-AirportInfo_Email.pdf
and the url to download the file is https://hazards-geoplatform.s3.amazonaws.com/ + urlencode(key), in this case:
https://hazards-geoplatform.s3.amazonaws.com/Region8%2FR8_MIT%2FRisk_MAP%2FData%2FBLE%2FSouth_Dakota%2F60601300_BrookingsCO%2FBrookings%20HYDA%2FHydraulics_DataCapture%2FCorrespondence%2F200724-CityBrookings-AirportInfo_Email.pdf
idk how to do it with curl/r, but here's how to do it in PHP, happy porting
<?php
declare(strict_types=1);
function curl_get(string $url): string
{
echo "fetching {$url}\n";
static $ch = null;
if ($ch === null) {
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_ENCODING => '',
CURLOPT_FOLLOWLOCATION=>1,
CURLOPT_VERBOSE=>0
));
}
curl_setopt($ch, CURLOPT_URL, $url);
$ret = curl_exec($ch);
if(curl_errno($ch)) {
throw new Exception("curl error ".curl_errno($ch).": ".curl_error($ch));
}
return $ret;
}
$base_url = 'https://hazards-geoplatform.s3.amazonaws.com/';
$xml = curl_get($base_url);
$domd = new DOMDocument();
#($domd->loadHTML($xml));
$xp = new DOMXPath($domd);
foreach($xp->query("//key[contains(text(),'Brookings HYDA')]") as $node) {
$relative = $node->nodeValue;
if($relative[-1] === '/'){
// it's a folder, ignore
continue;
}
$dir = dirname($relative);
if(!is_dir($dir)) {
mkdir($dir, 0777, true);
}
$url = $base_url . urlencode($node->nodeValue);
file_put_contents($relative, curl_get($url));
}
after running that for a few seconds i have
$ find
.
./fuk.php
./Region8
./Region8/R8_MIT
./Region8/R8_MIT/Risk_MAP
./Region8/R8_MIT/Risk_MAP/Data
./Region8/R8_MIT/Risk_MAP/Data/BLE
./Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota
./Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO
./Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA
./Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA/Hydraulics_DataCapture
./Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA/Hydraulics_DataCapture/Correspondence
./Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA/Hydraulics_DataCapture/Correspondence/200724-CityBrookings-AirportInfo_Email.pdf
./Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA/Hydraulics_DataCapture/Correspondence/2D_Exceptions_2021Update.pdf
./Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA/Hydraulics_DataCapture/DCS_Checklist_Hydraulics_BrookingsCoSD.xlsx
./Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA/Hydraulics_DataCapture/Simulations
./Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA/Hydraulics_DataCapture/Simulations/RAS
./Region8/R8_MIT/Risk_MAP/Data/BLE/South_Dakota/60601300_BrookingsCO/Brookings HYDA/Hydraulics_DataCapture/Simulations/RAS/0.2PAC
soo it seems to be working.
the last output from the command is
fetching https://hazards-geoplatform.s3.amazonaws.com/Region8%2FR8_MIT%2FRisk_MAP%2FData%2FBLE%2FSouth_Dakota%2F60601300_BrookingsCO%2FBrookings+HYDA%2FHydraulics_DataCapture%2FSimulations%2FRAS%2F0.2PAC%2FPostProcessing.hdf
PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 65019904 bytes) in /home/hans/test/fuk.php on line 17
meaning some of their files are over 134MB in size - it's easy to optimize the curl code to write directly to disk instead of storing the entire file in ram before writing to disk, but since you want to do this in R anyway, i won't bother optimizing the sample php script.

how to set the download path in php

I'm a web developer.
DownloadController.php
$local_file = 'file.zip';
$download_file = 'd:\temp\download.zip';
if(file_exists($local_file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($local_file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($local_file));
readfile($download_file);
}
I hope download the 'file.zip' and downloaded path that 'd:\temp\download.zip'
Anyone help me!
Thank u.
You can use following code to download a file:
return response()->download($pathToFile);
OR
return response()->download($pathToFile, $name, $headers)
The download method may be used to generate a response that forces the user's browser to download the file at the given path. The download method accepts a file name as the second argument to the method, which will determine the file name that is seen by the user downloading the file. Finally, you may pass an array of HTTP headers as the third argument to the method:
Docs

Unable to decode json file in a controller

I'm a new symfony user, and I'm actually trainning myself on it.
Here is my problem:
echo $this->container->get('templating.helper.assets')->getUrl('bundles/tlfront/js/channels.json');
$channels = json_decode($this->container->get('templating.helper.assets')->getUrl('bundles/tlfront/js/channels.json'));
var_dump($channels);
I would like to decode a JSON file in my controller, but here is what the echo and vardump give me:
/Symfony/web/bundles/tlfront/js/channels.json ( the echo)
null (the var_dump)
It seems that the path to the file is correct but json_decode doesn't work.
json_last_error() returns 4 which is JSON_ERROR_SYNTAX
But, when I run the json string in http://jsonlint.com/ it returns Valid JSON
Any ideas or advices ?
Dude, it has nothing to do with Symfony... json_decode only accepts strings:
http://php.net/manual/es/function.json-decode.php
That's why you're getting the syntax error. Just read the file with file_get_contents and you're done:
$path = $this->container->get('templating.helper.assets')->getUrl('bundles/tlfront/js/channels.json');
$content = file_get_contents($path);
$json = json_decode($content, true);
BTW, Symfony comes bundled with Finder, a really nice tool to search and get all the files you need: http://symfony.com/doc/current/components/finder.html

Wordpress not writing to folder using fwrite();

I have some php script that writes an html file to a folder. This works perfectly outside of WordPress. But when I try to incorporate my code into a plugin, it won't write to a folder anymore. I've even tried writing it to the original folder I tested it in at the root directory which is outside of WordPress and it won't write to that either.
Here is the function that writes to an html file.
function buildFrameFile($html, $filename){
$filename= '/wp-content/plugins/my-plugin/html/' . $filename . ".html";
$fh = fopen($filename, 'a');//open file and create if does not exist
fwrite($fh, $html);//write data
fclose($fh);//close file
return $filename;
}
I've even tried
$fh = fopen($filename, 'a');
$fh = fopen($filename, 'a+');
$fh = fopen($filename, 'w');
$fh = fopen($filename, 'a+');
None of these work either.
I'm thinking that within WordPress it may be something in a php.ini file and or .htaccess files that needs to go in the folder I want to write to, but I'm stuck.
* UPDATE **
I found some errors in the error log and are as follows:
Error: fwrite() expects parameter 1 to be resource, boolean given in....
$fh = fopen($filename, 'a');//open file and create if does not exist
fwrite($fh, $html);//write data
fclose($fh);//close file
SECOND UPDATE
I added the following code and it now writes the file to the folder
function buildFrameFile($html, $filename){
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
$filename= $DOCUMENT_ROOT. '/wp-content/plugins/my-plugin/html/' . $filename . ".html";
$fh = fopen($filename, 'a');//open file and create if does not exist
fwrite($fh, $html);//write data
fclose($fh);//close file
return $filename;
}
But now when it calls to open the file it try's to open it from the following link
/var/chroot/home/content/##/########/html/wp-content/plugins/my-plugin/html/c413c4976260c1a786e7a48be03f3ad2.html
and I don't believe that link is going to allow the file to be found as it doesn't show up in the browser.
Read your server's error_log and use the error message to diagnose the problem. If you find an error in the log, post it here for a better answer.
Edit based on error messages:
You can try hard-coding $filename into the fopen() function to test if the path to the file is incorrect in your $filename variable.
You'll need to figure out the value of $fh using something like var_dump() if $filename is correct. Most likely the path to $filename is not correct once you pass it in using wordpress through fopen. Instead you're passing in an error message from fopen of FALSE stating that it didn't get any data when it tried to open the file. It's possible that you just need to create a blank file with the proper name wherever wordpress is trying to open it.

WordPress fopen getting directory link

I'm using fwrite to create an html file in a folder within my plugin. The following code now allows me to write to the folder, but the link it tries to open is the full system path.
function buildFrameFile($html, $filename){
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
$filename= $DOCUMENT_ROOT. '/wp-content/plugins/my-plugin/html/' . $filename . ".html";
$fh = fopen($filename, 'a');//open file and create if does not exist
fwrite($fh, $html);//write data
fclose($fh);//close file
return $filename;
}
The path it now opens is:
/var/chroot/home/content/##/########/html/wp-content/plugins/my-plugin/html/79dda339bad8e65c425e580d62f41fa1.html
I need it to open from here:
/wp-content/plugins/my-plugin/html/79dda339bad8e65c425e580d62f41fa1.html
I'm not sure how to go about this.
I solved my problem. I ended up changing the code from:
function buildFrameFile($html, $filename){
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
$filename= $DOCUMENT_ROOT. '/wp-content/plugins/my-plugin/html/' . $filename . ".html";
$fh = fopen($filename, 'a');//open file and create if does not exist
fwrite($fh, $html);//write data
fclose($fh);//close file
return $filename;
}
To:
function buildFrameFile($html, $filename){
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
$filename2= $DOCUMENT_ROOT. '/wp-content/plugins/my-plugin/html/' . $filename . ".html";
$fh = fopen($filename2, 'a');//open file and create if does not exist
fwrite($fh, $html);//write data
fclose($fh);//close file
return $filename;
}
This way the file gets saved to the folder and only returns the actual name of the file not the whole link to the file.
Then in my header I changed the code from:
header("Location: /confirm" . $nvp_str . "&filename=" . $filename);
To:
header("Location: /confirm?" . $nvp_str . "&filename=" . '/wp-content/plugins/my-plugin/html/' . $filename . ".html");
and the iframe in my page calls the value of &filename which then returns the proper link to my file created and it loads perfectly!
First of all, you can rely on Wordpress' defines (or functions) to determinate the paths without any dirty hacks:
http://codex.wordpress.org/Determining_Plugin_and_Content_Directories#Available_Functions
http://codex.wordpress.org/Determining_Plugin_and_Content_Directories#Constants
Then again you can check things using PHP functions like file_exists(), is_dir(), is_writable():
http://pl1.php.net/manual/en/function.is-dir.php
http://php.net/manual/en/function.file-exists.php
http://pl1.php.net/manual/en/function.is-writable.php
To avoid complex fopen, fwrite, fclose handlers, you can go for file_put_contents() function there too. Either in appending or overwriting mode:
http://pl1.php.net/manual/en/function.file-put-contents.php
Not sure how relevant, but keep in mind if this is written by the webserver, you need to make sure the directory has write permissions there. Easiest way would be chmod 777 directory from shell, or SITE CHMOD 777 directory from FTP.
Your issue is most likely connected to weird godaddy's setup.
You can find more information here: http://www.quest4.org/etc/godaddy_path.htm
There's also a similiar issue posted here:
WordPress's plugins_url() function not working on shared hosting

Resources