htmlspecialchars - cakephp

if i submit data like my string using form on insert/edit view, on a list view i'll get my string as italic (like here).
how can i avoid that, and to have my string (with visible all html tags) on all forms?
i.e. so it appears like this: <i>my string</i>
thanks in advance!

So you're asking how you can escape the HTML code on your views when you render the results as they exist in the database... is that right?
Assuming that is what you're asking, in your view, you could simply wrap the DB field output
<?php
foreach ( $rows as $row ) {
echo $html->tag("p",htmlentities($row['Model']['field']));
}
// or more simply
foreach ( $rows as $row ) {
echo htmlentities($row['Model']['field']).'<br/>';
}
?>

Maybe the option 'escape'=>true will be useful, like in:
$html->tag('p', $text, array('escape'=>true));

Related

How to load/execute a view template from a string in CakePHP

I've developed a CakePHP plugin that allows the site administrator to define custom reports as a list of SQL queries that are executed and the results displayed by a .ctp template.
Now I need to allow the administrator to edit the template, stored in the DB together with the report.
Therefore I need to render a template that is inside a string and not in a .ctp file and I could not find anything in the core that helps.
I considered initially the approach to write the templates in .ctp files and load them from there, but I suspect this solution is rigged with flaws re: the location of the files and related permissions.
A better solution seems to override the View class and add a method to do this.
Can anyone suggest a better approach ?
P.S. Security is not a concern here, since the administrator is basically a developer without access to the code.
In CakePHP 2.0:
The View::render() method imports the template file using
include
The include statement includes and evaluates the specified file.
The evaluated template is immediately executed in whatever scope it was included. To duplicate this functionality, you would need to use
eval()
Caution: The eval() language construct is very dangerous because it
allows execution of arbitrary PHP code. Its use thus is discouraged.
If you have carefully verified that there is no other option than to
use this construct, pay special attention not to pass any user
provided data into it without properly validating it beforehand.
(This warning is speaking to you, specifically)
...if you wish to continue... Here is a basic example of how you might achieve this:
$name = 'world';
$template = 'Hello <?php echo $name ?>... <br />';
echo $template;
// Output: Hello ...
eval(' ?>' . $template . '<?php ');
// Output: Hello world...
Which is (almost) exactly the same as:
$name = 'world';
$template = 'Hello <?php echo $name ?>... <br />';
file_put_contents('path/to/template.php', $template);
include 'path/to/template.php';
Except people won't yell at you for using eval()
In your CakePHP application:
app/View/EvaluatorView.php
class EvaluatorView extends View
{
public function renderRaw($template, $data = [])
{
if (empty($data)) {
$data = $this->viewVars;
}
extract($data, EXTR_SKIP);
ob_start();
eval(' ?>' . $template . '<?php ');
$output = ob_get_clean();
return $output;
}
}
app/Controller/ReportsController.php
class ReportsController extends AppController
{
public function report()
{
$this->set('name', 'John Galt');
$this->set('template', 'Who is <?php echo $name; ?>?');
$this->viewClass = 'Evaluator';
}
}
app/View/Reports/report.ctp
// Content ...
$this->renderRaw($template);
Alternatively, you may want to check out existing templating engines like: Mustache, Twig, and Smarty.
Hmmm.. Maybe create a variable that will store the generated code and just 'echo' this variable in ctp file.
I had similar problem (cakephp 3)
Controller method:
public function preview($id = null) {
$this->loadModel('Templates');
$tempate = $this
->Templates
->findById($id)
->first();
if(is_null($template)) {
$this->Flash->error(__('Template not found'));
return $this->redirect($this->referer());
}
$html = $template->html_content;
$this->set(compact('html'));
}
And preview.ctp is just:
<?= $html

Settings page and multi edit rows

