I'm working on a Drupal 7 project. I'm using a batch, implenting some operations, and showing a progress bar. in my "formulaire_finished", wich is executed at the end, as last operation of the batch, I want to download a file, and then redirect to another page, because the process is over.
However, The readfile() function use a drupal_exit(), and so my redirection isn't done.
Here is my code:
function formulaire_finished($success, $results, $operations) {
if ($success) {
$path = $results['infos']['path'];
download_file($path);
// Redirection
drupal_goto($_SESSION['my_page'], array('query' => array('details' => '1')));
} else {
// An error occurred.
// $operations contains the operations that remained unprocessed.
$error_operation = reset($operations);
drupal_set_message(t('An error occurred while processing #operation with arguments : #args', array('#operation' => $error_operation[0], '#args' => print_r($error_operation[0], TRUE), )));
}
}
download function:
function download_file($path) {
$dir = $path;
$filename = basename($dir);
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
drupal_add_http_header('Pragma', 'public');
drupal_add_http_header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');
} else {
drupal_add_http_header('Pragma', 'no-cache');
}
drupal_add_http_header('Expires', '0');
drupal_add_http_header('Content-Type', 'application/vnd.ms-excel');
drupal_add_http_header('Content-Disposition', 'attachment; filename=' . basename($dir) . ';');
drupal_add_http_header('Content-Transfer-Encoding', 'binary');
drupal_add_http_header('Content-Length', filesize($dir));
readfile($dir);
unlink($dir);
drupal_exit();
}
All ideas are welcome.
In the below function , can you try to return true always from the below function.
function download_file($path) {
$dir = $path;
$filename = basename($dir);
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
drupal_add_http_header('Pragma', 'public');
drupal_add_http_header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');
} else {
drupal_add_http_header('Pragma', 'no-cache');
}
drupal_add_http_header('Expires', '0');
drupal_add_http_header('Content-Type', 'application/vnd.ms-excel');
drupal_add_http_header('Content-Disposition', 'attachment; filename=' . basename($dir) . ';');
drupal_add_http_header('Content-Transfer-Encoding', 'binary');
drupal_add_http_header('Content-Length', filesize($dir));
readfile($dir);
unlink($dir);
//drupal_exit();
// Can you use simple return here
return true;
}
I don't think you should output the file for download during the finish callback of a batch operation. You should save the file to drupal's file system and save a reference to the file. You can then download it after the batch finishes.
Related
I am trying to show the file uploaded from File Manager mform element. I could store the file to mdl_files. To get the file saved is a bit hard to program. I tried implementing few options from Moodle Forums, but was stuck here. I really hope that someone can provide a solution for Moodle File manager (a crucial part). Could anyone guide me where I went wrong and suggest me to get the fileurl.
<?php
require('config.php');
require_once($CFG->libdir.'/formslib.php');
class active_form extends moodleform {
function definition() {
$mform = $this->_form;
$fileoptions = $this->_customdata['fileoptions'];
$mform->addElement('filemanager', 'video', get_string('video', 'moodle'), null,
$fileoptions);
$this->add_action_buttons();
}
function validation($data, $files) {
$errors = parent::validation($data, $files);
return $errors;
}
}
// Function for local_statistics plugin.
function local_statistics_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload,
array $options=array()) {
global $DB;
if ($context->contextlevel != CONTEXT_SYSTEM) {
return false;
}
$itemid = (int)array_shift($args);
if ($itemid != 0) {
return false;
}
$fs = get_file_storage();
$filename = array_pop($args);
if (empty($args)) {
$filepath = '/';
} else {
$filepath = '/'.implode('/', $args).'/';
}
$file = $fs->get_file($context->id, 'local_statistics', $filearea, $itemid, $filepath,$filename);
if (!$file) {
return false;
}
// finally send the file
send_stored_file($file, 0, 0, true, $options); // download MUST be forced - security!
}
// Form Settings
$fileoptions = array('maxbytes' => 0, 'maxfiles' => 1, 'subdirs' => 0, 'context' =>
context_system::instance());
$data = new stdClass();
$data = file_prepare_standard_filemanager($data, 'video', $fileoptions, context_system::instance(),
'local_statistics', 'video', 0);
$mform = new active_form(null, array('fileoptions' => $fileoptions));
// Form Submission
if ($data = $mform->get_data()) {
$data = file_postupdate_standard_filemanager($data, 'video', $fileoptions,
context_system::instance(), 'local_statistics', 'video', 0);
$fs = get_file_storage();
$files = $fs->get_area_files($context->id, 'local_statistics', 'video', '0', 'sortorder', false);
foreach ($files as $file) {
$fileurl = moodle_url::make_pluginfile_url($file->get_contextid(), $file->get_component(),
$file->get_filearea(), $file->get_itemid(), $file->get_filepath(),
$file->get_filename());
echo $fileurl;
}
}
?>
I've had a quick look through your code and it all looks reasonable, but you've not included the code of the local_statistics_pluginfile() function in local/statistics/lib.php - without that function, Moodle is unable to authenticate any requests from the browser to serve files, so all files will return a 'file not found' message.
Have a look at the documentation for details of what the x_pluginfile function should look like (or look for examples in any of the core plugins in Moodle): https://docs.moodle.org/dev/File_API#Serving_files_to_users
In fuelphp, we can render template from controller. But I want prevent render template from package.
Example:
Step 1: fuelphp run controlelr -> render template
Step 2: run package -> have a command to clear all data in step 1. and
render blank page.
Result with a blank page
$this->template->content = ...
\Package::removeTemplate();
I tried with
\Event::forge(array('shutdown'));
\Fuel::finish();
But it is not success. How can I do it?
You can always modify your template, inside the controller in every function just use
$this->template
Example
class Controller_lorem extends Controller_Main {
public $template = 'template_default';
public function action_ipsum()
{
//use customize template other than default
$this->template = View::forge('template_custom');
}
I found a solution. Rewrite \Fuel::finish()
public static function finishS()
{
if (\Config::get('caching', false))
{
\Finder::instance()->write_cache('FuelFileFinder');
}
if (static::$profiling and ! static::$is_cli)
{
// Grab the output buffer and flush it, we will rebuffer later
$output = ob_get_clean();
$headers = headers_list();
$show = true;
foreach ($headers as $header)
{
if (stripos($header, 'content-type') === 0 and stripos($header, 'text/html') === false)
{
$show = false;
}
}
if ($show)
{
\Profiler::mark('End of Fuel Execution');
if (preg_match("|</body>.*?</html>|is", $output))
{
$output = preg_replace("|</body>.*?</html>|is", '', $output);
$output .= \Profiler::output();
$output .= '</body></html>';
}
else
{
$output .= \Profiler::output();
}
}
// Restart the output buffer and send the new output
ob_start();
**/// Remove this line echo $output;**
}
}
I've got an "addForm" and a "editForm". After I have added a document file in the addForm, it will be saved in my db. If I want to edit this form, I have to upload this document again. The old document will be deleted. I would like to make a function to check whether the document is already uploaded or not, so I do not have to upload it every time I want to edit an item. I just do not know where to start. A little help will be great.
my add/editform:
$pdf = new Zend_Form_Element_File('document');
$pdf->setLabel('Nieuwe PDF')
->addValidator('extension', true, array('docx',
'docx','pdf','txt'))
->addValidator('Count', false, 1)
->addValidator('Size', false, 10240000)
->setDestination( PUBLIC_PATH . '/../data/invoicespdf/')
->setRequired(false);
Try using this in the controller...modify it to fit your needs :
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
if ('administrator' == $user->role) {
$oldFileName = $form->getElement('oldfilename')->getValue(); //the hidden field
$data = $form->getValues();
$model->populate($data);
if (file_exists('uploads/cv/' . $oldFileName)) {
$form->getElement('cv')->setIgnore(true); //this is my Form File Element - the file exists, I don't need to store the filename
} else { // if you want you can unlink $oldFileName
$upload = new Zend_File_Transfer_Adapter_Http();
$info = $upload->getFileInfo('cv');
$upload->setDestination("uploads/cv/");
if (file_exists('uploads/cv/' . $info['cv']['name'])) {
$newFileName = time() . rand(0, 100000) . "-" . $info['cv']['name']; // I need to avoid overwriting file
} else {
$newFileName = $info['cv']['name'];
$upload->addFilter('Rename', $newFileName);
}
try {
$upload->receive();
} catch (Zend_File_Transfer_Exception $e) {
$e->getMessage();
}
}
$model->save();
return $this->_helper->redirector('list');
} else {
//some error message
$this->_helper->redirector('list');
}
} else { //form not valid
$this->view->form = $form;
}
} else {
$model->find($id);
$data = array();
$data = $model->toArray();
$data['oldfilename'] = $model->get_cv(); //the filename stored in db
$form->getElement('cv')->setRequired(false);
$form->populate($data);
$this->view->form = $form;
}
I seem to have a problem with uploadify. It always get stuck at 100% on the first file, no matter what the file is. I am using Zend on my Wamp and it works fine there but as soon as I upload it on my linux server it gets stuck. The file is uploaded and renamed but it never fires the onComplete event and stays at 100% on the first file.
Here is my javascript:
$('#fileInput').uploadify({
'uploader' : 'http://test.thevenuelist.co.uk/js/uploadify/uploadify.swf',
'script' : 'http://test.thevenuelist.co.uk/ajax/uploadify',
'cancelImg' : 'http://test.thevenuelist.co.uk/js/uploadify/cancel.png',
'folder' : '/userdata/images/',
'auto' : true,
'multi' : true,
'fileDesc' : 'Image Files (*.jpg;*.jpeg;*.gif;*.png)',
'fileExt' : '*.jpg;*.jpeg;*.gif;*.png',
'buttonText' : 'Upload Images',
'removeCompleted' : true,
'onComplete' : function (event, queueID, fileObj, response, data) {
var answer = eval('(' + response + ')');
if(answer.result == "success")
{
$("#hdnImages").val($("#hdnImages").val() + answer.fileName + ",");
var toAdd = "<li><img src='/images/delete.png' id='removeItem' rel='"+answer.fileName+"' style='cursor:pointer;' title='Remove' alt='Remove'/> Image "+answer.realName+" uploaded</li>";
$("#completedItemsList").append(toAdd);
}
},
'onError': function (event, queueID ,fileObj, errorObj) {
alert(errorObj.info);
}
});
And here is my Zend code behind:
$tempFile = $_FILES['Filedata']['tmp_name'];
$targetPath = $_SERVER['DOCUMENT_ROOT']. '/' . $_REQUEST['folder'] . '/';
$fileNameArray = explode('.',$_FILES['Filedata']['name']);
$hash = substr(md5(microtime()),0,5);
$finalFileName = $fileNameArray[0].$hash.'.'.$fileNameArray[1];
$targetFile = str_replace('//','/',$targetPath) . $finalFileName;
if(move_uploaded_file($tempFile,$targetFile))
{
$data = array("result"=>"success","fileName"=>$finalFileName,"realName"=>$_FILES['Filedata']['name']);
}
else
{
$data = array("result"=>"failed");
}
echo Zend_Json::encode($data);
Any help would be greatly appreciated. I have spent way too much time trying to figure it out. I need my onComplete event to work so I can finish my forms.
I found with uploadify I had to return either a 1 or a 0 for success or failure to get it to work.
I am new to php. have a task to ftp only todays files from the server containing files for over a week. how do i select or filter the files based on date and ftp to my local folder.
Help is much appreciated !!
Soloman
If you already have the filenames to check, use filemtime
Returns the time the file was last modified, or FALSE on failure. The time is returned as a Unix timestamp, which is suitable for the date() function.
To compare that today, you can use date('Y-m-d') to get today compare to date('Y-m-d', filemtime($filename))
To get the filenames, you could use readdir to read each one in turn.
<?php
if ($handle = opendir('/path/to/files')) {
echo "Directory handle: $handle\n";
echo "Files:\n";
while (false !== ($filename = readdir($handle))) {
echo "$filename\n";
}
closedir($handle);
}
?>
The manual also has an FTP example which should show you how to ftp the file once found.
So, combining all this, you could get something like:
<?php
// set up basic connection
$conn_id = ftp_connect($ftp_server);
// login with username and password
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
// check connection
if ((!$conn_id) || (!$login_result)) {
echo "FTP connection has failed!";
echo "Attempted to connect to $ftp_server for user $ftp_user_name";
exit;
} else {
echo "Connected to $ftp_server, for user $ftp_user_name";
}
if ($handle = opendir('/path/to/files')) {
while (false !== ($filename = readdir($handle))) {
if (date('Y-m-d') == date('Y-m-d', filemtime($filename))) {
// upload the file
$upload = ftp_put($conn_id, $destination_file, $filename, FTP_BINARY);
// check upload status
if (!$upload) {
echo "FTP upload has failed!";
} else {
echo "Uploaded $source_file to $ftp_server as $destination_file";
}
}
}
closedir($handle);
// close the FTP stream
ftp_close($conn_id);
?>
Of course, you will need to fill in the dummy values as appropriate.
Disclaimer: I typed this in notepad++ and it is not tested for any mistakes!
link :
http://www.php.net/manual/en/function.ftp-rawlist.php
you connect to the server ,
get the list of the files with ftp_rawlist()
and get only file you want via ftp_fget()
example
<?php
// set up basic connection
$conn_id = ftp_connect($ftp_server);
// login with username and password
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
// get the file list for /
$rawfiles = ftp_rawlist($conn_id, '/');
foreach ($rawfiles as $rawfile) {
# parse the raw data to array
if(!empty($rawfile)) {
$info = preg_split("/[\s]+/", $rawfile, 9);
$arraypointer[] = array(
'text' => $info[8],
'isDir' => $info[0]{0} == 'd',
'size' => byteconvert($info[4]),
'chmod' => chmodnum($info[0]),
'date' => strtotime($info[6] . ' ' . $info[5] . ' ' . $info[7]),
'raw' => $info
// the 'children' attribut is automatically added if the folder contains at least one file
);
// pseudo code check the date
if($arraypointer['date'] is today)
ftp_fget(file);
}
// close the connection
ftp_close($conn_id);
// output the buffer
var_dump($buff);
?>