Forum Moderators: coopster

Message Too Old, No Replies

complex array map question

htmlentities ENT_NOQUOTES

         

Stuperfied

11:59 am on Dec 15, 2006 (gmt 0)

10+ Year Member



How would I go about specifying ENT_NOQUOTES in a htmlentities array_map?

Would this be correct?


$value = array_map('htmlentities', $value, ENT_NOQUOTES);

eelixduppy

12:17 pm on Dec 15, 2006 (gmt 0)



Looks good.

Stuperfied

12:43 pm on Dec 15, 2006 (gmt 0)

10+ Year Member



Thanks anyway, answered my own question.


$attrib[0] = ENT_NOQUOTES;
$value = array_map('htmlentities', $value, $attrib);

Stuperfied

6:03 am on Dec 16, 2006 (gmt 0)

10+ Year Member



Ok, now im just confused. During all tests in a test.php script, all variations of the following code failed.

$value = array_map('htmlentities', $value, ENT_NOQUOTES);

After viewing repeated error messages stating that array_map expected parameter 3 to be an array, I decided to give it one and every one of my tests, using the following code, was then a success.


$attrib[0] = ENT_NOQUOTES;
$value = array_map('htmlentities', $value, $attrib);

However, in production, the same script failed as such.


function quote_smart($data) {
if (is_array($data)) {

// Trim & htmlentities
$data = array_map('trim', $data);
$attrib[] = ENT_NOQUOTES;
$data = array_map('htmlentities', $data, $attrib);

echo '<br />l_id: ' . $data['l_id']; // normally should return username but for some reason return's "" instead;

// Stripslashes
if (get_magic_quotes_gpc()) {
$data = array_map('stripslashes', $data);
}
else {
$data = array_map('addslashes', $data);
}

// Quote if not a number or a numeric string
if (!array_map("is_numeric", $data)) {
$data = array_map("mysql_real_escape_string", $data);
}
}
else {

// Trim & htmlentities
$data = trim($data);
$data = htmlentities($data, ENT_NOQUOTES);

// Stripslashes
if (get_magic_quotes_gpc()) {
$data = stripslashes($data);
}
else {
$data = addslashes($data);
}

// Quote if not a number or a numeric string
if (!is_numeric($data)) {
$data="'" . mysql_real_escape_string($data) . "'";
}
}

return $data;
}

Help please before I go insane!

pinterface

8:16 am on Dec 16, 2006 (gmt 0)

10+ Year Member



from array_map [php.net]:
If the arrays are of unequal length, the shortest one will be extended with empty elements.

In other words (using [] as shorthand for array()):

array_map('html_entities', [x, y, z], [ENT_QUOTES]);

is the same as
html_entities(x, ENT_QUOTES);
html_entities(y, null);
html_entities(z, null);

which is, naturally, not at all what you want.

Unfortunately, PHP's support for functional programming is sorely lacking. But this is a fairly simple case--all you need is to create a new function which calls html_entities:

function ehtml($x) { return html_entities($x, ENT_QUOTES); }
// ...
array_map('ehtml', [x, y, z]);

