Filter according to profile

Amitaibu - October 22, 2007 - 08:07
Project:Custom filter
Version:5.x-1.0
Component:Documentation
Category:support request
Priority:normal
Assigned:Unassigned
Status:closed
Description

Hi,
Is it possible to have the following:
* In the profile, I've added a field that user selects his working units CM or Inch.
* I'd like to have a filter that can handle something like [cm=1|inch=2.54]. The filter will need to check the settings from the profile, and act accordingly (i.e. show 1cm, or 2.54'').

#1

arhip - October 22, 2007 - 13:09

Yes, it is possible. You can get the unit being used from table {profile_values}. We need two parameters, fid and uid. uid can be retrieved using global variable $user->uid. fid can be retrieved from table {profile_fields}.

Below is the pattern & replacement code. First you must create a filterset, and create a new filter under that filterset. At line 13, $fieldname should be assigned to field name.

Pattern:

/([0-9]+(\.[0-9]*)?)(mm|cm|inch)/i

Replacement (with PHP code):

if (! isset($vars->units)) {  // following code will execute once
  global $user;

  $vars->units = array();

  // define the conversion table
  $vars->units['conv'] = array(
    'mm' => 0.1,
    'cm' => 1,
    'inch' => 2.54);

  // get the field name
  $fieldname = 'profile_unit';      // <--------- change this according to your field name

  // get field ID from table {profile_fields}
  $unitfield = db_fetch_array(
    db_query("SELECT fid FROM {profile_fields} WHERE name='%s'",
       $fieldname));

  // get user preferred unit
  $unitsel = db_fetch_array(
    db_query("SELECT value FROM {profile_values} WHERE fid=%d and uid=%d",
       $unitfield['fid'], $user->uid));

  // and assign to $vars->units['unit']
  $vars->units['unit'] = $unitsel['value'];
}

// the value is in the first bracket
$value = $matches[1];
// the unit is in the third bracket
$unit = $matches[3];

// Converts all values to cm
$valuecm = $value * $vars->units['conv'][$unit];
// Converts cm to user's preferred unit
$value2 = $valuecm / $vars->units['conv'][$vars->units['unit']];

return $value2 . $vars->units['unit'];

#2

Amitaibu - October 22, 2007 - 13:10

Thanks a lot! I'll check it and report back :)

#3

Amitaibu - October 22, 2007 - 13:20

Silly question, but what is the syntax that I should write?

#4

Amitaibu - October 22, 2007 - 13:28

Ok, seems to be a problem there:
When I type "This is 90cm", I get only "This is" and an error:

warning: Division by zero in C:\wamp\www\drupal\modules\customfilter\customfilter.module(1004) : runtime-created function on line 37.

Can't it be because in my profile working units appear as CM and Inch (i.e. case sensitive)?

#5

arhip - October 22, 2007 - 13:53

I think so.

Maybe you should change the line 34-37 into:

// Converts all values to cm
$valuecm = $value * $vars->units['conv'][strtolower($unit)];
// Converts cm to user's preferred unit
$value2 = $valuecm / $vars->units['conv'][strtolower($vars->units['unit'])];

to convert all units processed into lowercase.

AttachmentSize
Untitled-1_5.jpg 53.44 KB

#6

Amitaibu - October 25, 2007 - 16:26
Status:active» fixed

Dude, what a great module!

Here's my final version, for everybody to enjoy...

Name:

Working units

Pattern (that will except 1inch, 1 inch, 1.5 inch):

/([0-9]+(\.[0-9]*)?)[ ]*(mm|cm|meter|inch|yard)/i

Replacement text:

if (! isset($vars->units)) {  // following code will execute once
  global $user;

  $vars->units = array();

  // define the conversion table
  $vars->units['conv'] = array(
    'mm' => 0.1,
    'cm' => 1,
    'centimeter' => 1,
    'meter' => 100,
  // We'll make inch 2.5 instead of 2.54, and Yard 91.5 instead of 91.44
    'inch' => 2.5,
    'yard' => 91.4);

  // get the field name
  $fieldname = 'profile_working_units';      // <--------- change this according to your field name

  // get field ID from table {profile_fields}
  $unitfield = db_fetch_array(
    db_query("SELECT fid FROM {profile_fields} WHERE name='%s'",
       $fieldname));

  // get user preferred unit
  $unitsel = db_fetch_array(
    db_query("SELECT value FROM {profile_values} WHERE fid=%d and uid=%d",
       $unitfield['fid'], $user->uid));

  switch ($unitsel['value']) {
case 'Centimeter':
    $unitsel['value']='cm';
    break;
case 'Inch':
    $unitsel['value']='inch';
    break;
}

  // and assign to $vars->units['unit']
  $vars->units['unit'] = $unitsel['value'];
}

// the value is in the first bracket
$value = $matches[1];
// the unit is in the third bracket
$unit = $matches[3];

// Converts all values to cm
$valuecm = $value * $vars->units['conv'][strtolower($unit)];
// Converts cm to user's preferred unit
$value2 = $valuecm / $vars->units['conv'][strtolower($vars->units['unit'])];

return $value2 . $vars->units['unit'];

And the PHP code enabled.

Cheers!

#7

Amitaibu - October 25, 2007 - 16:35
Status:fixed» active

One problem, though...

Some users have CM in their profile and some Inch. I'd like the created content to show the values for every user according to their preference.

Is this module supposed/ can do this, or should I hack the theme?

#8

arhip - October 26, 2007 - 00:54

If I don't misunderstand, you want the content displayed like this:

Some title

User's working unit: CM

Some text some text some text some text some text some text some text some text some text some text some text some text some text some text some text some text some text some text some text some text some text some text some text some text

We can use ^ to insert the text we want at the top. ^ matches the beginning of the string. So you can create a new filter with this configuration:

Pattern:

/(^)/

Replacement:

return "<div class=\"workingunit\">User's working unit: {$vars->units['unit']}</div>";

with PHP Code checked.

Create this new filter under the same filterset you're working on, and make sure to set it's weight more than Working units filter, since $vars->units won't be recognized before Working units filter executed.

But I think it would be nicer if you put this working unit information in a block.

#9

Amitaibu - October 26, 2007 - 05:22

I actaully mean something a bit different.

Title: hello world

body:
Some text some text some text 1 Inch some text some text

Now, I'd like the users who have CM defined in their profile to see the text like this:

body:
Some text some text some text 2.54 cm some text some text.

#10

arhip - October 26, 2007 - 11:41

Oh, I'm sorry to misunderstand.

I'm sorry again to say that it is not possible (as long as I know) to do that only using this module. Since a filter will be executed once after we submit the content, we cannot change the content every time the content displayed. And since the current user's settings could affect a content only if the filter executed again, then there is no possible way to do that.

But I think we can get this effect by 2 way:

  • Combining with PHP filter, or
  • Inserts javascript

I'm trying each of this ways. I'll report you if any of these works.

#11

Amitaibu - October 26, 2007 - 15:47

Oh man, thank you so much for your help! waiting to see your results..

#12

Amitaibu - October 26, 2007 - 19:07

Not a developer, but I'm thinking maybe it's possible to use your filter to add for example <div class="working units>, that later will be replaced with to correct working units.

#13

arhip - October 27, 2007 - 00:56

I think we can't use <div>s nor javascripts, because we need to get $user->uid to know which user is being logged, and we can only do this on the server. The PHP filter solution does work, because it will be executed on the server. I attach the sample working units filter (as plain text file).

For this filter to work, you need to turn on PHP Filter in the input format, and make sure it weights more than working units filter, so the PHP script produced could be executed.

The filter works like this:

  • First, it declares all variables needed
  • Next, it replaces all occurence of values in your content with some PHP code to do the conversion. These values are temporarily converted into what I called universal factor.
  • Next, this writes a PHP script on the top of the content, to get the current user's information, and define the conversion table.
  • The PHP Filter will execute all PHP codes produced by previous filter.

The customfilter module lacks the function to turn off cache, so that filters will run only when a content submitted. If only this module could turn cache off for particular filterset, then the code you submit on #6 will work as you wish. I'm working on the patch version. Thanks for your question, it really helps me to improve this module.