I would like to make a configuration page like this for my CMS
http://img4.hostingpics.net/pics/72087272ok.png
I want this page (admin/settings/index) gets me the various settings (ID 1 to 21) came to my table and in case of change, I can, in this form, do an update
After 3 days of not especially fruitful research I found something. I put in my SettingsController:
admin_index public function () {
if (!empty($this->data)) {
$this->Setting->saveAll($this->request->data['Setting']);
} else {
$this->request->data['Setting'] = Set::combine($this->Setting->find('all'),
'{n}. Setting.id', '{n}. Setting');
}
}
and my view:
<?php
echo $this->Form->create('Setting', array ('class' => 'form-horizontal'));
foreach($this->request->data['Setting'] as $key => $value) {
echo $this->Form->input('Setting.' . $key . '.pair');
echo $this->Form->input('Setting.' . $key . '.id');
}
echo $this->Form->end(array('class' => 'btn btn-primary', 'label' => 'Save',
'value' => 'Update!', 'div' => array ('class' => 'form-actions')));
?>
he is recovering well all my information, I can even update. The trouble is that I do not really know how I can do to get the same result as my first screenshot. He puts everything in the textarea while in some cases I want the checkbox and / or drop-down.
please help me or explain to me how to make a page that retrieves configuration information from my table and allows me to edit without use an address like admin/settings/edit/ID
My table settings is something like this here
http://img4.hostingpics.net/pics/724403settings.png
If you are asking about how to format the output to produce a "settings" page, you will need to do it manually or add some kind of metadata to your table schema, such as "field_type".
Now Cake will automatically generate a checkbox for a boolean or tiny int, for example, but as you have varchars, ints, texts and so on, this won't work for you (pair is presumably varchar or text to allow for the different possible values.
You cannot really automagically generate the outputs you want without telling Cake.
One option would be to add a field_type to the table, so:
key value field
site_name My Site input
site_online 1 checkbox
meta_desc [some text] textarea
and something like
foreach($settings as $setting) {
echo $this->Form->{$setting['field']}($setting['key'],
array('value' => $setting['value']));
}
might do what you are after.
Or if($key=='site_name') // output a textbox
but this is not exactly ideal.

CakePHP question: How can i call a view of one controller from another controller?

