I have a webservice with a function like this
$app->get('/downloadPdf', function () use($app)
{
$log = 'example.pdf';
$res = $app->response();
$res['Content-Description'] = 'File Transfer';
$res['Content-Type'] = 'application/octet-stream';
$res['Content-Disposition'] ='attachment; filename=' . basename($log);
$res['Content-Transfer-Encoding'] = 'binary';
$res['Expires'] = '0';
$res['Cache-Control'] = 'must-revalidate';
$res['Pragma'] = 'public';
$res['Content-Length'] = filesize($log);
readfile($log);
});
Testing it with Advanced Rest Client works fine..
Question is .. how do i call it from my client with all the headers etc.
To specify more. I know there are a lot of examples on how to download a specific file by inserting its url into the curlopt_url with the complete address to the file. What i want is to let the webservice decide which file to return...
Thanks
Never got an answer .. so !!!
This is how i made it work....
Service Function can be seen below
$app->post('/downloadReport', 'authenticate', function() use ($app)
{
verifyRequiredParams(array('reportId'));
$body = $app->request()->getBody();
$params_str = urldecode($body);
$input = json_decode($params_str,true);
$report_id = $input['reportId'];
$db = new DbHandler();
$db->getReport($report_id);
$path = $db->getReportPdfPath($report_id);
$res = $app->response();
$res['Content-Description'] = 'File Transfer';
$res['Content-Type'] = 'application/octet-stream';
$res['Content-Disposition'] ='attachment; filename=' . basename($path);
$res['Content-Transfer-Encoding'] = 'binary';
$res['Expires'] = '0';
$res['Cache-Control'] = 'must-revalidate';
$res['Pragma'] = 'public';
$res['Content-Length'] = filesize($path);
readfile($path);
});
Called the function like this:
public function downloadReport($api_key,$id)
{
$curl_post_data = array('reportId' => $id);
$headers = array('Content-type: application/json','Authorization: '.$api_key,);
$fp = fopen (dirname(__FILE__) . '/localfile.tmp', 'w+');//This is the file where we save the information
$curl = curl_init(DONWLOAD_REPORT);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($curl_post_data));
curl_setopt($curl, CURLOPT_USERPWD, $api_key);
$file = curl_exec($curl);
if ($file === false)
{
$info = curl_getinfo($curl);
curl_close($curl);
die('error occured during curl exec. Additioanl info: ' . var_export($info));
}
curl_close($curl);
header('Content-type: ' . 'application/octet-stream');
header('Content-Disposition: ' . 'attachment; filename=report.pdf');
echo $file;
}
I have same problem with you,
I am using this code, and it works, return a pdf file from webservice.
$api = new RestClient(array(
'base_url' => 'http://another-webservice.com/',
'headers' => array(
'X-Token' => $res->headers->x_token,
'Accept' => 'application/pdf',
),
));
$result = $api->execute("reports/report",'GET', $params);
$filename = 'Report.pdf';
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
echo $result->response;
References: How to display PDF in Browser
Related
I have an issue when building a slim (slim 4) response with a streamed content (a huge xlsx file content).
$fileHandler = \fopen(getenv('SHARED_FILES_PATH') . $filename, 'r');
if (!$fileHandler) {
throw new \Exception('Unable to open file ' . getenv('SHARED_FILES_PATH') . $filename . ' for reading.');
}
$stream = GuzzleHttp\Psr7\Utils::streamFor($fileHandler);
// $this->response is Psr\Http\Message\ResponseInterface
$response = $this->response;
$response = $response->withHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
$response = $response->withHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$response = $response->withBody($stream);
return $response;
The error:
Fatal error: Uncaught RuntimeException: Unable to read from stream in /home/vincent/workspace/opco2i_applis/opco2i_portail/server/vendor/guzzlehttp/psr7/src/Stream.php on line 232
I have made some check and the file exists and is readable.
If i do the following after the fopen call:
$contents = '';
while (!feof($fileHandler)) {
$contents .= fread($fileHandler, 8192);
break;
}
fclose($fileHandler);
var_dump($contents);die();
, i can read some content of my file.
Can you help me to find why guzzle stream cannot work in this case ?
After some tests, i have found the solution.
I must use $response->getBody()->write($stream) instead of $response->withBody($stream);
$stream = GuzzleHttp\Psr7\Utils::streamFor($fileHandler);
// $this->response is Psr\Http\Message\ResponseInterface
$response = $this->response;
$response = $response->withHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
$response = $response->withHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$response = $response->getBody()->write($stream);
return $response;
i want to make dynamic zip, so when admin click .zip, it will download and zip all files in folder based on user ud
user will have document and store on folder with their id
i.e /public/stroage/file/ID001, so when user click button download it will force to download ID0001.zip
here is my code
$zip = new \ZipArchive();
$uploaddir = public_path().'/temp';
$tmp_file = tempnam($uploaddir,'');
$zip->open($tmp_file, \ZipArchive::CREATE);
// Loop through each file
foreach($files as $file){
$url2 = $url.$file->upload;
$url2 = str_replace(' ', '%20', $url2);
if (!function_exists('curl_init')){
die('CURL is not installed!');
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url2);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
curl_close($ch);
$download_file = $output;
$type = substr($url2, -5, 5);
#add it to the zip
$zip->addFromString(basename($url.$file->upload.'.'.$type),$download_file);
}
// close zip
$zip->close();
// Set Time Download
date_default_timezone_set("Asia/Kuala_Lumpur");
$time_name = date('Ymd');
$time_download = date('Y-m-d H:i:s');
$log_download = new Log_download;
$user = Auth::user();
$id_user = $user->id;
$log_download->id_praapplication = $id_pra;
$log_download->id_user = $id_user;
$log_download->Activity = 'Download ZIP File';
$log_download->type = 'Zip Archive';
$log_download->downloaded_at = $time_download;
$log_download->save();
# send the file to the browser as a download
ob_start();
$strFile = file_get_contents($tmp_file);
header('Content-disposition: attachment; filename=DOC-'.$id_pra.'-'.'.zip');
header('Content-type: application/zip');
echo $tmp_file;
while (ob_get_level()) {
ob_end_clean();
}
readfile($tmp_file);
//$filetopath=$public_dir.'/'.$zipFileName;
//$filetopath = public_path().'/storage/uploads/file/'. $id_pra.'/'.$zipFileName;
// Create Download Response
// if(file_exists($filetopath)){
// return response()->download($filetopath,$zipFileName,$headers);
//}
exit;
actually this code work. but every utton to dowload zip i clicked, will create a temporary file inside folder /public.
how to download zip without creating temp file or can i make a folder like /public/tmp and save all temp zip to that folder?
You should be able to do $zip->open('php://output', \ZipArchive::CREATE);. Complete code:
header('Content-disposition: attachment; filename=DOC-'.$id_pra.'-'.'.zip');
header('Content-type: application/zip');
$zip = new \ZipArchive();
$zip->open('php://output', \ZipArchive::CREATE);
// Loop through each file
foreach($files as $file){
$url2 = $url.$file->upload;
$url2 = str_replace(' ', '%20', $url2);
if (!function_exists('curl_init')){
die('CURL is not installed!');
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url2);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
curl_close($ch);
$download_file = $output;
$type = substr($url2, -5, 5);
#add it to the zip
$zip->addFromString(basename($url.$file->upload.'.'.$type),$download_file);
}
// close zip
$zip->close();
// Set Time Download
date_default_timezone_set("Asia/Kuala_Lumpur");
$time_name = date('Ymd');
$time_download = date('Y-m-d H:i:s');
$log_download = new Log_download;
$user = Auth::user();
$id_user = $user->id;
$log_download->id_praapplication = $id_pra;
$log_download->id_user = $id_user;
$log_download->Activity = 'Download ZIP File';
$log_download->type = 'Zip Archive';
$log_download->downloaded_at = $time_download;
$log_download->save();
exit;
However, the zip filesize should not exceed the PHP max memory limit. If it does, you'll end up with corrupted zip files.
I'm working with Moodle api functions and I want to get all grades for enrolled users in a specific course. The purpose is to print all grades in an excel file. I tried to get the data from gradereport_user_get_grade_items but its not working here is my php code.
<?php
require_once('./curl.php');
$course_id=4;
$domainname = '........'; //paste your domain here
$wstoken = 'e521817f5cf9798926e0563d452b7975';//here paste your getgradetoken
$wsfunctionname = 'gradereport_user_get_grade_items';
$restformat='xml';//REST returned values format
$grade = array( 'courseid' => $course_id , 'user_id'=> $user_id );
$user_grades = array($grade);
$params = array('user_grades' => $user_grades);
//REST CALL
header('Content-Type: text/plain');
$serverurl = $domainname . "/webservice/rest/server.php?wstoken=" . $wstoken . "&wsfunction=" . $wsfunctionname;
$curl = new curl;
//if rest format == 'xml', then we do not add the param for backwardcompatibility with Moodle < 2.2
$restformat = ($restformat == 'json')?'&moodlewsrestformat=' . $restformat:'';
$resp = $curl->post($serverurl . $restformat, $params);
print_r($resp);
//EXCEL
header("Content-Disposition: attachment; filename=\"gradereport.xls\"");
header("Content-Type: application/vnd.ms-excel;");
header("Pragma: no-cache");
header("Expires: 0");
$out = fopen("php://output", 'w');
foreach ($params as $data)
{
if (is_array($data)){
foreach ($data as $v) {
fputcsv($out, $v,"\t");
}
}
}
fclose($out);
?>
I'm using curl to fetch photos from Facebook url for authorized user, for each photo I'm adding it to a zip file to allow user to download whole album as zip.
if( !isset($_GET['id']) )
die("No direct access allowed!");
require 'facebook.php';
$facebook = new Facebook(array(
'appId' => 'removed',
'secret' => 'removed',
'cookie' => true,
));
if( !isset($_GET['id']) )
die("No direct access allowed!");
$params = array();
if( isset($_GET['offset']) )
$params['offset'] = $_GET['offset'];
if( isset($_GET['limit']) )
$params['limit'] = $_GET['limit'];
$params['fields'] = 'name,source,images';
$params = http_build_query($params, null, '&');
$album_photos = $facebook->api("/{$_GET['id']}/photos?$params");
if( isset($album_photos['paging']) ) {
if( isset($album_photos['paging']['next']) ) {
$next_url = parse_url($album_photos['paging']['next'], PHP_URL_QUERY) . "&id=" . $_GET['id'];
}
if( isset($album_photos['paging']['previous']) ) {
$pre_url = parse_url($album_photos['paging']['previous'], PHP_URL_QUERY) . "&id=" . $_GET['id'];
}
}
$photos = array();
if(!empty($album_photos['data'])) {
foreach($album_photos['data'] as $photo) {
$temp = array();
$temp['id'] = $photo['id'];
$temp['name'] = (isset($photo['name'])) ? $photo['name']:'photo_'.$temp['id'];
$temp['picture'] = $photo['images'][1]['source'];
$temp['source'] = $photo['source'];
$photos[] = $temp;
}
}
?>
<?php if(!empty($photos)) { ?>
<?php
$zip = new ZipArchive();
$tmp_file =tempnam('.','');
$file_opened=$zip->open($tmp_file, ZipArchive::CREATE);
foreach($photos as $photo) {
$url=$photo['source'];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$download_file=curl_exec($ch);
#add it to the zip
$file_added=$zip->addFile($download_file);
}
# close zip
$zip->close();
# send the file to the browser as a download
header('Content-Description: File Transfer');
header('Content-Type: application/force-download');
header('Content-Disposition: attachment; filename="albums.zip"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($tmp_file));
ob_clean();
flush();
readfile($tmp_file);
exit;
} ?>
problem: zip->open creates a file, zip->add returns 1 for each file added but the zip size is still 0 and readfile do not prompt for downloading.
At the moment, you're trying to do this:
foreach ($photos as $photo) {
$url = $photo['source'];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$download_file = curl_exec($ch);
$file_added = $zip->addFile($download_file);
}
This will not work because $dowload_file is a string and not a filename. You need to save your cURL parameter to a file, and pass the filename to $zip->addFile. If you look at PHP's documentation, it's expecting a filename, not a string:
The path to the file to add.
You need to do something like:
$temp_file = './temp_file.txt';
file_put_contents($temp_file, $download_file);
$file_added = $zip->addFile($temp_file);
// Delete after use
unlink($temp_file);
I have 2 functions: one that uses chunked uploading and the other that uploads the entire file
public function chunkedUpload($file, $filename = false, $path = '', $overwrite = true)
{
if (file_exists($file)) {
if ($handle = #fopen($file, 'r')) {
// Set initial upload ID and offset
$uploadID = null;
$offset = 0;
// Read from the file handle until End OF File, uploading each chunk
while ($data = fread($handle, $this->chunkSize)) {
$chunkHandle = fopen('php://temp', 'rw');
fwrite($chunkHandle, $data);
$this->OAuth->setInFile($chunkHandle);
// On subsequent chunks, use the upload ID returned by the previous request
if (isset($response['body']->upload_id)) {
$uploadID = $response['body']->upload_id;
}
$params = array('upload_id' => $uploadID, 'offset' => $offset);
$response = $this->fetch('PUT', self::CONTENT_URL, 'chunked_upload', $params);
$offset += mb_strlen($data, '8bit');
fclose($chunkHandle);
}
// Complete the chunked upload
$filename = (is_string($filename)) ? $filename : basename($file);
$call = 'commit_chunked_upload/' . $this->root . '/' . $this->encodePath($path . $filename);
$params = array('overwrite' => (int) $overwrite, 'upload_id' => $uploadID);
$response = $this->fetch('POST', self::CONTENT_URL, $call, $params);
return $response;
} else {
throw new Exception('Could not open ' . $file . ' for reading');
}
}
// Throw an Exception if the file does not exist
throw new Exception('Local file ' . $file . ' does not exist');
}
public function putFile($file, $filename = false, $path = '', $overwrite = true)
{
if (file_exists($file)) {
if (filesize($file) <= 157286400) {
$filename = (is_string($filename)) ? $filename : basename($file);
$call = 'files/' . $this->root . '/' . $this->encodePath($path . $filename);
// If no filename is provided we'll use the original filename
$params = array(
'filename' => $filename,
'file' => '#' . str_replace('\\', '\\', $file) . ';filename=' . $filename,
'overwrite' => (int) $overwrite,
);
$response = $this->fetch('POST', self::CONTENT_URL, $call, $params);
return $response;
}
throw new Exception('File exceeds 150MB upload limit');
}
// Throw an Exception if the file does not exist
throw new Exception('Local file ' . $file . ' does not exist');
}
I have tested these functions from the same server directory and they both work fine; however, chunkedUpload is able to upload from remote http:// and ftp:// urls but putFile is not able to. Why does this happen? Is there a problem within these two functions that might cause this?
this is because file_exists does not work on remote servers
file_exists() in PHP 5 does not accept URLs only local path names
use curl to send a head request instead
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'your url');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
var_dump($size);