AttachmentSize
workingunits.txt 3.89 KB

#14

Amitaibu - October 27, 2007 - 05:24

Sound interseting. One problem, though, is probably security - allowing user to use PHP. You think any posibble way not to use PHP filter for that?

#15

arhip - October 27, 2007 - 07:15

Yes, it is very vulnerable, unless we can create a filter that strips any <?php ... ?> before our filter executed. I have added option 'cache' in the filterset edit page. The development release should be available soon (within 12 hours - the tarball created every 12 hours). You can try it when available. Using this fixed module, you don't need PHP filter. I've tried your code #6 with cache turned off, and it worked. Note that you should refresh the Input Format for the filter work properly (by saving the configuration again).

#16

Amitaibu - October 28, 2007 - 10:15

Ari,
I've imported configuration from #13, but something seems to be written wrong there. Checkout the snapshot - all text is replaced with

1, 'mm' => 0.1, 'cm' => 1, 'm' => 100, 'inch' => 2.5, 'yard' => 91.4, );$unit_aliases = array('cm' => 'centimeter', 'mm' => 'milimeter', 'm' => 'meter', );$unitsel = db_fetch_array( db_query("SELECT value FROM {profile_values} WHERE fid=%d and uid=%d", 1, $user->uid)); $unit_unit = strtolower($unitsel['value']);$aliaskey = array_search($unit_unit, $unit_aliases); if ($aliaskey) $unit_unit = $aliaskey;$unit_precision = 2; ?>

AttachmentSize
Snap1_20.png 13.2 KB

#17

arhip - October 28, 2007 - 13:56

Oh, it seems that the PHP evaluator wasn't executed. Please check the:

  • Input Format configuration, have you check PHP evaluator?
  • Rearrange tab, make sure PHP evaluator weights more than Working Units

#18

Amitaibu - October 28, 2007 - 14:13

It works great! but the fact that I've enabled PHP evaluator doesn't mean that there is a security threat? How can I make sure users doesn't use PHP on my site?

#19

arhip - October 28, 2007 - 16:45

You can define a new filter that will flush all <?php ?>. This filter must be executed first, because we don't want any php code get into PHP evaluator.

Filterset: UnPHP

Filter: Strip PHP code

Pattern: /\<\?php(.*?)\?\>/s

Replacement: <code type="php">$1</code>

And you should rearrange the input format in this order:

  1. UnPHP
  2. Working Units
  3. PHP Evaluator

So that any PHP from users cannot reach PHP evaluator, while PHP produced by Working Units can.

#20

Amitaibu - December 20, 2007 - 14:51

What will happen if user enters <? php <?php print ('hello'); ?> ?> - does this replace it properly?

#21

arhip - December 31, 2007 - 12:01

No, that would be converted into

<code><?php print ('hello');< /code> ?>

But I think that's ok, that broken code wouldn't be executed. I think you'd better use the cache option (#15) instead of PHP filter.

#22

Amitaibu - December 31, 2007 - 13:09

use the cache option (#15) instead of PHP filter.

Didn't understand this part

p.s. welcome back :)

#23

arhip - December 31, 2007 - 15:58

CustomFilter 5.x-1.2 supports cache option in filterset edit operation. When Drupal saves a content, it can be cached, so that any filter applied to the input only calculated once and then the result cached. Or, we can turn off cache, so that any filter applied to the input will be calculated every time the content viewed.

For working unit case, we can turn off this option, because every unit written should be calculated every time the content viewed. If you're going to use this method, then you can just use your filter in #6, and turn off cache option in the filterset settings.

AttachmentSize
cache.png 6.24 KB

#24

kiamlaluno - July 1, 2009 - 14:44
Status:active» fixed

i am setting the report as fixed because it got an answer.

#25

kiamlaluno - July 1, 2009 - 14:44
Title:filter according to profile» Filter according to profile

#26

System Message - July 15, 2009 - 14:50
Status:fixed» closed

Automatically closed -- issue fixed for 2 weeks with no activity.

 
 

Drupal is a registered trademark of Dries Buytaert.