CakePHP how to combine process steps - cakephp

I am developing a system that allows users to download files, but IF they download a file I want to log this action in a special purpose table (MySQL).
I can already generate an icon with a link to appropriate file, but I can't see how I can make the record of the click on the icon to download the file also create the log record.
I am guessing I will have to use a button, and set the action of the button to run ... what? a controller action, a helper function, something else...
It is the last bit that I can't really get my head round. I would appreciate any advice from anyone who may have implemented something similar!
bw

You've got the right idea. Link to a controller action, which will write to the database & log, and will load the file and present it to the user.
Example:
class MyController extends AppController {
// Load the model
public $uses = ('DbTable');
public function get_file() {
// Save the DB record
$this->DbTable->save(...);
// Set the output header for content delivery
// (use the appropriate mime-type for your file)
header('Content-Type: image/jpg');
// Have it download as if it were an attachment
header('Content-Disposition: attachment; filename="filename.jpg"');
// Print out the file contents
echo file_get_contents('/path/to/filename.jpg');
// Prevent any further processing or rendering
exit();
}
}

Related

Error Image Upload and Get, Method App\Image::__toString() must not throw an exception, caught Illuminate\Database\Eloquent\JsonEncodingException

I am uploading user profile image which is uploading and moved to storage/app/upload/images folder but when I am trying to display that image, below given error occurs.
Method App\Image::__toString() must not throw an exception, caught Illuminate\Database\Eloquent\JsonEncodingException
Here is my controller function for displaying
public function userProfile() {
$image = Image::all();
return view('frontend.layouts.Profile',compact('image'));
}
My view in which I am displaying image
#foreach($image as $images)
<img style="width:210px ; height: 230px " src="/storage/app/upload/images/{{$images->image}}" >
#endforeach
Please Upload your image in Public directory and then try to access that, it will work fine
There are three ways of making an image available to a user:
1. As a public asset
Here the image is made available to everyone. For instance your website logo, or landing page image would be accessed by all. So there is a url to the image that is easily accessed by all. These sort of files would go straight to public/img/ folder.
2. As a protected image available only if specific url is requested
Here user specific images would be accessed by specific people. Think of your members' personal photos that you want to make available only to the member herself or to some specific person. In this case you would store the images in storage/app/public and make a symlink using the artisan command php artisan storage:link You can read more on this here. Assuming that you store your files using random names using str_random() you would then generate urls to your image using the asset() helper like: echo asset('storage/X3jf5j5b2j3n.jpg'); Given that the file names are random, it would be hard to access this image by everyone excepting those who have the url generated using the asset() helper.
3. As a protected image made available using Intervention library
In this case you would first check if user is logged in and then dynamically load the image using Intervention via another protected route. So in your web routes you would first have the user authorization using auth middleware:
Route::group(['middleware' => 'auth'], function () {
Route::get('user', 'UserController#userProfile');
Route::get('images/{image}', 'UserController#serveImage'); // this route serves the image only if user is logged in
});
Then once your have installed Intervention library using composer, our UserController would look like:
use Intervention;
class UserController extends Controller
{
public function userProfile()
{
$images = Image::all();
return view('frontend.layouts.Profile', compact('images'));
}
public function serveImage($image)
{
$filename = storage_path('app/images/'.$image);
return Intervention::make($filename)->response();
}
}
You can see that the image is now being served from the storage folder and not public folder. So this method serveImage() is called only when the route defined earlier for it is authorized. Intervention then works its magic to read the image and send it as a http response.
Your view would change one tad bit to accommodate the new route end point that we defined called images. I assume here that you are storing the filename of the image in db by a field named filename:
#foreach($images as $image)
<img style="width:210px ; height: 230px " src="{{ url('/images/'.$image->filename) }}" >
#endforeach
Note: Do bear in mind that the preferred way to serve images is by using method 2 since it is much faster. You can use method 3 sparingly if you really don't want anyone to even stumble upon the files using the urls.

saving the xml file generated through cakephp 2.3 serialize function

I am using cakephp 2.3 and using the default code from the cookbook. The xml is generated automatically, without having to create any view files.
class PostsController extends AppController {
public function index() {
$this->set(’posts’, $this->paginate());
$this->set(’_serialize’, array(’posts’));
}
}
However, I do not want to display the XML. Instead I want to save the generated XML file in the document root upon click of a button as Posts.xml. How can I do this? Please help.
You might not have look thoroughly enough:
http://book.cakephp.org/2.0/en/controllers/request-response.html#sending-files
It clearly states how to send files with the appropriate headers via response object.
So in your controller action, add:
$this->response->download('filename_for_download.xml');

how to clear the file name list after fineUploader (3.5) uploads file

