Get HTMLPurifier 4.5 to allow only one tag - htmlpurifier

HTMLPurifier by default allows a lot of tags that I don't want to allow. According to the documentation you have to add definitions like this:
$config = HTMLPurifier_Config::createDefault();
if ($def = $config->maybeGetRawHTMLDefinition()) {
$def->addAttribute('a', 'target', new HTMLPurifier_AttrDef_Enum(array('_blank','_self','_target','_top')));
}
$purifier = new HTMLPurifier($config);
The problem is that I can't find a way to remove all tags that comes from HTMLPurifier_Config::createDefault();.
For example the HTML <div>Sometext</div> will keep the DIV tag using the above initialization code.
How can I set HTMLPurifier to only allow <strong>, <a href="*"> and <p>?

You say: "According to the documentation you have to add definitions like this".
Unless something fundamental has changed since the last time I checked the library (a year ago, about), that's not quite true - that part exists for if you want to teach HTML Purifier new attributes that it isn't natively aware of. For example, if you wanted to teach your HTML Purifier to accept non-standard <font> attributes, like align="", you'd need to alter the raw HTML definition.
However, if your whitelist consists purely of regular HTML elements (and yours does!), you just need to use the $config object:
$config = HTMLPurifier_Config::createDefault();
$config->set('HTML.AllowedElements', array(
'strong','a','p'
));
$config->set('HTML.AllowedAttributes', array(
'a.href'
));
$purifier = new HTMLPurifier($config);
That should work. Are you running into problems with that constellation?
(Check out this document, too: http://htmlpurifier.org/live/INSTALL )

The solution I found was to use the old way of configuring HTMLPurifier;
if($def = $config->maybeGetRawHTMLDefinition()) {
$config->set('HTML.AllowedElements', array(
'strong','a','p'
));
$config->set('HTML.AllowedAttributes', array(
'a.href'
));
}
How this works in relation with the HTMLDefinition I don't know. Maybe they have a compatability layer.
The biggest concern I have is that this is not using the $def variable returned - and that the changes I do to the config is not cached.

Related

Auto generating a value during update

I am using ef-core 2.1 with MSSQL, in OnModelCreating I use the following which auto populates a created field correctly:
modelBuilder
.Entity<MyModel>()
.Property(e => e.Created)
.HasDefaultValueSql("GETUTCDATE()")
.ValueGeneratedOnAdd()
.Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;
Additionally, I want to populate (and update thereafter) another field as follows:
modelBuilder
.Entity<MyModel>()
.Property(e => e.Modified)
.HasDefaultValueSql("GETUTCDATE()")
.ValueGeneratedOnUpdate()
.Metadata.ValueGenerated = ValueGenerated.OnUpdate;
However, this has no effect. In reading value-generated-on-add-or-update it is not clear to me if no facility exists to support this and a trigger is the only option or I simply have the configuration wrong.
The fluent method calls appear to support this, anyone know what I am doing wrong?
Hmm, I am not real familiar with what you are trying with .Metadata.ValueGenerated, however, I am doing something very similar in my project with success (note that my db is MySQL).
Maybe try like below.
modelBuilder
.Entity<MyModel>()
.Property(e => e.Modified)
.HasDefaultValueSql("GETUTCDATE()")
.ValueGeneratedOnAddOrUpdate();

Drupal-7 how to get hook_field_[formatter_]prepare_view() invoked without overwriting existing formatter

From my module, I'm looking for a way to change text-fields value during rendering process, but WITHOUT creating a new formatter, and BEFORE the currently affected formatter works.
In other words I want my changes always made on any text-field, as a generic preparatory step, regardless of which formatter will work afterwards.
For this to work:
I first considered using hook_field_formatter_prepare_view().
To get it invoked, I wanted to use hook_field_formatter_info_alter()
to add my module name to each involved formatter found here. But it
appears that the "module" index only accepts a unique module-name,
not an array.
BTW I'm quite surprised by this lack: I seem it should make sense to allow a sequence of formatters, like are allowed a sequence of
filters!
Then I considered using hook_field_prepare_view(), which seemed to
be the best candidate since the doc sayd it runs before the
formatters own hook_field_formatter_prepare_view(). But that
doesn't work either: this hook is invoked only for a field created by
the involved module (this issue had been discussed here).
Any idea? Thanks in advance.
I actually found a pretty way to do what I looked for.
The method is quite invasive but works fine and may be re-used for different cases.
1. To be as clear as possible, first I rephrase my question in terms of a
general use case:
In the rendering process, how to permit a module to change value of one or more
fields (given field-id, given field-type...) before the formatter (if any) do its own job?
2. The problem to accomplish this:
We can't make the module define a new formatter, because only one may
be defined at the same time for the same field
3. The strategy which led me to the desired result:
use hook_field_formatter_info_alter() to run through existing formatters and "graft" my module inside of those where I wish to intervene
(see detail under 4 below)
use hook_field_formatter_prepare_view() to:
(a) execute the required changes in field values
(the job my module is intended to: here it may be done or not, upon all fields of a given type or precisely identified fiels and so on, depending on any detailed needs)
(b) again run through formatters list and, when involved, fire their own hook_field_formatter_prepare_view() if it exists
(see detail under 5 below)
do the same job as in (b) above, successively for each of the other possibly involved hooks of any formatter:
hook_field_formatter_view()
hook_field_formatter_setting_form()
hook_field_formatter_setting_summary()
4. Detail about how to graft my module in the process:
Whith hook_field_formatter_info_alter(&$info) we face the following $info structure:
$info = array(
['formatter machine name'] = array(
['label'] => 'Human readable formatter description',
['field types'] => array(
[0] => 'a_field_type,
[1] => 'another_field_type',
# ...
),
['settings'] => array(
['option A'] => 'option A value',
['option B'] => 'option B value',
# ...
),
['module'] => 'formatter_module_name',
),
['formatter machine name'] = array(
# ...
),
# ...
);
We can easily run through the formatters list and look at "field types" index to select which ones are concerned by our needs.
Then for each involved one, we can:
substitute our own module name to formatter module name in "module" index
add a new sub-index in "settings" index (say "our module graft") to register the original formatter module name
So our hook_field_formatter_info_alter() will be something like:
function mymodule_field_formatter_info_alter(&$info) {
if($info) {
foreach($info as $name=>$formatter) {
if(
!#$formatter['settings']['mymodule graft'] # or already grafted
and
array_intersect($formatter['field types'],
array('text','text_long','text_with_summary')) # here it is for text fields only
) {
# substitute mymodule to original module:
$info[$name]['settings']['mymodule graft']=$formatter['module'];
$info[$name]['module']='mymodule';
}
}
}
}
Once flushing class registry, now all involved fields have their formatting phase redirected to our own module.
NOTE: installing a new formatter now requires flushing class registry again, in order our module to take it in hand also.
5. Detail about how to make original formatters to work after us:
As stated above, now it is our own module which is notified when a field has to been formatted, rather than the originally affected formatter.
So we must react in our hook_field_formatter_prepare_view(), which should look like:
function mymodule_field_formatter_prepare_view(
$entity_type,$entities,$field,$instances,$langcode,&$items,$displays
) {
# here we do our own job with field values:
if($items) {
foreach($items as $nid=>$node_data) {
# ...
}
}
# then we give original formatter a chance to execute its own hook:
foreach($displays as $display) {
$hook=
$display['settings']['mymodule graft'].'_field_formatter_prepare_view';
if(function_exists($hook)) {
$hook(
$entity_type,$entities,$field,$instances,$langcode,$items,$displays
);
}
}
}
Finally we also must give a chance to other formatters hooks to execute.
For each one, it should look like (replace HOOK and ARGS by the right data for each hook):
function mymodule_field_formatter_HOOK(ARGS) {
$hook=$display['settings']['mymodule graft'].'_field_formatter_HOOK';
if(function_exists($hook)) {
return $hook(ARGS);
}
}
Hope this helps...

CakePHP 2.5 plugin routes not loading

I'm attempting to update a site to CakePHP 2.5 from 2.4 but for some reason it is ignoring the routes from my plugins. I've figured out that CakePlugin::loadAll needs updating to the following:-
CakePlugin::loadAll(array(array(
'MyPlugin' => array(
'routes' => true
)
)));
However, it ignores the routes from MyPlugin (they don't appear to get loaded at all. I've got CakePlugin::routes() in my app/Config/routes.php file.
I've taken a look inside CakePlugin and CakePlugin::$_plugins seems to be setting MyPlugin['routes'] to false.
Can anyone shed any light on what's wrong here?
I gave a look at CakePlugin::loadAll() function and it looks like you are using function parameters in wrong way.
Here is a actual function:
public static function loadAll($options = array()) {
$plugins = App::objects('plugins');
foreach ($plugins as $p) {
$opts = isset($options[$p]) ? (array)$options[$p] : array();
if (isset($options[0])) {
$opts += $options[0];
}
self::load($p, $opts);
}
}
Which translate to - For each plugin:
Check if option has plugin name as key, if yes consider it's value as plugin settings
If option has numeric key (0), i.e. option without any key name, consider it as global plugin setting and add it to every plugin's setting
Just remove extra array in your options, and it should be fine.
CakePlugin::loadAll(array(
'MyPlugin' => array(
'routes' => true
)
));

CakePHP's Translate Behavior not working with Containable

I've implemented CakePHP's Translate Behavior, and all went fairly smooth, but I've now noticed that my translated data from the i18n table doesn't exist when I contain() a model that is supposed to be translated.
Does the Translate Behavior not work for contained models? If so, doesn't that near-completely remove any usefulness of this behavior? (Or maybe it's just me - but I use Containable for just about everything).
Is there a different "CakePHP-way" to do translations fairly easily if I plan to use Containable a lot?
I've encountered similar problem, read dozens of pages from Google, but couldn't find a simple solution to my problem. After some debugging I've created this workaround snippet. Please take in consideration that this is jus a hack. It was mostly written for Croogo, so related models will appear translated on site. But i've browsed Translate behavior and it should work for it as well. Basically paste it in your AppModel Class. It's for Cake 2.x
// DIRTY LITTLE HACKS, FORCING TRANSLATE BEHAVIOR AFTERFIND CALLBACK
/**
* Hacking the afterFind so it will call the afterFind() from
* behavior
* Pase this in your AppModel Class
*
* #param array $results
* #param bool $primary
* #return array
*/
public function afterFind(array $results, $primary = false) {
parent::afterFind($results, $primary);
# calling only if not primary model, as they get translated pretty well
if (!$primary) {
# iterating behaviors to look for one that has something to do
# with translations ( Translate for cake general behavior, CroogoTranslate for Croogo based apps )
foreach ($this->Behaviors->enabled() as $behavior) {
if (preg_match('/(.*)[T|t]ranslate(.*)/', $behavior)) {
# setting locale, not sure if it gets set on secondary models
$this->locale = Configure::read('Config.language');
# hacking the result set to match behaviours requirments
# so basically creating the result set to look like called from originated model
# $k => array('ModelAlias' => array $results)
$results_tmp = array(
0 => array(
$this->alias => $results,
)
);
# if we find such behavior we force it's afterFind with prepared data
$results = $this->Behaviors->{$behavior}->afterFind($this, $results_tmp, true); # forcing true on primary - CroogoTranslate requires that
# restoring orginal structure like nothing ever happened
$results = $results[0][$this->alias];
# not sure if should break or not ?
# on one hand what's the point of having multiple translate behaviors in one app ?
# on the other i've seen more weird stuff that multiple translate behaviors
break;
}
}
}
return $results;
}
Apparently this is a common issue. The CakePHP Cookbook has some hints about how to handle it:
http://book.cakephp.org/2.0/en/core-libraries/behaviors/translate.html

how do i include a tpl file in my module drupal 7

I'm building a module using hook_preprocess_node()
I've made a new view mode for the node entity called ´vacancy_teaser´ using the hook_entity_info_alter()
this shows up in my node display settings and view
so I want to use the template included in my module when this view mode is used.
my code:
/**
* Implements hook_preprocess_node().
*/
function vacancies_preprocess_node(&$vars) {
if($vars['view_mode'] == 'vacancy_teaser') {
$vars['theme_hook_suggestions'][] = 'node_vacancy_teaser';
}
}
my template file is called: ´node-vacancy-teaser.tpl.php´ but is not used in the output of my view
$vars['view_mode'] == 'vacancy_teaser' in the view. ( tested )
but where does $vars['theme_hook_suggestions'][] = 'node_vacancy_teaser'; looks for the template file? somehow it's not included / used.
apparently in drupal 7 useing dubble underscores is required for some reason.
node_vacatures_vacancy_teaser.tpl.php placed in the active template folder seems to do the trick... although I don't think this is a neat solution since the tpl.php file is separated from the module.
Be sure to specify the template file in the hook_theme implementation. The examples project is great for finding out the details of how to do things like this. Specifically, check out the theming_example_theme() function in the theming_example module…
function theming_example_theme() {
return array(
// …
'theming_example_text_form' => array(
'render element' => 'form',
// In this one the rendering will be done by a tpl.php file instead of
// being rendered by a function, so we specify a template.
'template' => 'theming-example-text-form',
),
);
}
Instead of appending to the end of the $vars['theme_hook_suggestions'] array, try:
array_unshift($vars['theme_hook_suggestions'], 'node_vacancy_teaser');
This will pass your suggestion to the front of the array, and it will be found first. Most likely since you are appending it to the end of the array, Drupal is finding an existing theme suggestion first and using it instead (such as node.tpl.php).

Resources