This is posts/index.php =>
<?php foreach ($allposts as $post) {
echo '<tr class="class_row">';
echo '<td>';
echo $this->Html->link($post['Post']['title'],
array('controller'=>'posts','action'=>'view',$post['Post']['id']),
array('id'=>'id_anchor_title','class'=>'class_anchor_title') );
echo '<tr>';
echo '<td>';
}
?>
I want to call this posts/index.ctp from products/index.ctp => It will be a generic/common index.ctp for all controller. How can i do this ?
In posts/index.ctp the $allposts is used. It's set in posts/index action. But when i will call posts/index.ctp from products/index action different variable is set there. Suppose $this->set('allproducts',$allproducts); is set in products/index action. Now how can i use that allproducts variable in posts/index.ctp ?
As #Vins stated, you can use $this->render('view_name'); at the end of your controller action to render a different view (In your case it should be $this->render('/posts/index');)
In terms of using the variable you want, there are a couple things you can do. One would be to change your set function in each controller to use a common name. For example the posts controller could have $this->set('results',$allposts); and the products controller could have $this->set('results',$allproducts); Doing this, you can always reference $results in your view file. You might also want to set another variable, $pageModel. $this->set('pageModel','Product'); in your products controller for example. Then your posts/index.php file could do something like this:
<?php foreach ($results as $result) {
echo '<tr class="class_row">';
echo '<td>';
echo $this->Html->link($result[$pageModel]['title'],
array('controller'=>$this->controller,'action'=>'view',$result[$pageModel]['id']),
array('id'=>'id_anchor_title','class'=>'class_anchor_title') );
echo '<tr>';
echo '<td>';
}
?>
notice that I replaced 'controller' => 'posts' with 'controller' => $this->controller This will make your view dynamic so the links will always point to the view action of the correct controller.
I hope this helps!
We can use $this->render('view_name'); to use the another view for some other action. I'm not sure how exactly you're going to achieve your goal.
if you want to render posts/index.ctp instead of products/index.ctp, use $this->render('/posts/index');
Or you may want to put that in an element (that's the same idea of generic/common index.ctp).

How to reduce form code duplication in CakePHP

I have a form in CakePHP with a few dozen fields in it. From all the examples I have seen, there is duplicate form code for an add view and an edit view.
Is there any tricks to keep the duplication out? What is best method in CakePHP for this?
What I do, is to put all form fields in an element, and then insert the element in the add.ctp and edit.ctp
Don't forget to add the hidden field with the id in the edit.ctp
This way all visible elements are in one file, easier to maintain.
View/MyModel/add.ctp
echo $this->Form->create('MyModel');
echo $this->element('my_form');
echo $this->Form->end();
View/MyModel/edit.ctp
echo $this->Form->create('MyModel');
echo $this->Form->input('id');
echo $this->element('my_form');
echo $this->Form->end();
View/Elements/my_form.ctp
// your form inputs
// whatever they are
You should NOT merge those views, because add/edit are different actions and deserve separate view files. As your application grows you will realize that its good to have separate views to reduce complexity of if else conditions.
If you still want to avoid the separate files, Use
function add() {
.....
$this->render('edit')
}
I've done this before, but reverted back to having separate views, mainly for my own sanity.
It's easy enough to do. The edit requires an input for the record id. This is usually hidden. Any default form values for the add form will have to be contained in conditionals so that the stored values are not overwritten with defaults when you are editing a record
On the controller side of things, you'll need a conditional statement to decide whether to act as an add or edit depending on whether the $this->data['MyModel']['id'] is set.
I think that covers it - if I think of anything else I'll add it in.
My work pattern tends to be to build the edit view, then copy and paste to create the basis for the add view.
this code will check if you have admin_form.ctp or form.ctp which will make it use the same code for add / edit
https://github.com/infinitas/infinitas/blob/dev/app_controller.php#L389
1.3 submits the forms automatically to where the are from so when you go to /edit/1 it will post to there, and /add will post to add.
that is all you need to do. if you have a edit that is vastly different to the add, then you just create the 2 files. when you want them the same, just make the one.
in your app controller
public function render($view = null, $layout = null) {
$viewPaths = App::path('View', $this->plugin);
$rootPath = $viewPaths[0] . DS . $this->viewPath . DS;
$requested = $rootPath . $view . '.ctp';
if (in_array($this->request->action, array('admin_edit', 'admin_add', 'edit', 'add'))) {
$viewPath = $rootPath . $this->request->action . '.ctp';
if (!file_exists($requested) && !file_exists($viewPath)) {
if (strpos($this->request->action, 'admin_') === false) {
$view = 'form';
} else {
$view = 'admin_form';
}
}
}
return parent::render($view, $layout);
}
and in your view you can always check whether its edit or add
if ($this->request->params['action'] == 'admin_edit') {
//do something
}
if ($this->request->params['action'] == 'admin_add') {
//do something
}
in edit.ctp
if($this->data[ModelName]['id']) {
$this->Form->input('id');
}
// create rest of the fields
in Controller::add()
$this->autoRender=false; // at the start of function
$this->render('edit.ctp'); // at the point where you actually want to render
no need to create add.ctp

using cakephp, how do I handle model operations that return no results so my view doesn't break?

In my controller I have model operations that can return empty results. I've setup the view to display the results using a foreach loop. But if the model opertion is empty and returns no results then the foreach loop is breaking in my view.
This is the operation:
$match3 = $this->Draw->Match-> find('all',array('conditions'=>array('Match.draw_id'=>$id, 'Match.round_id'=> 1, 'Match.match_position' => 3)));
What do I need to add to the model operation to return null? Or is null the best way to handle this?
If there is no data then I don't want anything displayed.
I did try this but got an undefined index error:
if (!$match3)
return null;
else
return $match3;
Is there a best practice when it comes to handling empty model operations?
Much appreciated.
-Paul
IMO, the "best practice" isn't CakePHP-specific. If your result set it empty, it's critical to inform your users of that fact. It's a simple test (in this case for an empty array as indicated by Travis) and a simple result. I typically do it like this in my views:
<?php if( empty( $match3 ) ): ?>
<h2>Display an appropriate empty set message.</h2>
<?php else: ?>
# do whatever you need to do to display the result set
<?php endif; ?>
If your find operation has no results, it will just return an empty array.
In your view, just put some logic to make sure that $match3 isn't an empty array before you output that section. E.g., in the view
<?php
// some code here to output part of the page
if( !empty( $match3 ) )
foreach( $match3 as $matches )
; // do something with $matches
// rest of your view code
?>
Very much depending on your app, the following responses may be appropriate:
$result = $this->Model->find(…);
if (!$result) {
// redirect to another page and display message
$this->Session->setFlash('No results found');
$this->redirect(array('action' => 'index'));
}
or
if (!$result) {
// throw a 404 (or any other) error
$this->cakeError('error404');
}
Again, this very much depends on the app and the action in question, especially a 404 should not be a standard response. In many cases it's probably best to handle it in the view as advised by Rob.

Resources