I download fine uploader 3.5, created http handler for a file upload function in my little website . the website is done by asp.net ajax and jquery. it runs at IE9. every time I upload a file, there is a list of file names shown below the load button. if I don't want thme, what should I do?
my code is like this:
html: ...
'<tr><td><div id="jquery-wrapped-fine-uploader"></div></td></tr>...
'ajax/jquery:...
'$('#jquery-wrapped-fine-uploader').fineUploader({
'request: { endpoint: 'xxx.ashx' }
'})
'$('#jquery-wrapped-fine-uploader').on("complete",
'function (event, id, fileName, responseJSON) {
' alert("UPLOAD SUCCESS");
' $.ajax({some ajax calls here});
' })
// WHERE TO PUT this TO CLEAR the UPLOADED FILE LIST??? $('#jquery-wrapped-fine-uploader').fineUploader('reset');
XXX.ashx:
'... public void ProcessRequest (HttpContext context) {
'do some http request work..
'context.Response.ContentType = "text/plain";
'context.Response.Write("{\"success\":true}");
'}
My question is:
I want to completely remove the uploaded file list which shows automatically in green color ( or red if they fail), in order to clear them, I tried to put: $('#jquery-wrapped-fine-uploader').fineUploader('reset'); right after .on('complete'), it's not working, also #jquery-wrapped-fine-uploader seems cached all the time. please help on this.
If you don't want to see the file list at all, you should be using FineUploaderBasic mode instead of using FineUploader mode and then removing all elements in the pre-built UI. FineUploaderBasic mode gives you access to the API, options, and callbacks, but assumes you will be creating your own UI. In other words, FineUploaderBasic mode does not create any DOM elements (except the opaque file input element as a child of your button container, if you supply one). This is all explained (in a great amount of detail) in the documentation.
Start here: http://docs.fineuploader.com

CakePHP generate a Document to Webroot

I'm currently working with cakephp and I am generating a word document. My problem is how can I put the generated document on my web root and not as a download.
I am guessing you are using an action to generate a document, which gets output to the browser.
You should either use output buffering to "catch" the output and then write it to a file, or write the document data to a string, and write that string to a file on the server.
EDIT:
PHPWord has a SAVE method. In your action, you can save the document to a certain location, but output something else, i.e. success notification. This way, your action only generates the file:
public function generateWordDocument(){
//... your word file creation...
$wordDocumentLocation = TMP . 'word_files/';
$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
$objWriter->save($wordDocumentLocation . 'helloWorld.docx');
$this->Session->setFlash('Document generated!');
$this->redirect(array('action'=>'index')); //or wherever you want
}
If you want to protect that file, you could save the file to a "secure" folder (this can either be a folder outside the "app/webroot" folder, or a folder protected with .htaccess deny all instruction) and than use another action, like "getWordDocument":
function getWordDocument($documentName){
$wordDocumentLocation = TMP . 'word_files/';
if (file_exists($wordDocumentLocation . $documentName)) { //this is not really the safest way of doing it
$fp = fopen($wordDocumentLocation . $documentName, 'rb');
header("Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document");
header("Content-Length: " . filesize($wordDocumentLocation . $documentName));
fpassthru($fp);
exit();
}
}
Please note, that this code is just for "grasping the concept" and is in no way safe or optimal.
i think you want to add file in webroot but it is not downloadable for public users ,
You have several ways :
- protect folders with .htaccess (Like Js folder)
- create new folder in app folder like webroot and put files in it
- use Dispatcher Filters in cakephp : http://book.cakephp.org/2.0/en/development/dispatch-filters.html
and ....

How to create file in current system from within Grails controller action and save data fetched from database?

In my Grails application I need to create a file in current system in which I need to save information fetched from table in database. How to do this from within controller action? I don't have any idea of it.
I have created file as
File file=new File("file name.txt")
file.createNewFile();
then I have wrote values of MySQL database table fields in it as:
file<<patient.id
file<<patient.name
.
.
.
it stores data like continuous text but I want to have a .doc file in which data should get stored in table. I found Apache's POI for creating doc file but I am not getting how it works and how I should use it.
Not sure exactly what you want to store in a file but below is an example of how to easly write a String to a file using Apache-commons-io Which should be included in grails
import org.apache.commons.io.FileUtils;
class SomeController{
def writeToFile = {
def data = getSomeStringData();
def fileStore = new File("./path/to/files/ControllerOutput_${new Date()}.txt");
fileStore.createNewFile();
FileUtils.writeStringToFile(fileStore, data);
println("your file was created # {fileStore.absolutePath} and is ${fileStore.length()} bytes");
}
}
Does this help? If not, you need to explain exactly what your looking for.
This is a comment to Michael's answer (unfortunately I still don't have the reputation to reply on answers).
If you're struggling around the problem how to specifiy the relative path from within your controller's context, this might help you:
So if you have following folder you want to read/write files from/into"..
/myproject/web-app/temp/
you can access the file like this:
import org.codehaus.groovy.grails.commons.ApplicationHolder as AH
// getResource references to the web-app folder as root folder
Resource resource = AH.getApplication().getParentContext().getResource("/temp/myfile.txt)

Resources