or
array_map([url=http://php.net/create_function]create_function[/url]('$x', 'return html_entities($x, ENT_QUOTES);'), [x, y, z]);

Stuperfied

11:51 am on Dec 16, 2006 (gmt 0)

10+ Year Member



Unfortunately it seems, in actual fact, that it is a bit more complicated than all that. First of all, I understand completely what you are telling me, however I did not know that empty values were set to NULL. The first functional example you provided is what I have planed to use failing a shorter and simpler version.

My problem is that the results I am getting are not what are expected. For example, please examine the following code fragment.
- test.php -


$value[0] = '<a href="test.php">&quot;home&quot;</a>';
$value[1] = '<a href="test.php">&quot;home&quot;</a>';

$attrib[0] = ENT_NOQUOTES;
$attrib[1] = ENT_QUOTES;

echo "<br />before 1: " . $value[0];
echo "<br />before 2: " . $value[1];

$value = array_map('htmlentities', $value, $attrib);

echo "<br />after 1: " . $value[0];
echo "<br />after 2: " . $value[1];


In my test.php script, I got the results I expected which are as follows.

Document -
before 1: "home"
before 2: "home"
after 1: <a href="test.php">&quot;home&quot;</a>
after 2: <a href="test.php">&quot;home&quot;</a>

Source -
<br />
before 1: <a href="test.php">&quot;home&quot;</a><br />
before 2: <a href="test.php">&quot;home&quot;</a><br />

after 1: &lt;a href="test.php"&gt;&amp;quot;home&amp;quot;&lt;/a&gt;<br />
after 2: &lt;a href=&quot;test.php&quot;&gt;&amp;quot;home&amp;quot;&lt;/a&gt;


However, in my production page as follows.
- quote_smart.inc -

// $_POST = $l_id and $p_word as typed by the user in login.
// $data = $_POST and is passed to quote_smart.

function quote_smart($data) {
if (is_array($data)) {

// Trim & htmlentities
$data = array_map('trim', $data);
$attrib[0] = ENT_NOQUOTES;
$attrib[1] = ENT_NOQUOTES;
$data = array_map('htmlentities', $data, $attrib);

// Stripslashes
if (get_magic_quotes_gpc()) {
$data = array_map('stripslashes', $data);
}
else {
$data = array_map('addslashes', $data);
}

// Quote if not a number or a numeric string
if (!array_map("is_numeric", $data)) {
$data = array_map("mysql_real_escape_string", $data);
}
}
else {

// Trim & htmlentities
$data = trim($data);
$data = htmlentities($data, ENT_NOQUOTES);

// Stripslashes
if (get_magic_quotes_gpc()) {
$data = stripslashes($data);
}
else {
$data = addslashes($data);
}

// Quote if not a number or a numeric string
if (!is_numeric($data)) {
$data="'" . mysql_real_escape_string($data) . "'";
}
}

return $data;
}


In this code, the $data['l_id'] contains the username before the array_map but after the array_map, it is empty. I dont know why and I hope I have not confused you but I really do not understand how 2 pages with the same code can produce such different results. Any ideas?

pinterface

12:53 am on Dec 17, 2006 (gmt 0)

10+ Year Member



Another test you might want to try goes something like this:
function catenate ($x, $y = '!') { return $x . $y; }
$arr = ['cat' => 'hat', 'monkey' => 'poo'];
$args = ['ly', 'fy'];
print_r(array_map('catenate', $arr));
print_r(array_map('catenate', $arr, $args));

Notice the difference between the arrays returned by the first and the second array_map. Does that help explain the problem you're having?


That said, your function could be shortened quite a bit (untested, but should give you the general idea):

function quote_smart($data) {

    if (is_array($data)) {

      /* array_map already does what you want for strings and numbers, so why duplicate it? */
      return array_map('quote_smart', $data);

    } else {

      // Trim & htmlentities
      $data = htmlentities(trim($data), ENT_NOQUOTES);

      /* I'm fairly confident the else branch was a bug: it would end up inverting the effect of magic_quotes, so magic_quotes on meant off and off meant on. Presumably you only wanted to undo it being on. */

      // Stripslashes
      if (get_magic_quotes_gpc()) {
      $data = stripslashes($data);
      }

      // Quote if not a number or a numeric string
      if (!is_numeric($data)) {
      $data="'" . mysql_real_escape_string($data) . "'";
      }
      return $data;
    }
}

Stuperfied

5:25 am on Dec 17, 2006 (gmt 0)

10+ Year Member



You have explained it most clearly. Yes, you are correct in that it was a bug. I didnt notice that. Thank you for your suggestion in reducing the code, I will follow your example. However with limited time, for now I simply modified my code with your example.

$data = htmlentities(trim($data), ENT_NOQUOTES);

Here is the results.

Warning: array_map() [function.array-map]: Argument #3 should be an array in \test\template\lib\quote_smart.inc on line 9

Warning: array_map() [function.array-map]: Argument #2 should be an array in \test\template\lib\quote_smart.inc on line 16

Warning: array_map() [function.array-map]: Argument #2 should be an array in \test\template\lib\quote_smart.inc on line 20

Warning: array_map() [function.array-map]: Argument #2 should be an array in \test\template\lib\quote_smart.inc on line 21

Warning: Cannot modify header information - headers already sent by (output started at \test\template\lib\quote_smart.inc:9) in \test\template\admission\validate.php on line 42


I have obviously modified the path so as not to show a true location on the server but you get the idea.

Stuperfied

1:12 am on Dec 18, 2006 (gmt 0)

10+ Year Member



The finished product.

function quote_smart($data) {

if (is_array($data)) {
$data = array_map('quote_smart', $data);
}
else {

// Trim & htmlentities
$data = htmlentities($data, ENT_NOQUOTES);

// Stripslashes
if (get_magic_quotes_gpc()) {
$data = stripslashes($data);
}

// Quote if not a number or a numeric string
if (!is_numeric($data)) {
$data = mysql_real_escape_string($data);
}
}

return $data;
}


Thank you very much for all your help, it is most appreciated.